Skip to content

v1.27.0 — P3.3 atomic correctness + attachment-alt authorization

Choose a tag to compare

@BenKalsky BenKalsky released this 07 Aug 16:11
· 28 commits to main since this release
244a2bf

P3.3 — atomic (Elementor 4.0+) correctness

Writes to atomic elements now land as the typed prop shapes Elementor actually stores, instead of saving successfully and rendering as nothing.

Whole-tree prop coercion. Atomic_Props::coerce_tree() runs at the top of save_page_data() — before the governance snapshot — and coerces every element's settings against the widget's own prop schema, so a plain title: "Hi" becomes the envelope the prop declares. Candidate envelopes come only from members the prop described itself (get_key, get_prop_types, get_shape, get_item_type, aliases); the generic primitive fallback runs only for props that did not describe themselves. Eight review rounds converged on that rule: Elementor's primitive validation accepts an "empty" enveloped value for a non-required prop before the type/enum check, so a guessed foreign envelope stores a malformed prop that validates and then renders nothing.

Atomic style wiring. update-element-settings hoists root-level styles / editor_settings to their proper top-level keys, deep-merges instead of replacing, and syncs local class references so a written style is actually referenced from settings.classes. Hoisting requires a positive atomic signal — the e- slug prefix is a convention, not an authority, and when there is no answer the element is treated as classic (an un-hoisted key is inert; a wrongly hoisted one destroys data).

Shared convenience mapper. Elementor_MCP_Atomic_Widget_Map is the single source of the friendly-param → typed-prop mapping, so the add-atomic-* tools and build-page produce byte-identical settings for the same input — build-page previously passed settings through raw and an atomic widget given friendly params came out empty. Props the caller already typed pass through untouched rather than being sanitized to an empty string.

Security

The attachment alt write (_wp_attachment_image_alt) implied by add-atomic-image / build-page is now authorized against the attachment (edit_post on the attachment — editing the page a media item sits on never granted edit rights over the item) and deferred until the page save succeeds. A media prop the caller typed itself cancels the write outright: the alt belongs to the image the widget renders, and the friendly image_id then names an attachment that is not on the page.

Also fixed

  • Upstream-correct media shapese-image emits an id-XOR-url image-src with an image-attachment-id envelope and the alt inside src; e-self-hosted-video's source is the video-src shape on 4.x, where a bare url envelope makes Elementor refuse the element outright.
  • SEO extractor descends through an atomic image's src, and for a media-library image the library's alt is authoritative — Elementor renders _wp_attachment_image_alt and ignores src.alt, so an empty library alt is the real state.
  • Four upstream ports — silent-save verification (a truthy Document::save() that persisted nothing now falls back to direct meta), local style classes re-minted on duplicate, fatal-proof ability registration, and structuredContent normalization for strict MCP clients.

readme.txt also catches up: its Stable tag was two releases behind, and its changelog and upgrade notices were missing 1.26.0.

Tests: 852 green on PHP 8.0 / 8.1 / 8.2.

Full details in CHANGELOG.md.