> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wpos.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# The companion plugin

> elementor-ultra-mcp on the WordPress side: the REST seams agents deploy through, and the CSS lifecycle guards that make agent and editor coexistence safe.

The **elementor-ultra-mcp** companion plugin (GPL-2.0-or-later) is the
WordPress side of the stack. It does two jobs: it exposes the REST seams that
`exjsx deploy`, `eu-studio`, and the MCP server write through, and it hardens
the CSS lifecycle around Elementor's atomic pages so automated deploys and human
editor sessions can coexist. It ships bundled in the
[playground](/ultra/playground) snapshot and as a zip in the
[elementor-ultra-mcp releases](https://github.com/Algorismus-io/elementor-ultra-mcp)
for real sites.

All routes live under `elementor-ultra/v1`, authenticated with standard
WordPress application passwords and capability checks. The plugin loads
defensively: it serves what it can regardless of Pro presence or Elementor
version, and `site/capabilities` always answers so health checks work even on a
degraded site.

## The REST seams

| Area             | Routes (summary)                                                                                                                                                                                                  | What they add                                                                                                                                                                                                                                            |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Capabilities     | `site/capabilities`                                                                                                                                                                                               | Elementor and Pro versions, experiment states, plugin version. The first call every tool makes                                                                                                                                                           |
| Documents        | `documents`, `save`, `replace-tree`, `dry-run`, `rollback`, `backups`, `duplicate`, `export`                                                                                                                      | Validated page writes with server-side envelope validation (a 422 names the offending envelope), automatic backups, and rollback                                                                                                                         |
| CSS priming      | `documents/<id>/prime-css`                                                                                                                                                                                        | Makes V4 atomic CSS files actually exist after a headless save. Atomic CSS only renders on frontend hooks, so a REST-saved page has no CSS until primed; this endpoint runs the render dispatch in-process and asserts the files exist and are non-empty |
| Cache            | `cache/regen`                                                                                                                                                                                                     | V3 per-post CSS regen plus the full Elementor CSS flush, executed in-process (the only reliable way: it must run as the uid that owns the css upload dir, and it verifies deletion actually happened instead of trusting Elementor's success string)     |
| Design system    | `design/classes` (+ `usage`, `restore`), `design/variables` (+ batch, restore), `design/global-colors`, `design/global-fonts`, `design/fonts` (+ install, upload-zip), `design/deploy`, `design/element-defaults` | The global class store, variables, and fonts as a governed API, with backups and restore                                                                                                                                                                 |
| Content plumbing | `media` (+ `upload`, `sideload`), `templates`, `nav/menus`, `nav/bind-widget`, `schema/*`, `ops/log`, `batch/*`                                                                                                   | Media with mime gating and SVG sanitization, template import/export, menu binding, widget schemas, an operations log, batch plan/apply                                                                                                                   |

Notes agents hit in practice: `design/classes` is cursor-paginated (default
limit 25 with `next_cursor`); SVG uploads are sanitized with Elementor's own
sanitizer before import; media sideload byte-sniffs extensionless CDN URLs and
rejects anything that is not a known image type.

## The CSS lifecycle guards, in plain words

Elementor's atomic CSS pipeline has failure modes that only show up under
automation. The plugin defuses each one at the seam where it happens.

### Post-scoped invalidation

Priming one page must not invalidate every other page's CSS. The primer scopes
its cache invalidation to the post being primed (`local` and `global` per post
id, mirroring Elementor's own internal callers), instead of the unscoped form
that made multi-page sites play whack-a-mole: priming page B silently
invalidated the file page A's prime had just written. Only the shared `base`
stylesheet stays unscoped, because every page regenerates it identically.

### The license-churn defuse

Elementor runs a **full CSS cache wipe** whenever the Pro license option is
updated or deleted. On any site with Pro installed but unlicensed (every local
and dev stack), admin and editor sessions re-check the license on heartbeats,
churning that option: admin-ajax, license option write, sitewide CSS wipe, "the
whole site lost styling". The plugin detaches that wipe-on-churn hook. A real
license change still takes effect on the next save, deploy, or regen.

### Global-classes wipe protection: backup plus restore

The class store is the styling for every deployed atomic page, and a normal
Elementor editor visit has been observed to empty it. Defense in two parts:

* The plugin continuously snapshots the store whenever it is written
  **non-empty** (an empty store never overwrites a non-empty backup).
* `POST /elementor-ultra/v1/design/classes/restore` writes the snapshot back.

### The mass-deletion guard (409)

The editor keeps an in-memory copy of the class store and PUTs the whole store
back on save, last-writer-wins. If its copy was incomplete (a raced classes
fetch at editor load), that save silently deletes most of the classes sitewide.
The plugin refuses any single write that would delete more than half of a
non-trivial store, returning a 409 with code `EMCP_MASS_DELETE_BLOCKED` and a
message that explains the situation and the escape hatches: retry with the
header `X-EMCP-Allow-Mass-Delete: 1` if the deletion is intentional, and the
restore endpoint if it was not. A failed save the user can see beats a silent
wipe.

### The static-404 guard

Hosts that route unresolved static files into WordPress (the WASM playground;
any standard rewrite setup) let `redirect_canonical()` 301 a missing stylesheet
to the homepage, so HTTP clients see a healthy `200 text/html` for a sheet that
is gone, browsers silently drop it, and health checks read false positives. The
plugin makes any request for a missing asset file under `wp-content` or
`wp-includes` return a real 404. Files that exist on disk are untouched.

### The publish quarantine

A conversion or build that fails its verify gate marks the post quarantined,
and the plugin enforces it at `wp_insert_post_data`: the one seam every publish
flows through (core REST, wp-admin, WP-CLI, MCP). A quarantined post is forced
back to draft on any publish attempt, no matter the vector, until a passing
re-run or a human clears the flag.

## Why the editor and agents can coexist

Put together: deploys write through validated endpoints with backups and
rollback; priming is scoped so pages do not eat each other's CSS; the class
store is continuously backed up, guarded against editor mass-deletes, and
restorable; license churn cannot wipe the site; and dead assets fail loudly
instead of lying. An agent can deploy while a human owns the editor, and the
failure modes that used to silently unstyle a site now either cannot happen or
leave a visible, recoverable trace.

<Note>
  On the playground specifically, still avoid opening deployed pages in the
  editor; the dev bench favors fast iteration over full guard coverage. See
  [Playground](/ultra/playground).
</Note>
