Skip to content

Releases: Digitizers/elementor-mcp

v1.25.1 — de-brand upstream links + readme sync

Choose a tag to compare

@BenKalsky BenKalsky released this 08 Jul 16:07
47d09b6

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 proxy bin/README.md plugin 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)

Choose a tag to compare

@BenKalsky BenKalsky released this 08 Jul 13:27
d234b80

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 lazy before_global_classes_write() at the repo write site snapshots the whole transaction. apply-global-class stays 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-valued used_classes fallback the single-valued snapshot can't restore).
  • Corrected the delete-global-class description (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)

Choose a tag to compare

@BenKalsky BenKalsky released this 08 Jul 10:46
9707898

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 call before_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's snapshot_meta; run_governed() rolls the kit back on failure. A first-write create is fully reverted (SiteAgent's restore deletes 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

Choose a tag to compare

@BenKalsky BenKalsky released this 07 Jul 22:44
2e450a7

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.

  • numberminimum/maximum from min/max, and multipleOf from step only when an explicit min lands 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 unit enum (from size_units, else the range's unit keys) and, when the control offers exactly one unit, a size minimum/maximum from that unit's range. Multi-unit sliders leave size unconstrained.

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)

Choose a tag to compare

@BenKalsky BenKalsky released this 07 Jul 21:37
93a1143

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.com and 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_backup store, manage_options-gated, no license).
  • Sample Prompts tab — the 5 bundled .md blueprints with one-click copy.

Restored

  • Native uninstall.php (cleanup previously ran via Freemius's after_uninstall hook). Deletes plugin-owned options/transients/user-meta, runs the generated-executable-PHP cleanup, and is multisite-aware (iterates every site). Does not touch shared fs_* 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

Choose a tag to compare

@BenKalsky BenKalsky released this 07 Jul 16:53
d016be3

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-headingtag: { type: string, enum: [h1…h6] }, title: { type: html }, link: { type: link }, classes: { type: classes }
  • e-paragraph content prop is paragraph (not content); e-button is text.

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

Choose a tag to compare

@BenKalsky BenKalsky released this 07 Jul 16:02
0c9d9c3

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-widget with an unknown widget_typeinvalid_widget_type whose data includes suggestions (ranked exact → substring → smallest edit distance) and a schema_hint pointing at get-widget-schema.
  • elementor-mcp/get-widget-schema (the primary discovery tool) and Schema_Generator::generate() return the same suggestions in their widget_not_found error data.
  • 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)

Choose a tag to compare

@BenKalsky BenKalsky released this 07 Jul 15:37
5206c3d

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 an elementor_library template/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_permalink filter 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

Choose a tag to compare

@BenKalsky BenKalsky released this 07 Jul 13:31
231a64f

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

Choose a tag to compare

@BenKalsky BenKalsky released this 07 Jul 12:27
83d6ce0

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_Error or throws is rolled back; if the rollback itself fails, that more-severe partial-write condition surfaces as governance_rollback_failed.
  • Governance seamselementor_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).