Skip to content

Releases: Mrshahidali420/SiteHelm

SiteHelm 0.6.0

Choose a tag to compare

@Mrshahidali420 Mrshahidali420 released this 23 Aug 16:39
f5f81bf

Added

  • Three more Pro operations in the Tools-tab cataloguecontent-seo-schema-get,
    content-seo-schema-set and content-seo-audit-fix (SiteHelm Pro 0.2.0), so a site
    without the add-on sees them as locked rows in their groups.

  • Pro operations on the Tools tab. The SiteHelm Pro operations are listed in the
    groups they belong to, each with a Pro tag. Without the add-on they appear as locked
    rows — full description, no switch — under one note with the one link to the Add-Ons
    page; with it installed but unlicensed the note says so and points at the Account page;
    with it active the tag stays and the rows are ordinary switches. No admin notice, and
    nothing on any other screen.

  • The plugin now carries the Freemius SDK: an opt-in insights prompt on first run, and
    Account and Add-Ons pages under the SiteHelm menu. SiteHelm Pro is sold and licensed
    through it as an add-on; nothing about the free operations changes.

  • SEO scores and a site-wide SEO audit (REQ-0098, free part). Two new reads for sites
    running Yoast SEO or Rank Math. content-seo-score-get reports one post's SEO and
    readability scores exactly as the plugin stored them (never recomputed, so the number
    matches the editor; Rank Math has no separate readability score and says null), plus
    a list of findings derived from the metadata — missing, too-short or too-long
    description, over-long title, missing focus keyword or one absent from the title, a
    published post kept out of search, a score under the caller's floor.
    content-seo-audit walks a page of posts (default 50, at most 100) and reports each
    one's scores and findings with a count of every finding across the page, detecting
    duplicate titles and descriptions within it; posts the caller may not edit are skipped
    and counted, not shown. The finding vocabulary is fixed and published in both output
    schemas.

  • Term SEO metadata (REQ-0098, free part 2). content-term-seo-get and
    content-term-seo-set read and write a category's or tag's title, description,
    canonical, focus keyword and noindex in Yoast SEO (the wpseo_taxonomy_meta option)
    or Rank Math (term meta, with the robots directive list edited rather than replaced).
    Both admit on edit_posts and then ask the taxonomy's own edit capability, so a
    contributor cannot rewrite what a category archive tells search engines. The write
    is previewed, snapshotted and reversible like every other. 74 operations.

  • Extension points. Three hooks let another plugin extend SiteHelm without touching it:
    sitehelm_modules (add a module), sitehelm_register_operations (add operations to a
    module) and sitehelm_status_sections (add a section to the Health tab). Every hook is
    additive and contained: nothing an add-on returns can remove a built-in module, and a
    throwing handler is logged rather than allowed to break the boot.

  • SiteHelm Pro: deep SEO (REQ-0098, Pro part). Five Pro operations for sites running
    Yoast SEO or Rank Math, each gated by the licence first and manage_options second.
    seo-settings-get / seo-settings-set read and write an allowlist of the plugin's own
    settings — separator, knowledge-graph name and logo, default social image and
    breadcrumbs at site scope; title and description templates, noindex and sitemap
    inclusion per public post type — as one previewed, snapshotted, reversible change per
    scope, translating between the two plugins' option layouts (Yoast's separator codes,
    Rank Math's two-key robots rule). content-seo-bulk-set applies the content-seo-set
    fields to up to fifty posts at once as a single reversible change, refusing the whole
    set if one post is missing or not the caller's to edit. seo-404-log-list and
    seo-redirection-list page Rank Math's 404 monitor and redirections newest first (at
    most 200 a page), and say plainly when a Yoast site has no such tables or the Rank Math
    module is switched off. The free plugin is unchanged: the operation count stays at 74.

  • SiteHelm Pro foundation. A separate add-on plugin (source in a private repository, not part of the
    free zip) with an offline-signed per-site licence key, a Licence card on the Health tab, and
    a gate every Pro operation checks itself. The free plugin carries no Pro file, no nag and no
    crippled operation.

  • A Home tab. The console now opens on a plain-language summary: one sentence on how the
    week went, three tiles (changes this week, could not be done, undone), the last five things
    an app did, and a "Connect an app" prompt when nothing has happened yet.

  • Permission levels. Each module card on the Permissions tab carries four buttons — Off,
    Read, Edit, Full — in place of the single on/off switch. Read allows only reads; Edit adds
    writes that are neither destructive nor high risk; Full allows everything. A module whose
    per-operation switches match no level reads "Custom", and a link leads to the Tools tab for
    fine-tuning.

Changed

  • Tabs speak the owner's language. Modules is now Permissions, Operations is Tools,
    Activity is History, Status is Health, and the Connect tab is "Connect an app" at
    ?page=sitehelm-connect (the console's first page is now ?page=sitehelm, Home).

  • History reads as sentences — "claude-code changed the page About us" — with the
    operation id kept in small print underneath; the columns are When, What happened,
    Outcome, Took, Who, Undo.

  • The Tools tab opens with an "advanced" note saying most owners only need the
    Permissions tab.

  • Tabs no longer stretch to fill the bar, so the row can take more tabs and scrolls when
    it must.

  • The admin console's look. A new design throughout: indigo accents, Geist headings,
    one white content panel under the tab bar, headline stat tiles, and a "Get help" menu in
    the app bar that links to the documentation, the changelog and the issue tracker.

  • The Operations screen lays its operations out as cards — switch, name, description,
    module and required capability on each — in place of the table. Clicking anywhere on a
    card flips its switch, each tool's group can be collapsed, and "All on / All off" is now a
    segmented control.

v0.5.0

Choose a tag to compare

@Mrshahidali420 Mrshahidali420 released this 22 Aug 15:11

[0.5.0] — 2026-08-22

Added

  • A switch on every Modules card that turns the whole module's operations on or off
    together — the same switches the Operations screen shows one row at a time, stored in
    the same option, so a module half-switched off there reads "N of M operations on" here.

  • Per-operation switches on the Operations screen. Every operation now has an
    on/off switch, with per-group counts, "All on" / "All off" per tool, and a sticky
    save bar. A switched-off operation leaves the catalogue, is refused with the
    same answer an unknown operation gets, and system-operation-schema will not
    describe it either; everything is on by default, including
    operations a later update adds. Stored in sitehelm_disabled_operations.

  • A one-time notice after activation pointing at the Connect screen, shown to the
    first operator who can open the console and then gone.

  • A Site Health test under Tools → Site Health that says whether client
    credentials reach WordPress on this server, with the .htaccess fix when they do not
    and a warning when application passwords are switched off.

  • Connect and Status links on the Plugins screen, beside Deactivate, for the
    moment after activation.

  • Filter the Activity log by period. Last hour, 24 hours, 7 days or 30 days,
    alongside the other filters; the period travels with the pager and the CSV export.

  • The Status screen now tests whether the Authorization header reaches WordPress.
    A loopback to the endpoint with a login that cannot exist tells a server that passes
    the header through from one that strips it (Apache as CGI/FastCGI), which is the
    commonest reason a fresh credential is "wrong"; when it is stripped the screen gives
    the three .htaccess lines that fix it.

  • Export the Activity log as CSV. The Activity screen's filter row now ends in
    an Export CSV link that downloads every row matching the filters shown, newest
    first, up to 10,000 rows (the file says so on its last line when it stops there).
    Cells that a spreadsheet would read as formulas are neutralised.

  • Set how long records are kept, on the Status screen. The pruning window
    (1–365 days, default 30) that governs the activity log and the snapshots behind
    each rollback was previously only reachable by editing an option; it is now one
    number and a Save button under "Record retention".

  • A SiteHelm widget on the wp-admin Dashboard. Whether writes are paused,
    how many credentials are issued, and the five most recent operations with their
    client and outcome — each linked to the console screen that explains it. It shows
    nothing to anyone who cannot open the console, and offers no controls.

  • Filter the Activity screen by client. A "Filter by client" field joins the
    operation, correlation and outcome filters, and every named client in the actor
    column is now a link to everything that client did on the site.

  • See and revoke issued credentials on the Connect screen. A new "Issued
    credentials" section lists every application password SiteHelm has created for
    the accounts you can act for — which account it acts as, when it was created,
    when it was last used — each with a Revoke button. Revoking cuts that client
    off at WordPress sign-in; nothing already recorded is touched. Only
    SiteHelm-named passwords are listed or revocable, and the handler enforces the
    same account boundary as minting.

  • Pause all writes from the Status screen. A "Write access" section shows whether
    connected clients may change anything, with one button: "Pause all writes" puts
    the gateway in read-only mode so every write from every client is refused at the
    gate before any module runs; "Resume writes" lets them through again. Reads keep
    working either way, nothing already recorded is touched, and resuming never
    rewrites a mode the operator set some other way.

  • Roll a change back from the Activity screen. Every applied row now carries a
    "Roll back" button beside its reference. The first click asks the change engine
    for a preview and shows a confirm panel — target, reference, a field-by-field
    Now / After rollback table, and any warnings — with nothing changed yet; "Roll
    back now" restores exactly what was shown, and the result is reported at the top
    of the screen in the engine's own words when it refuses. The restoration runs
    through the same dispatcher, capability checks, audit record and verification as
    a client-requested rollback, is recorded against the client wp-admin, and is
    itself re-restorable. The plan token never reaches the browser; it sits in a
    five-minute, per-user transient and is spent on the second click only.

Changed

  • The console now says what a blocked module is waiting on, and which operations
    that blocks.
    A Modules card that is not active names the plugin and the lowest
    version SiteHelm accepts ("Activate Elementor 3.0.0 or newer", "Update to Advanced
    Custom Fields 5.9.0 or newer") and links to Plugins; a module backed by WordPress
    itself points at Status instead. Every Operations row names its module, and a row
    the site cannot run yet is dimmed, marked "Not active", and counted in the verdict
    — the catalogue stays complete, so an operator sees which rows are promises. The
    Status verdict's "N modules are not active" now links to the screen that explains
    why. The version floors are read from the same constants the gateway enforces, so
    the two cannot drift.

Fixed

  • Every string a request can carry now has an upper bound too. Ninety-four of
    the catalog's string arguments already declared a maximum length; five did not,
    including the redirect target, whose limit the handler was already enforcing
    without ever publishing it. All five are now declared, from what the storage can
    actually hold rather than from a round number. With lists, maps and strings all
    bounded, no argument the gateway accepts is unbounded in size.

  • Every map a request can carry now has an upper bound too. Six operations
    accept a free-form object whose keys are the site's own vocabulary — a widget's
    settings, a block's attributes, a typography entry — and none of them said how
    many members one request could carry. Elementor's known-key check is not that
    bound: it refuses names a widget does not declare, and it does not run at all
    when the widget type is unknown. maxProperties is now both applied by the
    validator and declared on all six, two of them from limits their handlers were
    already enforcing without publishing. An over-large object is refused whole.

  • Every list a request can carry now has an upper bound. Eight arrays across
    content-block-update, content-meta-update, content-terms-assign,
    elementor-theme-conditions-set, menu-item-create, menu-item-update and
    menu-items-reorder accepted a list of any length, so their size was discovered
    by running out of time or memory rather than by being refused. One of them —
    the term identifiers inside content-terms-assign — sat one level down, inside
    an entry of another list. elementor-theme-conditions-set already enforced its
    limit in the handler and simply never published it; the schema now names the same
    constant. A new registry-wide test sweeps every input schema recursively and
    fails on the first array that declares no bound.

  • Five constraints the operation schemas declared are now actually applied. The
    gateway validator applied type, enum, minimum, maxLength and the structural
    keywords, and silently ignored minLength, maximum, pattern, minItems and
    maxItems — 44 declarations across 22 files. A published schema is what an agent
    reads to learn what a site accepts, so a declared bound that is never checked is
    worse than an absent one: a well-behaved client stops checking for itself.
    maxItems was the only declared upper bound on array size anywhere in the catalog,
    so every batch operation accepted a list of any length and discovered the size only
    while walking it; an over-long array is now refused whole, before the walk. A new
    registry-wide test fails on the next keyword written into a schema that the
    validator does not apply.

  • A part-completed taxonomy assignment now says which taxonomies were already
    written.
    content-terms-assign writes one taxonomy at a time, but a failure
    reported the same two completed steps whichever write it happened on — so an
    operator whose second taxonomy failed was told that nothing had changed, when the
    first had already been applied. The rollback record was always complete; only the
    account of it was not.

  • A menu name too long to belong to any menu is now refused before the lookup.
    The four operations that take a menu argument — menu-get, menu-item-create,
    menu-items-reorder, menu-location-assign — accepted a string of any length. A menu
    is a nav_menu term, and all three ways to name one resolve against columns bounded at
    200 characters, so a longer string could never have matched one. It is now rejected by
    the argument schema, which says the bound, instead of by a not-found result after the
    search.

  • Importing from a URL now stops downloading at the size this site will actually
    accept.
    The transfer was bounded by the plugin's built-in 8 MiB ceiling on every
    site, so a site configured to accept 2 MiB still pulled up to 8 MiB across the
    network and held it in memory before refusing it for size — four times the transfer
    and four times the peak memory for a refusal that was never in doubt. Both the wire
    limit and the check after it now use the effective cap, the smaller of the built-in
    ceiling and the site's own upload limit. A site reporting no positive limit still
    falls back to the built-in ceiling rather than to zero.

  • Refusals on the import path no longer say "uploaded". Six messages shared by
    media-upload an...

Read more

v0.4.0 — 70 operations

Choose a tag to compare

@Mrshahidali420 Mrshahidali420 released this 18 Aug 21:49

70 operations across 11 dispatchers, up from 54 in 0.3.0. Sixteen new operations,
four fixes to things that were offered but did not work, and a console screen that
now reads like a record instead of a log dump.

New in this release

The block editor, addressed a block at a time. content-blocks-get returns the
outline of a page — every block, its address, its depth, the names of its attributes
and a short preview — so a client can find the paragraph it meant without spending a
context window on the ones it did not. content-block-update then changes one block
and leaves every other block byte-identical: because post_content is a single
column, the operation reproduces the document from its own parse and refuses, without
writing, if that reproduction is not byte-identical to what is stored.

Redirects. A retired URL can be pointed at its successor, so the traffic and the
ranking an old address earned survive a rename, and a page that is simply gone can
answer 410 instead of 404 forever. Redirects are served ahead of the front-end
request and never on an admin, cron, or REST request. A redirect that would send a
visitor back to the path they asked for is refused when written and when served,
because a rename months later can turn a good redirect into a loop.

content-links-check. A rename leaves a site pointing at its own old paths from
inside its own content, and nobody sees those until a visitor clicks one. Every answer
comes from this site's database — a link to another host is listed and left
unchecked, because a content operation that makes outbound requests is a content
operation that can be pointed anywhere.

SEO metadata, in one vocabulary. Read and written through a single vendor-neutral
set of names whichever SEO plugin the site runs.

Comment moderation. List the queue, move one comment between approved, pending,
spam and trash, and reply as the acting account. All three gate on the
comment-moderation capability alone, so a moderator with no editing rights can use
them. Nothing here deletes anything: spam and trash are reversible statuses, and the
value that would perform a permanent deletion is not in the vocabulary at all.

A user roster, and one-account role changes. user-role-set refuses four things
outright rather than letting a preview promise them: an unregistered slug, the acting
user's own account, the last remaining administrator, and a multisite super admin.
Seeing the roster and changing it are separate capabilities, and neither operation
accepts the other's.

Elementor theme templates and their display conditions, and
elementor-composition-get — a page digest whose size does not grow with the page,
including a count of how many elements carry no stored identifier, which is exactly
how much of the page no write can address.

Fixed

  • Rollback now works for redirects, comments and user roles. Reversing a change
    was built when every change belonged to a post, so those three writes handed back
    references that could not be redeemed. The offer was real; the redemption was not.
    Each write now takes its own changes back, and asks the same permission the original
    change asked.
  • The Activity screen reads as a record. English summaries instead of raw redacted
    JSON, a duration on every operation, an outcome filter, and a rollback reference that
    can be copied whole rather than clipped to what fitted.
  • Three reads ask for their own permission. audit-list, system-environment and
    image-size-list declared a capability and left the asking to the one request path
    that calls them. That path does ask, so nothing was exposed — but a handler reachable
    only one way is a guarantee about today rather than a guarantee. audit-list now
    checks before it looks at its storage, so a caller who may not read the change log no
    longer learns whether the log exists.
  • Secondary console text meets AA contrast, and the Connect screen's by-hand
    bridge check now runs on Windows
    — it was written in one shell dialect only, and in
    PowerShell that spelling is a parse error rather than a command that fails.

Compatibility

WordPress 6.6+, PHP 8.1+. No breaking changes to any operation's input or output
schema. Records written before this release carry no duration and show a dash.

Full detail in CHANGELOG.md.

v0.3.0 — the v1.1 surface

Choose a tag to compare

@Mrshahidali420 Mrshahidali420 released this 17 Aug 07:00

Fifty-four operations across eleven MCP dispatchers. This release closes out the whole v1.1 roadmap band.

Install sitehelm-0.3.0.zip from Plugins → Add New → Upload Plugin.

Added

media-resize brings an oversized image within a width and a height you name, so the size the site actually serves fits the sizes the theme renders. The original file is never overwritten and never deleted: the reduced image is written to a new file beside it, the media item is re-pointed at the new file, and the untouched original stays reachable through the same metadata WordPress uses for its own scaled uploads. A second reduction still reads the true original rather than the previous reduction, so detail is not thrown away twice. An image already within the requested maximum is refused rather than re-saved.

elementor-elements-update changes the settings of several elements on one Elementor page as a single reviewed change — one preview, one save, one rollback reference. Every entry is checked against the page before anything is written, so an entry naming a setting the widget does not declare, or an element that is not there, refuses the whole request and leaves the page untouched rather than landing the entries before it and stopping.

Global Elementor tokens. Read the site's shared colour palette and type styles, and correct either once at site level instead of editing every page. An update merges into the addressed entry, so setting a colour does not erase its title, and a write cannot re-point a token that published pages already reference.

A stdio bridge, shipped with the plugin. AI clients that cannot open an HTTP connection launch a local subprocess instead. The code that runs on the operator's machine is the code that was reviewed and installed here, rather than whatever a package registry serves at launch, and the credential travels in the config's env block instead of on a command line every process can read.

system-operation-schema returns one named operation's full input and output schema on demand. An operation the caller cannot see does not surrender its schema: an unknown name and a hidden one are refused identically.

A retired-domain guard on writes. A request that reaches the site at an address it no longer answers as is refused for every write, with a remediation naming the address to reconnect at. Reads stay available on purpose, so an operator whose connector points at an old domain can still run the diagnostics that say so.

Changed — action may be required

Dispatcher catalogs no longer carry each operation's inputSchema and outputSchema. A dispatcher holding a dozen operations spent most of a client's context window on schemas for operations it would never call. Each entry keeps its usage example, and the catalog names system-operation-schema as the way to fetch a full schema when one is actually needed.

If your client read schemas straight from a catalog, it must now ask for them. This is the reason this is a minor release rather than a patch.

Catalogs also list a write that arrived on a retired host as unavailable with the blocking reason retired_host, rather than advertising it as available and refusing it on use.

Unchanged by design

Arbitrary PHP execution, unrestricted SQL, unrestricted filesystem access, and irreversible permanent deletion remain permanently out of scope.

Full detail in CHANGELOG.md and the operations reference.

SiteHelm 0.2.1

Choose a tag to compare

@Mrshahidali420 Mrshahidali420 released this 16 Aug 20:29

The admin area is now a five-tab console rather than a single page, and Connect
covers eleven MCP clients rather than three.

Added

  • Modules — one card per capability pack: whether it is active, the version
    SiteHelm detected, and how many operations it actually registered this
    request. Packs that are not active are dimmed as well as badged.
  • Eight more clients on Connect — Claude Desktop, Claude on the web, VS Code,
    Codex CLI, Antigravity, OpenClaw, Hermes, and any stdio-only client over the
    public mcp-remote bridge. Each gets the config in the shape that client
    actually reads: the servers object for VS Code rather than the mcpServers
    object everything else wants, and a fragment to merge for OpenClaw rather than
    a whole file that would overwrite unrelated settings.
  • A request you can run to prove the endpoint answers. "It does not work" is
    almost always the wrong URL, a stripped Authorization header, or a revoked
    password, and one request separates those without involving a client at all.

Changed

  • Connect can create an Application Password for another account you have
    permission to edit, so an agency can hand a client's site a credential without
    signing in as them. The picker offers only accounts you may act for, and the
    request is re-checked when submitted rather than trusted from the form.
  • Status no longer repeats the module table. It reports the count and points
    at Modules.

Fixed

  • A module whose plugin is installed but deactivated now reads as not active
    rather than not installed. Presence is detected from loaded constants and
    classes, which cannot tell those two apart, and the old wording sent operators
    off to reinstall what they already had.
  • A module with no detected version omits the version line rather than printing
    "detected" followed by nothing.

Install

Download sitehelm-0.2.1.zip and upload it under Plugins → Add New → Upload
Plugin
. Requires WordPress 6.6 and PHP 8.1.

v0.2.0 — the admin console

Choose a tag to compare

@Mrshahidali420 Mrshahidali420 released this 16 Aug 15:17

Connecting a client used to mean reading the README, finding the REST route, minting an Application Password from your WordPress profile, and assembling the config by hand. This release replaces that with a screen.

Install: download sitehelm-0.2.0.zip below → Plugins → Add New → Upload PluginActivate → open SiteHelm → Connect.

Four screens, one menu

Connect — the MCP endpoint, an Application Password created in place and shown exactly once, and a ready-to-paste configuration for Claude Code, Cursor, or any other MCP client. It says "Ready to connect" until a client has actually called, warns when the site is not on HTTPS, and when Application Passwords are disabled it explains why rather than offering a button that cannot work.

Activity — every operation a client has performed, newest first, with target, outcome, actor and rollback reference. Filterable by operation or correlation id. It states a rollback reference rather than offering an undo button, so a rollback stays a deliberate act performed through the gateway.

Status — which modules are active, inactive or version-blocked, the detected version of each integration, whether the ledger tables exist, and the environment SiteHelm is running in. Storage being unavailable overrides the module verdict, because nothing can be recorded without it.

Operations — the full catalogue of what a connected client can ask this site to do, grouped by tool, each marked read or write and badged when it requires preview, is destructive, or is high risk.

The console is read-only apart from the single button that mints a credential. No options screen, no dashboard widget, no cron jobs.

Unchanged

The gateway, the 51 operations, the two-phase write pipeline, snapshots, verification, the change ledger and rollback are all exactly as they were in 0.1.0. This release adds a way to reach them; it changes nothing about how they behave.

Requires WordPress 6.6+ and PHP 8.1+. Always connect over HTTPS — an Application Password sent over plain HTTP is a credential sent in the clear.

Full detail in CHANGELOG.md.

SiteHelm 0.1.0

Choose a tag to compare

@Mrshahidali420 Mrshahidali420 released this 16 Aug 11:57

[0.1.0] — 2026-08-16

First release. The complete V1 surface: 51 operations across 11 MCP dispatchers, a
two-phase write pipeline, a change ledger, and rollback.

Added

Gateway

  • MCP over JSON-RPC 2.0 at the WordPress REST route sitehelm/v1/mcp, speaking protocol
    version 2025-06-18. Handles initialize, notifications/initialized, ping,
    tools/list, and tools/call.
  • Eleven dispatchers instead of one tool per operation, so a client's tool list stays small
    and each catalogue is fetched on demand.
  • Authentication through WordPress Application Passwords; every operation runs a real
    capability check against the authenticating user before any target is looked up.

The two-phase write

  • Every write is previewed first. The preview returns the exact after-state and a
    single-use plan token; applying without a token is refused, and so is reusing one,
    replaying an expired one, or presenting one whose arguments have since changed.
  • Pre-change state is captured to a snapshot, the write is applied, and the result is read
    back and compared with what the preview promised. A disagreement is reported as
    VerificationFailed with completedSteps saying how far the operation got.
  • A change ledger records what changed, when, and by whom, with a rollback reference where
    the change can be reversed.

Content — read one item, list with filters, list taxonomies; create, update, set
status, set the featured image, write registered meta, assign terms, trash (reversible,
never a permanent delete), and apply a rollback.

Media — read an attachment, list the library, list registered image sizes; upload from
supplied bytes, import from a URL, update alt text and captions, attach to a post.

Menus — list menus and their theme locations, read a menu's full item tree; create and
update items, reorder and re-parent a tree, assign a menu to a location.

Elementor (3.0.0+, optional) — list and read documents, read one element, search a
document by element type, text, or setting key, report which widget types the site actually
has, return a widget's control schema, and read the active kit's global colour and
typography tokens. Writes: add, update, move, duplicate, and remove elements, update a
widget's settings against its control schema, and update the global colour palette and type
styles site-wide. The stored document is edited directly and the generated CSS is flushed
afterwards, so changes appear on the front end without opening the editor.

The global-token writes address the active kit, so they gate on edit_theme_options — the
capability Elementor itself puts on the kit document. An update merges into the
addressed entry, so setting a colour does not erase its title, and kit settings outside the
palette are untouched. Typography setting names are validated by shape rather than against
a fixed allowlist, so a control added by a newer Elementor is not refused; an entry's own
_id stays unreachable, so a write cannot re-point a token that published pages already
reference. Element search names the setting keys that matched, never the values they hold.

Fields — ACF (5.9.0+) and Meta Box (5.3.0+), both optional. List groups, list fields,
read a value, write a value. Values are normalised per field type before writing and
verified by reading back; a field's formatted display value is never recorded as if it
were the stored value, so a restore puts back what was really in the database.

Diagnostics — confirm the connection and who is authenticated, report the WordPress and
PHP versions with registered post types and taxonomies, and report the health of every
optional integration as Active, Inactive, or VersionBlocked.

Security

  • media-import resolves and validates the host before connecting; private, loopback,
    link-local, and reserved ranges are refused; every redirect hop is re-validated and
    re-pinned; the resolved address is pinned so the connection cannot be re-pointed between
    the check and the fetch; the wire read is capped; and the refusal message is deliberately
    digit-free so it cannot be used as an SSRF oracle.
  • No response envelope carries a stack trace, filesystem path, SQL fragment, database error
    string, authorization header, or resolved IP address. Field names may appear; field
    values never appear in a warning or a refusal.
  • All SQL goes through $wpdb->prepare, and table names come from the installer rather
    than a hardcoded prefix.

Permanently excluded

Arbitrary PHP execution, unrestricted SQL, unrestricted filesystem access, and irreversible
permanent deletion are out of scope by design and will not be added. See
ROADMAP.md.