Releases: Digitizers/elementor-mcp
Release list
v1.25.1 — de-brand upstream links + readme sync
Maintenance release.
- De-branded the leftover upstream links. The admin header's Read the Docs and Get Support buttons pointed at the original author's commercial site (
emcp.msrbuilds.com/docs,support.msrbuilds.com) — content this fork does not serve — as did the proxybin/README.mdplugin link. All three now point at the fork's own GitHub (README + Issues). Attribution to@msrbuilds(GPL-3.0) is unchanged. - readme.txt Stable tag synced to 1.25.1, with the previously-missing 1.25.0 (global-classes governance) and 1.25.1 changelog entries added.
No functional/tool changes. Full suite 722 green.
v1.25.0 — global-classes governance (design-token reversal gap closed)
Global-classes governance (winning-plan P2, plank 2) — the Class Manager writers (create / update / delete-global-class) now snapshot-before-write + roll back on failure, closing the last design-token reversal gap. All Elementor design-token writes (pages, kit, global classes) are now snapshot-reversible under SiteAgent governance.
In Elementor 4.x a global class is its own CPT post (e_global_class), indexed by kit meta, and a delete cascades (rewrites every page whose _elementor_data referenced it). Reversing that is a multi-post transaction — kit index + sync-to-v3 map + class CPT posts + reverse usage index + cascade pages — captured in ONE snapshot_posts() call (SiteAgent's plank-2a primitive) for a single-restore rollback.
- Each writer declares
meta.governance.scope = 'global-classes'; a lazybefore_global_classes_write()at the repo write site snapshots the whole transaction.apply-global-classstays page-governed. - Fail-closed on every un-reversible edge: no active kit, unresolvable cascade, SiteAgent lacking
snapshot_posts, or an in-use class whose reverse index is empty (its pages found only via the multi-valuedused_classesfallback the single-valued snapshot can't restore). - Corrected the
delete-global-classdescription (Elementor does cascade page rewrites — verified against 4.1.4).
Converged over a 5-round Claude↔Codex review (3 P2 fixes: reverse usage index, fallback fail-closed, sync-to-v3 map; 1 false positive refuted). Full suite 722 green.
Requires SiteAgent's snapshot_posts primitive for global-class governance; standalone the writers behave as before.
v1.24.0 — kit-scoped governance (design-token writes)
Extends the SiteAgent governance bridge (snapshot-before-write + rollback, live for page writes since v1.17) to design-token writes — the winning-plan P2 'kit/repo-scoped write governance' item, plank 1.
The system-kit writers (replace-system-colors/replace-system-typography), the global-palette writers (update-global-colors/update-global-typography), and the v4 Variables writers (create/edit/delete/restore-variable) act on the active kit post, not a page, so they never reached the page write-site and had no reversal safety. Now they do.
How
- Each write tool declares
meta.governance.scope = 'kit'. The design-token write sites callbefore_kit_write()right before mutating the kit — the same lazy, write-site pattern page writes use — which snapshots the kit's design-token meta (_elementor_page_settings,_elementor_global_variables) via SiteAgent'ssnapshot_meta;run_governed()rolls the kit back on failure. A first-write create is fully reverted (SiteAgent'srestoredeletes keys absent at capture). - Snapshot strictly after validation — every executor validates (existence, size-token-needs-Pro, already-active no-op, per-slot hex) before the snapshot, so a rejected op never snapshots and a failed run never reverts a concurrent, unrelated kit change. Tombstone normalization (itself a kit write) runs under the snapshot.
- Fail-closed: no active kit / snapshot failure →
governance_snapshot_failed, the tool never runs. Grants (opt-in) checked before the snapshot. No render check (a kit affects the whole site).
Scope (verified against Elementor 4.1.4): system-kit + palette + variables live in kit-post meta (covered). Global classes are a separate Elementor CPT → plank 2. Interactions are page-data → already page-governed.
Suite green (705). No page-write behavior change.
v1.23.0 — numeric range constraints in get-widget-schema
get-widget-schema now carries a control's own numeric bounds into the generated JSON Schema, so an agent sees valid values in one lookup.
- number →
minimum/maximumfrommin/max, andmultipleOffromsteponly when an explicitminlands on the step grid (offset grids like min=1/step=2 → 1,3,5… and a stepless-base with no min are omitted rather than reject valid values). - slider → a
unitenum (fromsize_units, else the range's unit keys) and, when the control offers exactly one unit, asizeminimum/maximumfrom that unit's range. Multi-unit sliders leavesizeunconstrained.
Context: a source-verified pass confirmed the fork's runtime schema discovery already matches and exceeds the benchmark on widget reach (our get_full_controls() enables style/group controls outside the editor via Performance::set_use_style_controls(), which a bare get_controls() misses under Optimized Control Loading). This range enrichment closes the one remaining schema-richness delta.
Regression-tested (ControlMapperRangeTest, 10 cases). Full suite green (698). No MCP tool-surface change.
v1.22.0 — Freemius SDK removed (free features retained)
Removes the vendored Freemius SDK (~198 files) and the upstream hosted/licensed Pro marketplace it gated — severing the last runtime tie to upstream's monetization account (Freemius product 30577).
Removed
- Vendored Freemius SDK +
emcp_pro_fs()init. - The Templates and Skills admin tabs (purely hosted/licensed content) and the hosted fetchers behind Prompts/Brand-Kits, which pulled upstream's licensed content from
emcp.msrbuilds.comand phoned home the site URL. Permanently dormant here (no paid plans / no license path). - The two hosted brand-kit MCP tools (
list-brand-kits/apply-brand-kit) that never registered without a license.
Kept (free, local)
- Brand Kits tab — 10 bundled kits, apply + backup/restore (local
System_Kit_Writer+emcp_kit_backupstore,manage_options-gated, no license). - Sample Prompts tab — the 5 bundled
.mdblueprints with one-click copy.
Restored
- Native
uninstall.php(cleanup previously ran via Freemius'safter_uninstallhook). Deletes plugin-owned options/transients/user-meta, runs the generated-executable-PHP cleanup, and is multisite-aware (iterates every site). Does not touch sharedfs_*options. User page content + brand-kit backups preserved.
No change to the MCP tool surface — the 19 GPL tools already registered via emcp_fork_premium_tools_enabled() with no Freemius dependency (since 1.13.0). Distribution unchanged (GitHub releases). 688 tests green.
v1.21.0 — atomic schema-in-error
Atomic schema-in-error (P1.1, second slice)
When Elementor rejects invalid atomic widget settings — an Elementor 4 atomic widget throws on bad settings, which the write path surfaces as save_rejected — the error now carries the target atomic type's compact prop schema inline, so an agent can correct the settings in a single round trip instead of guessing.
Wired into add-atomic-widget, update-atomic-widget (the type is resolved from the element's widgetType), and the atomic convenience tools (add-atomic-heading / -paragraph / -button / -image / …).
Source-verified extraction
The schema is distilled from Elementor's own get_props_schema() (source-verified against Elementor 4.1.4): the atomic type is resolved via the widgets/elements manager, then each Prop_Type is read through its JsonSerializable form to { prop => { type, enum? } } — stable across Elementor's plain/object/union prop-type shapes. Examples:
e-heading→tag: { type: string, enum: [h1…h6] },title: { type: html },link: { type: link },classes: { type: classes }e-paragraphcontent prop isparagraph(notcontent);e-buttonistext.
New Elementor_MCP_Atomic_Props::schema_for() + enrich_save_rejection().
Surfaced in the error message
The MCP adapter surfaces only a tool error's message + code (it drops WP_Error data), so the schema is folded into the message itself, e.g.:
Elementor rejected the element data: … Valid e-heading props: classes (classes), tag (string: h1|h2|h3|h4|h5|h6), title (html), link (link).
The structured data.schema is kept for REST/direct callers. This release also fixes the same latent gap for v1.20.0's widget-type suggestions, which now appear in the message (" Did you mean: heading, button?").
Fail-safe
Only the save_rejected error is rewritten; a non-error, a different error code, or a type with no resolvable schema is returned untouched. Never throws.
Full suite 689 green; +6 AtomicSchemaTest cases. Converged in 2 Codex rounds.
v1.20.0 — schema-in-error widget-type suggestions
Schema-in-error widget-type suggestions (P1.1, first slice)
When a tool is given a widget type that doesn't exist, the error now carries the nearest valid widget type names inline, so an agent that used a wrong name self-corrects in a single round trip (Novamira's single-roundtrip correction contract) instead of guessing or making a second discovery call.
elementor-mcp/add-widgetwith an unknownwidget_type→invalid_widget_typewhosedataincludessuggestions(ranked exact → substring → smallest edit distance) and aschema_hintpointing atget-widget-schema.elementor-mcp/get-widget-schema(the primary discovery tool) andSchema_Generator::generate()return the samesuggestionsin theirwidget_not_founderrordata.- New
Elementor_MCP_Schema_Generator::suggest_types( $bad, $limit = 6 ).
Scope: this covers the wrong-widget-name mistake (the most common one). Attaching the full compact control schema to bad-settings rejections — which for Elementor 4 atomic widgets surface as save_rejected — needs an atomic prop-schema extractor and is the next slice. (The settings validator is deliberately advisory/non-fatal, so there's no settings-rejection path to enrich for legacy widgets.)
Full suite 683 green; +7 SchemaSuggestionsTest cases. Converged in 2 Codex rounds.
v1.19.0 — post-write render check (P0.2 complete)
Post-write render check with auto-revert — P0.2 complete
The third and final plank of P0.2 (bring fork writes under SiteAgent governance). Together with 1.17.0 (capture-before-write snapshot + rollback) and 1.18.0 (server-enforced Ed25519 grants), governed Elementor page edits now have snapshot → approve → write → verify-render → auto-revert safety end to end.
When enabled, after a successful governed edit the edited page's front end is fetched and, if it comes back definitely broken, the write is reverted to its pre-write snapshot and the tool returns governance_render_failed (or governance_rollback_failed if the revert itself fails). A write that succeeds at the data layer but produces a white screen / fatal no longer ships.
Fail-safe by construction
- Definitely broken = HTTP 5xx (a real PHP fatal is served with a 500) or an empty 2xx body (WSOD). A 200 body is never scanned for a fatal string, so ordinary page copy can't trip it.
- Baselined: the page's render is probed before the write; a rollback fires only when a confirmed-healthy page turns broken — never when the pre-write render couldn't be confirmed healthy (maintenance mode, unrelated 5xx, a flaky/inconclusive probe).
- Never reverts on ambiguity: a transient loopback
WP_Error, a 3xx/4xx (auth redirect, WAF 401/403), a draft/private page, or anelementor_librarytemplate/popup is inconclusive → the write stands. - Edits only: create-style tools aren't render-checked (reverting a create would leave an orphan post behind).
Loopback hardening (SSRF-safe)
- Validates the permalink is on the site's own origin (scheme + host + port) before fetching — a
get_permalinkfilter pointing off-origin is refused. - Does not follow redirects (
redirection => 0) — an open redirect can't turn the probe into an SSRF hop. - Keeps TLS verification on — a spoofed cert can't control the probe result.
- Cache-busts the probe and bounds the response size so a warm cache can't mask a fresh fatal and a large page can't exhaust memory.
Opt-in
Default OFF (adds a loopback per write); enable via the elementor_mcp_render_check option / filter (or emcp_governance_render_check()). Fires elementor_mcp_governance_render_reverted on revert; opt-in cleared on uninstall.
Tests
Full suite 676 green; 43 GovernanceFunctionalTest cases. Converged over 11 Codex review rounds — every round hardened the loopback probe (SSRF, TLS, memory, caching, baseline correctness, create/template handling). All 12 findings were real.
v1.18.0 — server-enforced approval grants
Server-enforced Ed25519 approval grants for governed Elementor writes
The second plank of P0.2 — the moat no competitor has: EMCP-grade breadth with server-enforced human approval on the destructive edits.
When SiteAgent's Ed25519 grant regime is active (a gateway key is provisioned) and grant enforcement is opted in for this plugin, a governed write must present a valid X-Aura-Approval-Grant bound to its exact tool + params. Verified via SiteAgent's Aura_Worker_Grant::verify() (signature, tool/params/site binding, validity window, single-use nonce).
Checked before the tool runs
The grant is verified before the callback executes — so a create-style tool (create-page, build-page, theme-template / popup creation) cannot even wp_insert_post() an unauthorized draft before approval. Missing grant → governance_grant_required; rejected → governance_grant_invalid; neither executes.
Previews are exempt (schema-driven, no hardcoded list)
A grant is skipped only for a dry-run preview: a tool is preview-capable iff its input schema declares an apply flag (the a11y/SEO generators). Such a tool invoked with apply falsy writes nothing and needs no grant. Everything else — edits and create-style writes — is gated. The grant binds to the exposed MCP tool name (/ → -, e.g. elementor-mcp-update-element), matching what the gateway signs.
Opt-in — cannot brick governed sites
Enforcement is OFF by default even when a gateway key exists. SiteAgent enforces grants for its own tools the moment a key is provisioned, but the gateway must also be minting grants for this plugin's tool names first — otherwise every Elementor edit would be denied. Operators enable it (elementor_mcp_require_grants option / filter, or emcp_governance_require_grants()) once the gateway is issuing Elementor-tool grants. With no key or the opt-in off, writes proceed exactly as before. The opt-in is cleared on uninstall.
Combines with 1.17.0's capture-before-write snapshot: an approved write is still snapshotted and rolled back on failure.
Tests
Full suite 657 green; 24 GovernanceFunctionalTest cases. Converged over 6 Codex review rounds — the create-tool-insert-before-write and preview tensions drove the design to "grant before the callback, preview detected from the schema apply flag."
v1.17.0 — SiteAgent governance bridge
SiteAgent governance bridge — capture-before-write for Elementor page edits
The first plank of P0.2 (bring fork writes under SiteAgent governance): agent-driven Elementor page edits now get the same reversal safety SiteAgent already gives its own power tools.
When the SiteAgent worker (digitizer-site-worker) is installed alongside this plugin, any write-capable ability that edits an existing page has the page's Elementor state (_elementor_data + _elementor_page_settings) snapshotted before the write and rolled back if the write fails.
Robust by construction — no hand-maintained tool list
The ability wrapper arms a governed run for the target post; the actual page-data write site (Elementor_MCP_Data::save_page_data() / save_page_settings()) captures the snapshot lazily on the first real write. So:
- Every page-data write is covered automatically — nothing to keep in sync as tools are added.
- Tools that write other state (template conditions →
_elementor_conditions, SEO meta) never reach the write site, so are never snapshotted — no wrong-key rollbacks. - Preview-only calls (an a11y/SEO generator with
apply=false) write nothing, so trigger no snapshot — no spurious denials.
Safety
- Soft dependency — with no SiteAgent installed,
is_active()is false, nothing is wrapped, behaviour is identical to the standalone plugin. Never hard-requires SiteAgent. - Fail closed — if the pre-write snapshot can't be captured (no rollback point), the write is refused rather than made blind.
- A write that returns
WP_Erroror throws is rolled back; if the rollback itself fails, that more-severe partial-write condition surfaces asgovernance_rollback_failed. - Governance seams —
elementor_mcp_governance_write(undo point for the gateway),elementor_mcp_governance_rolled_back,elementor_mcp_governance_rollback_failed.
Scope
Page-data writes. Kit-/repository-scoped writes (global classes, variables, system kit), server-enforced Ed25519 approval grants, and post-write render checks are follow-up planks.
Tests
Full suite 648 green; 15 new GovernanceFunctionalTest cases. Depends on the SiteAgent snapshot_meta primitive (Digitizers/SiteAgent#47). Converged over 4 Codex review rounds (a completeness finding drove the pivot from a fragile tool allowlist to the write-site chokepoint design).