You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This commit was created on GitHub.com and signed with GitHub’s verified signature.
Changed
A risk level for code, and the gate that goes with it (REQ-0107) — operations that
store or run code get their own tier above High, because the honest claim about them is
different: for everything else we can say what will change, and for a program we can only
say what was stored. Adding the tier turned up a real hole. The "Read & edit" permission
level — the one whose own description promises an app can change things but never delete —
decided what to allow by asking whether an operation was High, so anything above High was
not High and went straight through. It now compares levels in order, which refuses a new
top tier by default rather than admitting it. Nothing in the free plugin uses the new tier;
the console learns the words for it, and the test suite refuses any free operation that
claims either the tier or the code module. The Pro screen also lists the eighteen
operations that module will carry, so the console can say what switching it on would
let an app do before any of it is written.
A preview never reproduces an executable payload (REQ-0106) — where a change
touches a code field, the before-and-after shows a byte count and a short digest
instead of the body. The values a preview renders travel further than the preview:
into the response, into the stored plan an operator approves, and into the rollback
table in the console. A snippet's contents are routinely an API key or an SMTP
password, so those three places would have held a live credential. The change is
reported exactly as loudly as before — the field is named, and a rewritten payload
never describes the same as the one it replaced — and rollback still restores the
real body, because restoration reads the snapshot rather than the preview. No
operation writes to one of these fields yet; this lands first so that none can.
Added
SVG images can reach the media library, safely (REQ-0105) — media-svg-upload
adds one SVG so Elementor's icon and image controls can point at it. The file that is
stored is never the file that was sent: the document is rebuilt from an allowlist of
drawing elements, and scripts, event handlers, embedded HTML, stylesheets, external
references and entity declarations do not survive that rebuild. Everything removed is
reported as a warning and the exact document that will be stored is shown in the
preview, so what is approved is what will exist. It is the only path allowed to store
markup — the ordinary upload and import operations still refuse SVG outright — and it
asks for unfiltered_html as well as upload_files, because storing an SVG is closer
to publishing markup than to uploading a photograph. The site's own upload permissions
are untouched: nothing about the WordPress media screen changes.
Build, empty and create whole Elementor pages (REQ-0104) — elementor-document-build replaces a page's entire layout with one you supply, elementor-document-clear empties a page, and elementor-document-create makes a
new page for a layout to live on. All three refuse a layout using a widget this site
does not have installed, and refuse any setting key the widget carrying it does not
declare, rather than storing it and letting Elementor drop the text silently. Build
and clear both preview, snapshot and roll back, and both refuse a request that would
leave the page exactly as it already is instead of reporting a change that never
happened. A created page is always a draft, so nothing an agent sends can put an
unreviewed page in front of visitors, and it is a real Elementor page from the moment
it exists — the layout you ask for reaches its page settings, and every other
Elementor operation will work on it.
Elementor page settings, child order and element names (REQ-0103) — elementor-page-settings-get and elementor-page-settings-set read and change the
settings a page carries as a whole (its layout template, whether the title shows), elementor-elements-reorder sets the order of one element's children, and elementor-element-label-set names an element in the navigator. Page settings live in
their own meta row, so the write snapshots that row and not the document — a rollback
puts the settings back and leaves the page's content untouched. The write reaches a
closed list of settings and merges into the stored row, so anything SiteHelm does not
name survives it, while the read returns the whole row so an agent can see what else is
there. A reorder demands the parent's complete list of children, so a request written
against a page that has since gained one fails loudly instead of quietly guessing where
the new element belongs.
The Elementor template library, as a first-class surface (REQ-0102) — elementor-template-list and elementor-template-get read the templates the site has
saved, elementor-template-save stores a document or a single element as a new one, elementor-template-apply inserts one into a page, elementor-template-import brings
in a template this site did not produce, and elementor-theme-template-create makes an
empty theme document. An apply re-mints every element id against the destination page
and rebinds the styles that pointed at them, so the same template inserted twice does
not collide with itself. Apply and import both check a template against the widgets this
site actually has and name the missing ones, rather than writing a tree the page cannot
render. A theme document is created with no display conditions, so it shows nowhere
until elementor-theme-conditions-set says where.
Elementor 4 global classes (REQ-0101) — elementor-global-class-list, elementor-global-class-create, elementor-global-class-update, elementor-global-class-delete and elementor-global-classes-reorder cover the
reusable style classes Elementor 4 keeps site-wide: read them in cascade order, add one,
rename one or merge style properties into it, remove one, and set the order they cascade
in. The class set is one snapshotted unit, so every change is reversible as a whole. A
write refuses while the editor is holding unpublished class changes instead of
overwriting them, and the read reports that divergence as inEditorSync. A delete says
how many documents wear the class before it is approved, and never edits a document — so
restoring the class restyles every element that wore it.
Find a phrase everywhere on the site (REQ-0092, Free half) — content-search names
every post, page and custom post type whose title, content, excerpt or Elementor data
mentions a phrase, with a per-field count, a plain-text excerpt of the first occurrence,
and a link to each document. The phrase is matched whole, not split into words, so
searching for an old company name does not return every page carrying the word "name".
Results are filtered document by document against your own WordPress user's edit_post capability, so a search cannot become a way to read drafts you may not open.
Elementor pages are found — their text lives in post meta, which WordPress's own search
does not read — and reported at the document level, with elementor-element-search
naming the individual elements inside one of them. A phrase JSON would store escaped is
flagged elementorExact: false rather than presented as a complete answer, and a search
broad enough to match most of the site stops at five hundred documents and says so.
WooCommerce is a module the console knows about (REQ-0057, groundwork) — the
Modules screen lists WooCommerce alongside the built-in nine, with its own permission
level and its own requirement line, and the Pro screen names the eight operations it
brings: products listed, read, created and updated (name, description, SKU, price, sale
price, stock and categories), product categories listed, and orders and customers read.
Orders and customers are read-only by design — SiteHelm will not rewrite a shop's
financial record. The operations themselves ship in the SiteHelm Pro add-on; the free
plugin carries the identifier, the console copy and the capability reservation so that
an add-on can register them without the free plugin changing again.
Forms, listed and read (REQ-0084, Free tier) — form-list names every form the
site's form plugin holds with its embed shortcode, form-get reads one form's fields
(name, type, required) exactly as the stored template declares them, and form-entries-list reads a form's recent entries where the plugin stores any — for
Contact Form 7, which delivers each entry by email and stores none, the answer says so
plainly instead of erroring. Entries gate on manage_options because a submission can
carry a visitor's personal information. Everything is read-only: no form write, no
entry deletion. Other form plugins arrive through the same provider seam as an add-on.
Five more SEO plugins speak the shared vocabulary (REQ-0083) — All in One SEO,
SEOPress, The SEO Framework, Slim SEO, and SureRank now serve the six existing SEO
operations alongside Yoast SEO and Rank Math. The same field names read and write
whichever plugin the site runs, the answer names its provider, and precedence
across a multi-plugin site is fixed (Yoast, Rank Math, All in One SEO, SEOPress,
The SEO Framework, Slim SEO, SureRank). A field a plugin has nowhere to store reads
as null and a write to it promises null in the preview instead of failing after
the fact.
Site settings, read and write (REQ-0062) — site-settings-read answers the whole
thirteen-field allowlist (title, tagline, timezone, date and time formats, posts per
page, front page geometry, permalink structure, default comment and ping status,
search-engine visibility) typed in one call, and site-settings-set changes any subset
of it as one previewed, snapshotted, reversible change. Values are validated strictly
at plan time — a timezone must be a real identifier, a custom permalink structure must
keep every post's URL unique, a front page must be a published page — and nothing
outside the allowlist is reachable. Changing the permalink structure flushes rewrite
rules and warns that existing URLs change; turning search-engine visibility off warns
that removal from indexes is not guaranteed.