@wootsup/yt-builder-mcp 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -10
- package/dist/server.d.ts +14 -11
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +14 -11
- package/dist/server.js.map +1 -1
- package/dist/tools/pages/builders.d.ts.map +1 -1
- package/dist/tools/pages/builders.js +44 -1
- package/dist/tools/pages/builders.js.map +1 -1
- package/dist/tools/pages/handlers-audit.d.ts +31 -0
- package/dist/tools/pages/handlers-audit.d.ts.map +1 -0
- package/dist/tools/pages/handlers-audit.js +98 -0
- package/dist/tools/pages/handlers-audit.js.map +1 -0
- package/dist/tools/pages/handlers-write.d.ts +12 -2
- package/dist/tools/pages/handlers-write.d.ts.map +1 -1
- package/dist/tools/pages/handlers-write.js +13 -3
- package/dist/tools/pages/handlers-write.js.map +1 -1
- package/dist/tools/pages/index.d.ts +5 -1
- package/dist/tools/pages/index.d.ts.map +1 -1
- package/dist/tools/pages/index.js +5 -1
- package/dist/tools/pages/index.js.map +1 -1
- package/dist/tools/pages/schemas.d.ts +133 -0
- package/dist/tools/pages/schemas.d.ts.map +1 -1
- package/dist/tools/pages/schemas.js +110 -0
- package/dist/tools/pages/schemas.js.map +1 -1
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/skills/yt-builder-mcp/SKILL.md +185 -16
|
@@ -12,15 +12,15 @@ description: Drive the YOOtheme Pro Page Builder on WordPress or Joomla 5/6. Dis
|
|
|
12
12
|
> WordPress and Joomla 5/6.
|
|
13
13
|
|
|
14
14
|
This skill helps AI assistants drive the YOOtheme Pro Page Builder through the
|
|
15
|
-
`@wootsup/yt-builder-mcp` server. The server catalogues
|
|
16
|
-
idempotent tools (
|
|
15
|
+
`@wootsup/yt-builder-mcp` server. The server catalogues 48 typed, scoped,
|
|
16
|
+
idempotent tools (50 callable end-to-end with the two gateways). 41 of them
|
|
17
17
|
advertised as first-class entries in `tools/list`
|
|
18
|
-
(37 essential L1 forwards + 2 direct L3 entries + 2 gateways), and
|
|
18
|
+
(37 essential L1 forwards + 2 direct L3 entries + 2 gateways), and 9 advanced
|
|
19
19
|
tools reachable through the gateways. The write-capable
|
|
20
|
-
`yootheme_builder_advanced` gateway routes all
|
|
20
|
+
`yootheme_builder_advanced` gateway routes all 9; the read-only
|
|
21
21
|
`yootheme_builder_advanced_read` gateway routes only the read-only subset
|
|
22
22
|
(page_get_schema, inspect_sublayout, layout_query, local_content_types,
|
|
23
|
-
local_content_read) and is itself
|
|
23
|
+
local_content_read, pages_audit) and is itself
|
|
24
24
|
read-only-annotated, so MCP hosts can auto-allow pure inspection without a
|
|
25
25
|
per-call write-approval prompt. This 3-lane split keeps `tools/list` well below
|
|
26
26
|
the ~40-tool Cursor cap while every catalogued tool stays fully reachable.
|
|
@@ -55,7 +55,7 @@ entries when the user types "YT Builder MCP" into the picker:
|
|
|
55
55
|
|
|
56
56
|
- **`YT Builder MCP for YOOtheme Pro (unofficial)`**: the MCP **server**.
|
|
57
57
|
Provides the 41 first-class tools (37 essential, 2 direct, 2 gateways).
|
|
58
|
-
The `yootheme_builder_advanced` gateway routes all
|
|
58
|
+
The `yootheme_builder_advanced` gateway routes all 9 advanced tools; the
|
|
59
59
|
read-only `yootheme_builder_advanced_read` gateway routes the read-only
|
|
60
60
|
subset without a write-approval prompt.
|
|
61
61
|
- **`Von YT Builder MCP for YOOtheme Pro`**: the bundled **skill** (this
|
|
@@ -125,10 +125,11 @@ The server exposes:
|
|
|
125
125
|
step that turns a placeholder-filled skeleton into a finished-looking
|
|
126
126
|
page (see "Fill image slots with real on-topic photos" under Layout
|
|
127
127
|
Library).
|
|
128
|
-
- **
|
|
128
|
+
- **9 advanced captured tools**: everything else (page_get_schema,
|
|
129
129
|
element_unbind_source, clean_implode_directives,
|
|
130
|
-
`inspect_sublayout`, `layout_query`, `library_save_as`,
|
|
131
|
-
Content Read tools `local_content_types` / `local_content_read
|
|
130
|
+
`inspect_sublayout`, `layout_query`, `library_save_as`, the two Local
|
|
131
|
+
Content Read tools `local_content_types` / `local_content_read`, and
|
|
132
|
+
`pages_audit`).
|
|
132
133
|
Reachable through one gateway tool:
|
|
133
134
|
`yootheme_builder_advanced({ tool: "<name>", arguments: { ... } })`. For
|
|
134
135
|
example, to inspect a panel/grid_item `< SUBLAYOUT`:
|
|
@@ -143,6 +144,12 @@ The server exposes:
|
|
|
143
144
|
It flags `invalid_source_possible: true` when the saved subtree carries
|
|
144
145
|
bound dynamic sources that may not exist wherever it is later reloaded —
|
|
145
146
|
re-bind after inserting it elsewhere.
|
|
147
|
+
And to run a one-call site-wide SEO/structure/content/links audit
|
|
148
|
+
(read-only, severity-sorted findings + machine-executable fix_hints),
|
|
149
|
+
prefer the read gateway:
|
|
150
|
+
`yootheme_builder_advanced_read({ tool: "yootheme_builder_pages_audit", arguments: { checks: ["seo", "structure"] } })`
|
|
151
|
+
(the write gateway routes it too, if you prefer one entry point:
|
|
152
|
+
`yootheme_builder_advanced({ tool: "yootheme_builder_pages_audit" })`).
|
|
146
153
|
|
|
147
154
|
The core write/refactor + render-verify tools the Glöckle HANDOFF-4/5 ask for
|
|
148
155
|
are now **L1 — call them directly by name**, not through a gateway:
|
|
@@ -184,7 +191,8 @@ The server exposes:
|
|
|
184
191
|
- **2 gateway tools**: `yootheme_builder_advanced` (write-capable; can route
|
|
185
192
|
into delete/unbind, so hosts gate it) and `yootheme_builder_advanced_read`
|
|
186
193
|
(read-only; routes ONLY the read-only advanced subset — page_get_schema,
|
|
187
|
-
inspect_sublayout, layout_query, local_content_types, local_content_read
|
|
194
|
+
inspect_sublayout, layout_query, local_content_types, local_content_read,
|
|
195
|
+
pages_audit —
|
|
188
196
|
and is read-only-annotated so hosts auto-allow it). Prefer the read gateway
|
|
189
197
|
for pure inspection:
|
|
190
198
|
`yootheme_builder_advanced_read({ tool: "yootheme_builder_page_get_schema", arguments: { template_id } })`.
|
|
@@ -196,8 +204,8 @@ The server exposes:
|
|
|
196
204
|
`yootheme_builder_advanced({ tool: "yootheme_builder_local_content_read", arguments: { kind: "entities", type: "post" } })`.)
|
|
197
205
|
|
|
198
206
|
`tools/list` therefore advertises 41 names (37 + 2 + 2). That's 37 L1
|
|
199
|
-
essentials + 2 L3 direct + 2 gateways. The total callable surface is
|
|
200
|
-
(41 advertised +
|
|
207
|
+
essentials + 2 L3 direct + 2 gateways. The total callable surface is 50
|
|
208
|
+
(41 advertised + 9 advanced reachable through the gateways). If the AI
|
|
201
209
|
client reports "tool not found", you are almost certainly calling an
|
|
202
210
|
advanced tool by its raw name. Wrap it in
|
|
203
211
|
`yootheme_builder_advanced({ tool, arguments })` (or the read gateway for
|
|
@@ -736,6 +744,12 @@ must have **exactly one** `<h1>`). Set it explicitly on every headline:
|
|
|
736
744
|
for punch); a big stat number is `title_element: "div"` with
|
|
737
745
|
`title_style: "heading-medium"`.
|
|
738
746
|
|
|
747
|
+
**This `h1` default is specific to `headline`.** Container elements
|
|
748
|
+
(`grid`, `panel`, `slideshow`, and the rest of the item-carrier family)
|
|
749
|
+
default to `h3`, not `h1`, when `title_element` is left unset. See
|
|
750
|
+
"Workflow 6 (SEO audit)" below for the full per-type default table
|
|
751
|
+
`pages_audit` uses to find missing/multiple h1 issues across a whole site.
|
|
752
|
+
|
|
739
753
|
### Headline `content` is plain inline text — never wrapped in `<p>`
|
|
740
754
|
|
|
741
755
|
A `headline` renders its `content` **inside** the heading tag, so wrapping it
|
|
@@ -1238,7 +1252,161 @@ and the props payload you passed.
|
|
|
1238
1252
|
|
|
1239
1253
|
---
|
|
1240
1254
|
|
|
1241
|
-
##
|
|
1255
|
+
## Workflow 6: SEO audit (pages_audit)
|
|
1256
|
+
|
|
1257
|
+
**Goal:** Run one deterministic, site-wide sweep for structure, content,
|
|
1258
|
+
SEO, and link issues, drill into the pages a finding names, and fix them
|
|
1259
|
+
one page at a time through the existing write tools this server already
|
|
1260
|
+
exposes. Never analyze findings by hand and never bulk-apply a fix.
|
|
1261
|
+
|
|
1262
|
+
**Canonical tool-call sequence (real parameter names, snake_case):**
|
|
1263
|
+
|
|
1264
|
+
1. `yootheme_builder_advanced_read({ tool: "yootheme_builder_pages_audit", arguments: { checks: ["seo", "structure"] } })`
|
|
1265
|
+
sweeps the whole site in one call. `pages_audit` is a read-only
|
|
1266
|
+
advanced tool, so reach it through the read gateway (the write
|
|
1267
|
+
gateway routes it too, but the read gateway never triggers a
|
|
1268
|
+
write-approval prompt). Omit `checks`/`types` to run every category
|
|
1269
|
+
against every scanned template.
|
|
1270
|
+
2. Read the response's `findings` array. Each finding carries a `code`,
|
|
1271
|
+
`category`, `severity`, a `count`, up to 30 affected `pages`, and
|
|
1272
|
+
(where a safe automatic fix exists) a `fix_hint` naming the exact
|
|
1273
|
+
write tool and args template to run. `duplicate-layout` and
|
|
1274
|
+
`title-collision` never carry a `fix_hint` — they need a human
|
|
1275
|
+
decision (rename, merge, or intentionally keep as-is), not an
|
|
1276
|
+
automatic patch.
|
|
1277
|
+
3. `yootheme_builder_template_summary({ template_id })` drills into one
|
|
1278
|
+
page a finding names. It carries the same `heading_levels`,
|
|
1279
|
+
`images_missing_alt`, and `disabled_elements` counters the audit
|
|
1280
|
+
used, so you can see exactly which nodes are affected before
|
|
1281
|
+
writing.
|
|
1282
|
+
4. Fix that ONE page via the write tool named in `fix_hint.tool`, with
|
|
1283
|
+
`fix_hint.args_template` as a starting point (`element_update_settings`,
|
|
1284
|
+
`element_add`, etc), ETag-locked like every other write in this
|
|
1285
|
+
server.
|
|
1286
|
+
5. `yootheme_builder_page_publish({ template_id, etag })` republishes.
|
|
1287
|
+
The response's `quick_check` block (default on) re-checks THIS page
|
|
1288
|
+
with the same per-page codes, so you can confirm the fix landed
|
|
1289
|
+
without a second full sweep.
|
|
1290
|
+
|
|
1291
|
+
**Common pitfalls:**
|
|
1292
|
+
|
|
1293
|
+
- **Promising a full SEO audit.** `pages_audit` covers Builder structure
|
|
1294
|
+
and CMS basics only: heading hierarchy, empty/thin pages, missing
|
|
1295
|
+
image alt text, duplicate layouts, title collisions, non-pretty URL
|
|
1296
|
+
fallbacks, stale content, and dead in-page anchors. Every response
|
|
1297
|
+
carries a fixed disclaimer field:
|
|
1298
|
+
`"Meta title/description/OG live in your CMS SEO plugin — not covered here."`
|
|
1299
|
+
It does not read or evaluate Yoast/RankMath/any SEO-plugin meta
|
|
1300
|
+
title, meta description, or Open Graph tags. Say this scope boundary
|
|
1301
|
+
out loud and point the user at their SEO plugin for that layer.
|
|
1302
|
+
- **Confusing the CONTENT count with `pages_list.elements_count`.**
|
|
1303
|
+
`pages_list.elements_count` counts every node, including
|
|
1304
|
+
`section`/`row`/`column`/`fragment` layout wrappers. `pages_audit`
|
|
1305
|
+
instead uses a narrower CONTENT count (`elements_content` in the
|
|
1306
|
+
evidence) that excludes `section`/`row`/`column`/`fragment`/`layout`
|
|
1307
|
+
wrapper nodes: an empty section nested in three columns is correctly
|
|
1308
|
+
`0` content elements, not "not empty" just because the wrappers
|
|
1309
|
+
exist. Both numbers ride in the evidence (`elements_total` and
|
|
1310
|
+
`elements_content`). `thin-content` fires when `elements_content` is
|
|
1311
|
+
below `thin_content_threshold` (default 8); `empty-page` fires at
|
|
1312
|
+
`elements_content === 0`.
|
|
1313
|
+
- **The h1-default trap.** Only `headline` defaults to `h1` when
|
|
1314
|
+
`title_element` is unset. A container element (`grid`, `panel`,
|
|
1315
|
+
`slideshow`, and the rest) left unset does NOT become an `<h1>` — it
|
|
1316
|
+
becomes an `<h3>` (or stays a non-heading `div` for
|
|
1317
|
+
`description_list`). See the per-type default table below and
|
|
1318
|
+
"`title_style` vs `title_element`" above (that section's "defaults
|
|
1319
|
+
to `h1`" rule is specific to `headline` only). `meta_element` is a
|
|
1320
|
+
SECOND, independent heading channel on the same container types,
|
|
1321
|
+
defaulting to `div` and counting only when explicitly set to
|
|
1322
|
+
`h1`-`h6` with `show_meta` not `false`.
|
|
1323
|
+
- **Treating a bound-but-empty slot as missing.** Bound title/meta
|
|
1324
|
+
slots count as filled even when the static prop text is empty — a
|
|
1325
|
+
title bound to a dynamic source field is not "missing" just because
|
|
1326
|
+
the builder-side prop is blank. The same exemption applies to
|
|
1327
|
+
`image_alt`/`background_image_alt`: `images-missing-alt` never flags
|
|
1328
|
+
a bound image-alt slot, only an unbound, empty, or whitespace-only
|
|
1329
|
+
alt on a static image.
|
|
1330
|
+
- **Flagging every `#`-prefixed value as a dead anchor.** A
|
|
1331
|
+
`dead-anchor` finding fires only for a genuinely dangling `#name`
|
|
1332
|
+
link whose target element `id` does not exist anywhere on the same
|
|
1333
|
+
page. It explicitly excludes a bare `#` (a placeholder, never a real
|
|
1334
|
+
target), `mailto:`/`tel:` links, `http(s)://` external links, and
|
|
1335
|
+
cross-page links like `?page_id=…#…` (that anchor lives on a
|
|
1336
|
+
different page's render and cannot be verified from this page's own
|
|
1337
|
+
`props.id` set).
|
|
1338
|
+
- **Treating `missing-h1` as critical, or double-flagging it.**
|
|
1339
|
+
Severity is calibrated from live empirical review, not per-rule
|
|
1340
|
+
guessing: `no-headings` (zero headings anywhere on the page) is
|
|
1341
|
+
critical, but `missing-h1` (headings exist, but none is an effective
|
|
1342
|
+
h1) is only a warning, and it is suppressed entirely when
|
|
1343
|
+
`no-headings` already fired for the same page. Real sites
|
|
1344
|
+
legitimately have h2/h3-only pages with no h1.
|
|
1345
|
+
- **Treating `quick_check` findings as a publish failure.** `quick_check`
|
|
1346
|
+
is advisory only: publish and save always succeed regardless of what
|
|
1347
|
+
it reports. This is not the blocking render-precheck (which still
|
|
1348
|
+
gates on genuinely broken output) — SEO/structure findings are
|
|
1349
|
+
hints, not corruption. `quick_check` only ever includes checks whose
|
|
1350
|
+
`scope` is `"per-page"`; `duplicate-layout` and `title-collision`
|
|
1351
|
+
need the whole site swept to mean anything, so they never appear
|
|
1352
|
+
here — instead the block carries a fixed note:
|
|
1353
|
+
`"run pages_audit for site-wide checks"`. `page_publish` attaches
|
|
1354
|
+
`quick_check` by default (set `quick_check: false` to opt out, e.g.
|
|
1355
|
+
scripted bulk publishes); `page_save` carries it only when you opt
|
|
1356
|
+
in with `quick_check: true`.
|
|
1357
|
+
|
|
1358
|
+
**Per-type `title_element` default table (the correctness crux of every
|
|
1359
|
+
heading finding):**
|
|
1360
|
+
|
|
1361
|
+
| Element type(s) | `title_element` default | Counts as heading? |
|
|
1362
|
+
|---|---|---|
|
|
1363
|
+
| `headline` | `h1` | Yes, unless explicitly overridden. |
|
|
1364
|
+
| `comments` (WP source) | `h2` | Yes, always active. |
|
|
1365
|
+
| `alert`, `gallery`, `grid`, `map`, `overlay`, `overlay-slider`, `panel`, `panel-slider`, `popover`, `slideshow`, `switcher` | `h3` | Yes, when `show_title` is not `false` and the title is non-empty or bound. |
|
|
1366
|
+
| `description_list` | `div` | No. |
|
|
1367
|
+
| `section` (Section Title) | (no field; hardcoded `<div class="tm-section-title">`) | No, ever (counted only as an informational `section_titles` tally). |
|
|
1368
|
+
|
|
1369
|
+
`div` never counts as a heading whether it came from an explicit value
|
|
1370
|
+
or a type default.
|
|
1371
|
+
|
|
1372
|
+
**Worked example (tool-call snippet):**
|
|
1373
|
+
|
|
1374
|
+
```jsonc
|
|
1375
|
+
// Step 1. Sweep the site for SEO + structure issues.
|
|
1376
|
+
yootheme_builder_advanced_read({
|
|
1377
|
+
tool: "yootheme_builder_pages_audit",
|
|
1378
|
+
arguments: { checks: ["seo", "structure"] }
|
|
1379
|
+
})
|
|
1380
|
+
// A finding: { code: "missing-h1", category: "structure", severity: "warning",
|
|
1381
|
+
// count: 3, pages: [{ id: "page:42", label: "About" }, ...],
|
|
1382
|
+
// fix_hint: { tool: "element_update_settings",
|
|
1383
|
+
// args_template: { props: { title_element: "h1" } }, note: "..." } }
|
|
1384
|
+
|
|
1385
|
+
// Step 3. Drill into the flagged page.
|
|
1386
|
+
yootheme_builder_template_summary({ template_id: "page:42" })
|
|
1387
|
+
// heading_levels: { h1: 0, h2: 2, h3: 5, div: 1 }, images_missing_alt: 2
|
|
1388
|
+
|
|
1389
|
+
// Step 4. Fix that ONE page via the write tool the fix_hint named.
|
|
1390
|
+
yootheme_builder_element_update_settings({
|
|
1391
|
+
template_id: "page:42",
|
|
1392
|
+
element_path: "/children/0/children/0",
|
|
1393
|
+
props: { title_element: "h1" },
|
|
1394
|
+
etag: "abc123"
|
|
1395
|
+
})
|
|
1396
|
+
|
|
1397
|
+
// Step 5. Republish; quick_check re-confirms this page is clean.
|
|
1398
|
+
yootheme_builder_page_publish({ template_id: "page:42", etag: "def456" })
|
|
1399
|
+
// Response: { ..., quick_check: { clean: true } }
|
|
1400
|
+
```
|
|
1401
|
+
|
|
1402
|
+
**Success criterion:** A re-run of `pages_audit` (or the `quick_check`
|
|
1403
|
+
block on the next publish) no longer lists the fixed finding for that
|
|
1404
|
+
page, and the response's `summary.critical`/`warning`/`info` totals go
|
|
1405
|
+
down.
|
|
1406
|
+
|
|
1407
|
+
---
|
|
1408
|
+
|
|
1409
|
+
## When something doesn't fit one of these 6 workflows
|
|
1242
1410
|
|
|
1243
1411
|
- **Move an element** (intra-template reorder/reparent): use
|
|
1244
1412
|
`yootheme_builder_element_move({ template_id, element_path,
|
|
@@ -2016,7 +2184,7 @@ perform.
|
|
|
2016
2184
|
|
|
2017
2185
|
<!-- TOOL-CATALOG:BEGIN -->
|
|
2018
2186
|
|
|
2019
|
-
**
|
|
2187
|
+
**48 catalogued tools** plus the `yootheme_builder_advanced` (write) + `yootheme_builder_advanced_read` (read-only) gateways = **50 reachable via `tools/list`** (37 L1 + 2 L3 + 2 gateways = 41 advertised; the gateways route to 9 additional advanced tools, bringing the total to 50 callable). Generated by `scripts/extract-tools.mjs` from the compiled `buildAllTools()` registry. Do not hand-edit this section; re-run `npm run build && node scripts/extract-tools.mjs` after changing tool definitions.
|
|
2020
2188
|
|
|
2021
2189
|
| Tool | Kind | Input keys | Description |
|
|
2022
2190
|
| --- | --- | --- | --- |
|
|
@@ -2051,8 +2219,9 @@ perform.
|
|
|
2051
2219
|
| `yootheme_builder_page_dynamize` | mutating | `conditions`, `element_path`, `etag`, `leaf_map`, `list_source_name`, `page`, `remove_leaves`, `section_name`, `site_id`, `source_map`, `template_id` | One-call way to dynamize a designed section: copies the layout byte-identically and swaps only what you map. Use INSTEAD of hand-editing JSON. Give a REFERENCE (section_name from template_summary, or element_path) + list_source_name + a leaf_map (original leaf field-name → flat flow field; #parent + tuned props kept). A section with several source blocks (Played/Next/Later) dynamizes in ONE call via source_map ({match, source_name, leaf_map?}[]). Sub-query panels: key by "<subquery>.<leaf>". Returns page + `summary`. Requires page.title. Operates on the default site unless site_id is provided. |
|
|
2052
2220
|
| `yootheme_builder_page_get_layout` | read+idempotent | `cursor`, `fields`, `flat`, `force`, `max_chars`, `mode`, `post_id`, `site_id`, `template_id`, `url` | Get the layout tree for one template — address it by `template_id` (from pages_list), `post_id` (numeric post/article id), or `url`. For dynamize/bind prefer `mode:"bindings_only"` (binding skeleton, no style props). Default `mode:"full"` returns nested `{layout, etag}`; `flat:true` gives a depth-first `{elements:[...]}` array (with `fields[]`). A repeated unchanged read auto-skips (`force:true` re-fetches). `max_chars` bounds the text; a clipped read returns `next_cursor` (pass back as `cursor`) to page the rest. Operates on the default site unless site_id is provided. |
|
|
2053
2221
|
| `yootheme_builder_page_get_schema` | read+idempotent | `fields`, `max_chars`, `post_id`, `site_id`, `template_id`, `url` | Get the flat schema for a template — nodes with their JSON-Pointer paths and element types. Lighter than page_get_layout, enough to locate elements before editing. Address by `template_id` (pages_list), `post_id`, or `url`. `fields[]` slims each node; `max_chars` bounds output. Operates on the default site unless site_id is provided. |
|
|
2054
|
-
| `yootheme_builder_page_publish` | idempotent | `etag`, `site_id`, `template_id` | Publish a template — persist state, flush YT + WP caches, snapshot the published-state ETag. ETag optional — when provided, 412 on conflict; when omitted, last-write-wins. Recommended for collaborative edits. Operates on the default site unless site_id is provided. |
|
|
2055
|
-
| `yootheme_builder_page_save` | idempotent | `dry_run`, `etag`, `layout`, `site_id`, `template_id` | Re-run save-transforms + flush caches. Optionally REPLACE the template tree by passing the INNER {type:"layout",children:[...]} tree as `layout` — NOT the full template node page_get_layout returns (rejected 422, would blank the page). Validated + ETag-locked; on reject nothing persists. An unrenderable layout is refused PRE-WRITE (422). `dry_run:true` preflights; the success response carries `previous_layout` for 1-call rollback. Omit `layout` to re-run transforms only. ETag optional (412 on conflict; else last-write-wins). Operates on the default site unless site_id is provided. |
|
|
2222
|
+
| `yootheme_builder_page_publish` | idempotent | `etag`, `quick_check`, `site_id`, `template_id` | Publish a template — persist state, flush YT + WP caches, snapshot the published-state ETag. ETag optional — when provided, 412 on conflict; when omitted, last-write-wins. Recommended for collaborative edits. Operates on the default site unless site_id is provided. |
|
|
2223
|
+
| `yootheme_builder_page_save` | idempotent | `dry_run`, `etag`, `layout`, `quick_check`, `site_id`, `template_id` | Re-run save-transforms + flush caches. Optionally REPLACE the template tree by passing the INNER {type:"layout",children:[...]} tree as `layout` — NOT the full template node page_get_layout returns (rejected 422, would blank the page). Validated + ETag-locked; on reject nothing persists. An unrenderable layout is refused PRE-WRITE (422). `dry_run:true` preflights; the success response carries `previous_layout` for 1-call rollback. Omit `layout` to re-run transforms only. ETag optional (412 on conflict; else last-write-wins). Operates on the default site unless site_id is provided. |
|
|
2224
|
+
| `yootheme_builder_pages_audit` | read+idempotent | `checks`, `max_chars`, `site_id`, `stale_after_months`, `thin_content_threshold`, `types` | One-call site-wide SEO/structure/content/links audit — severity-sorted findings with machine-executable fix_hints (missing/multiple h1, empty/thin pages, missing image alt, duplicate layouts, title collisions, non-pretty URLs, stale content, dead anchors). Filter with `types`/`checks`. Disclaimer: SEO-plugin meta (title/description/OG) NOT covered. Drill in via template_summary; fix one page at a time via each finding's fix_hint. Operates on the default site unless site_id is provided. |
|
|
2056
2225
|
| `yootheme_builder_pages_create` | idempotent | `dry_run`, `layout`, `menu_item`, `published`, `site_id`, `slug`, `status`, `title` | Create a page (WordPress) or article (Joomla 5/6) with a YOOtheme per-page layout. Required: title. Optional: slug, status (default draft), published (default false → live on true: WP publish / Joomla state 1), layout (JSON), menu_item (Joomla SEF route), dry_run (preflight, no persist). Returns page_id (WP) / article_id (Joomla), slug, template_id (page:{id} or article:{id}), etag, warnings. Joomla: a published article has NO SEF route until a menu item points at it — pass menu_item, else frontend_url may 404. Operates on the default site unless site_id is provided. |
|
|
2057
2226
|
| `yootheme_builder_pages_delete` | destructive | `confirm`, `force`, `post_id`, `site_id` | Delete a page (WordPress) or article (Joomla 5/6) with its YOOtheme per-page layout. Requires confirm:true (gate against accidental deletion). Default: trash (recoverable). force:true: permanent delete. Refuses non-page/article types with 403 (Layer 9 defense). Returns deleted:true, page_id (WP) / article_id (Joomla), force_deleted, bumped etag. Operates on the default site unless site_id is provided. |
|
|
2058
2227
|
| `yootheme_builder_pages_list` | read+idempotent | `cursor`, `fields`, `label_contains`, `limit`, `max_chars`, `site_id` | List pages, templates, and layouts in the YOOtheme Pro builder (id, label, type, elements_count, frontend_url, builder_url, serves_context_kind, serves_context_ids per row). CALL THIS FIRST to discover template IDs before page_get_layout / element_list / page_get_schema. Paginates: up to `limit` rows (default 50) plus `total` and a `next_cursor` (pass it back as `cursor`) when more remain. Filter with `label_contains`. Slim rows with `fields:["id","label"]`; bound output with `max_chars`. Operates on the default site unless site_id is provided. |
|