AudiScale Connector

Description

AudiScale Connector is the companion component for the hosted AudiScale service (https://audiscale.com). It unlocks the SEO actions that WordPress core and the standard REST API do not allow — most notably printing a <meta name="description"> tag in the <head> without forcing you to install another SEO plugin.

Service disclosure (SaaS)

This plugin communicates with the third-party AudiScale service. No data is
sent until you have explicitly paired
your site from your AudiScale dashboard.
Once paired, AudiScale can remotely apply a fixed catalog of operations
(listed below), each of which is:

  • signed with HMAC-SHA256 using a per-site secret (rotatable and revocable);
  • subject to a WordPress capability check (manage_options);
  • logged (who, what, when, before/after value);
  • reversible where possible (draft/revision, dry-run).

The plugin never executes arbitrary code: there is no code-evaluation
endpoint and no remote code download. “Almost everything” means an enumerated,
hand-coded, audited catalog.

  • Terms of service: https://audiscale.com/en/terms
  • Privacy policy: https://audiscale.com/en/privacy

Operation catalog

  • SEO / <head>: meta description, SEO title, canonical, robots, Open Graph, Twitter cards, native sitemap exclusion
  • Redirects: create / update / delete (301, 302, 410)
  • Structured data: per-content JSON-LD
  • Content & media: field updates (via revision), draft creation, alternative text, status change (publish/draft only), move to trash and restore from it, listing of trashed contents
  • Taxonomies: read the taxonomies and terms a post type declares, assign existing terms to a content (never creates a term)
  • Site (read-only): robots.txt, public settings, content inventory, theme design system (global styles presets, theme supports, block patterns)
  • Draft preview: short-lived signed link rendering one draft in the real theme (never published, noindex)
  • Site (footer): marked HTML block printed on wp_footer (badge install / removal)
  • Plugins: inventory with update availability, forced update check, update of an installed plugin (the installed version is archived first), rollback to the archived version
  • Performance: preconnect / font preload hints, Google Fonts display=swap and self-hosting, removal of emojis / oEmbed / jQuery Migrate / Dashicons for visitors, script defer / async / delay until interaction, per-page removal of unused scripts and styles, scripts and styles inventory, server environment report — each one reversible, previewable before it goes live, and switched off at once from the Connection tab
  • Page builders: read and update a page in the builder it is edited with (Elementor, Divi, WPBakery, Beaver Builder), and create a new page directly in that builder
  • Crawl log (read-only): which pages search and AI crawlers request, with the HTTP status
  • Users (optional, see below): list the site’s users, change a role, sign a user out, revoke application passwords, send WordPress’s password-reset email, require a new password at next login, disable / re-enable login, delete with post reassignment
  • Connector: status, pairing, audit log

The plugin detects Yoast, Rank Math and SEOPress and stands down
automatically if one of them already manages the <head>, to avoid duplicate
tags.

Files downloaded to your site (performance features)

Only when AudiScale asks for it through a signed operation, never while a visitor
loads a page:

  • Google Fonts self-hosting (perf.fonts.set with selfHost): the plugin
    downloads the Google Fonts stylesheets the site already uses from
    fonts.googleapis.com and the font files they reference from
    fonts.gstatic.com, into wp-content/uploads/audiscale-fonts/. Visitors then
    load the fonts from your own domain, so their IP address is no longer sent to
    Google on each page view. No other host is contacted, and no request carries
    visitor data.
  • Plugin archives: once the site is paired, before any plugin update (from
    AudiScale, from wp-admin or a WordPress auto-update), the installed version is
    zipped into a private folder under wp-content/uploads/ (random folder and file
    names, an index.php in every folder, closed to web access on Apache) so it can
    be restored. One archive per plugin, deleted after 90 days; its SHA-256 checksum
    is verified before any restore. Nothing is archived on a site that is not paired.

Crawl log

On a paired site, the plugin records the requests of known search and AI
crawlers (Googlebot, Bingbot, Applebot, Amazonbot, GPTBot, OAI-SearchBot,
ChatGPT-User, PerplexityBot, ClaudeBot, CCBot, Bytespider, meta-externalagent):
the crawler name, whether its identity was verified, the requested path
without its query string, the HTTP status and the time. No IP address, no
User-Agent string and nothing about human visitors is stored
; a request that
does not come from a known crawler is never written.

Googlebot, Bingbot, Applebot and Amazonbot are verified the way their operators
document it (reverse DNS, then forward confirmation), cached one day under a
hashed key; a request that claims one of them and fails verification is dropped.
The other crawlers publish no such domain and are recorded as declared, not
verified. The log keeps 30 days and 30,000 rows at most, can be switched off
(and emptied) from “AudiScale Connection”, and AudiScale reads it once a day
through the signed crawl.log.read operation. A suggested paragraph is added
to the WordPress privacy policy guide (Settings Privacy).

The plugin never downloads or executes code: archives are only ever reinstalled
through the WordPress upgrader, from files the site itself produced.

Remote user management (optional, off by default)

Nothing here happens until the site owner explicitly turns on “user management”
for this site in AudiScale, and AudiScale then asks the owner to approve each
change before it sends it. What AudiScale can then do, on the current site only:

  • list the users: id, login, display name, email address, roles, registration
    date, last login, two-factor status (Two Factor, Solid Security, WP 2FA or
    Wordfence Login Security, when one of them is active), number of application
    passwords, and whether the account is disabled or must choose a new password
    (users.list, list_users);
  • change a user’s role (users.role.set, promote_users, limited to the roles
    the connected account may itself assign);
  • sign a user out everywhere (users.sessions.destroy, edit_users);
  • revoke all of a user’s application passwords (users.app_passwords.revoke,
    edit_users);
  • send WordPress’s own password-reset email to the user
    (users.password_reset.send, edit_users);
  • require a new password at the next login, and sign the user out
    (users.password_reset.force, edit_users) — lifted once the user resets
    their password through “Lost your password?”;
  • disable and re-enable login (users.disable, users.enable, edit_users):
    a disabled account can log in neither with its password nor with an
    application password; its content is left untouched;
  • delete a user (users.delete, delete_users; on multisite, remove_users
    and the user is only removed from this site), always reassigning their posts
    to another active user of the site. A deletion cannot be undone.

AudiScale never sees, sends or sets a password: a reset always goes through
WordPress’s own email and the user’s own choice. User lists are fetched on
demand and not stored by AudiScale.

Each change is logged locally in the plugin’s audit log: the operation, the
target user id, the roles or flags before and after (for a deletion, the login,
its roles and the user receiving the posts), the WordPress user AudiScale acts
as, and the time. No email address and no password is ever logged.

Safeguards, enforced by the plugin whatever AudiScale asks:

  • the last administrator able to log in can be neither demoted, disabled nor
    deleted;
  • the account AudiScale is connected with cannot have its role changed, be
    disabled, be deleted or lose its application passwords;
  • on multisite, only a super admin can act on a super admin, and WordPress’s own
    per-user capability checks always apply.

The login block and the forced reset live in user meta
(audiscale_login_disabled, audiscale_password_reset_required); deactivating
or uninstalling the plugin lifts them.

External services

This plugin connects to two external services.

AudiScale

The hosted AudiScale service (https://audiscale.com), which this plugin is the
companion of. Nothing is sent until an administrator pairs the site. Once paired,
AudiScale sends signed operation requests to the site, and after an update the
plugin sends the installed plugin version and the site URL back to AudiScale
(one request per version).

  • Terms of service: https://audiscale.com/en/terms
  • Privacy policy: https://audiscale.com/en/privacy

Google Fonts

Used only when AudiScale turns on Google Fonts self-hosting (perf.fonts.set with
selfHost), and only during that operation — never while a visitor loads a page.
The site’s server requests, from fonts.googleapis.com, the Google Fonts
stylesheets the site already loads, then, from fonts.gstatic.com, the font files
those stylesheets reference. The requests carry the server’s IP address and a
browser User-Agent string (Google only serves WOFF2 files to a browser it
recognizes); they carry no visitor data and no site data beyond the stylesheet URLs.
Afterwards visitors load the fonts from the site itself, so their IP address is no
longer sent to Google.

  • Google Terms of Service: https://policies.google.com/terms
  • Google Privacy Policy: https://policies.google.com/privacy
  • Google Fonts FAQ (privacy): https://developers.google.com/fonts/faq/privacy

Installation

  1. Install and activate the plugin (from wordpress.org or by uploading the ZIP).
  2. From your AudiScale dashboard, start pairing: AudiScale calls POST /wp-json/audiscale/v1/pair with a secret generated on the AudiScale side.
  3. That’s it — subsequent operations are signed with that secret.

To revoke access at any time: “Settings AudiScale Disconnect”, or disconnect
the site from AudiScale.

FAQ

Does the plugin send data without my consent?

No. No communication happens until the site is paired, and pairing requires an
administrator (manage_options).

What happens if I already have an SEO plugin?

AudiScale Connector detects Yoast / Rank Math / SEOPress and prints nothing in
the <head> to avoid duplicates.

How do I revoke access?

Unpairing erases the pairing secret: the command channel becomes inert
immediately. It also switches off every performance setting AudiScale applied.

How do I switch off the performance optimizations?

“AudiScale Connection Switch off AudiScale optimizations” removes them at
once, without AudiScale. Deactivating the plugin removes them too: they are
applied while pages load, nothing is written into your theme or plugin files.

My server runs nginx: are the plugin archives protected?

The archives live in a folder with a random name and random file names, with an
index.php in every folder, and an .htaccess that Apache honors. nginx ignores
.htaccess, so add this rule to the site’s server block:

location ~* /wp-content/uploads/audiscale-backup- { deny all; }

Can AudiScale see or change my users’ passwords?

No. Remote user management is off until you enable it for the site in AudiScale,
and every change needs your approval there. Even then AudiScale can only send
WordPress’s own password-reset email or require a new password at the next
login: the password is always chosen by the user, and is never read, sent or
logged.

What does uninstalling remove?

The plugin’s options, its pending proposals, its audit and crawl log tables, the self-hosted
Google Fonts and the plugin archives, and any login block or forced password reset it set
on user accounts. Your content, media, users and plugins are left as they are.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“AudiScale Connector” is open source software. The following people have contributed to this plugin.

Contributors

Translate “AudiScale Connector” into your language.

Interested in development?

Browse the code, check out the SVN repository, or subscribe to the development log by RSS.

Changelog

6.3.0

  • New connector.self_auto_update.set operation (update_plugins): turns
    WordPress’s own auto-update on or off for AudiScale Connector only, through
    the standard per-plugin setting. The auto-update setting of your other plugins
    is never read for anything else nor changed. A constant or an
    auto_update_plugin filter set on the site keeps the last word.
  • New connector.self_update.run operation (update_plugins): updates AudiScale
    Connector itself to the latest release now, exactly like a plugin update
    (previous version archived first, reactivated after the update). Does nothing
    when it is already up to date.
  • /status now reports whether AudiScale Connector is auto-updated
    (selfAutoUpdate).
  • Remote user management on the signed channel, used only once the site owner
    enables it in AudiScale and approves each change: users.list (list_users),
    users.role.set (promote_users), users.sessions.destroy,
    users.app_passwords.revoke, users.password_reset.send,
    users.password_reset.force, users.disable, users.enable (edit_users)
    and users.delete (delete_users; remove_users on multisite, where the user
    is only removed from the current site). Each also checks WordPress’s per-user
    capability, and each change is logged with roles, flags and counts only —
    never an email address or a password.
  • A disabled account can log in neither with its password nor with an
    application password. The refusal only shows after a correct password, so it
    does not reveal which accounts are disabled.
  • Safeguards: the last administrator able to log in cannot be demoted, disabled
    or deleted; the connected account cannot have its role changed, be disabled,
    be deleted or lose its application passwords; a deletion always reassigns the
    posts to another active user of the site; on multisite only a super admin can
    act on a super admin.
  • AudiScale never sees or sets a password: resets go through WordPress’s own
    email or a new password required at the next login.

6.2.0

  • New read-only site.design_system.get operation (edit_posts): the active
    theme’s global styles presets (color palette, font sizes, font families,
    spacing sizes, content and wide widths), its theme support flags, its block
    patterns (core patterns excluded) and the synced and unsynced patterns saved
    on the site. AudiScale uses them to write contents with the theme’s own preset
    classes and components instead of fixed values. Nothing is written.
  • New content.preview_link operation (edit_posts, plus the right to edit the
    content): a signed front URL, valid 30 minutes at most, that renders one draft
    or pending content in the real theme — uncached and noindex. Without a valid
    token the draft stays invisible to visitors; private and scheduled contents are
    never revealed. Nothing is published.
  • Crawl log: on a paired site, requests from known search and AI crawlers are
    recorded (crawler, verified or declared, path without query string, HTTP
    status, time — never an IP address or a User-Agent string). Googlebot,
    Bingbot, Applebot and Amazonbot are verified by reverse then forward DNS;
    impostors are dropped. Bounded to 30 days and 30,000 rows, switched off and
    emptied from the Connection screen, removed on uninstall, read by AudiScale
    through the signed crawl.log.read operation (cursor-paged, manage_options).
  • site.robots_txt.get now also says whether a physical robots.txt file shadows
    the value the plugin manages.
  • Suggested privacy policy text for the crawl log (Settings Privacy).
  • IndexNow: four operations on the signed channel (indexnow.key.set,
    indexnow.state.get, indexnow.auto_ping.set, indexnow.key.clear, all
    manage_options). The key is served as plain text at /<key>.txt on your
    site; nothing else is served. When automatic pings are on, publishing a
    public content, or updating a published one, sends its URL to api.indexnow.org
    (Bing, Yandex, Seznam, Naver) in the background, at most once a minute per
    URL. Password-protected contents, revisions and non-public types are never
    sent. Off by default, and removed on uninstall.
  • seo.robots.set and seo.canonical.set now write into the active SEO
    plugin’s own fields (Yoast SEO, Rank Math, SEOPress) so the directive really
    appears on the page. A change proposed in draft mode is still not applied
    until approved.

6.1.0

  • Read-only inside security checks, both on the signed channel with manage_options:
    security.files.scan walks plugins, themes, mu-plugins and uploads in short
    resumable slices (about 3 seconds, 400 files at most per call, resumed from a
    cursor) and reports each code file’s md5, size and date, plus malware
    signature matches with a short excerpt. Images and other media are never read.
    security.inside.audit reports administrator accounts (login, last login,
    application password dates — never a password or its hash), the active backup
    plugin and its last backup date, and malware signatures in autoloaded options.
  • The date of each administrator’s last login is now stored in the user meta
    audiscale_last_login (a timestamp, nothing else), so inactive administrator
    accounts can be spotted. Removed on uninstall.
  • Incident lockdown, on the signed channel with manage_options:
    security.sessions.destroy_all signs every user out (not reversible), and
    security.admins.password_reset.force signs administrators out and refuses
    their next login until they choose a new password through “Lost your
    password?” (security.admins.password_reset.clear lifts it). The flag is the
    user meta audiscale_password_reset_required, removed once the password is
    reset and on uninstall. wp-config.php is never written: regenerating the
    authentication salts stays a manual step.
  • Themes: themes.list (update offered by the site’s own index), themes.update
    (Theme_Upgrader, logged) and themes.activate (returns the previous theme, the
    call that undoes it). WordPress core REST offers no theme write.
  • Performance settings (perf.* operations, performance capability token):
    preconnect and font preload hints, Google Fonts display=swap and
    self-hosting, removal of emojis / oEmbed / jQuery Migrate / Dashicons for
    visitors, script defer / async (WordPress script strategies when available) and
    delay until the first interaction, per-page removal of unused scripts and
    styles (keepOn keeps them on some pages, onlyOn removes them only there), scripts and styles inventory, server environment report. All of them
    are applied while pages load and stored in the plugin’s own options — nothing is
    written into WordPress content or files, and the stock state hooks nothing.
  • Every setting supports publishMode (draft by default), dryRun, returns the
    exact call that undoes it, and is logged. A draft is only rendered for a
    request carrying a signed, 30-minute preview token (never cached, never
    indexed, identified by an X-AudiScale-Preview header); a visitor never sees
    it. perf.promote / perf.discard / perf.reset manage the lifecycle.
  • A preview token opens one page only (the URL it was issued for), lasts five
    minutes by default (30 at most), and never applies to the REST API, feeds or
    admin-ajax. Optimizations are never applied inside page-builder editors and
    previews, the customizer, or for logged-in users who can edit content.
  • The preview also renders pending page-builder documents and pending content
    drafts, so a change can be checked for breakage before it goes live. A pending
    Elementor or Beaver Builder document is rendered with the CSS/JS generated from
    it — under preview-only file names and an in-memory copy of the builder caches,
    so the files and cache rows visitors get are never touched — and the response
    says in X-AudiScale-Preview-Assets whether that generation worked.
  • New “Switch off AudiScale optimizations” button in the Connection tab.
    Unpairing switches them off too.
  • Elementor and Beaver Builder documents are stored in post meta, which WordPress
    never filters: they are written only for a user allowed to post unfiltered HTML
    (unfiltered_html), as Elementor itself requires — including when a pending
    change is approved from the “Pending” screen.
  • Page builders (builder.data.get, builder.data.update,
    builder.data.discard): read and update a page in the builder it is edited
    with — Elementor, Divi, WPBakery, Beaver Builder — with each builder’s own
    storage, a draft/approval cycle, and a refusal when the page changed since it
    was read. Oxygen and Bricks are detected and refused. Beaver layouts are read
    without instantiating any class other than stdClass.
  • WPBakery: writing a page rebuilds _wpb_shortcodes_custom_css exactly as
    WPBakery does when a page is saved in its editor, so design options apply
    without re-saving the page.
  • Elementor: builder.data.get and perf.environment.get report whether the
    Flexbox Container feature is active; a document built with containers is
    refused while it is not (Elementor would render nothing).
  • content.create_draft accepts builder + builderData to create a new page
    directly in the site’s builder (content.create_draft.builder token).
    Unchanged without them.
  • plugins.update archives the installed version first, and so does every
    plugin update WordPress runs (wp-admin, auto-updates). New plugins.rollback
    operation reinstalls that archive and reactivates the plugin; a rollback can
    itself be rolled back. Archives live in a private folder, one per plugin,
    purged after 90 days, 1 GB cap.
  • content.update_fields in draft mode returns pendingHash, the fingerprint
    the preview echoes.

5.9.0

  • New content.untrash operation (edit_posts capability): restores a page or a
    post from the WordPress trash. Until now AudiScale could move a content to the
    trash but never take it back out, so a content it had trashed had to be restored
    by hand in wp-admin. It calls wp_untrash_post() and nothing else, and replaying
    it on a content that is not in the trash reports “nothing to do” instead of an
    error, exactly as content.trash does on a content already trashed.
  • The response says which status the content actually came back with. Since
    WordPress 5.6 a restored content is set to draft — not to the status it had
    before it was trashed — unless the site filters wp_untrash_post_status. So the
    outcome cannot be deduced from the WordPress version, and the plugin reads it
    back after the write: after is the observed status, previousStatus the one
    the content had when it was trashed, and restoredToPreviousStatus says whether
    a page that was published is readable again or is now a draft.
  • New content.trashed.list operation (edit_posts capability, read-only): lists
    the trashed contents with their id, title, type, trash date and previous status.
    A trashed content answers no URL any more, so this is the only way to name the
    content to restore. Media are out of scope, like everywhere else: WordPress does
    not trash an attachment, it deletes it and its files for good.

5.8.0

  • New taxonomy.list operation (edit_posts capability, read-only): lists the
    taxonomies that apply to a post type — categories, tags, and any custom one the
    site declares — and, on request, one bounded page of their terms. AudiScale
    reads it so it can only ever propose a term that exists.
  • New content.terms.assign operation (manage_options capability): files a page
    or a post under existing terms. It adds by default: assigning one category
    no longer removes the others, and clearing the existing terms requires spelling
    out mode: "replace". It never creates a term: an unknown one is refused and
    reported, so a near-duplicate (“Actualités” on a site holding “Actualité”) is
    never silently created. The complete previous set of terms is written to the
    audit log, and the recorded result is re-read after the write, so it shows the
    default category WordPress reassigns to a post left without one.
  • New content.trash operation (delete_posts capability): moves a page or a post
    to the WordPress trash, from where you can restore it. Until now a draft created
    from AudiScale could not be removed from AudiScale. Nothing is ever deleted
    permanently: if the trash is disabled on your site the operation is refused
    instead of destroying the content, and media are out of scope — WordPress does
    not trash an attachment, it deletes it and its files for good.
  • The promote operation now also approves a page body prepared in draft mode
    (field: "content"). It previously handled SEO fields only, so a body drafted by
    AudiScale could be approved from WordPress and nowhere else.
  • content.set_page_template now honours publishMode like every other content
    operation: by default the new template waits on the “Pending” screen instead of
    being applied to the live site immediately.
  • content.status.set and content.trash now refuse to unpublish or trash the
    page used as the front page or as the posts page, which would leave the site
    without an entry point.
  • Every content operation now checks that its target is an editable content — not a
    revision, a menu item or a theme template — and that the current user may edit it.
    Custom content types declaring their own capabilities without asking WordPress to map
    them keep working: for those, the check falls back to the generic content capability
    rather than a primitive capability no role holds.
  • Behaviour change — a URL is now resolved to a content deterministically, and
    never guessed. The plugin reads, in order: the id declared in the URL (?p=,
    ?page_id=, ?attachment_id= — the three WordPress itself honours), then the
    site’s own rewrite rules, then the site root, and refuses otherwise with
    audiscale_url_needs_post_id (404). The slug fallback that used to search the
    path against every content type is removed: a slug read off a crawled URL
    names the right content only by luck, and every way it named a wrong one ended in
    a success on content nobody aimed at — on a shop holding both a page and a product
    named “contact”, the write landed on whichever the database returned last. A URL
    whose path WordPress does not resolve now needs an explicit content id; AudiScale
    resolves the target on its side and sends it.
  • A URL pointing at another domain is refused on the whole resolution, not on one
    branch of it: an id declared in the URL does not depend on the domain, so
    “https://autre.com/x/?p=12” used to trash the post 12 of YOUR site, and the root
    of any other domain used to serve your home page. Sites whose public domain is not
    the one WordPress stores (an origin behind a CDN, a migrated domain, one domain
    per language) keep working: the host the request came in on is trusted alongside
    home_url(), site_url() and the audiscale_trusted_hosts filter, and
    internationalized domains, punycode and a trailing dot compare equal.
  • An id declared in a URL now has to name editorial content in an editable state:
    a revision, an auto-draft, a trashed content or a media is refused instead of
    written to. post and post_id are no longer read as content ids — WordPress
    honours neither, while plugins use both as ordinary parameters, so a crawled
    “/recherche/?post_id=2” resolved to the post 2 instead of the search page.
  • Fix: on a site installed in a subdirectory (“https://site.fr/blog”), the address
    “https://site.fr/” was treated as the site root and served the WordPress home
    page, although this WordPress does not answer that address at all.
  • AudiScale is told, through a dedicated capability token, that this build honours
    publishMode on content.set_page_template — the operation id alone is the same as
    in 5.7.1, where the template was always applied immediately.
  • Fix: assigning a term whose slug is a number (“2024” on a taxonomy of years) was
    refused as an unknown term, because a digits-only value was only ever read as a
    term id.
  • Fix: a draft write no longer files a WordPress revision of a body it did not touch.
  • Refusals now carry a stable machine-readable code (and the details behind it,
    such as the templates the theme really declares) next to the message, so AudiScale
    can tell one refusal from another and suggest the right fix. The error field is
    unchanged.

5.7.1

  • Fix: a URL carrying a content id (?page_id=, ?p=, ?post=, ?post_id=) was
    read as the site root, because its path is /. Depending on the site it either
    failed with audiscale_no_front_page or — with a static front page — applied the
    operation to the home page instead of the content actually targeted. The declared
    id is now read first, and an id matching no content fails instead of falling back
    to the home page. Affects every operation resolving a URL, SEO ones included.

5.7.0

  • New media.upload operation (upload_files capability): sideloads a remote
    image or video into the media library and returns its attachment id, so a page
    AudiScale drafts can reference a real attachment instead of an external URL.
    The downloaded bytes are type-checked (no SVG), the source URL is validated
    against WordPress’ own SSRF guard, the transfer is capped at 25 MB (declared
    size checked before the download, response size capped during it), and nothing
    existing is overwritten. This operation is why the plugin requires WordPress
    6.0 or later: download_url() fetches through wp_safe_remote_get(), which
    re-validates every redirect target against the same SSRF guard rather than
    following it blindly.
  • New blocks.validate operation (edit_posts capability, read-only): parses
    block markup the way the editor does and reports content sitting outside any
    block, unknown block types, or markup that does not survive a parse/serialize
    round-trip. AudiScale calls it before proposing a draft, so a page never lands
    in the editor showing “This block contains unexpected or invalid content”.
  • New site.layout_options operation (edit_posts capability, read-only):
    lists the page templates the active theme actually declares, and whether the
    theme renders wide/full alignments. AudiScale reads it before offering any
    layout change, so it can only ever propose a layout the theme can render.
  • New content.set_page_template operation (manage_options capability):
    changes the template of an existing page or post, targeted by post_id or
    url. The value must be a template the active theme declares (or default);
    anything else is refused rather than written, and the before/after is recorded
    in the audit log.
  • content.create_draft and content.update_fields accept an optional
    page_template, validated the same way. On creation the template is checked
    before the post is inserted, so a refused template never leaves an orphan
    draft behind.

5.6.0

  • New plugins.check_updates operation (update_plugins capability): purges the
    update_plugins transient and re-runs WordPress’ update check immediately, with
    no staleness guard, then reports how many updates are now visible. WordPress only
    refreshes that cache about twice a day and its upgrader refuses any plugin the
    cache does not list, so updating a freshly released version from AudiScale failed
    for hours for no real reason. AudiScale now calls this before retrying, and the
    update goes through. plugins.list is unchanged.

5.5.0

  • After a plugin update or activation, the connector announces its own version to
    AudiScale over the existing HMAC-signed channel, so the version AudiScale shows
    and gates features on is right immediately instead of at the next manual check.
    One non-blocking request, only when the site is paired, and nothing is sent
    beyond the version number and the site URL.

5.4.0

  • New site.footer_snippet.set / .clear / .get operations: store a marked
    HTML block (a link and an image, no script) and print it on wp_footer. Used
    by AudiScale for the one-click “Verified” badge install. The block lives in an
    option, not in the theme’s footer.php, so a theme update cannot wipe it, and
    re-posing the same marker replaces the block instead of stacking a second one.

5.3.1

  • plugins.update no longer leaves a plugin deactivated after a successful
    update: a failed reactivation is now reported (reactivationFailed) instead
    of being swallowed, and a main file renamed by the update is re-resolved
    before reactivating.

5.3.0

  • New seo.sitemap.exclude operation: flags a content so the native
    wp-sitemap.xml skips it (reversible with excluded: false; draft/approve flow
    supported). No effect while a third-party SEO plugin provides the sitemap.
  • New content.status.set operation: switches a content between “publish” and
    “draft” only (strict whitelist — no trash, no private, no scheduling),
    publish_pages capability, audited before/after.
  • Declared compatibility with WordPress 7.1.

5.2.0

  • SEO title and meta description now write into the meta key of the SEO plugin
    that actually renders the page (Yoast, Rank Math, SEOPress) instead of the
    plugin’s own key. While one of those is active this plugin does not print its
    own tags — so a value you approved was stored but never appeared on the site.
    Approved changes now take effect. Sites with no third-party SEO plugin are
    unaffected.
  • The approval screen reads the current value from that same key, so the
    “current” column no longer shows empty against a field that is set.
  • The audit log records the key really written.

5.1.1

  • First public WordPress.org release: English readme and service disclosure,
    packaging hygiene, and internationalization (text domain loading).
  • plugins.update now keeps the target plugin active after upgrading it (the
    WordPress upgrader deactivates during the file swap and does not restore it on a
    programmatic call).

5.0.0

  • Actionable security.* operation family: hardenings applied at the PHP
    runtime, without touching wp-config and always reversible in a single call
    (file editor, REST user enumeration, XML-RPC + pingbacks, HTTP headers
    HSTS/nosniff/X-Frame-Options/Referrer-Policy, minor core auto-updates,
    version masking, ?author=N scan blocking).
  • Each op accepts dryRun (simulation without writing) and logs the before/after
    value for an undo via the inverse op. security.state.get exposes the current
    state. Disconnecting (unpair) resets all hardenings.
  • hsts is set only if HTTPS is actually enforced (anti-lockout guard).

4.0.0

  • New security.audit operation (read-only, manage_options capability):
    free hardening snapshot (versions, configuration flags, admin accounts, core
    integrity via wordpress.org checksums). No secret is returned.

3.0.0

  • New plugin-management operations: plugins.list (read, activate_plugins
    capability) and plugins.update (live, irreversible update, update_plugins
    capability).

2.0.0

  • content.update_fields op: URL targeting + fields object
    (title/excerpt/content), respecting publishMode.
  • The body is written faithfully (no destructive filtering on our side,
    Gutenberg block delimiters preserved); filtered flag if the user lacks the
    unfiltered_html capability.
  • draft mode for content: the proposal is queued and approved from the
    “AudiScale pending” screen.

1.1.0

  • draft mode: proposed values are stored “pending” without changing the live
    render.
  • Approval surface: “Pending AudiScale change” metabox on the edit screen + a
    central screen (Settings AudiScale pending) to approve/reject (nonce +
    capability).
  • promote operation to approve a field from AudiScale (consent equivalent to
    direct).

1.0.0

  • Initial version: SEO <head> output, redirects, structured data, HMAC-signed
    operation catalog, audit log.