You only need this page when you are looking for a particular extra function or want to know exactly what your assistant may do. For your first article or landing page, simply follow the Quick start. It explains every necessary step without this technical reference.
Source contract of this reference: Companion 0.4.121, Power 0.6.38, and CLI and Skills 0.4.91. This page describes the schemas and boundaries of that source contract. The public changelog records public availability. The installed version is authoritative for the schemas actually available.
An *ability* is one clearly limited action that your assistant is allowed to take on your WordPress site. For example, it can create a new draft, read an existing post, or check whether a page renders correctly. An ability may only do what is described here.
Free includes 34 core abilities. Paid unlocks the complete Companion feature set. Which abilities you see in your assistant also depends on your licence, the chosen feature profile, and compatible plugins on your WordPress site. Seeing fewer abilities is therefore not automatically an error.
This reference describes Companion, the normal and recommended part of WPAgently. Power is a separate plugin for development and staging tasks. As a regular WordPress user, leave Power turned off. If you deliberately need it for a test environment, read Power mode first.
Format per ability
Every entry gives the complete technical name (wp-agent/...), explains its purpose, and shows the information it needs and returns. It also states the WordPress permission that is checked. “Read-only” means the ability only looks at information. “Write” means it can change something. A short example helps you understand its use.
“Re-read-verified” means: after making a change, WPAgently reads the result from WordPress once more. It only reports success after that check confirms the change arrived.
Dynamic JSON documents
Where a public ability exposes provider-defined or otherwise dynamic JSON, it does not publish an open MCP object. Native block attributes and supports use the closed, versioned {format,json,sha256,bytes} envelope. format is wpagently.native-block-json.v1; bytes and sha256 bind the UTF-8 JSON. The Spectra, GenerateBlocks, and Kadence attribute writers accept the same envelope and return it in written_attributes.
Elementor and Beaver Builder use their own closed builder-document envelope, {json,sha256,bytes}, for dynamic elements, settings, and patches. It intentionally has no format member. Before a response or mutation, the server decodes the value and validates it again against the documented provider boundary. A dynamic value that exceeds the applicable size, depth, or item limit, or cannot be normalized to the public contract, fails closed instead of being truncated. Static fields retain their individual schemas. The envelope neither expands the write allowlist nor opens other provider data.
The source contract 0.4.121 additionally wraps only explicitly allowlisted legacy dynamic provider values in {format,json,sha256,bytes}. Its format is either wpagently-json-object-v1 or wpagently-json-array-v1. This covers the SEO and post-schema paths, post, product, and variation readback, Fluent Forms fields and entries, Gravity Forms input, Formidable Forms, form migrations, and the dynamic sections of get-site-context. It applies only to the named dynamic value, not to the ability's other fields. Each document is limited to at most 2 MiB. The complete public input or output remains bounded to 8 MiB, 32 levels, and 16,384 values. New open shapes are rejected at registration. Dynamic maps remain permitted only with a fixed value schema and then have at most 256 properties. Their keys are 1-191 bytes long and contain no ASCII control characters.
The confirmed Live Editor uses a further separate {format,json,sha256,bytes} envelope with format=wpagently.live-editor-json.v1. Gutenberg receives attributes and blocks in this form; Elementor receives element, elements, settings, settings_patch, and style_patch. Live Editor command results use the same form under result. A request and every envelope within it are limited to 100,000 bytes. The envelopes do not replace visible confirmation, approval, or provider validation.
1. Content lifecycle (posts and pages)
wp-agent/create-post-from-markdown
Purpose: The plugin's sole remote write path for new content. Converts Markdown server-side into valid Gutenberg blocks and creates a new post. The optional post_id path only marks an update attempt and currently returns HTTP 409 with manual_only without mutation. It prevents the silent core/freeform fallback (Classic Editor fallback) and reports a block report. See also wp-agent/update-post: the existing-post path is currently manual-only as well.
Capability: edit_posts (coarse gate) plus a fine-grained post-type check for new posts: the create capability (wpagent_post_type_create_cap) and the matching edit capability of the target post type (e.g. edit_pages for post_type=page). A post_id is rejected with manual_only before a remote update.
Traits: create is write and non-destructive. update is manual_only. The flat annotations are remote_create=true and manual_only_update=true; idempotent is false.
| Parameter | Type | Required | Description |
|---|---|---|---|
markdown | string | yes | Article text in Markdown. |
title | string | yes | Post title. |
status | string (enum: draft, publish, pending, private) | no | Default draft. |
slug | string | no | Optional slug. When creating, the ability passes it to WordPress's sanitize_title() function; the API schema limits the string to 200 characters. If omitted, WordPress generates the slug from the title. |
excerpt | string | no | |
category | string | no | Category name; created if needed and set exclusively. |
post_id | integer | no | Marks an update attempt. The current contract returns HTTP 409 with manual_only and performs no mutation. |
post_type | string | no | Target type for new content, must be registered and public. No remote update is performed for the manual-only update attempt. |
expected_state_hash | string | no | Fresh content_state_hash from get-post, reserved for supervised update planning. The current update path does not mutate. |
The CLI pipelines wp-agent article and wp-agent landing add a preflight check: an explicit slug must already be in WordPress's native stored form. The CLI rejects raw Unicode, uppercase letters, repeated or trailing hyphens, and 59 percent-encoded sequences that WordPress core normalizes while saving, including encoded spaces and punctuation. Stable percent-encoded UTF-8 sequences such as %e4%bd%a0%e5%a5%bd and repeated underscores remain allowed. Omit the slug to let WordPress generate it from the title.
| Output field | Type | Description |
|---|---|---|
post_id | integer | |
url | string | |
status | string | |
content_hash | string | SHA-256 of the converted content. |
content_state_hash | string | Full state hash of the newly created post. |
block_count | integer | |
freeform_count | integer | |
block_types | string[] | |
updated | boolean | false for a remote create; a manual-only update returns no success output. |
Example:
{ "title": "New blog post", "markdown": "# Heading\n\nText.", "status": "draft", "category": "SEO" }
A successful call creates a new post remotely. If post_id is supplied, the ability instead returns HTTP 409 with manual_only; no existing post is changed.
wp-agent/get-post
Purpose: Reads the core metadata of a post or page (any registered, public post type) including a block report, without needing a second render-check call.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id) (automatically resolves to the matching post-type capability, e.g. edit_pages).
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
post_id | integer | yes |
| Output field | Type |
|---|---|
id, parent, menu_order, block_count, freeform_count | integer |
post_type, status, title, slug, excerpt, date, modified | string |
state_hash | string |
state_hash is the exact SHA-256 state for supervised update planning. The current update-post call keeps it in the documented input contract but returns HTTP 409 with manual_only before any remote mutation.
Example: { "post_id": 42 }
wp-agent/list-posts
Purpose: Lists posts or pages of a post type with search, status, and pagination filters as a lean list. The post type is generic but validated against registered, public types.
Capability: edit_posts (coarse) plus the edit capability responsible for the specific post_type (wpagent_post_type_edit_cap).
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
post_type | string | no | Default post. |
status | string | no | Default any. |
search | string | no | |
per_page | integer | no | Default 20, capped at 100. |
page | integer | no | Default 1. |
| Output field | Type |
|---|---|
items[] | Objects with id, title, status, type, date, slug |
total | integer |
Example: { "post_type": "page", "status": "publish", "per_page": 10 }
wp-agent/update-post
Purpose: Preflight for a partial update of an existing post or page. The current remote writer is unavailable: the ability neither reads nor mutates the post, but returns HTTP 409 with manual_only. expected_state_hash remains part of the input contract but does not authorize a mutation. After a manual change, wp-agent/get-post can read the state again. The create mode of wp-agent/create-post-from-markdown remains a separate remote path.
Capability: edit_posts (coarse gate). The current callback exits before a post-specific remote check or mutation with manual_only.
Traits: manual-only, non-destructive, not idempotent. The current contract writes no post fields.
| Parameter | Type | Required | Description |
|---|---|---|---|
post_id | integer | yes | |
expected_state_hash | string | yes | Exact state_hash from a fresh get-post call. The current execution returns HTTP 409 with manual_only regardless of the hash. |
title | string | no | |
content_markdown | string | no | Converted server-side into blocks, same as with create-post-from-markdown. |
excerpt | string | no | |
slug | string | no | |
status | string (enum: draft, publish, pending, private, future) | no | It is not changed remotely under the current contract. |
date | string | no | Parseable date/time, interpreted as site time when no timezone is given. |
menu_order | integer | no | |
parent | integer | no |
| Output field | Type | Description |
|---|---|---|
post_id | integer | |
post_type | string | |
written | object | Schema field from the former success contract. It is not present in the current manual_only result. |
verified | boolean | Schema field from the former success contract, not proof of a current mutation. |
block_count, freeform_count | integer | Schema fields for content_markdown; absent in manual_only. |
block_types | string[] | Schema field for content_markdown; absent in manual_only. |
has_freeform | boolean | Schema field for content_markdown; absent in manual_only. |
previous_state_hash, state_hash | string | Schema fields for a former verified update contract; absent in manual_only. |
Example:
{ "post_id": 42, "expected_state_hash": "<64-character SHA-256 from get-post>", "title": "New title" }
The current response is HTTP 409 with manual_only and recovery_required: false; WordPress receives no change. Edit the post under supervision in WordPress, then read it again with wp-agent/get-post.
wp-agent/set-post-status
Purpose: Preflights a requested post or page status transition (publish, draft, pending, private, future) against the complete state from get-post. The current lifecycle writer performs no remote mutation. After a fresh re-read and conflict-hash check, it returns HTTP 409 with manual_only before WordPress changes the status. A future date remains part of input validation for future.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id) plus the capability matching the target status (wpagent_check_post_status_cap, e.g. publish_posts for publish).
Traits: manual-only, non-destructive, not idempotent. The current contract does not mutate post status.
| Parameter | Type | Required | Description |
|---|---|---|---|
post_id | integer | yes | |
status | string (enum: publish, draft, pending, private, future) | yes | |
date | string | for status=future | Must be in the future. |
| Output field | Type |
|---|---|
post_id | integer |
status | string |
verified | boolean |
Example: { "post_id": 42, "status": "publish" }
wp-agent/trash-post
Purpose: Preflights moving a post or page to the trash against the complete state from get-post. The current lifecycle writer performs no remote mutation and returns HTTP 409 with manual_only after a fresh re-read. The action must be completed in supervised WordPress administration. A manual trash action remains reversible through wp-agent/restore-post.
Capability: edit_posts (coarse) plus current_user_can('delete_post', $post_id).
Traits: manual-only, non-destructive, not idempotent. The current contract does not trash a post remotely.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
| Output field | Type |
|---|---|
post_id | integer |
status | string |
verified | boolean |
Example: { "post_id": 42 }
wp-agent/restore-post
Purpose: Preflights restoring a post or page from the trash against the complete state from get-post. The current lifecycle writer performs no remote mutation and returns HTTP 409 with manual_only after a fresh re-read. The action must be completed in supervised WordPress administration. There, the earlier status from _wp_trash_meta_status may be restored; future remains excluded because of the risk of immediate cron publishing.
Capability: edit_posts (coarse) plus current_user_can('delete_post', $post_id).
Traits: manual-only, non-destructive, not idempotent. The current contract does not restore a post remotely.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
| Output field | Type |
|---|---|
post_id | integer |
status | string |
restored | boolean |
verified | boolean |
Example: { "post_id": 42 }
wp-agent/delete-post
Purpose: Moves a post conflict-protected only to the reversible trash. force=true is rejected with HTTP 409 before any mutation. Permanently delete the post only manually in WordPress administration. Pages configured as the front page or posts page remain protected (wpagent_check_protected_post).
Capability: edit_posts (coarse) plus current_user_can('delete_post', $post_id).
Traits: write, non-destructive, not idempotent. The remote change requires a fresh expected_state_hash.
| Parameter | Type | Required | Description |
|---|---|---|---|
post_id | integer | yes | |
expected_state_hash | string | yes | Complete state_hash from get-post. |
force | boolean | no | Default false. true is rejected with HTTP 409 before any mutation. |
| Output field | Type |
|---|---|
post_id | integer |
forced, trashed, deleted, verified | boolean |
previous_state_hash, state_hash | 64-character SHA-256 string |
Example: { "post_id": 42, "expected_state_hash": "<SHA-256 from get-post>" }
wp-agent/search-replace-content
Purpose: Finds a literal string in the title, excerpt, or content of public posts and replaces it within strict bounds. Dry-run is the default. At most 1,000 candidates are scanned and at most 100 posts are changed per operation. HTML structure, block comments, and proprietary builder storage are rejected. Every real change is read back and linked to a seven-day undo snapshot.
Capability: edit_posts plus current_user_can('edit_post', $post_id) for every match.
Traits: write, non-destructive, not idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
search, replace | string | yes | Different literal values, at most 200 bytes each. |
fields | string[] | no | title, excerpt, content; all three by default. |
post_types, statuses, post_ids | arrays | no | Limit the search to public types, safe statuses, or at most 100 IDs. |
limit | integer | no | 1 to 100, default 100. |
dry_run | boolean | no | Default true. |
Output: dry_run, matched_posts, updated_posts, total_replacements, items, operation_id, verified.
Example: { "search": "490 dollars", "replace": "590 dollars", "post_types": ["page"], "dry_run": true }
wp-agent/undo-content-replace
Purpose: Restores the complete previous state of an operation created by search-replace-content. Before writing and again under an exclusive lock, it verifies that every affected field still exactly matches the replacement result. Any intervening change rejects the entire restore.
Capability: edit_posts plus edit_post for every affected post. Only the operation creator or a user with manage_options may undo it.
Traits: write, non-destructive, idempotent.
Input: operation_id (required), dry_run (default true). Output: dry_run, restorable_posts, undone, verified.
Example: { "operation_id": "123e4567-e89b-12d3-a456-426614174000", "dry_run": false }
2. Taxonomies
wp-agent/create-term
Purpose: Creates a new term in a taxonomy (e.g. category or tag). parent is only allowed for hierarchical taxonomies. Re-read-verified per field.
Capability: edit_posts (coarse) plus the manage_terms capability of the specific taxonomy (get_taxonomy($tax)->cap->manage_terms, fail-closed to do_not_allow).
Traits: write, non-destructive, idempotent (a duplicate name is rejected by wp_insert_term()).
| Parameter | Type | Required | Description |
|---|---|---|---|
taxonomy | string | yes | Must be registered (e.g. category, post_tag). |
name | string | yes | |
slug | string | no | |
parent | integer | no | Only for hierarchical taxonomies. |
description | string | no |
| Output field | Type |
|---|---|
term_id, parent | integer |
taxonomy, name, slug | string |
written | object |
verified | boolean |
Example: { "taxonomy": "category", "name": "WordPress" }
wp-agent/get-term
Purpose: Reads a single term (name, slug, description, parent term, count of assigned objects).
Capability: edit_posts (coarse) plus the weakest standard taxonomy capability, assign_terms (minimal sensible read gate).
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
term_id | integer | yes |
taxonomy | string | yes |
| Output field | Type |
|---|---|
id, parent, count | integer |
taxonomy, name, slug, description | string |
Example: { "term_id": 5, "taxonomy": "category" }
wp-agent/list-terms
Purpose: Lists terms of a taxonomy with search, hide_empty, and parent-term filters. number caps the result count (default 100, maximum 500).
Capability: edit_posts (coarse) plus assign_terms of the specific taxonomy.
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
taxonomy | string | yes | |
search | string | no | |
hide_empty | boolean | no | Default false. |
parent | integer | no | Only direct child terms. |
number | integer | no | Default 100, capped at 500. |
| Output field | Type |
|---|---|
items[] | Objects with id, name, slug, taxonomy, parent, count, description |
count | integer |
Example: { "taxonomy": "post_tag", "hide_empty": true, "number": 50 }
wp-agent/update-term
Purpose: Prepares a change to an existing term's name, slug, parent term, or description for manual WordPress administration. The ability does not update a term. It returns HTTP 409 with manual_only before any mutation. A term must not be its own parent term.
Capability: edit_posts (coarse) plus edit_terms of the specific taxonomy.
Traits: manual-only, change it in WordPress, no remote mutation.
Remote call: Not available. The callback returns HTTP 409 with manual_only before a term-specific content check or mutation. Change the term in WordPress and then read it again.
wp-agent/delete-term
Purpose: Checks the input for manually deleting a term from a taxonomy. The ability deletes no term and returns HTTP 409 with manual_only before any mutation. WordPress has no trash for terms. Do not delete a taxonomy's default term (for example, the default category).
Capability: edit_posts (coarse) plus delete_terms of the specific taxonomy.
Traits: manual-only, change it in WordPress, no remote mutation.
Remote call: Not available. The current term, hash, and confirmation checks can only prepare the delete. The callback does not delete and returns HTTP 409 with manual_only. Delete the term in WordPress and then read it again.
wp-agent/set-post-terms
Purpose: Checks a planned manual term assignment for a post. The ability assigns no terms, creates no new terms, and returns HTTP 409 with manual_only before any mutation. Make the change in WordPress.
Capability: current_user_can('edit_post', $post_id) plus assign_terms of the specific taxonomy.
Traits: manual-only, change it in WordPress, no remote mutation.
Remote call: Not available. The callback assigns no terms and returns HTTP 409 with manual_only. Change the requested assignments in the post editor and then read the post again.
3. Media
wp-agent/upload-media
Purpose: Downloads an image from a public http(s) URL and creates it as a new media item via media_handle_sideload(). Alt text is required and is re-read-verified. SSRF-protected: only http/https, localhost/.localhost blocked, every resolved DNS address (A and AAAA) as well as every redirect hop (maximum 3) is checked against private/loopback/link-local ranges (FILTER_FLAG_NO_PRIV_RANGE/FILTER_FLAG_NO_RES_RANGE), fail-closed for unresolvable hosts.
Capability: upload_files.
Traits: write, non-destructive, not idempotent (every call creates a new media item).
| Parameter | Type | Required | Description |
|---|---|---|---|
source_url | string | yes | Public http(s) URL. |
alt | string | yes | Not empty. |
post_id | integer | no | Default 0 (unattached). Parent post. |
| Output field | Type |
|---|---|
media_id, post_id | integer |
url, mime_type, alt | string |
verified | boolean |
Example: { "source_url": "https://example.com/image.jpg", "alt": "Product photo, front view" }
wp-agent/create-direct-media-upload
Purpose: Prepares a direct upload of a local file. The file does not pass through REST or MCP and does not need a public intermediary URL. The ability returns a POST endpoint and the required headers. The client then sends the raw file bytes as application/octet-stream.
Capability: valid Companion gate, a connected safe Editor without Administrator or Super Administrator privileges, and upload_files. A parent post additionally requires edit_post.
Traits: write, non-destructive, not idempotent. A new call replaces the same user's pending slot. The 256-bit token is valid for five minutes and one use, appears only in the X-WPAgent-Upload-Token header, and is stored server-side only as a SHA-256 hash. HTTPS is mandatory outside local development environments. The limit is the smaller of the WordPress server limit and 64 MiB. The filename, permitted WordPress file type, actual MIME content, image alt text, parent permission, file size, and unmodified transfer are validated fail-closed.
| Parameter | Type | Required | Description |
|---|---|---|---|
filename | string | yes | Local basename without a path. Its extension must map to a WordPress MIME type allowed for the Editor. |
alt | string | for images | Non-empty alt text. Optional for other media types. |
post_id | integer | no | Default 0. Optional parent post. |
max_bytes | integer | no | Optional smaller limit for this slot. |
| Output field | Type |
|---|---|
url, method, expires_at, filename | string |
user_id, post_id, max_bytes | integer |
one_time | boolean |
headers | object with X-WPAgent-Upload-Token and Content-Type |
After a successful upload, the HTTP endpoint responds with attachment_id, post_id, the actual stored filename, mime_type, bytes, alt, url, and verified=true. The file, size, MIME type, author, parent post, URL, and alt text are re-read after saving. If that check fails after creation, the new attachment is preserved and the response is HTTP 409 with code wpagent_direct_upload_recovery_required, recovery_required=true, and the non-secret attachment_id for manual inspection. WordPress has no atomic compare-and-delete operation here. The upload token, file contents, and file path are not exposed in this recovery response.
wp-agent/revoke-direct-media-upload
Purpose: Revokes the current safe Editor's pending direct-upload slot.
Capability: same as create-direct-media-upload.
Traits: write, non-destructive, idempotent. The output contains revoked as a Boolean.
wp-agent/set-alt-text
Purpose: Sets the alt text of an existing media item (_wp_attachment_image_alt). An empty string is a valid target value (deliberate clearing is possible).
Capability: edit_posts (coarse) plus current_user_can('edit_post', $attachment_id).
Traits: write, non-destructive, not idempotent. The write is bound to a fresh state hash and must not be blindly repeated after an unclear result.
| Parameter | Type | Required |
|---|---|---|
attachment_id | integer | yes |
alt | string | yes |
expected_state_hash | string | yes |
expected_state_hash is the fresh state_hash from the preceding read.
| Output field | Type |
|---|---|
attachment_id | integer |
alt | string |
verified | boolean |
previous_state_hash | 64-character SHA-256 string |
state_hash | 64-character SHA-256 string |
Example: { "attachment_id": 88, "alt": "Team photo at the summer party", "expected_state_hash": "<SHA-256 from list-media>" }
wp-agent/set-featured-image
Purpose: Sets an existing media item as the featured image (_thumbnail_id) of a post or page via set_post_thumbnail().
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id) and current_user_can('edit_post', $attachment_id). The connected user must be allowed to edit both the target post and the attachment.
Traits: write, non-destructive, not idempotent. The write is bound to a fresh state hash and must not be blindly repeated after an unclear result.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
attachment_id | integer | yes |
expected_state_hash | string | yes |
expected_state_hash is the fresh state_hash from the preceding read.
| Output field | Type |
|---|---|
post_id, attachment_id | integer |
verified | boolean |
previous_state_hash | 64-character SHA-256 string |
state_hash | 64-character SHA-256 string |
Example: { "post_id": 42, "attachment_id": 88, "expected_state_hash": "<SHA-256 from get-post>" }
wp-agent/delete-media
Purpose: Moves an attachment conflict-protected only to the reversible trash. force=true is rejected with HTTP 409 before any mutation. If the WordPress trash is disabled, WPAgently performs no remote deletion. Permanently delete the media item only manually in WordPress administration.
Capability: edit_posts (coarse) plus current_user_can('delete_post', $attachment_id).
Traits: write, non-destructive, not idempotent. The remote change requires a fresh expected_state_hash from list-media.
| Parameter | Type | Required | Description |
|---|---|---|---|
attachment_id | integer | yes | |
expected_state_hash | string | yes | Complete state_hash from list-media. |
force | boolean | no | Default false. true is rejected with HTTP 409 before any mutation. |
| Output field | Type |
|---|---|
attachment_id | integer |
forced, trashed, deleted, verified | boolean |
previous_state_hash, state_hash | 64-character SHA-256 string |
Example: { "attachment_id": 88, "expected_state_hash": "<SHA-256 from list-media>" }
wp-agent/list-media
Purpose: Lists media items (post_type=attachment, post_status=inherit, excluding trash) with search, MIME-type, and pagination filters.
Capability: upload_files.
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
search | string | no | |
mime_type | string | no | Full MIME type or prefix. |
per_page | integer | no | Default 20, capped at 100. |
page | integer | no | Default 1. |
| Output field | Type |
|---|---|
items[] | Objects with id, title, url, mime_type, alt, date |
total | integer |
Example: { "mime_type": "image", "per_page": 20 }
4. Menus
All five menu abilities share the same capability, edit_theme_options. This capability is, in WordPress's core roles, assigned exclusively to Administrators, not to the Editor role (wp-admin/includes/schema.php, populate_roles_300()). Menu management is Admin territory in WordPress itself, so a Companion bot set up as Editor gets a 403 from every ability in this group unless it is upgraded to Administrator.
wp-agent/create-menu
Purpose: Creates a new navigation menu (nav_menu taxonomy term). A duplicate menu name is reported as a user error (400), not a server error.
Traits: write, non-destructive, idempotent (a name conflict fails in a controlled way instead of creating a second menu).
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | yes | Must be unique within the site. |
| Output field | Type |
|---|---|
menu_id | integer |
name | string |
verified | boolean |
Example: { "name": "Main menu" }
wp-agent/add-menu-item
Purpose: Adds a new item to an existing menu: either a custom link (object=custom, requires url) or a reference to an existing object (object=page/post/category, requires object_id). Optionally as a sub-item via parent (must be an item in the same menu).
Traits: write, non-destructive, not idempotent (wp_update_nav_menu_item($menu_id, 0, ...) creates a new item on every call; there is no update key).
| Parameter | Type | Required | Description |
|---|---|---|---|
menu_id | integer | yes | |
title | string | yes | Visible text. |
object | string (enum: custom, page, post, category) | yes | |
object_id | integer | if object != custom | |
url | string | if object=custom | |
parent | integer | no | An item in the same menu. |
| Output field | Type |
|---|---|
item_id, menu_id, object_id, parent | integer |
title, type, object, url | string |
verified | boolean |
Example: { "menu_id": 3, "title": "Blog", "object": "page", "object_id": 10 }
wp-agent/list-menus
Purpose: Lists all existing navigation menus as a lean list.
Traits: read, non-destructive, idempotent.
No input parameters.
| Output field | Type |
|---|---|
items[] | Objects with id, name, slug, count |
total | integer |
Example: {}
wp-agent/assign-menu-location
Purpose: Assigns a menu to a location registered by the active theme (e.g. primary). Locations are not a database entity but come from $_wp_registered_nav_menus; the assignment itself lives in the theme mod nav_menu_locations and therefore doesn't automatically survive a theme switch.
Traits: write, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
menu_id | integer | yes | |
location | string | yes | Must be registered by the active theme. |
| Output field | Type |
|---|---|
menu_id, previous_menu_id | integer |
location | string |
verified | boolean |
Example: { "menu_id": 3, "location": "primary" }
wp-agent/delete-menu
Purpose: Checks the input for manually deleting a navigation menu. The ability deletes no menu and returns HTTP 409 with manual_only before any mutation. Menu items and assignments remain unchanged. WordPress has no trash for menus.
Traits: manual-only, change it in WordPress, no remote mutation.
| Parameter | Type | Required |
|---|---|---|
menu_id | integer | yes |
| Output field | Type |
|---|---|
menu_id | integer |
manual_only | HTTP 409, without a change |
Example: { "menu_id": 3 }
5. Settings
All three abilities share the same fixed allowlist WPAGENT_SETTINGS_ALLOWLIST (includes/settings-allowlist.php): blogname, blogdescription, posts_per_page, show_on_front, page_on_front, page_for_posts, permalink_structure, timezone_string, start_of_week, date_format, time_format, default_category. In addition to the allowlist, a hard denylist always applies: siteurl, home, active_plugins, wp_user_roles, users_can_register, admin_email, as well as any option name containing salt, key, or secret as a substring, are never readable or writable, even if they were accidentally in the allowlist.
wp-agent/get-setting
Purpose: Reads a single setting from the allowlist.
Capability: manage_options.
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
name | string | yes |
| Output field | Type |
|---|---|
name | string |
exists | boolean |
value | any |
Example: { "name": "blogname" }
wp-agent/update-setting
Purpose: Sets a setting from the writable allowlist. Every name goes through its own type/enum/existence check before writing. Two special cases are handled explicitly: (1) show_on_front/page_on_front/page_for_posts are checked for logical consistency (show_on_front=page without a set page_on_front is rejected; page_on_front and page_for_posts must not be the same page); (2) permalink_structure runs via $wp_rewrite->set_permalink_structure() followed by flush_rewrite_rules(), because a raw update_option() call alone would not update the active rewrite rules.
Capability: manage_options.
Traits: write, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | yes | From the writable allowlist. |
value | any | yes | Type depends on the name (string, integer, or enum string). |
| Output field | Type |
|---|---|
name | string |
value | any |
verified | boolean |
actions[] | string[] |
Example: { "name": "posts_per_page", "value": 12 }
wp-agent/list-settings
Purpose: Lists all settings from the allowlist with their current value, without needing to query each setting individually via get-setting.
Capability: manage_options.
Traits: read, non-destructive, idempotent.
No input parameters.
| Output field | Type |
|---|---|
items[] | Objects with name, exists, value |
total | integer |
Example: {}
wp-agent/get-ase-free-generator-tag
Purpose: Reads only the verified ASE Free switch that removes the WordPress generator meta tag. The path applies only to Admin and Site Enhancements Free 9.0.0 and also reports whether its parent “Disable Smaller Components” group is enabled.
Capability: manage_options.
Traits: read, non-destructive, idempotent. No parameters.
| Output field | Type |
|---|---|
provider_version | string, exactly 9.0.0 |
smaller_components_enabled, generator_tag_disabled | boolean |
state_hash | SHA-256 over the blog, provider version, and unchanged provider state |
Example: {}
wp-agent/update-ase-free-generator-tag
Purpose: Changes only that ASE Free switch. The path requires the current conflict hash, binds the mutation to the WordPress blog, uses an atomic compare with a renewable lock, and reads the stored provider state back exactly. If the state is unsafe after writing, it returns recovery_required without an automatic follow-up mutation.
Capability: manage_options.
Traits: write, non-destructive, idempotent. ASE Free 9.0.0 and a manually enabled “Disable Smaller Components” group are prerequisites.
| Parameter | Type | Required |
|---|---|---|
disabled | boolean | yes |
expected_hash | SHA-256 from get-ase-free-generator-tag | yes |
| Output field | Type |
|---|---|
provider_version, smaller_components_enabled, generator_tag_disabled, state_hash | as on the read path |
verified, effective_after_new_request | boolean |
Example: { "disabled": true, "expected_hash": "<64-character SHA-256 from get-ase-free-generator-tag>" }
6. Comments
All four abilities share the coarse gate moderate_comments; a fine-grained edit_comment/edit_post check against the specific target is always additionally applied (see below for each), analogous to the content lifecycle pattern.
wp-agent/list-comments
Purpose: Lists comments with optional post, status, and pagination filters plus a total count.
Capability: moderate_comments.
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
post_id | integer | no | |
status | string | no | Default all (approved + pending, excluding spam/trash). Accepts, among others, hold, approve, spam, trash, all, any. |
per_page | integer | no | Default 20, capped at 100. |
page | integer | no | Default 1. |
| Output field | Type |
|---|---|
items[] | Objects with id, post_id, parent, author, author_email, content, status, date |
total | integer |
Example: { "post_id": 42, "status": "hold" }
wp-agent/moderate-comment
Purpose: Sets an existing comment's status directly (approve, hold, spam, trash). Explicitly handles the vocabulary difference between the input (hold) and the return value of wp_get_comment_status() (unapproved), so the re-read verification doesn't fail falsely.
Capability: moderate_comments (coarse) plus current_user_can('edit_comment', $comment_id).
Traits: write, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
comment_id | integer | yes |
status | string (enum: approve, hold, spam, trash) | yes |
| Output field | Type |
|---|---|
comment_id | integer |
status | string |
verified | boolean |
Example: { "comment_id": 15, "status": "approve" }
wp-agent/reply-to-comment
Purpose: Creates a new, immediately approved comment: either as a reply to an existing comment (comment_id, becomes its child) or as a top-level comment on a post (post_id). Exactly one of the two is required. The author is always the currently logged-in user (the bot), never anonymous. Deliberately uses wp_insert_comment() instead of the public-facing wp_new_comment(), to bypass flood/duplicate checks meant for anonymous visitors and the comment_status=open check (the caller is already privileged).
Capability: moderate_comments (coarse) plus, depending on the target, edit_comment (for comment_id) or edit_post (for post_id).
Traits: write, non-destructive, not idempotent (every call creates a new comment).
| Parameter | Type | Required | Description |
|---|---|---|---|
comment_id | integer | no | Comment being replied to. |
post_id | integer | no | Post for a top-level comment, if comment_id is absent. |
content | string | yes |
| Output field | Type |
|---|---|
comment_id, post_id, parent, author_id | integer |
verified | boolean |
Example: { "comment_id": 15, "content": "Thanks for the heads-up, we'll look into it." }
wp-agent/delete-comment
Purpose: Moves only a regular comment conflict-protected to the reversible trash. Pingbacks, trackbacks, and notes remain unchanged. force=true is rejected with HTTP 409. If the comment trash is disabled, WPAgently performs no remote deletion. Permanently delete the comment only manually in WordPress administration.
Capability: moderate_comments (coarse) plus current_user_can('edit_comment', $comment_id) (delete_comment is not a registered meta-capability case in WordPress and would otherwise always return false).
Traits: write, non-destructive, not idempotent. The remote change requires a fresh expected_state_hash.
| Parameter | Type | Required | Description |
|---|---|---|---|
comment_id | integer | yes | |
expected_state_hash | string | yes | Complete state_hash from list-comments. |
force | boolean | no | Default false. true is rejected with HTTP 409. |
| Output field | Type |
|---|---|
comment_id | integer |
forced, trashed, deleted, verified | boolean |
previous_state_hash, state_hash | 64-character SHA-256 string |
Example: { "comment_id": 15, "expected_state_hash": "<SHA-256 from list-comments>" }
7. Users
The entire user management group is heavily gated: all five capabilities (list_users, edit_users, promote_users, create_users, delete_users) are reserved exclusively for Administrators in a default installation. The Companion bot, set up as Editor, always gets a 403 here.
wp-agent/list-users
Purpose: Lists WordPress users with role, search, and pagination filters.
Capability: list_users.
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
role | string | no | Must be registered. Without it: all roles. |
search | string | no | |
per_page | integer | no | Default 20, capped at 100. |
page | integer | no | Default 1. |
| Output field | Type |
|---|---|
items[] | Objects with id, username, display_name, email, roles[], registered |
total | integer |
Example: { "role": "editor" }
wp-agent/get-user
Purpose: Reads a single user's profile data. Never returns the password hash field (user_pass), the password reset key, or session tokens; the result is deliberately assembled field by field from WP_User.
Capability: edit_users (the capability WordPress itself requires for access to a single user profile, not the leaner list_users).
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
user_id | integer | yes |
| Output field | Type |
|---|---|
id | integer |
username, email, display_name, first_name, last_name, registered, url | string |
roles[] | string[] |
Example: { "user_id": 3 }
wp-agent/set-user-role
Purpose: Sets an existing user's role directly (replaces all existing roles with exactly one). Two hard, unbypassable protections: user ID 1 is never changed, and the calling account (i.e. the bot itself) may never change its own role. Additional soft gate: roles with the manage_options capability (administrator-equivalent) require the explicit flag i_grant_admin=true.
Capability: promote_users (the capability WordPress itself ties role changes to, not the broader edit_users).
Traits: write, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
user_id | integer | yes | |
role | string | yes | Must be registered. |
i_grant_admin | boolean | no | Default false. Required true for administrator-equivalent roles. |
| Output field | Type |
|---|---|
user_id | integer |
role | string |
verified | boolean |
Example: { "user_id": 7, "role": "author" }
wp-agent/create-user
Purpose: Creates a new user via wp_insert_user(). Without a password, a strong password is generated server-side and returned once in the result (generated_password, never appears in later read operations). Same administrator gate as set-user-role.
Capability: create_users.
Traits: write, non-destructive, not idempotent (a duplicate username fails at the WordPress core level instead of reporting the same state).
| Parameter | Type | Required | Description |
|---|---|---|---|
username | string | yes | |
email | string | yes | |
role | string | yes | Must be registered. |
password | string | no | Without it, one is generated. |
i_grant_admin | boolean | no | Default false. |
| Output field | Type | Description |
|---|---|---|
user_id | integer | |
username, email, role | string | |
password_generated | boolean | |
generated_password | string | Only present if password_generated=true. |
verified | boolean |
Example: { "username": "new.author", "email": "author@example.com", "role": "author" }
wp-agent/delete-user
Purpose: Checks the input for manually deleting a user. The ability deletes no user, reassigns or deletes no content, and returns HTTP 409 with manual_only before any mutation. Decide how to handle content and delete the user in WordPress. User ID 1 and the calling account itself may never be deleted.
Capability: delete_users.
Traits: manual-only, change it in WordPress, no remote mutation.
| Parameter | Type | Required | Description |
|---|---|---|---|
user_id | integer | yes | |
reassign_to | integer | no | Target user for content takeover. |
delete_content | boolean | no | Default false. Alternative to reassign_to. |
| Output field | Type |
|---|---|
user_id, reassigned_to | integer |
manual_only | HTTP 409, without a change |
Example: { "user_id": 9, "reassign_to": 2 }
8. Plugins and themes
wp-agent/list-plugins
Purpose: Lists installed plugins with file path, name, version, and active status. Serves as an independent re-read source for activate-plugin/deactivate-plugin.
Capability: activate_plugins.
Traits: read, non-destructive, idempotent.
No input parameters.
| Output field | Type |
|---|---|
items[] | Objects with file, name, version, active |
total | integer |
Example: {}
wp-agent/activate-plugin
Purpose: Activates an installed plugin and verifies via re-read (is_plugin_active). Catches throwables from a faulty plugin hook instead of taking down the whole REST request (genuine, uncatchable PHP fatals like memory limit/timeout remain a WordPress core edge case). wp-agent-companion and wp-agent-power are hard-excluded (self-protection).
Capability: activate_plugins.
Traits: write, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
plugin_file | string | yes | Relative path as returned by get_plugins(), e.g. akismet/akismet.php. |
| Output field | Type |
|---|---|
plugin_file | string |
active, verified | boolean |
Example: { "plugin_file": "akismet/akismet.php" }
wp-agent/deactivate-plugin
Purpose: Deactivates an installed plugin and verifies via re-read. wp-agent-companion and wp-agent-power can never be deactivated through this ability (use wp-agent/disable-power specifically for power mode).
Capability: activate_plugins.
Traits: write, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
plugin_file | string | yes |
| Output field | Type |
|---|---|
plugin_file | string |
active, verified | boolean |
Example: { "plugin_file": "hello-dolly/hello.php" }
wp-agent/list-themes
Purpose: Lists installed themes with stylesheet folder name, name, version, and active status.
Capability: switch_themes (the same capability as switch-theme; shares the scope analogously to list-plugins/activate-plugin; also not granted to Editor by WordPress by default).
Traits: read, non-destructive, idempotent.
No input parameters.
| Output field | Type |
|---|---|
items[] | Objects with stylesheet, name, version, active |
total | integer |
Example: {}
wp-agent/switch-theme
Purpose: Switches the active theme. Rejects unknown, faulty themes (WP_Theme::errors(), which goes beyond the plain exists() check) or themes incompatible with the current WP/PHP version up front, instead of activating them or letting switch_theme() internally trigger wp_die().
Capability: switch_themes.
Traits: write, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
stylesheet | string | yes | Theme folder name, e.g. twentytwentyfive. |
| Output field | Type |
|---|---|
stylesheet, previous_stylesheet | string |
verified | boolean |
Example: { "stylesheet": "twentytwentyfive" }
9. Reusable blocks
Post type wp_block (Gutenberg synced patterns). wpagent_validate_post_type() is deliberately not used for this post type, because wp_block is registered in WordPress core with 'public' => false, and this generic allowlist check would otherwise falsely deny access.
wp-agent/create-reusable-block
Purpose: Creates a reusable block from Markdown. The server turns it into allowed Core blocks. Already-serialized block markup and free HTML are not accepted. The block is always created as publish, because core/block only renders a referenced block at this status (a block created as draft would silently stay empty on every page that embeds it).
Capability: edit_posts (coarse) plus the actual creation capability for wp_block: publish_posts (WordPress core comment: "You need to be able to publish posts, in order to create blocks"), not the usual create_posts/edit_posts.
Traits: write, non-destructive, not idempotent (every call creates a new wp_block post).
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | yes | |
content_markdown | string | yes | Converted server-side into allowed Gutenberg Core blocks. |
| Output field | Type |
|---|---|
block_id | integer |
status | string |
written | object |
verified, has_freeform | boolean |
block_count, freeform_count | integer |
block_types | string[] |
Example: { "title": "Newsletter CTA box", "content_markdown": "**Sign up now!**" }
wp-agent/update-reusable-block
Purpose: Checks a planned manual change to an existing reusable block's title or content. The ability changes no block and returns HTTP 409 with manual_only before any mutation. Edit the block in WordPress, then read its current state again.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $block_id).
Traits: manual-only, change it in WordPress, no remote mutation.
Remote call: Not available. The callback returns HTTP 409 with manual_only without reading, converting, or saving title or content_markdown. Open the reusable block in WordPress, make the change there, then check its current state again.
wp-agent/list-reusable-blocks
Purpose: Lists reusable blocks with search, status, and pagination filters. No post_type parameter; hardwired to wp_block.
Capability: edit_posts (coarse) plus explicitly the read capability responsible for wp_block (literally mapped to edit_posts in core).
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
status | string | no | Default any. |
search | string | no | |
per_page | integer | no | Default 20, capped at 100. |
page | integer | no | Default 1. |
| Output field | Type |
|---|---|
items[] | Objects with id, title, status, date, slug |
total | integer |
Example: { "per_page": 10 }
wp-agent/delete-reusable-block
Purpose: Moves a reusable block conflict-protected to the trash. force=true is retained for compatibility, additionally requires confirm_permanent_delete=true, and then responds with HTTP 409 without a mutation. Permanently delete the block only manually in WordPress administration.
Capability: edit_posts (coarse) plus current_user_can('delete_post', $block_id).
Traits: write, reversible trash, not idempotent. The remote change requires a fresh expected_state_hash.
| Parameter | Type | Required | Description |
|---|---|---|---|
block_id | integer | yes | |
expected_state_hash | string | yes | Complete block state hash from the preceding read. |
force | boolean | no | Default false. With true, confirm_permanent_delete=true is also required, then HTTP 409 follows without a mutation. |
confirm_permanent_delete | boolean | no | Confirmation for the deliberately rejected force compatibility path. |
| Output field | Type |
|---|---|
block_id | integer |
forced, trashed, deleted, verified | boolean |
previous_state_hash | 64-character SHA-256 string |
Example: { "block_id": 55, "expected_state_hash": "<SHA-256 from list-reusable-blocks>" }
10. SEO
wp-agent/get-seo-meta
Purpose: Reads stored post-level SEO data from Rank Math, Yoast, AIOSEO, or SEOPress through the provider's effective storage or Ability path and returns one normalized shape. Without a supported active SEO plugin, the Ability fails closed with HTTP 409. robots_noindex and robots_nofollow report the provider's post-level flags. Global SEO defaults are not misrepresented as stored post overrides. AIOSEO post-SEO runtime coverage is currently evidenced only on MariaDB; MySQL and SQLite are outside this evidence. A successful output is closed and contains every field listed below, including state_hash.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id).
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
| Output field | Type |
|---|---|
post_id | integer |
plugin | string |
seo_title, seo_description, focus_keyword, canonical_url | string |
robots_noindex, robots_nofollow | boolean |
open_graph_title, open_graph_description | string |
twitter_title, twitter_description | string |
cornerstone_supported | boolean |
cornerstone | boolean or null |
state_hash | string |
Example: { "post_id": 42 }
wp-agent/set-seo-meta
Purpose: Detects Rank Math, Yoast, AIOSEO, or SEOPress through their runtime APIs and preflights the requested post fields before a possible manual change. The current public writer performs no remote mutation for any provider. After input validation, a fresh provider re-read, and a conflict-hash check, it returns HTTP 409 with manual_only before the first provider write because no complete conditional provider write path is currently proven. This covers title, description, focus keyword, canonical URL, robots flags, and Open Graph and X/Twitter text for Rank Math, Yoast, AIOSEO, and SEOPress. get-seo-meta remains the provider-neutral read path. Changes currently belong in the relevant plugin administration UI and should then be read again. AIOSEO post-SEO read-path runtime coverage is practically evidenced only on MariaDB with transactional InnoDB tables; MySQL and SQLite are outside this runtime evidence. Without a supported active SEO plugin, the Ability also fails closed with HTTP 409 instead of storing ineffective fallback fields.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id).
Traits: manual-only, non-destructive, not idempotent. The current contract does not mutate provider state.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
seo_title | string | no |
seo_description | string | no |
focus_keyword | string | no |
canonical_url | string | no |
robots_noindex, robots_nofollow | boolean | no |
open_graph_title, open_graph_description | string | no |
twitter_title, twitter_description | string | no |
cornerstone | boolean | no, Rank Math and Yoast only |
| Output field | Type | Description |
|---|---|---|
post_id | integer | |
plugin | string | rankmath, yoast, aioseo, or seopress. Without a supported plugin, the call returns an error. |
written | object | At least { persisted } for every supplied field; direct meta paths also include meta_key. With rolled_back:true, this describes the failed write attempt before rollback, not the restored final state. |
verified | boolean | |
indexable_verified | boolean or null | For Yoast, true when the effective Meta Surface agrees with the written output fields. null for the other providers. |
rolled_back | boolean | true when WPAgently restored the previous state after a failed or unverified write. |
rollback_verified | boolean or null | For a rollback, true when the restored provider state was read back and confirmed. null without a rollback. false requires immediate manual inspection. |
In the current runtime contract, set-seo-meta returns HTTP 409 with manual_only before any provider mutation. The following success fields remain documented for schema compatibility and are not returned as a successful write in this manual result.
Example: { "post_id": 42, "seo_title": "Best WordPress Hosting 2026", "focus_keyword": "wordpress hosting" }
wp-agent/get-seo-settings
Purpose: Reads global title templates, archive rules, and identity data from the active Rank Math, Yoast SEO, AIOSEO, or SEOPress installation through one normalized contract. supported_fields describes the fields exposed by the normalized provider read path. It does not currently authorize a remote write because set-seo-settings returns HTTP 409 with manual_only after a fresh re-read and conflict-hash check, before any mutation. If an existing template contains an unknown native provider token, the field appears in unmapped_template_fields and remains readable but read-only. homepage_source distinguishes a global homepage from a static page. Templates use only the WPAgently placeholders returned in template_tokens. The complete raw state of the affected provider options contributes to state_hash but is never exposed.
Capability: manage_options.
Traits: read, non-destructive, idempotent.
The Ability takes no input. Its output contains plugin, supported_fields, unmapped_template_fields, template_syntax, template_tokens, homepage_source, settings, and the 64-character state_hash.
wp-agent/set-seo-settings
Purpose: Preflights a bounded subset of global SEO settings against the immediately preceding provider read. Depending on the plugin, this includes the title separator, global homepage templates, author, date, and search archives, identity, logo, and website names. Provider-native placeholders, HTML, control characters, line breaks, and surrounding whitespace are still rejected. After input validation, a fresh re-read, and the expected_hash check, the current writer returns HTTP 409 with manual_only for every provider before any mutation. Changes currently belong in the relevant plugin administration UI and should then be read again through get-seo-settings.
Capability: manage_options.
Traits: manual-only, non-destructive, not idempotent. The current contract does not mutate provider state.
expected_hash and a non-empty partial settings object are required. The authoritative field list is supported_fields from the immediately preceding read. Output includes plugin, the field-level written report, verified, rolled_back, rollback_verified, previous_hash, and the new state_hash.
In the current runtime contract, set-seo-settings returns HTTP 409 with manual_only before any provider mutation. The named success fields remain documented for schema compatibility and are not returned as a successful write in this manual result.
Example: { "expected_hash": "<64 hex>", "settings": { "homepage_title_template": "{{site_name}} {{separator}} {{tagline}}", "search_noindex": true } }
wp-agent/get-post-schema
Purpose: Reads custom Rank Math schemas with their stable schema_id values or Yoast's stored page and article types. It includes the provider's available type catalog and a SHA-256 state_hash for the complete managed state. AIOSEO and SEOPress fail closed with HTTP 409 because no equivalent post-schema path has been confirmed.
Capability: edit_posts plus edit_post. Rank Math additionally requires rank_math_onpage_snippet.
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
wp-agent/set-post-schema
Purpose: Creates a Rank Math schema or updates exactly one existing schema by schema_id. New types must be available in the active Rank Math catalog and require a reusable idempotency_key. Size, depth, node count, keys, internal shortcode ID, primary status, and provider permissions are validated before the native write path runs. For Yoast, the Ability accepts only confirmed page_type and article_type values. An empty type removes the corresponding Yoast override. expected_hash, read-back, a per-post lock, and rollback protect against stale, silent, or concurrent failed mutations.
Capability: edit_posts plus edit_post. Rank Math additionally requires rank_math_onpage_snippet.
Traits: write, non-destructive, idempotent through schema_id or idempotency_key.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
expected_hash | string | yes, exact state_hash from get-post-schema |
idempotency_key | string | for a new Rank Math schema, 8-64 safe characters |
schema_id | string | no, for a Rank Math update |
schema | object | for Rank Math |
page_type, article_type | string | at least one for Yoast |
Example: { "post_id": 42, "expected_hash": "<64 hex>", "page_type": "AboutPage" }
wp-agent/delete-post-schema
Purpose: Checks the input for manually deleting a custom Rank Math schema. The ability deletes no schema, disables no rich-snippet status, and returns HTTP 409 with manual_only before any mutation. The stable schema_id must be repeated exactly as confirm_schema_id. Delete the schema in Rank Math.
Capability: edit_posts plus edit_post. Rank Math additionally requires rank_math_onpage_snippet.
Traits: manual-only, change it in WordPress, no remote mutation.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
schema_id | string | yes, stable ID from get-post-schema |
confirm_schema_id | string | yes, must exactly repeat schema_id |
expected_hash | string | yes, exact state_hash from get-post-schema |
Output: HTTP 409 with manual_only, without a change. Read the provider state again with get-post-schema after the manual change.
Example: { "post_id": 42, "schema_id": "schema-731", "confirm_schema_id": "schema-731", "expected_hash": "<64 hex>" }
wp-agent/get-term-seo-meta
Purpose: Reads the stored SEO data of a term in a publicly viewable taxonomy through Rank Math, Yoast, or SEOPress. It normalizes the title, description, focus keyword, canonical, robots, and Open Graph and X/Twitter text. The complete raw provider state contributes to state_hash. AIOSEO Free has no native term SEO interface and therefore fails closed with HTTP 409.
Capability: edit_posts (coarse) plus the taxonomy's concrete edit_terms capability.
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
term_id | integer | yes |
taxonomy | string | yes |
The output matches the normalized post SEO contract, replaces post_id with term_id and taxonomy, and adds the SHA-256 state_hash.
Example: { "term_id": 17, "taxonomy": "category" }
wp-agent/set-term-seo-meta
Purpose: Checks the current term SEO state and the supplied expected_hash. The Ability does not change provider data. Rank Math, Yoast, and SEOPress do not provide a provably atomic compare-and-write operation here, so WPAgently returns HTTP 409 with manual_only after validation. Change the values in the active SEO plugin's UI, then read them again with get-term-seo-meta.
Capability: edit_posts (coarse) plus the taxonomy's concrete edit_terms capability.
Traits: compatibility endpoint without remote mutation, manual, non-destructive, and conflict-protected.
| Parameter | Type | Required |
|---|---|---|
term_id | integer | yes |
taxonomy | string | yes |
expected_hash | string (SHA-256) | yes |
seo_title, seo_description, focus_keyword, canonical_url | string | no |
robots_noindex, robots_nofollow | boolean | no |
open_graph_title, open_graph_description | string | no |
twitter_title, twitter_description | string | no |
There is no success output because no remote mutation occurs. Valid input returns HTTP 409 with manual_only.
Example: { "term_id": 17, "taxonomy": "category", "expected_hash": "<64-character SHA-256>", "seo_title": "WordPress Tips" }
wp-agent/list-seo-redirections
Purpose: Lists up to 5,000 non-trashed Rank Math redirections. Rules with multiple sources or contains, start, end, or regex comparisons remain readable but are marked writable:false. collection_hash covers the complete collection and protects a subsequent create against concurrent changes.
Capability: rank_math_redirections.
Traits: read, non-destructive, idempotent.
Parameters: Optional status (any, active, inactive), search (at most 200 bytes), page, and per_page (1-100). The output contains redirections, total, page, per_page, total_pages, and collection_hash.
wp-agent/get-seo-redirection
Purpose: Reads one non-trashed Rank Math redirection. Each source contains pattern, comparison, and ignore_case. The output adds destination, HTTP code, activation status, hit count, writability, and state_hash. Hit count is deliberately excluded from the conflict hash so real traffic does not block a configuration-only change.
Capability: rank_math_redirections.
Traits: read, non-destructive, idempotent.
Parameters: redirection_id is required.
wp-agent/create-seo-redirection
Purpose: Creates exactly one local exact source. HTTP 301, 302, 307, 410, and 451 are supported. Sources are canonically decoded and may not contain the home page, a query, fragment, dot segments, control characters, or ambiguous percent encoding. Destinations must be absolute or local HTTP or HTTPS URLs without credentials. HTTP 410 and 451 require an empty destination. A fresh expected_collection_hash, atomic lock, source collision check, and cycle detection protect creation. A semantically identical retry returns the existing object with created:false.
Capability: rank_math_redirections.
Traits: write, marked destructive, idempotent, and conflict-protected.
Required parameters: source, destination, http_code, and expected_collection_hash. status and ignore_case are optional. The output contains redirection, created, and verified.
wp-agent/update-seo-redirection
Purpose: Updates only a single exact provider rule. Complex rules remain unchanged. expected_state_hash, the lock, collision and cycle checks, complete read-back, and verified rollback protect the write.
Capability: rank_math_redirections.
Traits: write, marked destructive, idempotent, and conflict-protected.
Required parameters: redirection_id and expected_state_hash, plus at least one of source, destination, http_code, status, or ignore_case. The output contains redirection and verified.
wp-agent/delete-seo-redirection
Purpose: Moves a Rank Math redirection to the provider trash. The row is not hard-deleted. The operation requires a current state hash and explicit confirmation. A failed read-back restores and verifies the previous row.
Capability: rank_math_redirections.
Traits: write, destructive, not idempotent, and conflict-protected.
Required parameters: redirection_id, expected_state_hash, and confirm:true. The output contains redirection_id, deleted, and verified.
wp-agent/get-seopress-post-redirection
Purpose: Reads the simple post redirect for a published, publicly reachable post through the native SEOPress Free route. The source is derived from the current canonical post URL. The response contains only the confirmed enabled state, HTTP 301, 302, or 307, a local destination on the same WordPress site, and a complete state hash. Ambiguous, duplicate, or non-local provider values fail closed.
Capability: object-specific edit_post. Traits: read-only, non-destructive, idempotent. Required: post_id.
wp-agent/set-seopress-post-redirection
Purpose: Sets or disables a simple local post redirect through the native SEOPress Free route. The destination must belong to the same WordPress site and may not contain credentials, a query, a fragment, dot segments, or ambiguous encoding. The complete graph of published and publicly reachable posts is read within strict bounds and without a postmeta N+1 query. Direct and multi-step cycles are rejected before the write. A current expected_hash, post and graph locks, exact raw-state attribution, provider read-back, and a real HTTP read-back protect the operation. Once the provider write has started, an uncertain state returns recovery_required. No automatic follow-up mutation can overwrite an external provider change.
Capability: object-specific edit_post. Traits: write, marked destructive, idempotent, conflict-protected. Required: post_id, expected_hash, and enabled; when enabled:true, also destination and optionally http_code with 301, 302, or 307.
11. Landing pages, global styles, theme files, and the Site Editor
wp-agent/upsert-pattern
Purpose: Builds a landing page (post_type=page) from a declarative section list (hero, features, media-text, logos, cta, pricing, testimonials, faq, stats, gallery, steps, comparison) as valid Gutenberg core blocks, and creates or updates it through slug or post_id. The contract is not annotated as idempotent, although slug resolution prevents unintended duplicates. Supports optional background images (core/cover for hero), image-text splits (core/media-text), galleries (core/gallery), accordions (core/details), comparison tables (core/table), and a native icon set (bundled Phosphor SVGs as core/image). Color, spacing, and font-size slugs are resolved against the effective global styles. Before saving, parse_blocks checks that guaranteedly 0 freeform blocks result; every section type is additionally confirmed recovery-free in the real Gutenberg editor.
Capability: edit_pages (not edit_posts, because post_type=page is always created).
Traits: write, non-destructive, not idempotent. Slug or ID resolution prevents unintended duplicates but is not an idempotency annotation.
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | yes | |
sections | array | yes | Ordered list; each section has type (hero|features|media-text|logos|cta|pricing|testimonials|faq|stats|gallery|steps|comparison) plus the type-dependent text, color, button, image, icon, columns[], and items[] fields. The input_schema in tools/list is the binding source of truth. |
slug | string | no | For matching without post_id. The ability normalizes it server-side with WordPress's sanitize_title() and uses the result for lookup and storage; the API schema limits the string to 200 characters. It prevents unintended duplicates but is not an idempotency guarantee. If omitted, the title is used. |
post_id | integer | no | Highest priority, ahead of slug. |
status | string (enum: draft, publish, pending, private) | no | Default draft. |
wp-agent landing adds the CLI preflight described in the article path: an explicit slug must already be in WordPress's native stored form. The CLI rejects raw Unicode, uppercase letters, repeated or trailing hyphens, and 59 percent-encoded sequences that WordPress core normalizes while saving. Stable percent-encoded UTF-8 sequences such as %e4%bd%a0%e5%a5%bd and repeated underscores remain allowed. Omit the slug to use the title.
| Output field | Type |
|---|---|
post_id | integer |
url, status | string |
block_count, freeform_count | integer |
block_types | string[] |
updated | boolean |
Example:
{
"title": "Webinar landing page",
"slug": "webinar-signup",
"status": "draft",
"sections": [
{ "type": "hero", "heading": "Free webinar", "image_url": "https://your-domain.tld/wp-content/uploads/hero.webp", "cta_label": "Sign up now", "cta_url": "#form" },
{ "type": "features", "heading": "What you'll learn", "items": [ { "title": "First point", "text": "Briefly explained.", "icon": "rocket" } ] },
{ "type": "faq", "heading": "Frequently asked questions", "items": [ { "title": "What does the webinar cost?", "text": "Nothing, attendance is free." } ] },
{ "type": "cta", "heading": "Only a few spots left", "button_label": "Reserve your spot", "button_url": "#form" }
]
}
wp-agent/get-global-styles
Purpose: Reads the complete user Global Styles record as a type-preserving, exportable JSON snapshot. The snapshot is capped at 512 KiB and includes a SHA-256 conflict hash bound to the active theme, record ID, and exact stored content. That hash is required for every subsequent design write.
Capability: edit_theme_options.
Traits: read, non-destructive, idempotent.
| Output field | Type |
|---|---|
post_id, snapshot_bytes | integer |
theme, state_hash | string |
snapshot | object |
If the active theme has no user Global Styles record yet, the ability returns HTTP 409 with code wpagent_gs_no_post. This read path remains strictly non-writing and does not create the record automatically. Open and save Global Styles once in the WordPress Editor, then repeat the read. Only then is there a valid state_hash for a design write.
wp-agent/set-global-styles
Purpose: Sets colors, font sizes, spacing, font families, and a narrowly allowed subset of standard styles in WordPress's own wp_global_styles record. Theme files and theme presets remain unchanged. Custom presets are replaced or appended by slug. An exact conflict hash and a shared short-lived lock prevent concurrent overwrites. The state is read back directly from the database and any mismatch restores the previous bytes.
Capability: edit_theme_options.
Traits: write, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
expected_hash | string | yes | Exact state_hash from get-global-styles. |
colors | array | no | Entries with slug, color, optional name. |
fontSizes | array | no | Entries with slug, size, optional name. |
spacingSizes | array | no | Entries with slug, size, optional name. |
fontFamilies | array | no | Entries with slug, fontFamily, optional name. |
styles | object | no | Selected color values, spacing.blockGap, and button/link colors are allowed. |
replace | boolean | no | Replaces only the supplied custom categories. Default is upsert by slug. |
At least one token category or styles must be set. Preset references in styles are checked against the slugs actually available after the merge.
A write also requires an existing record and a fresh expected_hash. If the record is missing, the ability returns HTTP 409 with wpagent_gs_no_post and performs no mutation. Initialize Global Styles once manually in the WordPress Editor, then read get-global-styles again and use its new state_hash.
| Output field | Type |
|---|---|
post_id, version | integer |
theme, state_hash | string |
replace, verified | boolean |
applied | object |
palette_slugs | string[] |
Example: { "expected_hash": "<SHA-256 from get-global-styles>", "colors": [{ "slug": "brand-primary", "color": "#6d45f9", "name": "Primary" }], "replace": false }
Native Global Style variations
The following three abilities mirror the WordPress Site Editor's style variations. They include a native default choice for resetting user design changes and every full, color, and typography variation supplied by the active theme. Variation IDs are bound to the theme, scope, position, and exact content. A theme switch or changed variation file intentionally invalidates an older ID.
| Ability | Purpose | Parameters |
|---|---|---|
wp-agent/list-global-style-variations | Lists the default choice and theme variations as compact records. | Optional scope: all, full, color, or typography. |
wp-agent/get-global-style-variation | Reads one variation completely and without losing JSON types. | variation_id. |
wp-agent/apply-global-style-variation | Applies the variation with conflict protection, a shared lock, exact read-back, and safe rollback. | variation_id, fresh expected_hash, confirm=true. |
All three require edit_theme_options. The write path is destructive and idempotent. Full variations replace user settings and ordinary styles. Free root and block CSS is retained according to the Site Editor's rules. Color variations replace color groups only. Typography variations replace typography and spacing groups. The resulting record is capped at 512 KiB. A mismatch caused by the write itself restores the exact previous bytes. If an external writer changes the already verified state again, that version is preserved and the ability returns HTTP 409.
Style variation read and export paths do not create a missing record. This also applies to wp-agent/export-spectra-one-design-snapshot, wp-agent/export-spectra-one-portable-snapshot, and wp-agent/preflight-spectra-one-portable-snapshot when the Global Styles part is evaluated. In these cases the path returns HTTP 409 with wpagent_gs_no_post. Initialize the record in the WordPress Editor first, then repeat the read or preflight.
Spectra One 1.2.3 is practically verified through these native WordPress paths. The test confirms its catalog of nine style choices, a verified Global Styles color write, and exact restoration of the initial state.
wp-agent/write-theme-file
Purpose: Writes a file exclusively into the active (child) theme directory. Only the extensions .html, .json, and .css are allowed. Path traversal is prevented both lexically (no .. segment, no absolute path) and via a realpath check against the theme directory; symlinks as a target are rejected.
Capability: edit_themes (a filesystem-adjacent, privileged action that an Editor does not have by default).
Traits: write, non-destructive, idempotent (overwriting the same file is repeatable).
| Parameter | Type | Required | Description |
|---|---|---|---|
rel_path | string | yes | Relative path within the theme folder, e.g. patterns/hero.html. |
contents | string | yes | File content. |
| Output field | Type |
|---|---|
path, rel_path, theme | string |
bytes | integer |
Example: { "rel_path": "patterns/hero.html", "contents": "<!-- wp:heading --><h2>Hello</h2><!-- /wp:heading -->" }
Site Editor templates, template parts, and block navigations
These 15 abilities manage the three native WordPress Site Editor data surfaces. All require edit_theme_options, so they are Administrator features by default. Template write paths refuse classic themes. Raw block markup is not an input field. The server instead serializes up to 50 structured Core components. Supported components are Markdown, template part, block pattern, site logo and title, block navigation, post title, featured image, content, excerpt, date, author, terms, query title, query loop, separator, and spacer.
Spectra One 1.2.3 is practically verified as a real block theme through a complete template-part create, read, and delete lifecycle. The compatibility matrix therefore reports the native wp_global_styles+site-editor storage path and marks the theme as installed only while it is active.
The write path recursively rejects free HTML, shortcodes, freeform blocks, unregistered blocks, and non-Core blocks. Registered and therefore executable shortcodes are blocked even inside an allowed Core block. Referenced template parts, block navigations, patterns, and synced Core blocks are also checked recursively. Validation covers both stored raw content and blocks that WordPress injects at runtime through Block Hooks. Circular references across these data surfaces are blocked. Content is capped at 1 MiB. Changes use a SHA-256 state hash, an atomic resource lock, complete read-back, and exact rollback including timestamps. Creation, update, and deletion of the same resource share the same lock key. Theme and plugin templates are overridden only with confirm_theme_override=true. Deletion first performs a reversible step, verifies it, and then removes only the database version. An underlying theme or plugin template remains available. Template parts and navigations that are still referenced additionally require confirm_references=true.
| Ability | Required fields | Result and special behavior |
|---|---|---|
list-site-templates | none | Effective theme, plugin, and database templates, with optional search and per_page. |
get-site-template | slug | Complete resource with raw content, origin, block report, and hash. |
create-site-template | slug, title, components | Creates only a new custom block template. |
update-site-template | slug, expected_hash | Partial title, description, or component update. A theme or plugin source requires the additional confirmation. |
delete-site-template | slug, expected_hash, confirm | Deletes a custom template or reverts an override to its source. |
list-template-parts | none | Same as the template list, optionally filtered by area. |
get-template-part | slug | Also returns the area such as header, footer, or uncategorized. |
create-template-part | slug, title, area, components | Creates a new template part in a registered area. |
update-template-part | slug, expected_hash | Partial update with an optional area change and the same conflict and override gates. |
delete-template-part | slug, expected_hash, confirm | Finds uses in posts, templates, and template parts. |
list-block-navigations | none | Published wp_navigation posts, with optional search and per_page. |
get-block-navigation | id | Navigation with raw content, item count, block report, and hash. |
create-block-navigation | title, items | Creates up to 100 internal, external, or nested items with a maximum depth of three levels. |
update-block-navigation | id, expected_hash | Updates the title or complete item list with exact rollback. |
delete-block-navigation | id, expected_hash, confirm | Finds references and uses verified two-stage deletion. |
Template resources contain id, wp_id, theme, slug, type, source, origin, title, description, status, content, area, has_theme_file, is_custom, modified, the deep block report, and hash. Navigation resources contain id, slug, title, status, content, modified, item_count, the deep block report, and hash. For a query-loop component, per_page, post_type, order, and order_by form an explicit query by default. Only inherit_query=true deliberately inherits the current archive query.
12. Verification and infrastructure
wp-agent/render-check
Purpose: Parses the post content, counts blocks, flags core/freeform (the silent Classic Editor fallback), and renders the server HTML (do_blocks()) for inspection.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id).
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
| Output field | Type |
|---|---|
post_id, rendered_html_length, word_count, block_count, freeform_count | integer |
has_freeform | boolean |
block_types | string[] |
Example: { "post_id": 42 }
wp-agent/refresh-hooks
Purpose: Catches up on admin-/save-only follow-up work that would otherwise be missing when writing via REST/abilities instead of via the editor: (1) flush_rewrite_rules(false), (2) clean_post_cache() for the most recently changed posts (or an explicit post_ids list), (3) if Rank Math is active, additionally invalidates the sitemap cache (Cache::invalidate_storage(), fallback Cache_Watcher::clear(), otherwise the documented WP-CLI fallback wp rankmath sitemap generate).
Capability: edit_posts.
Traits: write, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
limit | integer | no | Default 20 (1 to 100), number of most recently changed posts. |
post_ids | integer[] | no | Explicit list instead of the most recently changed posts. |
| Output field | Type |
|---|---|
actions[] | string[] |
cleaned_post_ids[] | integer[] |
rankmath | object (active, method, cli_fallback) |
Example: { "limit": 5 }
wp-agent/disable-power
Purpose: A panic switch that deliberately lives in the verified core plugin (not in wp-agent-power itself), so the core can disable raw-access/developer mode (wp-agent-power, including exec-php and all other power abilities) even if that plugin misbehaves. Immediately disables wp-agent-power via deactivate_plugins(), if installed.
Capability: activate_plugins.
Traits: write, non-destructive (reversible at any time via wp-agent/activate-plugin), idempotent.
No input parameters.
| Output field | Type |
|---|---|
power_installed, disabled | boolean |
note | string |
Example: {}
wp-agent/create-browser-link
Purpose: Creates a one-time link to the dashboard, posts, pages, or media for the currently authenticated safe non-administrator with content-editing permissions. The random token has 256 bits of entropy, only its SHA-256 hash is stored, it expires after 120 seconds, and HTTPS is required outside local development environments. The token is not placed in the URL. The browser tool must send it as the X-WPAgent-Browser-Token header so it cannot enter access logs, referrers, or browser history.
Capability: edit_posts, but neither manage_options nor super-administrator status. These are the same boundaries applied to guided connection users. The link does not expand WordPress permissions.
Traits: write, non-destructive, not idempotent.
Input: optional destination (dashboard, posts, pages, media). Output: url, headers, expires_at, user_id, destination, one_time. Use headers unchanged and only for this single request.
wp-agent/revoke-browser-link
Purpose: Revokes the currently authenticated safe non-administrator's pending one-time backend link.
Capability: the same as create-browser-link.
Traits: write, non-destructive, idempotent. Output: revoked.
13. Page builders, ACF, WooCommerce, and forms
Native WPForms abilities
WPForms provides its own abilities. WPAgently does not duplicate their form logic. It adds only abilities that are currently registered and published by WPForms with meta.mcp.public: true to its MCP server. The control center separates form reads (list-forms, get-form, get-form-stats), sensitive entries (get-entry-summaries, get-entry, search-entries), and the write surface published together with describe-editing-schema (create-form, add-field, update-field, update-form-settings). Unknown future WPForms abilities remain individually manageable only when WPForms also publishes them for MCP.
WPForms Lite normally restricts these paths to Administrators. The connection page can instead grant the three WPAgently capabilities wpagently_wpforms_forms_access, wpagently_wpforms_entries_access, and wpagently_wpforms_write_access to a safe Editor. The official wpforms_current_user_can filter then accepts only the documented form, entry, and write checks at the exact WPAgently MCP endpoint. Normal WPForms admin, AJAX, and foreign REST surfaces, as well as unknown permissions such as deletion, remain denied. WPForms' own write toggle remains an additional hard requirement. IP addresses in native entry responses are masked for this agent user through the official masking filter. Revocation and uninstallation remove only additions tracked by WPAgently. Tracked grants remain revocable from the connection page even after WPForms is deactivated.
wp-agent/get-wpforms-delivery
Purpose: Reads existing WPForms confirmations and compact email notifications through the native form handler. By default, notifications expose only their ID, name, subject, and a complete item hash. include_notification_details: true additionally returns recipients, sender, reply-to address, carbon copies, and message. Unknown add-on data participates in conflict detection but is never returned. state_hash binds a later write to the complete raw form content.
Capability: wpagently_wpforms_write_access at the WPAgently MCP endpoint plus WPForms' native object-specific edit_form_single check. Traits: read-only, non-destructive, idempotent. Requires form_id. Optional: include_notification_details, default false.
wp-agent/update-wpforms-confirmation
Purpose: Checks a planned manual change to an existing WPForms confirmation against bounded safe values. The ability changes no confirmation and returns HTTP 409 with manual_only before any mutation. Make the change in WPForms.
Capability: the same as get-wpforms-delivery. Traits: manual-only, change it in WordPress, no remote mutation.
wp-agent/create-wpforms-confirmation
Purpose: Creates the first effective confirmation or, with WPForms Pro, an additional confirmation with the next safe numeric ID. Name and type are required. Messages, page targets, and redirects use the same bounds as the update path. WPForms Lite rejects a second rule because safe multiple selection depends on Pro conditional logic. Multiple rules on WPForms Pro remain empirically unverified without a legally licensed practical fixture.
Capability: the same as get-wpforms-delivery. Traits: write, non-destructive, not idempotent. Requires form_id, expected_hash, and confirmation.
wp-agent/delete-wpforms-confirmation
Purpose: Checks the input for manually deleting an additional WPForms confirmation. The ability deletes no confirmation and returns HTTP 409 with manual_only before any mutation. The last confirmation remains unchanged.
Capability: the same as get-wpforms-delivery. Traits: manual-only, change it in WordPress, no remote mutation.
wp-agent/update-wpforms-notification
Purpose: Checks a planned manual change to a WPForms email notification against bounded safe values. The ability changes neither the notification nor the global delivery switch and returns HTTP 409 with manual_only before any mutation. Make the change in WPForms.
Capability: the same as get-wpforms-delivery. Traits: manual-only, change it in WordPress, no remote mutation.
wp-agent/create-wpforms-notification
Purpose: Creates the first effective email notification or, with WPForms Pro, another one with the next safe numeric ID. Name, recipient, subject, sender name, sender address, and message are required. notifications_enabled can explicitly set global delivery. WPForms Lite rejects a second rule because its runtime sends only the first notification. Multiple rules on WPForms Pro remain empirically unverified without a legally licensed practical fixture.
Capability: the same as get-wpforms-delivery. Traits: write, non-destructive, not idempotent. Requires form_id, expected_hash, and notification. Optional: notifications_enabled.
wp-agent/delete-wpforms-notification
Purpose: Checks the input for manually deleting a WPForms email notification. The ability deletes no notification, changes no global delivery switch, and returns HTTP 409 with manual_only before any mutation.
Capability: the same as get-wpforms-delivery. Traits: manual-only, change it in WordPress, no remote mutation.
Native Ninja Forms abilities
Ninja Forms 3.14.10 registers 32 abilities and publishes 29 of them for MCP. WPAgently does not blindly grant the broad provider capability nf_edit_forms. Instead, it places 24 known public tools into four separate groups:
| Group | Native abilities | Dedicated user capability |
|---|---|---|
| Form reads | list-forms, get-form, list-field-types, list-actions, list-calculations, export-form-definition | wpagently_ninjaforms_forms_access |
| Submissions | get-submissions, get-submission, get-submission-fields, export-submissions | wpagently_ninjaforms_submissions_access |
| Form editing | create-form, add-field, update-form, update-field, reorder-fields, duplicate-form, add-action, update-action, add-calculation, update-calculation, import-form, embed-form, get-public-link | wpagently_ninjaforms_write_access |
| Email delivery | process-submission | wpagently_ninjaforms_delivery_access |
The broad capability is mediated only during a matching request at the exact WPAgently MCP endpoint. It is never persisted on the user account. A JSON-RPC batch receives access only if every contained Ninja Forms tool is known and allowed through its respective group. Mixed tool batches and batches with more than 100 messages are rejected. A user who already has persistent nf_edit_forms access is not considered a safe agent user. Revocation and uninstallation remove only the four group capabilities recorded as additions by WPAgently.
The eight abilities ninjaforms/delete-action, ninjaforms/delete-calculation, ninjaforms/delete-form, ninjaforms/delete-submission, ninjaforms/get-plugin-settings, ninjaforms/remove-field, ninjaforms/update-plugin-settings, and ninjaforms/update-submission remain quarantined. The reasons are missing technical confirmation, permanent deletion, global side effects, and possible secrets in plugin settings. ninjaforms/process-submission can send real email. It therefore has its own double opt-in group and must be used only after an explicit instruction. Submissions may contain personal data and are never enabled together with the basic form-read permission.
wp-agent/detect-builder
Purpose: Detects, per post, which page builder/format its content is actually stored in (not merely which builder plugins are active). Checks three storage families introspectively (never merely assumed): JSON in postmeta (Elementor, Bricks, Beaver Builder, Breakdance, Oxygen), Gutenberg block comments in post_content (Core, Kadence, Spectra, GenerateBlocks), and shortcodes (WPBakery, [vc_*]). Cascade when there are multiple postmeta signals: Bricks before Beaver Builder before Oxygen before Breakdance before Elementor. ACF is always additive, unless the post itself is an ACF field group.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id).
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
| Output field | Type | Description |
|---|---|---|
primary | string | Detected authoritative builder, e.g. elementor, spectra, classic. |
signals[] | Objects with type, key, location | All signals found. |
storage_location | string | postmeta, post_content, or mixed. |
is_block_based | boolean | |
write_supported | boolean | True only when the existing storage can be changed through a safe WPAgently path. It is false for third-party block documents. |
recommended_ability | string | Safe next write path, or empty when none exists. |
block_types[] | string[] | |
notes[] | string[] |
Example: { "post_id": 42 }
wp-agent/list-block-types
Purpose: Lists the block types actually registered on the site for the Core, Kadence, GenerateBlocks, and Spectra namespaces. Search, namespace filtering, and pagination are bounded. Results contain the name, namespace, title, category, API version, dynamic flag, and attribute count, but no callbacks or local source paths.
Capability: edit_posts.
Traits: read, non-destructive, idempotent. Optional parameters are search, namespace with all, core, kadence, generateblocks, or uagb, page, and per_page up to 500.
wp-agent/get-block-type
Purpose: Reads one registered block type including redacted attributes, supports, parent rules, and ancestor rules. Keys that indicate passwords, tokens, API keys, cookies, or other secrets, as well as non-JSON runtime values, are removed. The dynamic attributes and supports fields are each the closed, versioned {format,json,sha256,bytes} envelope from the preceding section, not open objects.
Capability: edit_posts.
Traits: read, non-destructive, idempotent. name is required in namespace/block format from one of the four approved namespaces.
wp-agent/get-native-block-document
Purpose: Reads the complete stored post_content of an authorized post together with status, modification time, recursive block count, freeform count, block types, detected builder, and a stable content hash. This allows an agent to inspect real document structures instead of guessing from plugin documentation.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id).
Traits: read, non-destructive, idempotent. post_id is required. There is deliberately no ability that writes serialized block markup back. Core content is generated only through the existing Markdown or declarative server paths. Kadence and GenerateBlocks blocks remain fail-closed outside their respective narrow attribute paths. Static Spectra blocks remain closed as well, with exactly two version-bound abilities for the three responsive alignment attributes and the classic headingColor and subHeadingColor values of one uagb/advanced-heading on Spectra 2.20.1. The following bounded attribute path covers the server-registered dynamic Spectra subset.
wp-agent/get-spectra-blocks-separator
Purpose: Reads exactly one separately registered spectra/separator at an explicit recursive block path. The contract applies exclusively to Spectra Blocks 1.0.4 with a server-side render callback and a fully matching attribute schema. It returns only style, alignment, width, height, and color. Raw markup, free CSS values, inner blocks, further responsive values, and divergent provider attributes remain closed.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id).
Traits: read, non-destructive, idempotent. post_id and a path of 1 through 32 non-negative indices are required. The document must be below 1 MiB and stably parseable and serializable with WordPress.
| Output field | Type |
|---|---|
post_id, path, rendered_html_length | integer or integer[] |
version | string, exactly 1.0.4 |
settings | separator_style, separator_align, separator_width, separator_height, separator_color |
hash | SHA-256 of the complete document state |
Example: { "post_id": 42, "path": [0, 1] }
wp-agent/update-spectra-blocks-separator
Purpose: Changes only the style, alignment, width, height, and color of that exactly verified Spectra Blocks separator. Style is limited to eight provider values, alignment to left, center, or right, width to 1-100 % or 1-2,000 px, height to 1-400 px, and color to six-digit hexadecimal values. The action does not change text, raw markup, or any other provider attribute.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id).
Traits: write, non-destructive, non-idempotent. post_id, path, at least one approved settings value, and the current expected_hash are required. The path checks Spectra Blocks 1.0.4, canonical document structure, and provider markup, locks the post exclusively, creates a revision, writes with byte-exact CAS, renders, and reads the result back. On unsafe read-back it attempts to restore the previous state and otherwise returns recovery_required; a foreign change is never overwritten.
| Output field | Type |
|---|---|
post_id, path, rendered_html_length, revision_id | integer or integer[] |
version, hash, previous_hash | string |
settings | complete verified separator state |
changed, verified | boolean |
Example: { "post_id": 42, "path": [0, 1], "settings": { "separator_color": "#1a73e8" }, "expected_hash": "<64-character SHA-256 from get-spectra-blocks-separator>" }
wp-agent/update-spectra-block-attributes
Purpose: Changes only schema-known attributes of a visible dynamic Spectra block at an explicit recursive block path. The target must be present both in Spectra's visible registry and in WordPress with a callable render callback and an attribute schema. Bounded booleans, numbers, plain-text values, and bounded arrays with scalar item schemas are supported. Objects, internal IDs, metadata, locks, class names, Core styles, raw HTML, block comments, active script and HTML data URIs, free CSS declarations, unknown attributes, and static Spectra blocks registered only in JavaScript are rejected.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id).
Traits: write, non-destructive, non-idempotent. Required fields are post_id, a path of 1-32 indices, and expected_hash. attributes may set up to 50 values through the closed native-block {format,json,sha256,bytes} envelope, while remove_attributes may reset up to 50 registered values to their provider defaults. A successful write consumes the expected document hash, so automatically replaying the same request is unsafe. The path locks the post, checks the complete document hash, bounds the patch and document size, creates a verified revision, serializes through WordPress, confirms that the block structure did not change, renders server-side, reads content and attributes back exactly, and invalidates Spectra's post and asset cache. Once mutation begins, it restores the previous content only when the exact expected candidate is still stored and the restoration can be verified. On foreign drift, capability loss, or lock loss it preserves current state and returns recovery_required; the created revision is then the manual inspection path. Results include the target block, path, requested changes, revision ID, render length, and the previous and new hashes.
wp-agent/update-spectra-static-heading-alignment
Purpose: Changes only headingAlign, headingAlignTablet, or headingAlignMobile on a static uagb/advanced-heading at an explicit block path. This contract applies exclusively to Spectra 2.20.1. It accepts only left, center, or right; markup, text, block_id, and every other attribute remain unchanged. Any other Spectra version, a dynamically registered target, or a divergent provider contract fails closed before mutation.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id).
Traits: write, non-destructive, not idempotent. Required fields are post_id, path, alignment, and expected_hash. Optional viewport is limited to desktop, tablet, or mobile and defaults to desktop when omitted. The path requires a canonically parseable and serializable document, locks the post, renews and proves lock ownership before and after mutations, creates a revision, checks the structure and static target markup, refreshes Spectra's cache, and reads the stored state and target markup back. A failed check or lost lock after the mutation starts returns recovery_required. Lock loss never triggers an automatic counter-mutation; the current state and revision require manual inspection.
wp-agent/update-spectra-static-heading-colors
Purpose: Changes only headingColor, subHeadingColor, and optional separatorColor on a static uagb/advanced-heading at an explicit block path. The contract applies exclusively to Spectra 2.20.1 in classic color mode. Every supplied value must be a six-digit hex color or inherit. inherit stores the provider's native empty value. separatorColor is accepted only when exactly one existing separator with an allowlisted provider style and the exact static wrapper is proven. Gradients, CSS variables, free CSS syntax, markup, text, block_id, and every other attribute remain blocked.
Capability: edit_posts broadly plus current_user_can('edit_post', $post_id).
Traits: write, non-destructive, not idempotent. Required fields are post_id, path, heading_color, description_color, and expected_hash; separator_color is optional. The alignment and color paths share the same exclusive document lock. This path requires a canonical block document and the exact verified static provider wrapper, creates a revision before the byte-exact compare-and-swap, proves lock ownership around every effective phase, refreshes Spectra's cache, and reads content, attributes, and target markup back. The real end-to-end test binds all three colors to the exact target selectors emitted by Spectra 2.20.1 and rejects a separator color without the provider wrapper. Lock loss or unsafe read-back after mutation starts returns recovery_required without an automatic counter-mutation.
wp-agent/update-generateblocks-block-attributes
Purpose: Changes only five version-bound GenerateBlocks attributes. generateblocks/query-page-numbers.midSize accepts an integer from 0 through 10. generateblocks/query.paginationType accepts only standard or instant. In addition, tagName permits only div, section, article, aside, header, footer, nav, or main on the Query wrapper, only div, section, or nav on Page Numbers, and only p, span, div, or h1 through h6 on one canonical plain-text block. Interactive tags and existing inline markup remain blocked. The server replaces only the previously verified canonical provider markup and keeps the comment attributes, innerHTML, and innerContent consistent together. The block, attribute, and type must also exist in the live WordPress schema. Free markup, every other attribute, block type, and CSS function remain blocked.
Capability: edit_posts broadly plus current_user_can('edit_post', $post_id).
Traits: write, non-destructive, not idempotent. Required fields are post_id, path, and expected_hash; at least one approved attribute is written or removed through the closed native-block {format,json,sha256,bytes} envelope. The path uses a short-lived lock, verified revision, byte-exact database compare-and-swap, exact provider structure validation, GenerateBlocks cache invalidation, a frontend render reduced to verified Query ancestors and the target, and exact read-back. Only an approved tagName changes the canonical wrapper together with the attribute. A foreign concurrent change is preserved and returns recovery_required.
wp-agent/update-kadence-block-attributes
Purpose: Changes only forty-one narrowly approved attributes on existing kadence/advancedheading, kadence/spacer, or kadence/progress-bar blocks. Advanced Heading keeps its level, three responsive alignments, text transformation, font style, font weight, three responsive pixel font sizes from 8 through 200, three responsive pixel line heights from 8 through 300, three responsive pixel letter-spacing values from -10 through 50, four pixel margins from -500 through 500, and classic six-digit text and background colors. When an existing, safely shaped provider icon is present, icon and hover-icon color, icon side, and vertical icon alignment are also available. Margins use only the px unit. The canonical Spacer permits only positive desktop, tablet, and mobile heights from 1 through 2,000 and the px, rem, or vh unit. Desktop height remains mandatory while responsive overrides may be removed. The simple Progress Bar must use the native line type, contain no labels, masks, links, free text, or inner blocks, and accepts only the progress value, maximum, three stroke widths from 1 through 20, and two six-digit colors. The progress value cannot exceed the maximum. The block, attribute, and type must also exist in the live WordPress schema. Different markup, every other attribute, and free CSS functions remain blocked.
Capability: edit_posts broadly plus current_user_can('edit_post', $post_id).
Traits: write, non-destructive, not idempotent. Required fields are post_id, path, and expected_hash; at least one approved attribute is written or removed through the closed native-block {format,json,sha256,bytes} envelope. The path renews its short-lived lock around every critical transition and uses a verified revision, byte-exact database compare-and-swap, structure validation, frontend rendering including CSS verification, and exact read-back. Kadence Blocks 3.7.8 updates its output on render. Conflicts and foreign concurrent changes are never overwritten. If lock ownership is lost after a write starts, the mutation remains for manual review and the path returns recovery_required without an automatic rollback.
wp-agent/get-acf-fields
Purpose: Reads the ACF fields assigned to a post, user, term, comment, or ACF options store through the official ACF APIs (acf_get_field_groups(), acf_get_fields(), and get_field()), never through raw metadata. Returns the portable unformatted value, the real field_ key, the canonical ACF object identifier, and a SHA-256 hash over the target, value, side effects, and effective field definition. Post, media, and user references that the account cannot read are omitted.
Capability: Dynamic for the target. Requires edit_post, edit_user, edit_term, edit_comment, or manage_options for the generic options store. A registered ACF options page uses its configured capability. User fields additionally require list_users. The writable output flag is false for every field because no ACF field value can be changed remotely. The ability to assign terms in the configured taxonomy is only field and capability metadata for a manual change in WordPress administration. It does not lift the manual_only boundary of update-acf-field. Requires Advanced Custom Fields, otherwise returns HTTP 409.
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
post_id | integer | alternative | Backward-compatible shorthand for a post. |
object_type | string | alternative | post, user, term, comment, or options. |
object_id | integer or string | alternative | Positive ID for WordPress objects. For options, use options or the registered options-page slug. |
| Output field | Type |
|---|---|
object_type | string |
object_id | integer or string |
acf_object_id | string, for example 42, user_7, term_9, comment_11, or options |
post_id | integer, only for a post target |
fields[] | Objects with key (field_...), name, label, type, state_hash, writable, redacted, unsupported_reason, and value |
Examples: { "post_id": 42 } or { "object_type": "term", "object_id": 9 }. post_id and the explicit object contract may appear together only when both identify the same post exactly.
wp-agent/update-acf-field
Purpose: Directs a requested change to an assigned ACF field on a post, user, term, comment, or options store to the manual path in Advanced Custom Fields or the appropriate WordPress administration screen. The ability does not call update_field() and returns HTTP 409 with manual_only before any mutation. Change the value manually, then read it again.
The REST and MCP schema validates only the structural input envelope. It permits bounded keys, basic types, patterns, size limits, and the bounded JSON value envelope. It does not read an ACF field definition. It does not perform an ACF or provider value validation. The manual-only callback reads no ACF value or taxonomy assignment, takes no lock, and performs neither read-back nor rollback. All ACF field types, values, and nested structures remain read-only remotely.
Capability: Dynamic as described for get-acf-fields. References require the additional read or assignment permissions described above. An uploadedTo media field remains read-only outside a post. Taxonomy fields with load_terms or save_terms remain read-only in options storage. Requires Advanced Custom Fields.
Traits: manual-only, change it in WordPress, no remote mutation.
Remote call: Not available. After REST and MCP schema validation, the callback returns HTTP 409 with manual_only without reading an ACF state or field definition. Change the field value in Advanced Custom Fields or the appropriate WordPress administration screen and then read it again.
Shared contract for persistent ACF field groups
The following six abilities manage only ACF field groups stored in the database. Groups registered through PHP or Local JSON are neither listed as mutable nor opened through a known key. All six paths require manage_options, which normally means an Administrator. They use native ACF APIs and never change wp_posts or wp_postmeta directly.
The portable write path supports no more than 100 fields per group and 200 choices per field. It accepts text, textarea, number, range, email, url, true_false, select, checkbox, radio, and button_group. Location rules must consist of simple exact post_type == ... rules. Complex rules, conditional logic, other field types, and truncated definitions are marked portable: false when read and are rejected in full for updates or duplication.
Each response contains a SHA-256 hash over the complete raw group and field definitions without volatile database IDs. wp-agent/update-acf-field-group and wp-agent/delete-acf-field-group are manual-only: they neither change nor delete a group and return HTTP 409 with manual_only before any mutation. Make the change in Advanced Custom Fields and then read the group again. The other documented read, creation, and duplication paths retain their own contract.
wp-agent/list-acf-field-groups
Purpose: Lists persistent field groups alphabetically with search and pagination. Each group contains its title, active state, simple post types, bounded field definitions, field count, portability, location-rule count, and conflict hash.
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
search | string | no | Up to 100 characters, searches the title and group key. |
page | integer | no | Default 1. |
per_page | integer | no | Default 20, at most 50. |
wp-agent/get-acf-field-group
Purpose: Reads one persistent field group by its group_ key in the same complete response format as the list operation.
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
group_key | string | yes |
wp-agent/create-acf-field-group
Purpose: Creates a portable field group with new cryptographically random group_ and field_ keys. An unverifiable partial creation is removed.
Traits: write, non-destructive, not idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
title | string | yes | Plain text, 1-200 characters. |
post_types | string[] | yes | 1-20 registered post types with an administration UI. |
fields | object[] | yes | Complete portable field list. An empty list is allowed. |
active | boolean | no | Default true. |
wp-agent/update-acf-field-group
Purpose: Checks a planned manual change to a portable group's title, active state, post types, or field list. The ability changes no group, removes no fields, and returns HTTP 409 with manual_only before any mutation. Make the change in Advanced Custom Fields.
Traits: manual-only, change it in WordPress, no remote mutation.
Remote call: Not available. Change the field group in Advanced Custom Fields and then read it again.
wp-agent/duplicate-acf-field-group
Purpose: Copies a portable persistent group with new group and field keys. The source is reread under a write lock and must match expected_hash.
Traits: write, non-destructive, not idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
group_key | string | yes | Source group. |
expected_hash | string | yes | Last-read source state. |
title | string | no | Appends “Copy” when omitted. |
wp-agent/delete-acf-field-group
Purpose: Checks the input for manually deleting a persistent field group. The ability deletes neither the group nor its field definitions and returns HTTP 409 with manual_only before any mutation. Delete it in Advanced Custom Fields.
Traits: manual-only, change it in WordPress, no remote mutation.
Remote call: Not available. Delete the field group in Advanced Custom Fields and then read it again.
Shared contract for persistent ACF post types and taxonomies
The following ten abilities manage only persistent ACF definitions stored in the database. Definitions from PHP or Local JSON remain excluded. Every path requires manage_options and Advanced Custom Fields 6.1 or newer. Writes use the native ACF APIs. Every new or changed record is reread as a complete definition and additionally checked against the effective WordPress runtime registration.
The lossless path supports shared labels, description, active state, visibility, hierarchy, REST and AI access, and an optional rewrite slug. Post types add a bounded WordPress support list, registered taxonomies, and archive enablement. Taxonomies add 1-20 registered object types and the admin column. The post-type or taxonomy slug itself is immutable after creation. Further ACF settings produce portable: false and block updates.
Every response contains content_count, portable, registration_conflict, and a SHA-256 hash over the complete definition. registration_conflict: true means that another WordPress component registered the same runtime slug. Such a definition is neither updated nor automatically deleted. Creates and updates use atomic expiring locks. Updates require the last-read expected_hash; deviations introduced by an ACF hook trigger rollback.
| Ability | Traits | Required parameters | Purpose |
|---|---|---|---|
wp-agent/list-acf-post-types | read, idempotent | none | Lists persistent post types with search and pagination. |
wp-agent/get-acf-post-type | read, idempotent | key | Reads a definition by its post_type_ key. |
wp-agent/create-acf-post-type | write, not idempotent | post_type, singular_label, plural_label, supports | Creates a post type with a random ACF key and verifies the definition and registration. |
wp-agent/update-acf-post-type | write, destructive, idempotent | key, expected_hash | Changes at least one portable property with conflict protection. |
wp-agent/delete-acf-post-type | write, destructive, not idempotent | key, expected_hash, confirm | Deletes only the definition. Posts remain. Existing posts additionally require confirm_content=true. |
wp-agent/list-acf-taxonomies | read, idempotent | none | Lists persistent taxonomies with search and pagination. |
wp-agent/get-acf-taxonomy | read, idempotent | key | Reads a definition by its taxonomy_ key. |
wp-agent/create-acf-taxonomy | write, not idempotent | taxonomy, singular_label, plural_label, object_types | Creates a taxonomy with a random ACF key and verifies the definition and registration. |
wp-agent/update-acf-taxonomy | write, destructive, idempotent | key, expected_hash | Changes at least one portable property with conflict protection. |
wp-agent/delete-acf-taxonomy | write, destructive, not idempotent | key, expected_hash, confirm | Deletes only the definition. Terms remain. Existing terms additionally require confirm_content=true. |
Lists optionally accept search, page, and per_page (at most 50). Post-type write paths additionally accept description, active, public, hierarchical, show_ui, show_in_rest, allow_ai_access, ai_description, rewrite_slug, supports, taxonomies, and has_archive. Taxonomy write paths accept the same shared fields plus object_types and show_admin_column.
Native Custom Post Type UI definitions
Ten administrator-only abilities manage persistent post-type and taxonomy definitions from Custom Post Type UI 1.19.3 or newer. Definitions registered through PHP remain excluded. The slug is immutable after creation. CPT UI applies the effective runtime registration on the next WordPress request, so successful mutations report reload_required: true.
Every read response contains a SHA-256 hash over the complete option state for that definition kind. Updates and deletions require this hash and use one atomic short-lived lock per option kind. Partial updates change only approved fields and preserve unknown provider data. The write path limits definition count and total size, reads the exact option state back, and restores the previous value including autoload metadata after a mismatch. Deletion removes only the definition. Posts and terms remain stored and require confirm_content=true when content exists.
| Ability | Traits | Required parameters | Purpose |
|---|---|---|---|
wp-agent/list-cptui-post-types | read, idempotent | none | Searches and paginates persistent CPT UI post types. |
wp-agent/get-cptui-post-type | read, idempotent | slug | Reads the definition, runtime state, content count, unknown fields, and option hash. |
wp-agent/create-cptui-post-type | write, not idempotent | slug, both labels, supports | Creates a bounded persistent post-type definition. |
wp-agent/update-cptui-post-type | write, destructive, idempotent | slug, expected_hash, at least one change | Changes labels, visibility, REST, hierarchy, rewrite, supports, taxonomies, or archive state. |
wp-agent/delete-cptui-post-type | write, destructive, idempotent | slug, expected_hash, confirm | Deletes only the definition and retains posts. |
wp-agent/list-cptui-taxonomies | read, idempotent | none | Searches and paginates persistent CPT UI taxonomies. |
wp-agent/get-cptui-taxonomy | read, idempotent | slug | Reads the definition, runtime state, term count, unknown fields, and option hash. |
wp-agent/create-cptui-taxonomy | write, not idempotent | slug, both labels, object_types | Creates a bounded persistent taxonomy definition. |
wp-agent/update-cptui-taxonomy | write, destructive, idempotent | slug, expected_hash, at least one change | Changes labels, visibility, REST, hierarchy, rewrite, object types, or admin column. |
wp-agent/delete-cptui-taxonomy | write, destructive, idempotent | slug, expected_hash, confirm | Deletes only the definition and retains terms. |
Native ACPT Lite definitions
Ten administrator-only abilities manage persistent post-type and taxonomy definitions from ACPT Lite 2.0 or newer through its native model and repository classes. Native synchronized WordPress or third-party definitions, reserved identifiers, slug changes, and rewrite collisions with existing pages, post types, or taxonomies remain blocked. The currently managed registration is excluded during safe partial updates. ACPT Lite applies new or changed runtime registrations on the next WordPress request, so successful mutations report reload_required: true.
Every read response includes a SHA-256 hash over the complete provider model, including its ID, labels, settings, and associations. Updates and deletions require that hash and use one shared atomic short-lived lock across both definition kinds. Concurrent post-type and taxonomy operations therefore cannot mutate the same ACPT association table. ACPT's persistent provider cache is cleared before each conflict comparison and read-back. Partial updates retain custom labels and unknown settings. A mismatch or partially failed association update triggers a verified rollback. Deletion removes only the definition. Posts and terms remain stored and require confirm_content=true when content exists. Linked ACPT meta fields block deletion.
| Ability | Traits | Required parameters | Purpose |
|---|---|---|---|
wp-agent/list-acpt-post-types | read, idempotent | none | Searches and paginates non-native ACPT Lite post types. |
wp-agent/get-acpt-post-type | read, idempotent | slug | Reads the definition, runtime state, content count, unknown settings, meta-field links, and model hash. |
wp-agent/create-acpt-post-type | write, not idempotent | slug, both labels, supports | Creates a bounded persistent post-type definition. |
wp-agent/update-acpt-post-type | write, destructive, idempotent | slug, expected_hash, at least one change | Changes labels, visibility, REST, hierarchy, rewrite, supports, taxonomies, or archive state. |
wp-agent/delete-acpt-post-type | write, destructive, idempotent | slug, expected_hash, confirm | Deletes only the definition and retains posts. |
wp-agent/list-acpt-taxonomies | read, idempotent | none | Searches and paginates non-native ACPT Lite taxonomies. |
wp-agent/get-acpt-taxonomy | read, idempotent | slug | Reads the definition, runtime state, term count, unknown settings, meta-field links, and model hash. |
wp-agent/create-acpt-taxonomy | write, not idempotent | slug, both labels, object_types | Creates a bounded persistent taxonomy definition. |
wp-agent/update-acpt-taxonomy | write, destructive, idempotent | slug, expected_hash, at least one change | Changes labels, visibility, REST, hierarchy, rewrite, object types, or admin column. |
wp-agent/delete-acpt-taxonomy | write, destructive, idempotent | slug, expected_hash, confirm | Deletes only the definition and retains terms. |
Native Pods content models and fields
Seven administrator-only abilities manage bounded Pods models and fields through its native PHP API. This model and field path covers only independent post types and taxonomies with storage=meta. Extended WordPress core objects, definitions of table-backed Advanced Content Types, renames, and unknown provider states remain read-only in this path. Five separate abilities for bounded records of existing, standard-configured ACTs are documented in the following section. New models and missing fields cannot be proven atomically with a positive provider read-back. Therefore, create-pods-model and upsert-pods-field for a missing field return HTTP 409 before any mutation. delete-pods-model and delete-pods-field are manual-only and return HTTP 409 with manual_only before any mutation. Create or delete those models and fields manually in Pods, then read them again.
Model hashes include the complete raw model and field definitions. Field hashes include the complete raw field definition. Updates require the last observed hash, and every write uses an atomic short-lived lock followed by a complete provider read-back. A mismatch restores and verifies the previous state. Pods options not managed by WPAgently are reported by name and preserved during partial updates.
The field path supports text, website, phone, email, paragraph, wysiwyg, datetime, date, time, number, currency, file, avatar, oembed, pick, boolean, and color. Relationship fields may target registered post types, taxonomies, users, or media. Changing a field type when values exist requires confirm_data_migration=true. The manual-only deletion paths remove neither definitions nor relationship data. Delete through the Pods administration screen, then read the model again.
| Ability | Characteristics | Required parameters | Purpose |
|---|---|---|---|
wp-agent/list-pods-models | read, idempotent | none | Searches and paginates supported Pods models. |
wp-agent/get-pods-model | read, idempotent | name | Reads the model, fields, content and relationship counts, and conflict state. |
wp-agent/create-pods-model | manual-only, no remote mutation | kind, name, singular_label, label | Returns HTTP 409 with manual_only before creation. Create the model manually in Pods. |
wp-agent/update-pods-model | write, destructive, idempotent | name, expected_hash | Changes at least one approved model option with conflict protection. |
wp-agent/delete-pods-model | manual-only, no remote mutation | name, expected_hash, confirm | Returns HTTP 409 with manual_only before deletion. Model and field definitions remain unchanged. |
wp-agent/upsert-pods-field | write for existing fields, fail-closed for missing fields | model_name, expected_model_hash, name | Changes an existing approved field with its expected_field_hash; rejects a missing field with HTTP 409 before mutation. |
wp-agent/delete-pods-field | manual-only, no remote mutation | model_name, name, both hashes, confirm | Returns HTTP 409 with manual_only before deletion. The field definition remains unchanged. |
Pods Advanced Content Type records
Five additional administrator-only abilities manage records only in standalone, table-based Pods Advanced Content Types with type=pod, storage=table, the standard table configuration, and no more than 20 non-repeatable text fields. Pods must provide version 3.3.9 or newer within major version 3. Modified system fields, author system fields, custom configurations, repeatable or non-text fields, foreign subsites, and unknown provider states remain fail-closed. SQLite is available for reads only. Writes remain blocked there because Pods 3.3.9 does not unambiguously confirm a create operation with a positive record ID.
Lists and individual reads use the native pods() API and return only the approved text values, the schema hash, and a complete SHA-256 conflict hash for each record. Creation and updates require manage_options, bind the subsite, model, and schema under an atomic short-lived lock, use only Pods::add() or Pods::save(), and read the result back through the provider. delete-pods-act-record is manual-only and returns HTTP 409 with manual_only before any mutation. Delete the record in Pods and then read its absence again.
| Ability | Characteristics | Required parameters | Purpose |
|---|---|---|---|
wp-agent/list-pods-act-records | read, idempotent | model_name | Lists up to 50 records per page and returns fields, totals, pagination, and the schema hash. |
wp-agent/get-pods-act-record | read, idempotent | model_name, record_id | Reads exactly one record with value and conflict hashes. |
wp-agent/create-pods-act-record | write, non-idempotent | model_name, expected_schema_hash, values | Creates a record with no more than 20 bounded text values and exact read-back. |
wp-agent/update-pods-act-record | write, idempotent | model_name, record_id, expected_schema_hash, expected_hash, values | Updates only approved text fields of an unchanged record. |
wp-agent/delete-pods-act-record | manual-only, no remote mutation | model_name, record_id, both hashes, confirm=true | Returns HTTP 409 with manual_only before deletion. The record remains unchanged. |
Native Meta Box content models, field values, relationships, and settings pages
Thirty-nine abilities provide bounded native paths for Meta Box 5.14, MB Builder 5.4, MB Custom Post Type 2.12, MB Relationships 1.13, and MB Settings Page. wp-agent/get-meta-box-status reports the detected core and Builder versions, the native provider ability count, and Settings Page contract availability. A missing extension returns HTTP 409 for the affected operation instead of silently falling back to raw post meta.
Meta Box proxy abilities never inherit an open native schema. They publish only a closed, bounded derived contract and validate both input and provider output against it. If the native ability contract, REST schema validator, or a required Meta Box extension is unavailable, the affected proxy returns HTTP 409. There is no raw-meta or raw-provider fallback. A provider result outside the derived contract is not emitted.
Field groups, individual field definitions, post types, and taxonomies require manage_options. ACF field values require the WordPress capability appropriate to the concrete target: edit_post, edit_user, edit_term, edit_comment, or, for option stores, manage_options or the capability configured for a registered ACF options page. Meta Box field values remain post-only and first require edit_posts as well as the provider's native object-level permission. Meta Box must know the field. Arbitrary meta keys, unreadable references, non-editable objects, and settings without administrator access remain blocked.
The field read path corrects an MB Builder 5.4.2 defect that prevents the first field at index 0 from being read. WPAgently uses a strict index lookup and the public Builder normalization for that read. The format ability removes only the extra field_id property that Meta Box 5.14 returns even though its output schema forbids it.
The eleven paths that change or delete existing field groups, fields, post types, taxonomies, and field values are registered manual-only abilities: update-meta-box-field-group, delete-meta-box-field-group, update-meta-box-field, delete-meta-box-field, move-meta-box-field, update-meta-box-post-type, delete-meta-box-post-type, update-meta-box-taxonomy, delete-meta-box-taxonomy, update-meta-box-field-value, and delete-meta-box-field-value. Meta Box provides no reliable versioned compare-and-swap check for them. The callback therefore returns HTTP 409 with manual_action_required=true before any provider mutation. Make changes or deletions in WordPress and read the result again afterwards. The respective create and read abilities remain separate.
The eight relationship abilities always require manage_options. Listing and individual reads remain read-only. create-meta-box-relationship and add-meta-box-connection are the two remote write paths: definitions accept only approved settings and IDs up to 44 characters, PHP-registered IDs are never overwritten, and connections use the public MB Relationships API. Both paths validate provider state and input, use their atomic lock, and read the result back. update-meta-box-relationship, delete-meta-box-relationship, and delete-meta-box-connection are registered manual-only abilities instead. Meta Box has no storage-atomic compare-and-set or compare-and-delete operation for those existing objects. They therefore return HTTP 409 with manual_only before any mutation; changes, deletion, and permanent deletion must happen in WordPress and then be read again.
The five settings-page abilities also require manage_options and the fully active combination of MB Settings Page and MB Builder. Listing and individual reads remain read-only. create-meta-box-settings-page is the only remote write path: it manages persistent Builder definitions only, never overwrites PHP-defined pages, blocks PHP callbacks, active SVG data URLs, and known broad default capabilities, and reads both persistent and active definitions back. update-meta-box-settings-page and delete-meta-box-settings-page are manual-only. Because Meta Box has no storage-atomic compare-and-set or compare-and-delete operation for existing Settings Page definitions, they return HTTP 409 with manual_only before any mutation. They neither trash definitions nor delete them permanently. Changes or deletion happen in the WordPress dashboard and are then read again. Value access through the proprietary runtime extension remains uncertified without a legally licensed practical installation.
| Abilities | Traits | Required parameters | Purpose |
|---|---|---|---|
wp-agent/get-meta-box-status | read, idempotent | none | Reads core, Builder, and ability status. |
wp-agent/list-meta-box-field-groups, wp-agent/get-meta-box-field-group | read, idempotent | id for a single item | Searches field groups or reads fields and settings. |
wp-agent/create-meta-box-field-group | write, non-idempotent | title | Creates a persistent field group through MB Builder. |
wp-agent/update-meta-box-field-group | manual-only, no remote mutation | id | Returns HTTP 409 with manual_action_required=true before any change. The field group remains unchanged. |
wp-agent/delete-meta-box-field-group | manual-only, no remote mutation | id | Returns HTTP 409 with manual_action_required=true before any deletion. The field group remains unchanged. |
wp-agent/list-meta-box-fields, wp-agent/get-meta-box-field | read, idempotent | field_group_id, plus field_id for one field | Reads all fields or one field, including the first list item. |
wp-agent/create-meta-box-field | write, not idempotent | field_group_id, field | Adds a normalized field definition with a unique ID. |
wp-agent/update-meta-box-field, wp-agent/move-meta-box-field | manual-only, no remote mutation | field_group_id, field_id, change or target | Return HTTP 409 with manual_action_required=true before any change or move. The field remains unchanged. |
wp-agent/delete-meta-box-field | manual-only, no remote mutation | field_group_id, field_id | Returns HTTP 409 with manual_action_required=true before any deletion. The field definition remains unchanged. |
wp-agent/list-meta-box-post-types, wp-agent/get-meta-box-post-type | read, idempotent | id for a single item | Searches persistent Meta Box post-type definitions or reads one definition. |
wp-agent/create-meta-box-post-type | write, non-idempotent | title, settings | Creates a post type through MB Custom Post Type. |
wp-agent/update-meta-box-post-type | manual-only, no remote mutation | id | Returns HTTP 409 with manual_action_required=true before any change. The post type remains unchanged. |
wp-agent/delete-meta-box-post-type | manual-only, no remote mutation | id | Returns HTTP 409 with manual_action_required=true before any deletion. The definition remains unchanged. |
wp-agent/list-meta-box-taxonomies, wp-agent/get-meta-box-taxonomy | read, idempotent | id for a single item | Searches persistent taxonomy definitions or reads one definition. |
wp-agent/create-meta-box-taxonomy | write, non-idempotent | title, settings | Creates a taxonomy through MB Custom Post Type. |
wp-agent/update-meta-box-taxonomy | manual-only, no remote mutation | id | Returns HTTP 409 with manual_action_required=true before any change. The taxonomy remains unchanged. |
wp-agent/delete-meta-box-taxonomy | manual-only, no remote mutation | id | Returns HTTP 409 with manual_action_required=true before any deletion. The definition remains unchanged. |
wp-agent/get-meta-box-field-value-format, wp-agent/get-meta-box-field-value | read, idempotent | field type or field_id, object_id | Reads the expected value shape or a registered field value. |
wp-agent/update-meta-box-field-value | manual-only, no remote mutation | field_id, object_id, value | Returns HTTP 409 with manual_action_required=true before any change. The field value remains unchanged. |
wp-agent/delete-meta-box-field-value | manual-only, no remote mutation | field_id, object_id | Returns HTTP 409 with manual_action_required=true before any deletion. The field value remains unchanged. |
wp-agent/list-meta-box-settings-pages, wp-agent/get-meta-box-settings-page | read, idempotent | id for a single item | Lists persistent settings pages with pagination or reads the definition, active runtime state, and conflict hash. |
wp-agent/create-meta-box-settings-page | write, not idempotent | title, settings | Creates a published or draft Builder definition with strict validation and provider read-back. |
wp-agent/update-meta-box-settings-page | manual-only, no remote mutation | id, expected_hash, settings | Returns HTTP 409 with manual_only before any change. The page remains unchanged. |
wp-agent/delete-meta-box-settings-page | manual-only, no remote mutation | id, expected_hash | Returns HTTP 409 with manual_only before deletion. The definition remains unchanged. |
wp-agent/list-meta-box-relationships, wp-agent/get-meta-box-relationship | read, idempotent | id for a single item | Lists persistent definitions with pagination or reads one definition with its complete conflict hash. |
wp-agent/create-meta-box-relationship | write, not idempotent | title, settings | Creates a normalized definition with approved from and to sides and exact provider read-back. |
wp-agent/update-meta-box-relationship | manual-only, no remote mutation | id, expected_hash, settings | Returns HTTP 409 with manual_only before any change. The definition remains unchanged. |
wp-agent/delete-meta-box-relationship | manual-only, no remote mutation | id, expected_hash | Returns HTTP 409 with manual_only before deletion. The definition remains unchanged. |
wp-agent/list-meta-box-connections | read, idempotent | relationship_id, direction, object_id | Lists at most 100 connections per page including order and state hash. |
wp-agent/add-meta-box-connection | write, not idempotent | relationship_id, from, to | Connects two matching objects through the provider API and verifies the database state. |
wp-agent/delete-meta-box-connection | manual-only, no remote mutation | relationship_id, from, to, expected_hash | Returns HTTP 409 with manual_only before deletion. The connection remains unchanged. |
wp-agent/get-product
Purpose: Reads a complete WooCommerce product through WC_Product: core data, prices, stock, visibility, shipping dimensions, media, categories, tags, shipping class, and attributes. Raw post meta is never used.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $product_id) (resolved by WooCommerce's map_meta_cap() to the WooCommerce capability edit_products, by default only Shop Manager and Administrator, not Editor). Requires WooCommerce (otherwise 400).
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
product_id | integer | yes |
| Output field | Type | Description |
|---|---|---|
product_id | integer | |
type, status, name, slug, sku, prices, stock status, descriptions, visibility, weight | string | |
stock_quantity | integer|null | null if stock isn't tracked. |
manage_stock, virtual, downloadable, featured | boolean | |
dimensions, attributes | object/array | Dimensions and native product attributes. |
| Media, category, tag, and shipping IDs | integer/array | IDs of associated WooCommerce objects. |
Example: { "product_id": 120 }
wp-agent/update-product
Purpose: Partial update of a WooCommerce product exclusively via the WC_Product object (official setters plus save()), never directly via wp_update_post()/update_post_meta(). Reason: a raw update_post_meta() call does change the postmeta row, but neither WooCommerce's object cache nor the lookup table wp_wc_product_meta_lookup, which the shop frontend uses for price sorting/filtering. Checks a duplicate SKU up front via wc_get_product_id_by_sku() (instead of letting the synchronously thrown WC_Data_Exception from set_sku() turn into an uncaught HTTP 500).
Capability: edit_posts (coarse) plus current_user_can('edit_post', $product_id) (WooCommerce edit_products). Requires WooCommerce.
Traits: write, non-destructive, idempotent.
| Parameter | Type | Required | Description |
|---|---|---|---|
product_id | integer | yes | |
name | string | no | |
regular_price | string | no | Numeric string, e.g. 19.99. Empty removes the price. |
sale_price | string | no | Same as regular_price. |
sku | string | no | Checked up front for collision. |
stock_quantity | integer | no | |
manage_stock | boolean | no | |
status | string (enum: draft, publish, pending, private) | no | |
short_description | string | no | |
description | string | no | |
virtual, downloadable, featured | boolean | no | |
catalog_visibility, stock_status | enum | no | Native WooCommerce values. |
weight, length, width, height | string | no | Non-negative numeric strings. |
image_id, gallery_image_ids, category_ids, tag_ids, shipping_class_id | integer/array | no | Associated media and taxonomies. |
attributes | array | no | Name, options, visibility, and variation use. |
| Output field | Type |
|---|---|
product_id | integer |
type | string |
written | object |
verified | boolean |
Example: { "product_id": 120, "regular_price": "24.99", "stock_quantity": 50 }
wp-agent/get-woocommerce-store-settings
Purpose: Reads a bounded, secret-free snapshot of effective WooCommerce store configuration. It includes base country and state, currency and formatting, tax status, price and weight settings, dimension unit, stock management, guest checkout, account creation, HTTPS checkout, and the published shop, cart, checkout, and account pages. Credentials, payment-provider configuration, webhooks, email addresses, and raw options are never returned.
Capability: manage_woocommerce. Traits: read-only, non-destructive, idempotent. No parameters.
wp-agent/list-products
Purpose: Searches and filters products through WC_Product_Query and the official Product Data Store. Supports search, exact sku, status, type, page, and per_page up to 100. Returns complete product objects plus total and pages.
Capability: edit_products. Traits: read-only, non-destructive, idempotent.
wp-agent/preview-woocommerce-bulk-price-update
Purpose: Creates a confirmable preview for a bounded WooCommerce price operation across the products in one category or tag. selection contains only taxonomy with product_cat or product_tag, a positive term_id, and include_variations. operation permits an integer discount from 1 through 90 percent, a positive fixed sale price, or clearing the sale price. Products with scheduled sale windows fail closed.
The selection contains at most 50 independently priced products or variations. Product and variation queries stop at the 51st target before further objects are fully hydrated. The preview returns exact target IDs, previous and planned prices, related variable parent products, and a SHA-256 hash. That hash binds the subsite, WooCommerce version, currency and price formatting, selection, operation, target order, product state, and parent state.
Capability: edit_products. Traits: read-only, non-destructive, idempotent.
wp-agent/execute-woocommerce-bulk-price-update
Purpose: Executes only an unchanged bulk-price preview. Required fields are blog_id, the same selection and operation, the exact sorted item_ids list, preview_collection_hash, and confirm=true. Before writing, it revalidates the complete selection, target set, prices, term membership, parent state, and store context.
Every target has a separate short-lived lock, is read again immediately before its native WC_Product::save() mutation, and is read back afterward together with lookup state and, where applicable, the variable parent price. The global execution lease is renewed before and after every save. Lost ownership, an uncertain provider state, or divergent read-back returns recovery_required; prices already written are not automatically reverted, and foreign changes are never overwritten.
Capability: edit_products plus native edit_post permission for every target and variable parent product. Traits: write, non-destructive, not idempotent.
wp-agent/create-product
Purpose: Creates simple or variable products through WC_Product_Simple or WC_Product_Variable. type and name are required. Every product field accepted by update-product can be set directly. SKU collisions and invalid prices are rejected before saving, then the stored product is read back.
Capability: native product creation capability, plus publish_products when publishing. Traits: write, non-destructive, non-idempotent.
wp-agent/delete-product
Purpose: Moves a product conflict-protected and reversibly to the WordPress trash. force=true or permanent=true is rejected with HTTP 409 before any mutation. If the trash is disabled, WPAgently performs no remote deletion. Required are product_id, a fresh expected_state_hash, and confirm: true.
Capability: object-specific delete_post. Traits: write, reversible trash, not idempotent.
wp-agent/list-product-variations
Purpose: Lists every variation of a variable product through its native child IDs and WC_Product_Variation. Requires product_id.
Capability: object-specific edit_post on the parent product. Traits: read-only, non-destructive, idempotent.
wp-agent/upsert-product-variation
Purpose: Creates or updates a variation through WC_Product_Variation. Creation requires product_id and at least one variation attribute enabled on the parent. Supplying variation_id performs a partial update. Prices, SKU, stock, status, media, dimensions, and digital properties are stored natively. The parent, lookup data, and transients are synchronized afterward.
Capability: object-specific edit_post on the parent product. Traits: write, non-destructive, idempotent for updates.
wp-agent/delete-product-variation
Purpose: Moves a variation belonging to the supplied parent product conflict-protected and reversibly to the WordPress trash. force=true or permanent=true is rejected with HTTP 409 before any mutation. If the trash is disabled, WPAgently performs no remote deletion. Required are product_id, variation_id, a fresh expected_state_hash, and confirm: true. The variable product is synchronized afterward.
Capability: delete_post on the variation plus edit access to the parent. Traits: write, reversible trash, not idempotent.
wp-agent/list-product-attributes
Purpose: Lists all global WooCommerce product attributes freshly through wc_get_attribute_taxonomies(). Each result contains ID, name, slug, taxonomy name, type, ordering, archive status, dependent term count, and a complete SHA-256 state hash. Term counts for the whole list are loaded in one shared database query.
Capability: manage_product_terms. Traits: read-only, non-destructive, idempotent. Requires WooCommerce and its public attribute API.
wp-agent/get-product-attribute
Purpose: Reads exactly one global attribute definition by attribute_id and returns the same complete state as the list operation.
Capability: manage_product_terms. Traits: read-only, non-destructive, idempotent. An unknown ID returns HTTP 404.
wp-agent/upsert-product-attribute
Purpose: Creates or updates a global attribute definition exclusively through wc_create_attribute() or wc_update_attribute(). Creation requires name. slug, type, order_by, and has_archives are optional. An update requires attribute_id, expected_state_hash, and at least one changed field. Slugs may optionally start with pa_ and must contain no more than 28 characters after sanitization. Registered WooCommerce attribute types are validated at runtime.
Safety: The ability holds an atomic global short-lived lock, compares the fresh complete state including the dependent term count, reads the result back through WooCommerce, and verifiably rolls back any create or update that is not confirmed exactly. It also detects a partial failure where a WooCommerce hook aborts only after the database insert. Slug renames run through WooCommerce so product attributes, variation metadata, and the term ordering option are migrated natively.
Capability: manage_product_terms. Traits: write, destructive, non-idempotent. Updates are marked destructive because a rename changes catalog structure.
wp-agent/delete-product-attribute
Purpose: Checks the input for manually deleting a global WooCommerce attribute definition. The ability does not call wc_delete_attribute(), removes no attributes or terms, and returns HTTP 409 with manual_only before any mutation. Delete the attribute in WooCommerce.
Capability: manage_product_terms. Traits: manual-only, change it in WordPress, no remote mutation.
Product categories, product tags, and terms of global attributes are managed through the generic taxonomy abilities. Shipping classes are explicitly blocked there and use the specialized abilities below. These four attribute abilities manage WooCommerce's global attribute definitions themselves.
wp-agent/list-product-shipping-classes
Purpose: Lists WooCommerce shipping classes with pagination and no N+1 queries. Each result contains its ID, name, slug, plain-text description, product usage, and complete state hash.
Capability: manage_woocommerce. Traits: read-only, non-destructive, idempotent. Optional: search, page, per_page.
wp-agent/get-product-shipping-class
Purpose: Reads one shipping class with the same confirmed state and conflict hash. An unknown ID returns HTTP 404.
Capability: manage_woocommerce. Traits: read-only, non-destructive, idempotent. Required: shipping_class_id.
wp-agent/upsert-product-shipping-class
Purpose: Creates or updates a shipping class through the native WooCommerce taxonomy. Names, slugs, and plain-text descriptions are bounded; duplicate names or slugs are rejected. Updates require a fresh expected_state_hash. Provider permissions, an atomic lock, exact read-back, and the unambiguous new term ID protect the operation. If WooCommerce reports success but the state cannot be attributed exactly afterward, the ability returns recovery_required and performs no automatic delete or rewrite.
Capability: manage_woocommerce. Traits: write, marked destructive, non-idempotent. Creation requires name. An update requires shipping_class_id, expected_state_hash, and at least one mutable field. Remote deletion remains blocked because external WooCommerce writers do not share the same lock, so an orphaned product relationship cannot be ruled out without a race.
wp-agent/list-orders
Purpose: Lists WooCommerce orders through wc_get_orders() and the active WooCommerce data store. The practically verified path uses HPOS. Personal, address, payment, and line-item data is omitted by default. Each group appears only through its separate include_customer, include_payment, or include_items switch. Responses are limited to 100 orders and 200 line items per order.
Capability: read_private_shop_orders. Traits: read-only, non-destructive, idempotent. Optional: status, customer_id, the three include_* switches, page, and per_page. Output: orders, total, total_pages, page, per_page.
wp-agent/get-order
Purpose: Reads exactly one order through wc_get_order(). The compact default response contains status, timestamps, and totals, but no customer, address, payment, or line-item data. Those groups must be requested separately as for list-orders. Refund objects are not accepted as orders.
Capability: read_private_shop_orders. Traits: read-only, non-destructive, idempotent. Requires order_id. Optional: include_customer, include_payment, include_items.
wp-agent/list-order-notes
Purpose: Lists at most 100 WooCommerce order notes. type limits the response to all, internal, or customer. Notes may themselves contain personal communications and therefore belong to the separately gated order group.
Capability: read_private_shop_orders. Traits: read-only, non-destructive, idempotent. Requires order_id. Optional: type, limit.
wp-agent/set-order-status
Purpose: Sets a registered order status through the native WC_Order object and reads the order back. confirm: true is mandatory because a transition can trigger emails, stock movements, webhooks, and third-party automation. expected_date_modified rejects stale writes with HTTP 409. refunded and checkout-draft are blocked. A refund requires its own payment and amount operation and is never simulated by this ability.
Capability: edit_shop_orders. Traits: write, destructive, idempotent. Requires order_id, status, confirm. Optional: expected_date_modified. Output: freshly read order and verified.
wp-agent/add-order-note
Purpose: Adds a sanitized plain-text note through WC_Order::add_order_note() and reads it back. Customer-visible notes require confirm_customer_notification: true because WooCommerce may send an email. The required idempotency_key binds one payload to one order. Retries return the existing note, while a different payload under the same key is rejected with HTTP 409.
Capability: edit_shop_orders. Traits: write, destructive, idempotent. Requires order_id, note, idempotency_key. Optional: customer_note, confirm_customer_notification. Output: note, verified, reused.
Order permissions are never granted with ordinary WooCommerce catalog access or when an agent user is created. The connection page can explicitly add read_private_shop_orders and edit_shop_orders to a safe Editor. Disabling access or uninstalling WPAgently removes recorded additions only and preserves pre-existing grants. The complete orders group appears only in Full and Custom profiles. Read-only may expose the three read abilities, but the capability remains mandatory. The Content profile contains no order abilities. Order creation, line-item changes, refunds, and payment operations are not supported.
wp-agent/list-contact-forms
Purpose: Lists Contact Form 7 forms through WPCF7_ContactForm::find(). Supports search and pagination and returns each form's ID, immutable provider identifier, complete SHA-256 state hash, slug, title, locale, and embeddable shortcode.
Capability: wpcf7_read_contact_forms. Contact Form 7 grants this plugin capability to Editors by default.
Traits: read-only, non-destructive, idempotent. Optional parameters: search (string), page (integer, at least 1), per_page (integer, 1-100). Output: forms[], total, page, per_page.
wp-agent/get-contact-form
Purpose: Reads a Contact Form 7 form through its object API, never raw post meta. Returns the form-tag template, parsed fields, safe projections of both mail configurations, messages, shortcode, the complete SHA-256 state hash, and current results from the native WPCF7_ConfigValidator. Mail projections contain activation, subject, sender, recipient, plain-text body, one managed Reply-To, blank-field handling, and format. Attachment paths, arbitrary additional headers, and raw additional_settings are omitted. Boolean indicators report preserved but hidden advanced configuration.
Capability: wpcf7_read_contact_forms plus object-specific wpcf7_edit_contact_form.
Traits: read-only, non-destructive, idempotent. Required parameter: form_id (integer).
wp-agent/create-contact-form
Purpose: Creates a form with wpcf7_save_contact_form(). Without a custom template, Contact Form 7 supplies its locale-aware default. A custom template may contain only CF7 form tags and tightly allowlisted structural markup without scripts, inline styles, or raw form controls. For a custom template, WPAgently builds a valid default notification from the field tags that actually exist. Safe mail changes are limited to subject, sender, recipient, body, reply_to, exclude_blank, additionally active for the autoresponder, and switching to format: plain. Messages are plain text under known CF7 keys. The candidate passes the native configuration validator and a mail-tag allowlist before it is stored. An exact complete read-back is mandatory. A mismatch removes the incomplete form automatically.
Capability: wpcf7_edit_contact_forms.
Traits: write, non-destructive, non-idempotent. Required parameter: title. Optional: locale, form, mail, mail_2, messages. Raw additional_settings, attachments, arbitrary headers, and enabling HTML mail are not writable. Output: form and verified.
wp-agent/update-contact-form
Purpose: Updates only the safe properties accepted by create-contact-form. expected_hash binds the write to the complete previously read state. An atomically acquired short-lived lock prevents concurrent agent writes. Omitted and hidden provider data is preserved in full. Structural markup, mail tags, mailboxes, confirmation text, and the complete affected CF7 configuration are checked before persistence. After persistence, the complete logical state must exactly match the validated candidate. A save error, drift, or post-save validation error restores the complete previous state through the native object API and verifies that rollback again by SHA-256.
Capability: wpcf7_edit_contact_forms plus object-specific wpcf7_edit_contact_form.
Traits: write, non-destructive, idempotent. Required parameters: form_id, expected_hash. Optional properties match create-contact-form.
wp-agent/duplicate-contact-form
Purpose: Duplicates a form through WPCF7_ContactForm::copy() and save(). expected_hash and the same form-specific short-lived lock prevent copying a stale or concurrently changed state. The complete source must be valid before persistence. The copy receives a new ID and preserves every provider property. Its complete logical state is read back exactly. A divergent copy is deleted automatically.
Capability: wpcf7_edit_contact_forms plus object-specific wpcf7_edit_contact_form.
Traits: write, non-destructive, non-idempotent. Required parameters: form_id, expected_hash; optional title. Output: form and verified.
wp-agent/delete-contact-form
Purpose: Checks the input for manually deleting a Contact Form 7 form. The ability does not call delete() and returns HTTP 409 with manual_only before any mutation. The form remains unchanged and is deleted in the Contact Form 7 administration screen.
Capability: wpcf7_edit_contact_forms plus object-specific wpcf7_delete_contact_form.
Traits: manual-only, change it in WordPress, no remote mutation. Required parameters: form_id, expected_hash, confirm. Output: HTTP 409 with manual_only, without a change.
wp-agent/list-fluent-forms
Purpose: Lists Fluent Forms forms through the native FormService. Search, status, and pagination are bounded. The underlying Fluent Forms API path applies form-specific manager scopes. Unknown model, add-on, and form-meta data is omitted.
Capability: fluentform_dashboard_access. Traits: read-only, non-destructive, idempotent. Optional: search, status (published, unpublished, all), page, per_page (1-100).
wp-agent/get-fluent-form
Purpose: Reads a form through FormService::find(). The response allowlists only ID, title, status, type, payment flag, timestamps, shortcode, field count, and the complete field hash. Raw provider field structures remain internal. The native Fluent Forms ACL is checked with the concrete form ID.
Capability: fluentform_forms_manager plus form-specific Fluent Forms ACL. Traits: read-only, non-destructive, idempotent. Requires form_id.
wp-agent/create-fluent-form
Purpose: Creates the native blank template through FormService::store(), then applies the exact title, status, and optional submit label through the native updater. Fields are subsequently created only through the safe field ability. A fresh read-back is compared with the intended payload. A mismatched incomplete form is removed and that deletion is verified.
Capability: fluentform_forms_manager. Traits: write, non-destructive, non-idempotent. Requires title. Optional: status, submit_label. Output: form, verified.
wp-agent/update-fluent-form
Purpose: Checks a planned manual change to a Fluent Forms form's title, status, or submit label. The ability does not call FormService::update() and returns HTTP 409 with manual_only before any mutation. Make the change in Fluent Forms.
Capability: fluentform_forms_manager plus form-specific Fluent Forms ACL. Traits: manual-only, change it in WordPress, no remote mutation. Requires form_id. Optional: title, status, submit_label, expected_hash.
wp-agent/duplicate-fluent-form
Purpose: Duplicates a form through FormService::duplicate() so Fluent Forms also copies its metadata and files. An optional rename uses the native updater. ID, status, and fields are compared with the source. A faulty or unverifiable copy is removed and that deletion is checked.
Capability: fluentform_forms_manager plus form-specific Fluent Forms ACL. Traits: write, non-destructive, non-idempotent. Requires form_id; optional title.
wp-agent/delete-fluent-form
Purpose: Checks the input for manually deleting a Fluent Forms form. The ability does not call FormService::delete() and returns HTTP 409 with manual_only before any mutation. The form remains unchanged.
Capability: fluentform_forms_manager plus form-specific Fluent Forms ACL. Traits: manual-only, change it in WordPress, no remote mutation. Requires form_id, confirm.
wp-agent/get-fluent-form-fields
Purpose: Reads a form's compact, secret-free field structure. The response includes field keys, normalized types, safe settings, submit label, field count, the complete fields_hash, and a type catalog derived from provider components loaded on the actual installation. Text, email, textarea, number, select, multi-select, radio, checkbox, name, address, country, URL, and date are safely mapped. Phone, file, and image are available only when the concrete Fluent Forms installation provides their native components. Unknown add-on fields are represented as unsupported placeholders without raw settings.
Capability: fluentform_forms_manager plus form-specific Fluent Forms ACL. Traits: read-only, non-destructive, idempotent. Requires form_id. Output: form_id, fields, field_count, fields_hash, empty, submit_label, field_types.
wp-agent/upsert-fluent-form-field
Purpose: Checks a planned manual creation or change to a supported Fluent Forms field against the safe field template. The ability creates and changes no field and returns HTTP 409 with manual_only before any mutation. Make the field change in Fluent Forms.
Capability: fluentform_forms_manager plus form-specific Fluent Forms ACL. Traits: manual-only, change it in WordPress, no remote mutation. Requires form_id, field_key, expected_hash, field. Optional: after_field_key. Output: HTTP 409 with manual_only, without a change.
wp-agent/delete-fluent-form-field
Purpose: Checks the input for manually deleting a supported Fluent Forms field. The ability deletes no field and returns HTTP 409 with manual_only before any mutation. Unknown add-on fields remain outside this manual preparation path.
Capability: fluentform_forms_manager plus form-specific Fluent Forms ACL. Traits: manual-only, change it in WordPress, no remote mutation. Requires form_id, field_key, expected_hash, confirm. Optional: allow_empty_form. Output: HTTP 409 with manual_only, without a change.
wp-agent/get-fluent-form-delivery
Purpose: Reads the submission confirmation and compact email notifications through the native Fluent Forms SettingsService. By default, each notification contains only its ID, name, enabled state, recipient type, subject, and complete item hash. include_notification_details: true additionally returns the recipient address or form field, sender, reply-to address, BCC, message, and template key. Unknown add-on settings and secrets remain hidden in both views. confirmation_hash covers the complete raw general and advanced form settings. notifications_hash covers the complete raw notification records, including fields that are not returned. Compact and detailed responses use identical conflict hashes.
Capability: fluentform_forms_manager plus form-specific Fluent Forms ACL. Traits: read-only, non-destructive, idempotent. Requires form_id. Optional: include_notification_details, default false. Output: form_id, confirmation, confirmation_hash, notifications, notifications_hash, notification_details_included.
wp-agent/update-fluent-form-confirmation
Purpose: Checks a planned manual change to a Fluent Forms confirmation against the bounded safe values. The ability changes no message, behavior, or redirect destination and returns HTTP 409 with manual_only before any mutation. Make the change in Fluent Forms.
Capability: fluentform_forms_manager plus form-specific Fluent Forms ACL. Traits: manual-only, change it in WordPress, no remote mutation. Requires form_id, expected_hash, confirmation. Output: HTTP 409 with manual_only, without a change.
wp-agent/upsert-fluent-form-notification
Purpose: Checks a planned manual creation or change to a Fluent Forms email notification against the bounded safe values. The ability creates or updates no notification and returns HTTP 409 with manual_only before any mutation. Make the change in Fluent Forms.
Capability: fluentform_forms_manager plus form-specific Fluent Forms ACL. Traits: manual-only, change it in WordPress, no remote mutation. Requires form_id, expected_hash, notification; optional notification_id for an update. Output: HTTP 409 with manual_only, without a change.
wp-agent/delete-fluent-form-notification
Purpose: Checks the input for manually deleting a Fluent Forms email notification. The ability deletes no notification and returns HTTP 409 with manual_only before any mutation. The notification remains unchanged.
Capability: fluentform_forms_manager plus form-specific Fluent Forms ACL. Traits: manual-only, change it in WordPress, no remote mutation. Requires form_id, notification_id, expected_hash, confirm. Output: HTTP 409 with manual_only, without a change.
Fluent Forms does not grant these permissions to a regular Editor automatically. The connection page can add fluentform_dashboard_access and fluentform_forms_manager specifically to a safe agent user. Form-specific manager restrictions remain effective. Disabling access or uninstalling removes only recorded additions made by WPAgently and preserves preexisting user permissions.
wp-agent/list-fluent-entries
Purpose: Lists at most 100 entries for one concrete form through the native Fluent Forms Entry API. Search, status, and pagination are bounded. Field values remain hidden by default. IP address, browser data, payment data, transactions, and unknown metadata are omitted even when include_values: true is requested.
Capability: fluentform_entries_viewer plus form-specific Fluent Forms ACL. Traits: read-only, non-destructive, idempotent. Requires form_id. Optional: search, status, include_values, page, per_page.
wp-agent/get-fluent-entry
Purpose: Reads the field values of one entry through the native Fluent Forms Entry API. The response contains only allowlisted core properties and bounded form values. A SHA-256 version covers status, favorite state, response, and modification time.
Capability: fluentform_entries_viewer plus form-specific Fluent Forms ACL. Traits: read-only, non-destructive, idempotent. Requires entry_id.
wp-agent/set-fluent-entry-status
Purpose: Sets a status supported by the concrete form through the native Fluent Forms bulk service. expected_version can reject concurrent changes with HTTP 409. The entry is read back. An exception after mutation or a mismatched read-back triggers a verified rollback to the previous status.
Capability: fluentform_manage_entries plus form-specific Fluent Forms ACL. Traits: write, destructive, idempotent. Requires entry_id, status. Optional: expected_version.
wp-agent/set-fluent-entry-favorite
Purpose: Idempotently sets or removes the favorite marker through the native Fluent Forms bulk service. The result is read back. Exceptions after mutation and mismatched results are rolled back to the previous value, and that rollback is verified.
Capability: fluentform_manage_entries plus form-specific Fluent Forms ACL. Traits: write, non-destructive, idempotent. Requires entry_id, favorite. Optional: expected_version.
wp-agent/delete-fluent-entry
Purpose: Checks the input for manually deleting a Fluent Forms entry. The ability deletes neither the entry nor its associated data and returns HTTP 409 with manual_only before any mutation.
Capability: fluentform_manage_entries plus form-specific Fluent Forms ACL. Traits: manual-only, change it in WordPress, no remote mutation. Requires entry_id, confirm. Optional: expected_version.
Fluent Forms entry permissions are separate from form permissions because submissions may contain personal data. They are never granted automatically when an agent user is created. The entries group is fully exposed only by the Full and Custom profiles. The connection page can add fluentform_entries_viewer and fluentform_manage_entries explicitly and later removes only recorded additions.
wp-agent/list-kadence-forms
Purpose: Lists native kadence_form objects on Kadence Blocks Free 3.7.8 with bounded pagination. The output contains only ID, title, status, and modified time, never recipients, messages, or other delivery data.
Capability: edit_kadence_forms and edit_post for every result. Traits: read-only, non-destructive, idempotent. Optional: search, status, page, per_page (1-100).
wp-agent/get-kadence-form-settings
Purpose: Reads one native Kadence form, its bounded field types, and the safe subset of description, browser validation, local redirect, hide-after-submit, and compact email settings. The output flags unknown or advanced actions, headers, and provider states and binds the complete raw form state to a SHA-256 hash.
Capability: edit_kadence_forms and edit_post for the form. Traits: read-only, non-destructive, idempotent. Required: form_id.
wp-agent/update-kadence-form-settings
Purpose: Changes only description, browser validation, a root-relative or same-origin redirect, hide-after-submit, and a single email action with exactly one recipient. Unknown actions, duplicate actions, Pro, CC, BCC, headers, unsafe URLs, and non-canonical provider states remain blocked. A complete expected_hash, a renewable create-only lock, repeated capability and provider checks, and exact raw-state read-back protect the operation. After a started mutation that cannot be confirmed unambiguously, the ability returns recovery_required and performs no automatic follow-up mutation.
Capability: edit_kadence_forms and edit_post for the form. Traits: write, non-destructive, idempotent. Required: form_id, expected_hash, settings.
wp-agent/list-gravity-forms
Purpose: Lists Gravity Forms forms through GFAPI::get_forms(). Supports search, pagination, and the status filters active, inactive, trash, and all. It returns documented basic properties only, never unknown add-on settings.
Capability: gravityforms_edit_forms. Traits: read-only, non-destructive, idempotent. Optional: search, status, page, per_page (1-100).
wp-agent/get-gravity-form
Purpose: Reads a form through GFAPI::get_form() and returns documented core properties, fields, button, notifications, confirmations, and an allowlisted set of documented form settings. Unknown form-level add-on data is deliberately omitted because it may contain credentials.
Capability: gravityforms_edit_forms. Traits: read-only, non-destructive, idempotent. Requires form_id.
wp-agent/create-gravity-form
Purpose: Creates a form through GFAPI::add_form() and reads it back through the public GFAPI. Supports title, description, up to 500 fields, up to 200 notifications and confirmations, and an allowlist of documented settings. Unknown form-level settings are rejected.
Capability: gravityforms_create_form. Traits: write, non-destructive, non-idempotent. Requires title. Output: form, verified.
wp-agent/update-gravity-form
Purpose: Checks a planned manual change to a Gravity Forms form. The ability does not call GFAPI::update_form() and returns HTTP 409 with manual_only before any mutation. Make the change in Gravity Forms.
Capability: gravityforms_edit_forms. Traits: manual-only, change it in WordPress, no remote mutation.
wp-agent/duplicate-gravity-form
Purpose: Duplicates a form through GFAPI::duplicate_form(). An optional title is set through GFAPI::update_form_property(). If renaming fails, the incomplete copy is deleted. Fields and optional title are verified by read-back.
Capability: gravityforms_create_form and gravityforms_edit_forms. Traits: write, non-destructive, non-idempotent. Requires form_id; optional title.
wp-agent/delete-gravity-form
Purpose: Checks the input for manually deleting a Gravity Forms form. The ability does not call GFAPI::delete_form() and returns HTTP 409 with manual_only before any mutation.
Capability: gravityforms_delete_forms. Traits: manual-only, change it in WordPress, no remote mutation.
Gravity Forms does not grant these three form capabilities to a regular Editor automatically. The connection page can add them specifically to a safe agent user. Removing access or uninstalling the plugin removes only capabilities that WPAgently itself added and recorded. Existing role or user grants are preserved.
Formidable Forms
The six abilities list-formidable-forms, get-formidable-form, create-formidable-form, update-formidable-form, duplicate-formidable-form, and delete-formidable-form use only the native model methods provided by FrmForm and FrmField. Lists are bounded to 100 results per page and 5,000 forms in total. Read responses contain only explicitly allowlisted form and field properties. Unknown add-on options are not exposed. Default values of existing password and hidden fields are redacted and cannot be changed.
New fields are limited to the portable types text, email, url, phone, number, textarea, checkbox, radio, and select. Descriptions and values are treated as plain text. Each form is limited to 500 fields and each field to 500 choices. Text lengths and nested default values are bounded as well. Larger existing forms are rejected with HTTP 413 instead of producing an unbounded MCP response. Creates, updates, and duplicates are read back and verified. Partial updates preserve omitted form values and unknown internal field options. When Formidable has already returned a form ID for an unverifiable creation or copy, the form and any submissions made by another actor in the meantime are preserved. The ability then returns HTTP 409 wpagent_formidable_recovery_required, recovery_required: true, and the non-sensitive form_id; review the current state manually. If native FrmForm::create() or FrmForm::duplicate() stops after a stored creation or copy but before it returns the ID, the ability returns HTTP 409 wpagent_formidable_recovery_required, recovery_required: true, and no form_id, because it has no safe locator. A failed form allocation contains no form ID and returns HTTP 500 wpagent_formidable_create_failed, rather than a recovery response. An unverifiable partial update also triggers no automatic follow-up mutation. Duplication may legitimately rewrite field IDs assigned by Formidable. wp-agent/delete-formidable-form is manual-only: it deletes no form, fields, or entries and returns HTTP 409 with manual_only before any mutation. Delete the form in Formidable Forms. expected_form_key can reject a concurrently replaced record with HTTP 409.
Reads require frm_view_forms, writes require frm_edit_forms, and deletion requires frm_delete_forms. The connection page can grant these three capabilities specifically to a safe agent user and later removes only additions recorded by WPAgently. The mutation lock expires and can be released only by its owner.
Form migration between six form providers
wp-agent/preview-form-migration supports WPForms, Ninja Forms, Contact Form 7, Fluent Forms, Gravity Forms, and Formidable Forms. It reads an existing form through its provider's permission-checked native path and converts the portable field structure into the versioned wpagently-portable-form format. For WPForms, the native response is internally supplemented with the stored field properties required for reliable structure verification. Contact Form 7 is read through its public object and form-tag APIs. Portable field types are text, email, textarea, number, checkbox, radio, and select. Title, field order, type, label, help text, placeholder, default value, required state, and choices are preserved. The submit label is preserved as well unless Formidable Forms is either the source or the target. Its bounded safe adapter does not expose that property. portable_submit_label: false and omitted: ["submit_label"] report the limitation.
Complex name fields, phone fields, HTML, layout, and proprietary special fields, as well as values requiring truncation or sanitization, appear in unsupported_fields. The same applies to non-portable field semantics such as calculations, input masks, ranges, multiple selection, separate choice values, choice images, or conditional logic. portable_fields_lossless is then false. Preview performs no writes and is bounded to 200 source fields and 200 choices per field.
wp-agent/migrate-form additionally requires confirm: true and rejects every portable field structure that the target cannot represent in full with HTTP 409. It creates only a new structure copy in one of the other five providers. It then reads the target back in full and compares every portable property. A mismatch deletes the target copy and fails visibly. If deletion also fails, the ability returns wpagent_form_migration_rollback_failed and requests a manual check. The source form is neither changed nor deleted. Contact Form 7 receives newly generated accessible markup. Checkbox and radio groups use a valid fieldset with legend, preventing CF7 from placing multiple controls inside one label. Each CF7 source field needs an unambiguous associated label. Duplicate field names, more than 200 choices, a missing, empty, or repeated submit control, and values that cannot be represented safely in a form tag all block the preview. Its radio fields are always required. A simultaneous placeholder plus default value cannot be migrated either. Notifications, confirmations, conditional logic, original markup and layout, provider-specific form settings, and existing entries are deliberately not copied. target_behavior: provider_defaults and omitted[] report this in machine-readable form. A new CF7 target receives a validated default notification built from its actually generated field tags. Other targets use their provider defaults. Every target must be reviewed before production use.
WPForms Lite, Ninja Forms, Contact Form 7, Fluent Forms, and Formidable Forms have been practically verified against real installed plugins. Fluent Forms, Gravity Forms, and Formidable Forms also have complete read, target, read-back, and rollback contract tests. The bidirectional Fluent Forms mapping is tested against a real Ninja Forms installation. Fluent Forms 6.2.11 and Formidable Forms 6.33.1 additionally pass a real portable create, read-back, and delete cycle. Practical migration testing with the licensed original Gravity Forms plugin remains outstanding.
Preview requires the corresponding WPAgently read permission for the source provider. Migration additionally requires both read and write permission for the target provider because the new target must be read back in full. If either permission is missing, the request fails before any write. WPForms' own MCP write opt-in and Ninja Forms quarantine remain effective. Traits: preview is read-only and idempotent; migration is write, non-destructive to the source, and non-idempotent.
Weglot
wp-agent/get-weglot-settings reads the active Weglot version, connection state, original and destination languages, automatic language redirection, bounded language-switcher presentation settings, and URL and CSS-selector exclusions. Private and public API keys, custom CSS, translation content, and unknown provider options are never returned. Existing regular expressions in URL exclusions are visible and included in the state hash, but cannot be created or changed through WPAgently because of their runtime risk.
wp-agent/update-weglot-settings checks the service connection and otherwise returns HTTP 409 with manual_only before any mutation. It changes no Weglot setting. The key must already be configured in Weglot itself. Configure languages, switcher presentation, URL exclusions, and CSS selectors in Weglot, then read the safe project state again.
Both abilities require manage_options. Traits: read is idempotent. wp-agent/update-weglot-settings is manual-only, no remote mutation.
Astra
wp-agent/get-astra-design detects an active Astra theme or Astra child theme and reads 21 curated areas through Astra's native WordPress abilities. They cover the container, body and heading typography, H1 through H6, paragraph spacing, link underlines, the global palette, background colours, buttons, the blog archive, single posts, single pages, the sidebar, scroll to top, and Header and Footer Builder layouts. For each available area, the response contains the current provider state and strict input schema, plus a SHA-256 hash over astra-settings, astra-color-palettes, and the active theme identity. Raw options are not returned. If Astra is inactive or its read and edit abilities are disabled, the operations list remains empty.
wp-agent/update-astra-design requires expected_hash, exactly one of the 21 operations, and a non-empty settings object. Font names, responsive font sizes, line height, letter spacing, colours, container values, button presets, content widths, and Header or Footer zones are validated more narrowly than Astra's provider contract. The palette uses nine named roles instead of error-prone numeric JSON keys. Header and Footer layouts accept only documented components in known responsive zones, bound list sizes, and reject duplicates. Every submitted zone list is the complete desired final state of that zone, not a partial list to append. Background images, arbitrary CSS values, button spacing, logo downloads, local font files, and performance switches remain outside this global path. Individual post metadata uses the separate post-specific contract below. Every global write locks the complete Astra state for five minutes, checks the hash again after acquiring the lock, writes through Astra's implementation, and forces the matching native read ability through an uncached read-back. Only an exact semantic confirmation succeeds. Provider failures or mismatches restore both astra-settings and astra-color-palettes and verify the complete hash. A rollback that cannot be verified fails with HTTP 500 and requests immediate manual inspection.
wp-agent/get-astra-post-design reads 16 normalised Astra overrides for a specific post_id. They cover content and sidebar layout, content and sidebar style, global, above, primary, below, and mobile headers, the footer, title, banner, breadcrumbs, featured image, related posts, and transparent header. inherit means that no post-specific value is stored and Astra's global setting applies. Raw post metadata and unrelated metadata are not exposed. The state hash binds the theme identity, post ID, post type, existence and exact value of every permitted provider field, and Astra's internal layout migration flag.
wp-agent/update-astra-post-design requires the same post_id, a fresh expected_hash, and at least one strictly typed override. Partial updates change only named fields. inherit deletes only that individual override. Modern layout values maintain Astra's migration flag according to the layout overrides that actually remain. The write shares the global Astra short-lived lock, reads every permitted metadata field back after persistence, and confirms every requested end value. A failure or read-back mismatch restores the existence and exact value of all permitted fields, including the migration flag, and verifies the complete previous state. Unrelated post metadata remains untouched.
The two global abilities require manage_options. The two post-specific abilities broadly require edit_posts and additionally check WordPress' concrete edit_post meta-capability for the target on every call. All four belong to the Design exposure group. Astra itself needs Abilities and Edit Abilities enabled under Astra > Dashboard > Settings only for the two global paths. A regular WPAgently Editor does not gain administrator capabilities. Traits: both reads are idempotent. Both updates are write, non-destructive, and idempotent.
GeneratePress
wp-agent/get-generatepress-design detects GeneratePress or an active GeneratePress child theme and reads five curated areas from the theme's native settings state: layout, global colours, surface colours, buttons, and typography. The response contains the active theme version, the bounded sections, and a SHA-256 hash over the complete stored generate_settings value plus the parent and child theme identities. Raw options and unknown provider data are not exposed. When the theme is inactive, the safe section set remains empty. Missing GeneratePress runtime functions fail closed.
wp-agent/update-generatepress-design requires expected_hash, exactly one section, and a non-empty settings object. It permits bounded layout values, existing global-colour slugs, twelve selected surface colours, four button colours, and the typography targets body, h1, h2, h3, and buttons. Arbitrary CSS, new palette entries, arbitrary selectors, font files, GeneratePress Premium Elements, unknown theme options, and uncontrolled values remain outside this path. Every write locks the complete settings state for five minutes, checks the conflict hash inside the lock, preserves unknown provider data, and rebuilds GeneratePress's native dynamic CSS cache. Both the saved section and CSS cache must exactly confirm the expected state. A provider failure or mismatch restores and verifies the complete previous settings value and both GeneratePress cache options.
Both abilities require manage_options and belong to the Design exposure group. GeneratePress 3.6.1 is locally covered by real layout, colour, typography, lock, conflict, CSS-cache, and rollback tests. The prepared GitHub Actions fixture installs the current WordPress.org release and will run for the first time after commit and push. Traits: read is idempotent. Update is write, non-destructive, and idempotent.
wp-agent/get-generatepress-post-design reads four native overrides for a public post or page: sidebar layout, footer-widget count, content container, and title visibility. inherit means no effective individual value is stored. The state hash binds the post ID, post type, parent and child theme, and the existence and exact raw value of all four metadata fields. Missing and officially empty defaults both normalize to inheritance while remaining distinguishable for conflict detection and rollback. Duplicate single-value rows and unknown provider values fail closed.
wp-agent/update-generatepress-post-design requires post_id, a fresh expected_hash, and at least one change. Partial updates change only named fields. inherit removes only the selected override. The write checks the concrete edit_post capability, locks only the target post, compares the complete raw state inside the lock, and additionally confirms explicit values through GeneratePress's real runtime functions. Persistence failures or mismatches restore the exact previous representation, including stored empty defaults, and verify its hash. The configured posts page remains blocked because GeneratePress enforces the global blog layout there and individual page values would be ineffective. Attachments, revisions, autosaves, non-public post types, and Premium Elements remain outside this contract. Both abilities belong to the Design exposure group. Traits: read is idempotent. Update is write, non-destructive, and idempotent.
OceanWP
wp-agent/get-oceanwp-design detects OceanWP or an active OceanWP child theme from version 4.1 and reads five curated areas from native theme mods: layout, global colours, responsive typography, buttons, and header style. Typography covers body text and global headings with desktop, tablet, and mobile values. The response includes the active theme version and a SHA-256 hash over the complete theme-mod option plus parent and child theme identity. Raw options and unknown provider data are not exposed. Invalid known provider values fail closed.
wp-agent/update-oceanwp-design requires expected_hash, exactly one section, and a non-empty settings object. It permits documented layouts, container width and unit, six global colour roles, four button colours, seven built-in header styles, and bounded responsive typography. Custom headers, arbitrary CSS, font files, Ocean Extra modules, and unknown theme options remain outside this safe path. Every write locks the complete theme-mod option for five minutes, checks the hash inside the lock, preserves unknown provider data, and confirms the stored section with a fresh read-back. Provider failures or mismatches restore the complete previous option and verify its hash.
Both abilities require manage_options and belong to the Design exposure group. Writes are available only in OceanWP's head mode for Customizer CSS. The free theme has no reliably callable regeneration path for file mode, so a write stops before mutation with HTTP 409 and migration guidance. OceanWP 4.2.2 is locally covered by real layout, colour, typography, header, lock, conflict, persistence, and rollback tests. The public GitHub Actions fixture installs the current WordPress.org release. Traits: read is idempotent. Update is write, non-destructive, and idempotent.
wp-agent/get-oceanwp-post-design reads the native ocean_post_layout and ocean_both_sidebars_style overrides for a public post or page. The normalized response uses inherit when Ocean Extra stored its official empty default or when the meta row is absent. It also returns the post type and a SHA-256 conflict hash over the post, parent and child theme identity, and exact allowed raw meta state. Duplicate single-value rows and unknown provider values fail closed.
wp-agent/update-oceanwp-post-design requires post_id, expected_hash, and at least one change. layout permits inherit, a right or left sidebar, full width, full-screen width, or both sidebars. both_sidebars_style permits inherit and OceanWP's three native orders. The write checks edit_post, locks only the target post, compares the complete raw state inside the lock, preserves untouched metadata, and additionally verifies explicit values through OceanWP's runtime functions. Persistence failures or mismatches restore the exact previous representation, including a stored empty default, and verify its hash. Attachments, revisions, autosaves, non-public post types, and other Ocean Extra areas remain outside this contract. Both abilities belong to the Design exposure group. Traits: read is idempotent. Update is write, non-destructive, and idempotent.
wp-agent/get-oceanwp-post-title and wp-agent/update-oceanwp-post-title are two additional, version-bound Ocean Extra abilities for individual page-title overrides. They are available only while OceanWP 4.2.2 and Ocean Extra 2.5.8 are active. Read returns the normalized page-header, heading, style, custom-title, and subheading values with a state hash. Write requires post_id, expected_hash, and at least one narrowly validated setting. Only documented selection values and bounded text overrides are allowed. Other Ocean Extra modules, headers, and raw metadata remain excluded. Once an Ocean mutation has started, an unsafe persistence, read-back, or runtime check fails closed with recovery_required. There is then neither an automatic rollback nor an automatic follow-up mutation. Inspect the current state manually.
wp-agent/get-oceanwp-post-layout-overrides and wp-agent/update-oceanwp-post-layout-overrides add a separate layout path that is likewise bound exactly to OceanWP 4.2.2 and Ocean Extra 2.5.8. Read returns only normalized header visibility and style, footer widgets and bottom area, an active registered custom sidebar, and content width with a state hash. Write requires post_id, expected_hash, and at least one bounded setting. Individual content width is permitted only with the native both-sidebars post layout. CSS, HTML, file paths, unregistered sidebars, and every other provider field remain excluded.
The write revalidates the post, subsite, provider, permission, and selected provider values after acquiring the lock. It renews the post-bound lock immediately before mutation and after provider and runtime read-back. Divergent or unsafe-to-read state after mutation starts returns only recovery_required; there is no automatic follow-up mutation and no claim of a complete rollback.
wp-agent/get-oceanwp-extra-modules and wp-agent/update-oceanwp-extra-module read or change exactly one of five module switches verified against Ocean Extra 2.5.8. My Library, the demo catalogue, and admin notifications are readable and writable. SVG uploads and the front-end style editor can only be disabled. The state hash binds the subsite, theme and plugin versions, and all five raw options. Write requires manage_options, a create-only lock, a fresh hash, and exact full-state read-back. Ambiguity after mutation returns recovery_required without an automatic rollback. Changes take effect on a new WordPress request because Ocean Extra loads modules during bootstrap.
wp-agent/list-oceanwp-library-templates lists at most 100 published, passwordless My Library templates per page. Only static, shortcode-free Core blocks without Elementor, SiteOrigin, or Beaver Builder state are accepted. Each result includes a content hash and block types. wp-agent/get-oceanwp-post-library-templates reads the native header and footer assignments of an editable post. wp-agent/update-oceanwp-post-library-templates requires the post hash and the fresh content hash of every newly selected template. Write locks the target post, rechecks provider, permission, raw metadata, and templates, changes only ocean_header_style, ocean_custom_header_template, and ocean_custom_footer_template, and verifies OceanWP's native runtime functions. Any mismatch after mutation starts returns recovery_required without an automatic follow-up mutation.
Kadence
wp-agent/get-kadence-design detects Kadence or an active Kadence child theme from version 1.5 and reads six curated areas from native provider state: content widths, all 15 colours in the active global palette, global surface and link colours, responsive typography for body text and H1-H6, global buttons, and placements of free desktop and mobile Header Builder components. The response includes the active theme version and a SHA-256 hash over the settings storage actually used by Kadence, kadence_global_palette, and the parent and child theme identities. In the normal theme-mod mode, the settings storage is theme_mods_<stylesheet>. A different option mode is accepted only when the Kadence runtime reports the exact expected option name. Raw options and unknown provider data are not exposed. Invalid known provider values fail closed.
wp-agent/update-kadence-design requires expected_hash, exactly one section, and a non-empty settings object. It permits bounded content widths, switching between the three existing palettes, individual colours in the active palette, four global colour roles, font family, Google-font flag, weight, responsive size and line height, plus button colours and responsive radii. In the header section, exactly one approved Kadence Free component can be moved, inserted, or removed in a native desktop or mobile zone. Positions, components, rows, zones, total count, and uniqueness are validated strictly. Arbitrary CSS, new palette entries, font files, unknown theme options, and Kadence Pro settings remain outside this safe path. Kadence Forms use the separate contract documented above.
Every write locks both provider states together for five minutes, refreshes the lock before and after mutation, rechecks permission, runtime, and the conflict hash inside the lock, preserves unknown provider data, and confirms the stored section through an exact read-back. The write itself is a byte-exact compare-and-swap over the raw value and autoload attribute. A third-party change in the final write window is therefore retained and returns HTTP 409 without a WPAgently mutation. A rollback changes only the option row written by this request and only while it still matches the expected write byte for byte. Third-party changes, lock loss, or uncertain state are retained and return recovery_required. The test additionally confirms the Header Builder result through Kadence's real render function.
Both abilities require manage_options and belong to the Design exposure group. Kadence 1.5.2 is locally covered by real layout, palette, colour, typography, button, Header Builder, lock, conflict, expiry, concurrent-change, persistence, rendering, and atomic CAS write and rollback tests. The public GitHub Actions fixture installs the current WordPress.org release. Traits: read is idempotent. Update is write, non-destructive, and idempotent.
wp-agent/list-gravity-entries
Purpose: Lists at most 100 entries for one form through GFAPI::get_entries(). Status, full-text search, calendar range, and pagination are bounded. Field values, IP address, user agent, and payment data remain hidden by default and are returned only with include_values: true.
Capability: gravityforms_view_entries. Traits: read-only, non-destructive, idempotent. Requires form_id. Optional: status, search, start_date, end_date, include_values, page, per_page.
wp-agent/get-gravity-entry
Purpose: Reads one entry through GFAPI::get_entry(). The response contains documented core properties, values for field and input IDs that actually exist in the current form, and documented payment fields. All unknown add-on metadata is deliberately omitted because it may contain credentials.
Capability: gravityforms_view_entries. Traits: read-only, non-destructive, idempotent. Requires entry_id.
wp-agent/update-gravity-entry
Purpose: Updates read state, starred state, and up to 100 existing numeric field or input IDs through GFAPI::update_entry_property() and GFAPI::update_entry_field(). expected_date_updated can reject concurrent changes. Partial failures and failed read-backs trigger a best-effort rollback.
Capability: gravityforms_edit_entries. Traits: write, non-destructive, idempotent. Requires entry_id and at least one of is_read, is_starred, or field_updates.
wp-agent/set-gravity-entry-status
Purpose: Sets an entry to active, spam, or trash, reads it back, and rolls back a status change that cannot be verified. Optional expected_date_updated rejects a stale write with HTTP 409.
Capability: gravityforms_edit_entries. Traits: write, destructive, idempotent. Requires entry_id, status.
wp-agent/delete-gravity-entry
Purpose: Checks the input for manually deleting a Gravity Forms entry. The ability does not call GFAPI::delete_entry() and returns HTTP 409 with manual_only before any mutation.
Capability: gravityforms_delete_entries. Traits: manual-only, change it in WordPress, no remote mutation.
Entry permissions are fully separated from form permissions because entries can contain personal and payment data. They are never granted automatically when an agent user is created. The entries group is fully exposed only by the Full and Custom profiles. The Read-only profile may expose the two read tools, but the Gravity Forms capability is always required as an additional check. The connection page can add the three entry capabilities explicitly and later removes only recorded additions.
wp-agent/refresh-builder-cache
Purpose: Detects a post's builder signals (reuses detect-builder) and triggers the builder-specific cache/regeneration invalidations, so the frontend doesn't stay stuck on stale output. Empirically checked against the actually installed plugin versions (not merely taken from documentation): Spectra 2.20.1 (__uagb_asset_version option plus _uag_page_assets meta deletion, equivalent to wp spectra regenerate-css), GenerateBlocks 2.3.0 (GenerateBlocks_Enqueue_CSS::post_update_option()), WooCommerce 10.9.4 (wc_delete_product_transients()). Kadence 3.7.8 and WPBakery are self-healing on render, no action needed. Elementor, Breakdance, and Oxygen: best-effort via known in-request APIs, if the classes/functions are loaded; no WP-CLI shell-out from within the REST request. Bricks is not included in the cache map in the underlying blueprint, so no action is claimed for it.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id) (via reuse of detect-builder).
Traits: write, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
| Output field | Type |
|---|---|
primary | string |
actions[] | Objects with builder, action, executed, verified |
notes[] | string[] |
Example: { "post_id": 42 }
wp-agent/get-builder-compatibility
Purpose: Returns a machine-readable matrix for Gutenberg, Spectra One, Kadence, Spectra, GenerateBlocks, Elementor, Beaver Builder, Bricks, Breakdance, Oxygen, and WPBakery. Each entry reports active status, version, storage, native write support, cache coverage, and practical, practical-read, or defensive validation. Proprietary builders without a stable public write interface are explicitly listed under fail_closed.
Capability: edit_posts.
Traits: read, non-destructive, idempotent. The ability changes no builder data.
Output: builders[] contains the entries. summary.native_write[] lists natively supported data surfaces and summary.fail_closed[] lists deliberately rejected write paths. Spectra One uses the native WordPress Global Styles and Site Editor surfaces. Kadence Blocks, Spectra, and GenerateBlocks are practically readable but remain closed to raw block-markup writes.
wp-agent/get-elementor-document
Purpose: Reads an existing Elementor document through Elementor's public document API. The response contains the normalized element tree and stored page settings, each in the closed {json,sha256,bytes} builder-document envelope, together with an element and widget summary, Elementor version, edit URL, and a canonical SHA-256 conflict hash covering structure and settings.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id) and Elementor's own is_editable_by_current_user() check.
Traits: read, non-destructive, idempotent. Without active Elementor or for a post that was not built with Elementor, the ability fails closed with HTTP 409.
Required: post_id. Output: post_id, built_with_elementor, elements and settings as builder-document envelopes, element_count, widget_types[], elementor_version, edit_url, hash.
wp-agent/get-elementor-design-system
Purpose: Reads Elementor's active global kit through its native kit API. The response contains the four system colors, custom colors, four system typography tokens, custom typography, responsive sizes and spacing, fallback font, Elementor version, kit ID, and a canonical SHA-256 conflict hash over the complete semantic design state.
Capability: manage_options plus Elementor's own kit editability check.
Traits: read, non-destructive, idempotent. The ability fails closed without an active editable Elementor kit. Custom colors and typography are each limited to 100 tokens. Color values, IDs, titles, and typography values are validated during reads as well.
wp-agent/update-elementor-design-system
Purpose: Checks a planned manual change to previously read Elementor design areas against bounded safe values. The ability saves no kit and returns HTTP 409 with manual_only before any mutation. Make the change in Elementor.
Capability: manage_options plus Elementor's own kit editability check.
Traits: manual-only, change it in WordPress, no remote mutation. At least one design area is required in addition to expected_hash. Read the complete state again after the manual change.
wp-agent/get-elementor-global-classes
Purpose: Reads the complete Global Class state of Elementor v4 Atomic Elements. The path exposes no raw CSS rules. It returns the classes managed by the active kit, their native variants, available breakpoints, and a canonical SHA-256 conflict hash for the complete state.
Capability: manage_options plus Elementor's own Global Class capability.
Traits: read, non-destructive, idempotent. Its input is exclusively an empty object. The ability fails closed unless Elementor v4 with Atomic Elements is active. It processes at most 1,000 Global Classes.
Output: kit_id, elementor_version, breakpoints[], classes[], total, hash.
wp-agent/create-elementor-global-class
Purpose: Creates a new Elementor v4 Global Class through the native Atomic Elements contract. The class receives a safe CSS class label and one or more validated variants, never an open CSS or raw-data surface.
Capability: manage_options plus Elementor's own Global Class capability.
Traits: write, non-destructive, non-idempotent. Required are expected_hash, a label of 2 to 50 safe CSS-class characters, and variants with 1 to 64 entries. Every variant permits only breakpoint and state in meta and requires a non-empty props object with at most 100 entries. Active breakpoints and Elementor's native schema validate every value. A lock, compare-and-swap, revision, full read-back, frontend check, and automatic rollback protect the write path.
Output: the complete Global Class state plus class, previous_hash, changed, verified, rolled_back.
wp-agent/update-elementor-global-class
Purpose: Changes only the label and/or variants of an existing Elementor v4 Global Class. Unrelated classes and open raw-CSS paths remain untouched or closed.
Capability: manage_options plus Elementor's own Global Class capability.
Traits: write, non-destructive, idempotent for an unchanged target state. Required are expected_hash and class_id. label and variants are optional, but at least one must be present. The same label, variant, meta, and props bounds apply as on creation. Lock, compare-and-swap, revision, read-back, frontend check, and rollback also protect this update.
Output: the complete Global Class state plus class, previous_hash, changed, verified, rolled_back.
wp-agent/delete-elementor-global-class
Purpose: Checks the input for manually deleting an Elementor v4 Global Class. The ability deletes no class and returns HTTP 409 with manual_only before any mutation. The class and its document uses remain unchanged.
Capability: manage_options plus Elementor's own Global Class capability.
Traits: manual-only, change it in WordPress, no remote mutation. Required are expected_hash, class_id, confirm=true, and affected_post_ids as the exact current list of at most 100 IDs. The ability fails closed unless that list matches current usage.
Output: HTTP 409 with manual_only, without a change.
wp-agent/set-elementor-element-global-classes
Purpose: Sets the Global Class assignment of one Elementor element through its v4 Atomic Elements interface. The path accepts only known Global Class IDs and offers no raw-CSS substitute.
Capability: manage_options plus Elementor's own Global Class capability.
Traits: write, non-destructive, idempotent. Required are post_id, element_id, the document expected_hash, and global_class_ids as a unique list of at most 100 IDs. The target must belong to an Elementor v4 Atomic Elements document. Native schema and breakpoint validation, a lock, compare-and-swap, revision, full read-back, frontend check, and rollback protect the assignment.
Output: the normal Elementor element write state plus global_class_ids.
wp-agent/list-elementor-widgets
Purpose: Lists widget types from the active Elementor installation's registry with search, category filtering, and pagination. Raw HTML and shortcode widgets, as well as every legacy adapter prefixed with wp-widget-, remain excluded. Titles, categories, and keywords are sanitized and bounded. Faulty third-party widgets are skipped instead of breaking the entire registry request.
Capability: edit_posts.
Traits: read, non-destructive, idempotent. Optional: search, category, page, per_page (maximum 200). Output: widgets[], total, page, per_page, total_pages, elementor_version. Each widget reports its total number of writable controls as controls_count and whether its schema is capped by the 500-control limit as controls_truncated.
wp-agent/get-elementor-widget-schema
Purpose: Reads the writable value controls of a safe widget type directly from the active Elementor registry. Elementor 4 stores optimized style controls separately from ordinary controls. The read path merges both public registry areas instead of silently omitting colors and typography. Structural UI controls such as sections, tabs, headings, and buttons are not exposed as writable. Each control includes its name, type, label, tab, section, style, responsive and dynamic state, active devices, registered value type, a bounded JSON default, and at most 200 options. The output is limited to 500 controls. controls_count gives the number returned, controls_total the complete count, and controls_truncated indicates any truncation.
Capability: edit_posts.
Traits: read, non-destructive, idempotent. Required: widget_type. Unsafe and unknown widget types fail closed.
wp-agent/get-elementor-element
Purpose: Reads exactly one element by element_id from an existing Elementor document. The response includes its exact index path, the element in the closed {json,sha256,bytes} builder-document envelope, and the complete document's conflict hash. Lookup is bounded to 2,000 elements and 64 levels and rejects duplicate IDs.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id) and Elementor's own is_editable_by_current_user() check.
Traits: read, non-destructive, idempotent. Required: post_id, element_id. Output: post_id, element_id, path[], element, document_hash, elementor_version.
wp-agent/create-elementor-page
Purpose: Creates a new Elementor post through Document::save(). Every element must have a unique ID, an element or widget type registered in the active installation, JSON-compatible settings, and a child list. Raw HTML, shortcode, and unfiltered legacy widgets, as well as executable markup, remain blocked. The path is bounded to 2 MiB, 2,000 elements, and 64 levels. After saving, the Elementor-normalized structure, requested page settings, post status, and frontend output are checked again. A mismatch removes the new post.
Capability: edit_posts (coarse), the post type's concrete create_posts capability, and WordPress's required publish capability when publishing.
Traits: write, non-destructive, non-idempotent. Required: title, elements. Optional: post_type (default page), status (draft, pending, private, publish; default draft), settings.
wp-agent/update-elementor-document
Purpose: Replaces the complete Elementor structure and/or a subset of page settings through Document::save(). An explicitly empty settings object deletes stored page settings through Elementor's public settings API. expected_hash must match the last state read. An atomic short-lived lock serializes concurrent WPAgently writes. An Elementor-compatible WordPress revision is created and verified against the expected state before saving. Unknown, unsafe, or unregistered element and widget types, executable markup, duplicate IDs, oversized data, and excessive nesting are rejected before any write. The structure and requested settings are then read back, and frontend output is generated. Save, read-back, or render failures automatically restore structure and settings from the revision.
Capability: edit_posts (coarse) plus edit_post and Elementor's own editability check.
Traits: write, non-destructive, idempotent for the same conflict hash and input. Required: post_id, expected_hash, plus at least one of elements or settings. Output matches the read path and adds verified, frontend_verified, previous_hash, and the restorable revision_id.
wp-agent/update-elementor-element
Purpose: Changes or removes only registered value controls on one element without replacing sibling structure. style_patch adds a safe device-aware path for registered styles. Each style is keyed by its control name and Elementor's active desktop, tablet, or mobile device. null removes that device value. The path supports strictly validated colors, sliders, dimensions, numbers, selects, choices, and switchers with bounded CSS units and keywords. Media, URLs, free-form font values, shadow objects, and other CSS-adjacent raw structures remain closed. Responsive suffixes and required group activation values are derived only from Elementor's public control and breakpoint registries. expected_hash protects the complete document from stale writes. Before writing, the ability checks document permission, target ID, widget safety, the control registry, JSON values, markup, size, and structure. A short-lived lock serializes WPAgently writes. It then creates a revision, saves through Elementor's document API, performs an exact complete read-back check, verifies frontend rendering, and compiles the expected style values through Elementor's public post CSS class. Any mismatch triggers an automatic rollback. A semantic no-op creates no revision.
Capability: edit_posts (coarse) plus edit_post and Elementor's own editability check.
Traits: write, non-destructive, idempotent. Required are post_id, element_id, expected_hash, and at least one of settings_patch, remove_settings, or style_patch. settings_patch and style_patch each use the closed {json,sha256,bytes} builder-document envelope. CSS-adjacent controls must be changed or removed through style_patch. Output matches the Elementor write path plus element_id, path[], element, and changed.
wp-agent/create-elementor-element
Purpose: Creates a bounded Elementor subtree at a chosen position. Omit parent_id for the document root and omit index to append to the selected child list. The public element body accepts only elType, widgetType, settings, elements, and isInner. Caller-supplied IDs are discarded and securely regenerated throughout the subtree. Element and widget types and every supplied control must be registered and writable in the active Elementor installation. Widgets can act as parent nodes only when Elementor explicitly reports nesting support. Unsafe widgets, executable markup, unknown fields or controls, oversized data, and excessive nesting fail before any write.
Capability: edit_posts (coarse) plus edit_post and Elementor's own editability check.
Traits: write, non-destructive, non-idempotent. Required: post_id, expected_hash, element. Optional: parent_id, index. Output matches the Elementor write path and adds operation, changed, element_id, path[], and the freshly read element.
wp-agent/duplicate-elementor-element
Purpose: Duplicates an existing Elementor subtree and inserts the copy at the chosen position. Every structural ID in the copy is regenerated, while the source and its siblings remain unchanged. Provider-specific references inside settings are deliberately not guessed or rewritten. They remain exactly as stored in the source and are covered by the full read-back and frontend checks.
Capability: edit_posts (coarse) plus edit_post and Elementor's own editability check.
Traits: write, non-destructive, non-idempotent. Required: post_id, element_id, expected_hash. Optional: parent_id, index. Output additionally contains the new element_id, path[], source previous_path[], and duplicated element.
wp-agent/move-elementor-element
Purpose: Moves an existing subtree within the same document while preserving its IDs, settings, and children. Self and descendant targets fail as cycles, and widgets cannot accept children. index denotes the final position after removing the source. Omitting index appends the subtree.
Capability: edit_posts (coarse) plus edit_post and Elementor's own editability check.
Traits: write, non-destructive, idempotent. Required: post_id, element_id, expected_hash. Optional: parent_id, index. Output includes previous_path[], freshly read path[], element, and changed. An already reached target position creates no revision.
wp-agent/delete-elementor-element
Purpose: Checks the target, permission, and current document hash. The Ability does not delete remotely because Elementor has no atomic compare-and-delete operation that protects against concurrent editor changes. It returns HTTP 409 after validation. Delete the subtree manually in the Elementor editor.
Capability: edit_posts (coarse) plus edit_post and Elementor's own editability check.
Traits: compatibility endpoint without remote mutation, manual, and intended to be destructive. Required: post_id, element_id, expected_hash, confirm=true. There is no success output.
Create, duplicate, and move use a conflict hash, short-lived lock, revision, read-back, and frontend verification. Delete remains manual-only.
wp-agent/restore-elementor-revision
Purpose: Restores only Elementor structure and page settings from an Elementor revision belonging to the post. Before writing, the revision content is checked against the same size, structure, widget, and markup boundaries as a regular update. Empty revision settings fully remove newer page settings. The title, excerpt, status, and other WordPress post fields are deliberately not copied from the general revision. The current expected_hash protects intervening Elementor changes. An additional safety revision is created before restore. The target is read back and rendered through the frontend; failures automatically restore the safety revision.
Capability: edit_posts (coarse) plus edit_post and Elementor's own editability check.
Traits: write, destructive to the current Elementor structure, non-idempotent. Required: post_id, revision_id, expected_hash. Output additionally includes safety_revision_id.
wp-agent/get-beaver-document
Purpose: Reads an active Beaver Builder layout through its model API as a bounded flat node list. Output contains node type, module type, parent ID, position, writability, Beaver version, and a canonical SHA-256 conflict hash. Each node's settings are in the closed {json,sha256,bytes} builder-document envelope. Global, linked, unknown, and unsafe modules remain immutable, and oversized or unnormalizable public values are not exposed.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id). Traits: read, non-destructive, idempotent. Required: post_id.
wp-agent/list-beaver-modules
Purpose: Lists installed modules from the active Beaver Builder registry. Executable raw modules such as HTML, shortcodes, and embedded WordPress widgets are excluded. Search, group filtering, and pagination are bounded.
Capability: edit_posts. Traits: read, non-destructive, idempotent. Optional: search, group, page, per_page.
wp-agent/get-beaver-module-schema
Purpose: Reads the bounded writable fields of a safe module type from the active Beaver registry. Structural form fields, unknown field types, executable values, and oversized option lists remain excluded.
Capability: edit_posts. Traits: read, non-destructive, idempotent. Required: module_type.
wp-agent/create-beaver-page
Purpose: Creates a page through Beaver Builder's model API from bounded rows, columns, and safe modules. Layouts and modules must be registered in the active installation, and settings are validated against their provider schemas. After finalization, the page title, status, requested nodes, settings, parents, positions, safe provider-created default descendants, and frontend output are checked. A faulty or incomplete draft is removed completely.
Capability: edit_posts, the page type's concrete create_posts capability, and its publish capability when publishing. Traits: write, non-destructive, non-idempotent. Required: title, rows. Optional: status.
wp-agent/update-beaver-node
Purpose: Changes or removes only schema-validated settings on an existing local node. expected_hash protects the complete layout. Required: post_id, node_id, expected_hash, and settings_patch as the closed {json,sha256,bytes} builder-document envelope; optional: remove_settings.
Capability: edit_posts plus edit_post. Traits: write, non-destructive, idempotent.
wp-agent/create-beaver-module
Purpose: Inserts a registered safe module into an existing Beaver column. The position cannot exceed the end of the existing child list. Any default descendants created automatically by the module must also satisfy the safe write contract. Required: post_id, parent_id, module_type, expected_hash; optional: position, settings.
Capability: edit_posts plus edit_post. Traits: write, non-destructive, non-idempotent.
wp-agent/create-beaver-column-group
Purpose: Creates a native column group in a local row or exactly one nested column level inside a local column. The layout must be registered in Beaver Builder. Position is measured across every direct child of the parent and cannot exceed the end of that child list. Global or linked parents, a second nested level, and layouts exceeding the node boundary remain blocked. Required: post_id, parent_id, layout, expected_hash; optional: position.
Capability: edit_posts plus edit_post. Traits: write, non-destructive, non-idempotent.
wp-agent/duplicate-beaver-node
Purpose: Duplicates a local row, column, or safe module through the native model API. The complete subtree is checked before writing. Read-back requires the same structure and every explicitly stored setting. Provider default fields materialized by Beaver Builder during copying may additionally appear. Global, linked, unknown, or unsafe descendants reject the entire operation.
Capability: edit_posts plus edit_post. Traits: write, non-destructive, non-idempotent. Required: post_id, node_id, expected_hash.
wp-agent/move-beaver-node
Purpose: Moves only a local safe module into an existing Beaver column. Rows and columns are not reparented by the safe path. Required: post_id, node_id, parent_id, expected_hash; optional: position.
Capability: edit_posts plus edit_post. Traits: write, non-destructive, annotated as non-idempotent. An already reached target position creates no revision.
wp-agent/delete-beaver-node
Purpose: Checks the local node, its descendants, and the current layout hash after confirm=true. The Ability does not delete remotely because Beaver Builder has no atomic compare-and-delete operation. It then returns HTTP 409. Delete the node manually in the Beaver Builder editor.
Capability: edit_posts plus edit_post. Traits: compatibility endpoint without remote mutation, manual, and intended to be destructive. Required: post_id, node_id, expected_hash, confirm.
wp-agent/restore-beaver-revision
Purpose: Checks after confirm=true that the revision belongs to the post, is safely readable, and matches the current hash. The Ability does not restore remotely because Beaver Builder has no atomic compare-and-restore operation. It then returns HTTP 409. Restore the revision manually in the Beaver Builder editor.
Capability: edit_posts plus edit_post. Traits: compatibility endpoint without remote mutation, manual, and intended to be destructive. Required: post_id, revision_id, expected_hash, confirm.
The five remote write paths for existing Beaver layouts use the same complete conflict hash, atomic short-lived lock, revision verified against the initial state, semantically exact read-back, frontend render verification, and cache invalidation. Depending on the operation, verification covers complete node settings, parents and positions, or equality of duplicated subtrees. Positions outside the existing target node are rejected before writing. Provider, save, read-back, and render failures trigger a verified complete rollback. If even the rollback cannot be verified exactly, the recovery revision is retained and the operation reports an explicit rollback error. delete-beaver-node and restore-beaver-revision validate permission, target, and current hash but perform no remote mutation.
wp-agent/list-spectra-blocks
Purpose: Reads the block library visible in Spectra's own administration UI from the native registry. Internal child blocks, extensions, deprecated blocks, and blocks with a missing plugin dependency remain excluded. Every item contains its slug, block name, title, description, categories, default state, and effective activation state. The hash covers the complete raw _uagb_blocks option, including unknown future keys.
Capability: manage_options. Traits: read, non-destructive, idempotent. Optional: search, status (all, enabled, disabled), page, per_page. Output: version, items[], pagination, and hash.
wp-agent/set-spectra-block-status
Purpose: Enables or disables exactly one visible Spectra block through UAGB_Admin_Helper::update_admin_settings_option(). Internal and unknown slugs are rejected. A short-lived lock and expected_hash prevent concurrent WPAgently writes and stale changes. The complete option value is read back. A mismatch restores only the target key so concurrently added unrelated keys remain intact.
Capability: manage_options. Traits: write, non-destructive, idempotent. Required: slug, enabled, expected_hash. Output: block, verified, previous_hash, hash.
wp-agent/list-spectra-popups
Purpose: Lists Spectra's spectra-popup post type with search, status, type, activation, and pagination filters. Output is limited to the ID, title, slug, status, type, activation, repetition, modified time, and state hash. Arbitrary unrelated post metadata remains hidden.
Capability: manage_options. Traits: read, non-destructive, idempotent. Optional: search, status, type, enabled, page, per_page, order, order_by.
wp-agent/get-spectra-popup
Purpose: Reads an existing Spectra popup including raw content and a recursive block report. The report exposes block count, freeform count, block types, and whether the required uagb/popup-builder wrapper exists. Content larger than 1 MiB is rejected. Unrelated metadata is not returned.
Capability: manage_options. Traits: read, non-destructive, idempotent. Required: id. Output: the popup summary plus content, block_count, freeform_count, block_types, has_popup_wrapper.
wp-agent/create-spectra-popup
Purpose: Creates a native Spectra popup or banner from 1-20 bounded Core components. Supported components are Markdown, separators, and spacers up to 400 pixels. The provider wrapper matches the actual serialization emitted by Spectra 2.20.1. New objects remain disabled regardless of WordPress status and must be enabled separately after review.
Capability: manage_options. Traits: write, non-destructive, idempotent. Required: title, type (popup or banner), components, idempotency_key. Optional: status (draft, pending, private, publish), repetition (1-100). Reusing the same key returns the same object only while the requested and stored state remain identical. A different request or later edit under that key is rejected as a conflict. A key-scoped short-lived lock prevents concurrent duplicate creation. Title, status, type, disabled state, repetition, exact content, native wrapper, and the bounded inner Core blocks are verified after storage. Each of the three internal idempotency values must exist exactly once and remain unchanged. An incomplete or ambiguous creation is removed completely. Output: popup, verified, created.
wp-agent/update-spectra-popup
Purpose: Changes only the title, WordPress status, popup type, activation state, and repetition of an existing Spectra object. Only published popup or banner objects containing a Popup Builder wrapper may be enabled. A type change updates the native block attribute, wrapper and container classes, and accessible close label together. Arbitrary popup content and unrelated metadata cannot be written. A hash and short-lived lock protect against conflicts. All target fields and the expected content are read back, and hook mutations trigger a complete semantic rollback.
Capability: manage_options. Traits: write, non-destructive, idempotent. Required: id, expected_hash, and at least one of title, status, type, enabled, repetition. Output: popup, verified, previous_hash.
wp-agent/delete-spectra-popup
Purpose: Moves an existing Spectra popup conflict-protected to the trash after confirm: true. force: true returns HTTP 409 without deleting because WordPress has no atomic compare-and-delete operation against concurrent editor changes. If WordPress trash is disabled, the reversible path refuses the operation. expected_hash prevents deleting an object that changed in the meantime.
Capability: manage_options. Traits: write, reversible trash, not idempotent. Required: id, expected_hash, confirm. Optional: force. Output: id, trashed, deleted.
The Spectra specialization continues to separate the general Core-block pipeline from the provider-specific wrapper. Only create-spectra-popup may emit the practically verified uagb/popup-builder contract. Free-form Spectra markup, provider-specific inner blocks, arbitrary popup-content edits, and deep style or breakpoint settings remain blocked.
wp-agent/render-verify
Purpose: Renders a post server-side against the effective frontend output (apply_filters('the_content', ...), not the raw DB row, not via a self-directed HTTP request) and checks it against four proven "read-back lies" traps: (a) core/freeform (silent Classic Editor fallback), (b) builder render mismatch (a postmeta-JSON builder dataset is stored, but the associated plugin is not active, so the frontend renders only raw post_content), (c) Contact Form 7 trap (form configuration lives in postmeta _form; post_content is inert for this post type), and (d) SEO read-back. Rank Math and SEOPress are read through their provider-owned post meta, AIOSEO through its native SEO Ability, and Yoast through its effective Meta Surface, which accounts for the Indexable in production. Only the currently active supported SEO plugin is checked.
Capability: edit_posts (coarse) plus current_user_can('edit_post', $post_id) (via reuse of detect-builder).
Traits: read, non-destructive, idempotent.
| Parameter | Type | Required |
|---|---|---|
post_id | integer | yes |
| Output field | Type | Description |
|---|---|---|
post_id | integer | |
rendered.html_length, rendered.word_count, rendered.block_count, rendered.freeform_count | integer | |
rendered.has_freeform | boolean | |
rendered.block_types[] | string[] | |
checks[] | Objects with check, subject, agrees, severity (info|warn), note | Up to four checks (a through d), depending on which apply. |
verdict.renders_ok | boolean | false on freeform or an active builder mismatch. |
verdict.warnings | integer | |
notes[] | string[] |
Example: { "post_id": 42 }
14. Agent knowledge and design profile
These 17 abilities store explicit, bounded site context in fixed WordPress options or read redacted local system diagnostics. They do not record conversations automatically and cause no external data transfer. Read paths require edit_posts. Changes to site context, skills, the design profile, and design directions require manage_options. An Editor can deliberately save and delete memories.
| Ability | Input and limit | Output |
|---|---|---|
get-site-context | none | context with site name, audience, voice, goals, constraints, and notes |
update-site-context | the same six text fields, 200-5,000 characters per field | stored context, verified |
get-system-diagnostics | none | versions, environment, database driver, control checks, redacted connection diagnostics, and privacy flags without users, content, full URLs, plugin paths, or credentials |
list-skills | none, at most 100 stored skills | alphabetical items, total |
get-skill | safe id | one skill or 404 |
upsert-skill | id, title, description, instructions, up to 20,000 instruction characters | skill, verified |
delete-skill | id | deleted |
list-memory | optional search, tag, and limit up to 100, at most 250 stored memories | latest matches and total |
save-memory | optional id, otherwise UUID, title, content up to 10,000 characters, at most 20 tags | memory, verified |
delete-memory | id | deleted |
get-design-profile | none | colors, font families, base size, spacing, radii, and notes |
set-design-profile | at most 30 tokens per map, hex colors, bounded CSS lengths, and at most 10 font families | validated profile, verified |
list-design-directions | none, at most 20 stored design directions | compact list with version and active state |
get-design-direction | safe id | full direction with rules, design profile, and preview |
upsert-design-direction | id, title, and exactly one of profile or source; source accepts up to 30,000 characters as a JSON profile, safe CSS custom properties, or labelled lines with one literal heading and body font each; updates require expected_version | versioned direction, verified |
activate-design-direction | id, expected_version, optional approve_warnings | applies the profile after consistency review, verified |
delete-design-direction | id, expected_version; active direction is protected | id, deleted |
The six read collections Site Context, design profile, design directions, skills, memory, and system diagnostics are also exposed as authenticated MCP resources at wpagently://site/context, wpagently://site/design, wpagently://site/design-directions, wpagently://site/skills, wpagently://site/memory, and wpagently://site/diagnostics. Site skills with prompt exposure enabled additionally appear as native MCP prompts.
Font imports ignore CSS comments and values inside ordinary CSS strings, honor the last effective declaration when a custom property occurs more than once, and accept the final declaration in a block without a semicolon. Dynamic expressions such as var(), url(), calc(), or clamp() and dimensions supplied as fonts are rejected. The preview exposes separate heading and body fonts. When an administrator edits a direction, the backend preserves its stored profile unless a new import or the current global profile is selected explicitly.
15. Confirmed Live Editor
These five abilities connect the bound Editor user to a short-lived browser workspace opened by an administrator in the native Gutenberg or Elementor editor. They reuse the existing MCP connection. The agent receives neither the administrator cookie nor a second local server. Before every command, the server rechecks the session, user role, and permission to edit the open post. Every write is approved visibly and individually. Gutenberg changes remain in the browser until the separately approved save-post command. A complete SHA-256 state hash protects the block structure and post fields against concurrent changes. Autosaves remain locked for the duration of the session. New and changed Gutenberg blocks are limited to the core, kadence, generateblocks, and uagb namespaces. Their attributes are checked against the schema actually registered in the browser before mutation. Dynamic input and output use the Live Editor envelope described above. After approval, Elementor changes run through the verified server-side Elementor abilities with a separate document hash, revision, readback, and frontend verification.
wp-agent/get-live-editor-status
Purpose: Reads the active session, open post, readiness, dirty state, state hash, expiry, and pending-command count. Capability: a safe non-administrator with edit_posts, bound to this exact session. Traits: read, idempotent.
wp-agent/live-editor-read
Purpose: Enqueues a bounded read command. action accepts inspect-page, gutenberg-structure, list-block-types, get-block-schema, or get-block-attributes. Depending on the action, block_name, client_id, include_text, text_limit up to 10,000, or search up to 100 bytes is allowed. Page inspections, schema results, and attribute results share a result budget that accounts for WordPress's stronger JSON encoding of Unicode and slashes. Keys recognized as secrets and non-serializable provider values are redacted. Malformed unpaired UTF-16 surrogates are safely replaced. Runtime errors are limited to 8,000 bytes before completion. The response contains a command_id. Capability: the bound safe non-administrator with permission to edit the open post. Traits: read, not idempotent because it creates a short-lived queue entry.
wp-agent/live-editor-write
Purpose: Enqueues a visible action that requires individual approval. action accepts open-post, create-block, update-block, delete-block, move-block, replace-inner-blocks, undo, redo, or save-post. reason is always required. Except for open-post, the current 64-character expected_state_hash is required. Depending on the action, the input requires post_id, client_id, parent_client_id, block_name, index, bounded attributes, or at most 200 bounded blocks. Before mutation, agent changes are checked against the namespace allowlist, registered attributes, types, enum values, secret keys, and active content. The save gate checks the full structure again for size, depth, and active content. Safe existing blocks remain saveable when a provider ships schema-inconsistent defaults or when their plugin has been deactivated. Capability: the bound safe non-administrator with permission to edit the target post. Traits: write, marked destructive, not idempotent, always requires approval.
wp-agent/live-editor-elementor-write
Purpose: Enqueues one visible Elementor Free operation that requires individual approval. operation accepts open-document, update-document, update-element, create-element, duplicate-element, move-element, delete-element, or restore-revision. reason and post_id are always required. Every mutation requires the current 64-character expected_hash; depending on the operation, bounded elements, settings, style changes, identifiers, position, or a revision ID are also validated. After approval, only the server invokes the existing Elementor ability. It rechecks ownership, permissions, and session state after acquiring the lock, creates a revision, verifies readback and frontend state, and returns failures or recovery_required as terminal results. Capability: the bound safe non-administrator with permission to edit the target post plus individual administrator approval. Traits: write, marked destructive, not idempotent, always requires approval.
wp-agent/get-live-editor-result
Purpose: Reads the status, result, or redacted error for the caller's command using its 24-character command_id. Terminal results are retained within a fixed bound. Expired, foreign, and missing commands fail closed. Capability: the bound safe non-administrator. Traits: read, idempotent.
16. Quick reference: capability per ability
| Ability | Capability (coarse) | Traits |
|---|---|---|
create-post-from-markdown | edit_posts + post-type fine check | write, not idempotent |
get-post | edit_posts + edit_post | read, idempotent |
list-posts | edit_posts + post-type fine check | read, idempotent |
update-post | edit_posts + edit_post | manual-only, change it in WordPress, no remote mutation |
set-post-status | edit_posts + edit_post + status cap | manual-only, change it in WordPress, no remote mutation |
trash-post | edit_posts + delete_post | manual-only, change it in WordPress, no remote mutation |
restore-post | edit_posts + delete_post | manual-only, change it in WordPress, no remote mutation |
delete-post | edit_posts + delete_post | write, reversible trash; force returns HTTP 409, not idempotent |
search-replace-content | edit_posts + edit_post per match | write, not idempotent |
undo-content-replace | edit_posts + edit_post per match | write, idempotent |
create-term | edit_posts + manage_terms (taxonomy) | write, not idempotent |
get-term | edit_posts + assign_terms (taxonomy) | read, idempotent |
list-terms | edit_posts + assign_terms (taxonomy) | read, idempotent |
update-term | edit_posts + edit_terms (taxonomy) | manual-only, change it in WordPress, no remote mutation |
delete-term | edit_posts + delete_terms (taxonomy) | manual-only, change it in WordPress, no remote mutation |
set-post-terms | edit_post + assign_terms (taxonomy) | manual-only, change it in WordPress, no remote mutation |
upload-media | upload_files | write, not idempotent |
create-direct-media-upload | safe Editor + upload_files | write, not idempotent |
revoke-direct-media-upload | safe Editor + upload_files | write, idempotent |
set-alt-text | edit_posts + edit_post | write, not idempotent, fresh expected_state_hash required |
set-featured-image | edit_posts + edit_post | write, not idempotent, fresh expected_state_hash required |
delete-media | edit_posts + delete_post | write, reversible trash; force returns HTTP 409, not idempotent |
list-media | upload_files | read, idempotent |
create-menu | edit_theme_options | write, not idempotent |
add-menu-item | edit_theme_options | write, not idempotent |
list-menus | edit_theme_options | read, idempotent |
assign-menu-location | edit_theme_options | write, not idempotent |
delete-menu | edit_theme_options | manual-only, change it in WordPress, no remote mutation |
get-setting | manage_options | read, idempotent |
update-setting | manage_options | write, not idempotent |
list-settings | manage_options | read, idempotent |
get-ase-free-generator-tag | manage_options (ASE Free 9.0.0 only) | read, idempotent |
update-ase-free-generator-tag | manage_options (ASE Free 9.0.0 only, with “Disable Smaller Components” enabled) | write, conflict-protected, idempotent |
list-comments | moderate_comments | read, idempotent |
moderate-comment | moderate_comments + edit_comment | write, not idempotent |
reply-to-comment | moderate_comments + edit_comment/edit_post | write, not idempotent |
delete-comment | moderate_comments + edit_comment | write, reversible trash; force returns HTTP 409, not idempotent |
list-users | list_users | read, idempotent |
get-user | edit_users | read, idempotent |
set-user-role | promote_users | write, not idempotent |
create-user | create_users | write, not idempotent |
delete-user | delete_users | manual-only, change it in WordPress, no remote mutation |
list-plugins | activate_plugins | read, idempotent |
activate-plugin | activate_plugins | write, not idempotent |
deactivate-plugin | activate_plugins | write, not idempotent |
list-themes | switch_themes | read, idempotent |
switch-theme | switch_themes | write, not idempotent |
create-reusable-block | edit_posts + publish_posts | write, not idempotent |
update-reusable-block | edit_posts + edit_post | manual-only, change it in WordPress, no remote mutation |
list-reusable-blocks | edit_posts | read, idempotent |
delete-reusable-block | edit_posts + delete_post | write, reversible trash; force returns HTTP 409, not idempotent |
get-seo-meta | edit_posts + edit_post | read, idempotent |
set-seo-meta | edit_posts + edit_post | manual-only, change it in the SEO plugin, no remote mutation |
get-seo-settings | manage_options | read, conflict-protected, idempotent |
set-seo-settings | manage_options | manual-only, change it in the SEO plugin, no remote mutation |
get-post-schema | edit_posts + edit_post + provider permission | read, conflict-protected, idempotent |
set-post-schema | edit_posts + edit_post + provider permission | write, conflict-protected, not idempotent |
delete-post-schema | edit_posts + edit_post + Rank Math provider permission | manual-only, change it in the SEO plugin, no remote mutation |
get-term-seo-meta | edit_posts + taxonomy edit_terms | read, conflict-protected, idempotent |
set-term-seo-meta | edit_posts + taxonomy edit_terms | manual-only, change it in the SEO plugin, no remote mutation |
list-seo-redirections / get-seo-redirection | rank_math_redirections | read, conflict-protected, idempotent |
create-seo-redirection | rank_math_redirections | write, marked destructive, conflict-protected, idempotent |
update-seo-redirection | rank_math_redirections | write, marked destructive, conflict-protected, idempotent |
delete-seo-redirection | rank_math_redirections | write, destructive, conflict-protected, not idempotent |
upsert-pattern | edit_pages | write, not idempotent |
get-global-styles | edit_theme_options | read, idempotent |
set-global-styles | edit_theme_options | write, conflict-protected, not idempotent |
list-global-style-variations / get-global-style-variation | edit_theme_options | read, idempotent |
apply-global-style-variation | edit_theme_options | write, destructive, conflict-protected, idempotent |
write-theme-file | edit_themes | write, not idempotent |
list-site-templates / get-site-template | edit_theme_options | read, idempotent |
create-site-template | edit_theme_options | write, non-idempotent |
update-site-template | edit_theme_options | write, conflict-protected, non-idempotent |
delete-site-template | edit_theme_options | write, destructive, conflict-protected |
list-template-parts / get-template-part | edit_theme_options | read, idempotent |
create-template-part | edit_theme_options | write, non-idempotent |
update-template-part | edit_theme_options | write, conflict-protected, non-idempotent |
delete-template-part | edit_theme_options | write, destructive, reference-protected |
list-block-navigations / get-block-navigation | edit_theme_options | read, idempotent |
create-block-navigation | edit_theme_options | write, non-idempotent |
update-block-navigation | edit_theme_options | write, conflict-protected, non-idempotent |
delete-block-navigation | edit_theme_options | write, destructive, reference-protected |
render-check | edit_posts + edit_post | read, idempotent |
refresh-hooks | edit_posts | write, not idempotent |
disable-power | activate_plugins | write, not idempotent |
create-browser-link | safe non-administrator with edit_posts | write, not idempotent |
revoke-browser-link | safe non-administrator with edit_posts | write, idempotent |
detect-builder | edit_posts + edit_post | read, idempotent |
get-builder-compatibility | edit_posts | read, idempotent |
list-block-types | edit_posts | read, idempotent |
get-block-type | edit_posts | read, idempotent |
get-native-block-document | edit_posts + edit_post | read, idempotent |
get-spectra-blocks-separator | edit_posts + edit_post (Spectra Blocks 1.0.4 only) | read, idempotent |
update-spectra-blocks-separator | edit_posts + edit_post (Spectra Blocks 1.0.4 only) | write, conflict-protected, non-idempotent |
update-spectra-block-attributes | edit_posts + edit_post (Spectra and a server-side dynamic schema required) | write, conflict-protected, non-idempotent |
update-spectra-static-heading-alignment | edit_posts + edit_post (only Spectra 2.20.1 and uagb/advanced-heading.headingAlign, uagb/advanced-heading.headingAlignTablet, and uagb/advanced-heading.headingAlignMobile) | write, conflict-protected, not idempotent |
update-spectra-static-heading-colors | edit_posts + edit_post (only Spectra 2.20.1, classic mode, and six-digit headingColor and subHeadingColor) | write, conflict-protected, not idempotent |
update-generateblocks-block-attributes | edit_posts + edit_post (GenerateBlocks and a live schema required) | write, conflict-protected, not idempotent |
update-kadence-block-attributes | edit_posts + edit_post (Kadence Blocks and a live schema required) | write, conflict-protected, not idempotent |
get-elementor-document | edit_posts + edit_post + Elementor check | read, idempotent |
get-elementor-design-system | manage_options + Elementor kit check | read, idempotent |
update-elementor-design-system | manage_options + Elementor kit check | manual-only, change it in Elementor, no remote mutation |
get-elementor-global-classes | manage_options + Elementor Global Class check | read, idempotent |
create-elementor-global-class | manage_options + Elementor Global Class check | write, non-idempotent |
update-elementor-global-class | manage_options + Elementor Global Class check | write, idempotent |
delete-elementor-global-class | manage_options + Elementor Global Class check | manual-only, change it in Elementor, no remote mutation |
set-elementor-element-global-classes | manage_options + Elementor Global Class check | write, idempotent |
list-elementor-widgets / get-elementor-widget-schema | edit_posts | read, idempotent |
get-elementor-element | edit_posts + edit_post + Elementor check | read, idempotent |
create-elementor-page | edit_posts + create_posts, optional publish capability | write, not idempotent |
update-elementor-document | edit_posts + edit_post + Elementor check | write, idempotent |
update-elementor-element | edit_posts + edit_post + Elementor check | write, idempotent |
create-elementor-element | edit_posts + edit_post + Elementor check | write, not idempotent |
duplicate-elementor-element | edit_posts + edit_post + Elementor check | write, not idempotent |
move-elementor-element | edit_posts + edit_post + Elementor check | write, idempotent |
delete-elementor-element | edit_posts + edit_post + Elementor check | manual-only, change it in Elementor, no remote mutation |
restore-elementor-revision | edit_posts + edit_post + Elementor check | write, destructive, not idempotent |
get-beaver-document | edit_posts + edit_post (Beaver required) | read, idempotent |
list-beaver-modules / get-beaver-module-schema | edit_posts (Beaver required) | read, idempotent |
create-beaver-page | edit_posts + concrete create_posts capability, optional publish capability | write, not idempotent |
update-beaver-node | edit_posts + edit_post (Beaver required) | write, idempotent |
create-beaver-module | edit_posts + edit_post (Beaver required) | write, not idempotent |
create-beaver-column-group | edit_posts + edit_post (Beaver required) | write, not idempotent |
duplicate-beaver-node | edit_posts + edit_post (Beaver required) | write, not idempotent |
move-beaver-node | edit_posts + edit_post (Beaver required) | write, not idempotent |
delete-beaver-node | edit_posts + edit_post (Beaver required) | manual-only, change it in Beaver Builder, no remote mutation |
restore-beaver-revision | edit_posts + edit_post (Beaver required) | manual-only, change it in Beaver Builder, no remote mutation |
list-spectra-blocks | manage_options (Spectra required) | read, idempotent |
set-spectra-block-status | manage_options (Spectra required) | write, conflict-protected, idempotent |
list-spectra-popups | manage_options (Spectra required) | read, idempotent |
get-spectra-popup | manage_options (Spectra required) | read, idempotent |
create-spectra-popup | manage_options (Spectra required) | write, idempotent, disabled by default |
update-spectra-popup | manage_options (Spectra required) | write, conflict-protected, idempotent |
delete-spectra-popup | manage_options (Spectra required) | write, reversible trash; force returns HTTP 409, conflict-protected |
get-acf-fields | object-specific: edit_post, edit_user, edit_term, edit_comment, or options capability (ACF required) | read, idempotent |
update-acf-field | object-specific as for get-acf-fields (ACF required) | manual-only, change it in WordPress, no remote mutation |
list-acf-field-groups | manage_options (ACF required) | read, idempotent |
get-acf-field-group | manage_options (ACF required) | read, idempotent |
create-acf-field-group | manage_options (ACF required) | write, not idempotent |
update-acf-field-group | manage_options (ACF required) | manual-only, change it in ACF, no remote mutation |
duplicate-acf-field-group | manage_options (ACF required) | write, not idempotent |
delete-acf-field-group | manage_options (ACF required) | manual-only, change it in ACF, no remote mutation |
list-acf-post-types | manage_options (ACF 6.1+ required) | read, idempotent |
get-acf-post-type | manage_options (ACF 6.1+ required) | read, idempotent |
create-acf-post-type | manage_options (ACF 6.1+ required) | write, not idempotent |
update-acf-post-type | manage_options (ACF 6.1+ required) | write, destructive, idempotent |
delete-acf-post-type | manage_options (ACF 6.1+ required) | write, destructive, not idempotent |
list-acf-taxonomies | manage_options (ACF 6.1+ required) | read, idempotent |
get-acf-taxonomy | manage_options (ACF 6.1+ required) | read, idempotent |
create-acf-taxonomy | manage_options (ACF 6.1+ required) | write, not idempotent |
update-acf-taxonomy | manage_options (ACF 6.1+ required) | write, destructive, idempotent |
delete-acf-taxonomy | manage_options (ACF 6.1+ required) | write, destructive, not idempotent |
list-cptui-post-types / get-cptui-post-type | manage_options (CPT UI 1.19.3+ required) | read, idempotent |
create-cptui-post-type | manage_options (CPT UI 1.19.3+ required) | write, not idempotent |
update-cptui-post-type / delete-cptui-post-type | manage_options (CPT UI 1.19.3+ required) | write, destructive, idempotent |
list-cptui-taxonomies / get-cptui-taxonomy | manage_options (CPT UI 1.19.3+ required) | read, idempotent |
create-cptui-taxonomy | manage_options (CPT UI 1.19.3+ required) | write, not idempotent |
update-cptui-taxonomy / delete-cptui-taxonomy | manage_options (CPT UI 1.19.3+ required) | write, destructive, idempotent |
list-acpt-post-types / get-acpt-post-type | manage_options (ACPT Lite 2.0+ required) | read, idempotent |
create-acpt-post-type | manage_options (ACPT Lite 2.0+ required) | write, not idempotent |
update-acpt-post-type / delete-acpt-post-type | manage_options (ACPT Lite 2.0+ required) | write, destructive, idempotent |
list-acpt-taxonomies / get-acpt-taxonomy | manage_options (ACPT Lite 2.0+ required) | read, idempotent |
create-acpt-taxonomy | manage_options (ACPT Lite 2.0+ required) | write, not idempotent |
update-acpt-taxonomy / delete-acpt-taxonomy | manage_options (ACPT Lite 2.0+ required) | write, destructive, idempotent |
list-pods-models / get-pods-model | manage_options (Pods 3.0+ required) | read, idempotent |
create-pods-model | manage_options (Pods 3.0+ required) | manual-only, change it in Pods, no remote mutation |
update-pods-model | manage_options (Pods 3.0+ required) | write, destructive, idempotent |
delete-pods-model | manage_options (Pods 3.0+ required) | manual-only, change it in Pods, no remote mutation |
upsert-pods-field | manage_options (Pods 3.0+ required) | write, destructive, idempotent |
delete-pods-field | manage_options (Pods 3.0+ required) | manual-only, change it in Pods, no remote mutation |
list-pods-act-records / get-pods-act-record | manage_options (Pods 3.3.9-3.x, table-storage ACT) | read, idempotent |
create-pods-act-record | manage_options (Pods 3.3.9-3.x, table-storage ACT) | write, not idempotent |
update-pods-act-record | manage_options (Pods 3.3.9-3.x, table-storage ACT) | write, not idempotent |
delete-pods-act-record | manage_options (Pods 3.3.9-3.x, table-storage ACT) | manual-only, change it in Pods, no remote mutation |
get-product | edit_posts + edit_post (WooCommerce required) | read, idempotent |
update-product | edit_posts + edit_post (WooCommerce required) | write, not idempotent |
list-products | edit_products (WooCommerce required) | read, idempotent |
preview-woocommerce-bulk-price-update | edit_products (WooCommerce required) | read, idempotent |
execute-woocommerce-bulk-price-update | edit_products + edit_post for every target | write, not idempotent, fail-closed with recovery_required |
create-product | create_products, optionally publish_products | write, not idempotent |
delete-product | edit_post + delete_post | write, reversible trash; permanent flags return HTTP 409, not idempotent |
list-product-variations | edit_post on parent product | read, idempotent |
upsert-product-variation | edit_post on parent product | write, idempotent for updates |
delete-product-variation | parent edit_post + variation delete_post | write, reversible trash; permanent flags return HTTP 409, not idempotent |
list-product-attributes | manage_product_terms (WooCommerce required) | read, idempotent |
get-product-attribute | manage_product_terms (WooCommerce required) | read, idempotent |
upsert-product-attribute | manage_product_terms (WooCommerce required) | write, destructive, not idempotent |
delete-product-attribute | manage_product_terms (WooCommerce required) | manual-only, change it in WooCommerce, no remote mutation |
list-orders | read_private_shop_orders | read, idempotent |
get-order | read_private_shop_orders | read, idempotent |
list-order-notes | read_private_shop_orders | read, idempotent |
set-order-status | edit_shop_orders | write, destructive, idempotent |
add-order-note | edit_shop_orders | write, destructive, idempotent |
list-contact-forms | wpcf7_read_contact_forms | read, idempotent |
get-contact-form | wpcf7_read_contact_forms + wpcf7_edit_contact_form | read, idempotent |
create-contact-form | wpcf7_edit_contact_forms | write, not idempotent |
update-contact-form | wpcf7_edit_contact_forms + wpcf7_edit_contact_form | write, idempotent |
duplicate-contact-form | wpcf7_edit_contact_forms + wpcf7_edit_contact_form | write, not idempotent |
delete-contact-form | wpcf7_edit_contact_forms + wpcf7_delete_contact_form | manual-only, change it in Contact Form 7, no remote mutation |
list-fluent-forms | fluentform_dashboard_access | read, idempotent |
get-fluent-form | fluentform_forms_manager + form ACL | read, idempotent |
create-fluent-form | fluentform_forms_manager | write, not idempotent |
update-fluent-form | fluentform_forms_manager + form ACL | manual-only, change it in Fluent Forms, no remote mutation |
duplicate-fluent-form | fluentform_forms_manager + form ACL | write, not idempotent |
delete-fluent-form | fluentform_forms_manager + form ACL | manual-only, change it in Fluent Forms, no remote mutation |
get-fluent-form-fields | fluentform_forms_manager + form ACL | read-only, idempotent |
upsert-fluent-form-field | fluentform_forms_manager + form ACL | manual-only, change it in Fluent Forms, no remote mutation |
delete-fluent-form-field | fluentform_forms_manager + form ACL | manual-only, change it in Fluent Forms, no remote mutation |
get-fluent-form-delivery | fluentform_forms_manager + form ACL | read, idempotent |
update-fluent-form-confirmation | fluentform_forms_manager + form ACL | manual-only, change it in Fluent Forms, no remote mutation |
upsert-fluent-form-notification | fluentform_forms_manager + form ACL | manual-only, change it in Fluent Forms, no remote mutation |
delete-fluent-form-notification | fluentform_forms_manager + form ACL | manual-only, change it in Fluent Forms, no remote mutation |
list-fluent-entries | fluentform_entries_viewer + form ACL | read-only, idempotent |
get-fluent-entry | fluentform_entries_viewer + form ACL | read-only, idempotent |
set-fluent-entry-status | fluentform_manage_entries + form ACL | write, destructive, idempotent |
set-fluent-entry-favorite | fluentform_manage_entries + form ACL | write, idempotent |
delete-fluent-entry | fluentform_manage_entries + form ACL | manual-only, change it in Fluent Forms, no remote mutation |
list-kadence-forms | edit_kadence_forms + edit_post per result | read-only, idempotent |
get-kadence-form-settings | edit_kadence_forms + edit_post | read-only, idempotent |
update-kadence-form-settings | edit_kadence_forms + edit_post | write, non-destructive, idempotent, fail-closed with recovery_required |
list-gravity-forms | gravityforms_edit_forms | read, idempotent |
get-gravity-form | gravityforms_edit_forms | read, idempotent |
create-gravity-form | gravityforms_create_form | write, not idempotent |
update-gravity-form | gravityforms_edit_forms | manual-only, change it in Gravity Forms, no remote mutation |
duplicate-gravity-form | gravityforms_create_form + gravityforms_edit_forms | write, not idempotent |
delete-gravity-form | gravityforms_delete_forms | manual-only, change it in Gravity Forms, no remote mutation |
list-formidable-forms | frm_view_forms | read, idempotent |
get-formidable-form | frm_view_forms | read, idempotent |
create-formidable-form | frm_edit_forms | write, not idempotent |
update-formidable-form | frm_edit_forms | write, idempotent |
duplicate-formidable-form | frm_edit_forms | write, not idempotent |
delete-formidable-form | frm_delete_forms | manual-only, change it in Formidable Forms, no remote mutation |
preview-form-migration | WPAgently source-provider read permission | read, idempotent |
migrate-form | source read permission + target read and write permission | write, non-destructive, not idempotent |
get-weglot-settings | manage_options | read, idempotent |
update-weglot-settings | manage_options | manual-only, change it in the Weglot dashboard, no remote mutation |
get-astra-design | manage_options | read, idempotent |
update-astra-design | manage_options | write, non-destructive, idempotent |
get-astra-post-design | edit_posts plus edit_post for the target post | read, idempotent |
update-astra-post-design | edit_posts plus edit_post for the target post | write, non-destructive, idempotent |
get-generatepress-design | manage_options | read, idempotent |
update-generatepress-design | manage_options | write, non-destructive, idempotent |
get-oceanwp-design | manage_options | read, idempotent |
update-oceanwp-design | manage_options | write, non-destructive, idempotent |
get-oceanwp-post-title | edit_posts + edit_post (only OceanWP 4.2.2 + Ocean Extra 2.5.8) | read, idempotent |
update-oceanwp-post-title | edit_posts + edit_post (only OceanWP 4.2.2 + Ocean Extra 2.5.8) | write, fail-closed with recovery_required |
get-oceanwp-post-layout-overrides | edit_posts + edit_post (only OceanWP 4.2.2 + Ocean Extra 2.5.8) | read, idempotent |
update-oceanwp-post-layout-overrides | edit_posts + edit_post (only OceanWP 4.2.2 + Ocean Extra 2.5.8) | write, fail-closed with recovery_required |
get-oceanwp-extra-modules | manage_options (only OceanWP 4.2.2 + Ocean Extra 2.5.8) | read, idempotent |
update-oceanwp-extra-module | manage_options (only OceanWP 4.2.2 + Ocean Extra 2.5.8) | write, fail-closed with recovery_required |
list-oceanwp-library-templates | edit_posts + read_post (only OceanWP 4.2.2 + Ocean Extra 2.5.8) | read, idempotent |
get-oceanwp-post-library-templates | edit_posts + edit_post (only OceanWP 4.2.2 + Ocean Extra 2.5.8) | read, idempotent |
update-oceanwp-post-library-templates | edit_posts + edit_post (only OceanWP 4.2.2 + Ocean Extra 2.5.8) | write, fail-closed with recovery_required |
get-kadence-design | manage_options | read, idempotent |
update-kadence-design | manage_options | write, non-destructive, idempotent |
refresh-builder-cache | edit_posts + edit_post | write, not idempotent |
render-verify | edit_posts + edit_post | read, idempotent |
get-site-context | edit_posts | read, idempotent |
update-site-context | manage_options | write, idempotent |
get-system-diagnostics | edit_posts | read, idempotent, redacted, no automatic transmission |
list-skills | edit_posts | read, idempotent |
get-skill | edit_posts | read, idempotent |
upsert-skill | manage_options | write, idempotent |
delete-skill | manage_options | write, destructive, idempotent |
list-memory | edit_posts | read, idempotent |
save-memory | edit_posts | write, idempotent |
delete-memory | edit_posts | write, destructive, idempotent |
get-design-profile | edit_posts | read, idempotent |
set-design-profile | manage_options | write, idempotent |
list-design-directions | edit_posts | read, idempotent |
get-design-direction | edit_posts | read, idempotent |
upsert-design-direction | manage_options | write, not idempotent |
activate-design-direction | manage_options | write, idempotent |
delete-design-direction | manage_options | write, destructive, idempotent |
get-live-editor-status | bound non-administrator + edit_posts | read, idempotent |
live-editor-read | bound non-administrator + edit_post | read, not idempotent |
live-editor-write | bound non-administrator + edit_post + individual administrator approval | write, marked destructive, not idempotent |
live-editor-elementor-write | bound non-administrator + edit_post + individual administrator approval | write, marked destructive, not idempotent |
get-live-editor-result | bound non-administrator + edit_posts | read, idempotent |
Evidenced contracts in the current source state
The following contracts are paid-only. They belong to the source contract for Companion 0.4.121, Power 0.6.38, and CLI and Skills 0.4.91. The public changelog records public availability. They document this source contract's capability boundaries.
| Ability | Purpose and hard boundary | Capability | Traits |
|---|---|---|---|
get-oceanwp-breadcrumbs-customizer | Reads the native, bounded breadcrumb visibility, source, and position settings from OceanWP 4.2.2. | manage_options | read, idempotent |
update-oceanwp-breadcrumbs-customizer | Updates those three settings with complete theme-mod CAS, locking, read-back, and path-specific recovery. | manage_options | write, non-destructive, idempotent |
get-oceanwp-post-format-overrides | Reads link or quote format overrides for one post with Ocean Extra 2.5.8. HTML and shortcodes remain excluded. | edit_posts + edit_post | read, idempotent |
update-oceanwp-post-format-overrides | Updates only safe URL, target, plain-text, and format overrides with a hash, lock, provider read-back, and fail-closed recovery. | edit_posts + edit_post | write, non-destructive, not idempotent |
update-kadence-single-button | Updates only text, URL, target, and four link flags on a unique direct kadence/singlebtn child of kadence/advancedbtn in Kadence Blocks 3.7.8. Style, icons, CSS, and other attributes remain unchanged. | edit_posts + edit_post | write, non-destructive, not idempotent |
create-acpt-woocommerce-product-data | Creates only a new group with Text, Number, and Select fields using ACPT Lite 2.0.11 and WooCommerce 10.9.4. MySQL/MariaDB with InnoDB and a native SERIALIZABLE transaction are required; SQLite closes without mutation. | ACPT Lite product-data management permission | write, non-destructive, not idempotent |
delete-acpt-woocommerce-product-data | Deletes a safe product-data group and its field and option definitions only after a fresh hash and explicit confirmation. The transaction and InnoDB boundary remains in force. | ACPT Lite product-data management permission | write, destructive, not idempotent |
The Operation Ledger is an administrative HMAC-chained history without an ability or MCP tool. The installed MCP adapter does not provide a secure pre-execution hook for an additional WPAgently approval. The existing individual approval and each provider contract therefore remain authoritative.
Additional current release contracts
The following nine Companion abilities also belong to the current release set. Their provider contracts and remaining limits are documented in the compatibility matrix and the roadmap. The activity log and connection setup card are administrative and onboarding features without an ability registration.
| Ability | Purpose and hard boundary | Capability | Traits |
|---|---|---|---|
update-spectra-editor-settings | Changes only confirmed Spectra/UAGB Free 2.20.1 editor toggles and the bounded Google Font configuration. Unknown or secret provider data is retained, or the operation closes. | manage_options | write, conflict-protected, with read-back and its own recovery |
update-oceanwp-footer-customizer | Changes only modelled OceanWP 4.2.2 footer Customizer values. | manage_options | write, complete theme-mod conflict state, read-back, and selective recovery |
update-oceanwp-blog-customizer | Changes only modelled OceanWP 4.2.2 blog Customizer values. | manage_options | write, complete theme-mod conflict state, read-back, and selective recovery |
update-oceanwp-woocommerce-customizer | Changes only modelled OceanWP 4.2.2 WooCommerce Customizer values when WooCommerce is active. | manage_options | write, complete theme-mod conflict state, read-back, and selective recovery |
update-spectra-blocks-button-text | Changes only plain text of at most 200 characters in a directly contained spectra/button of a spectra/buttons block in Spectra Blocks 1.0.4. | edit_posts plus edit_post | write, document hash, revision, lock, cache, and render check |
configure-spectra-one-transfer-secret | Stores a separate transfer secret for portable Spectra One transfers. | manage_options | write; never returns the secret |
export-spectra-one-portable-snapshot | Exports an HMAC-bound, bounded snapshot of Spectra One 1.2.3. | edit_theme_options | read, time-limited, without raw markup or theme files |
preflight-spectra-one-portable-snapshot | Checks a transferred snapshot on the separate target site before every mutation. | edit_theme_options | read, HMAC, version, source, and collision checks |
import-spectra-one-portable-snapshot | Imports only new allowed Spectra One 1.2.3 resources. Overwriting, deletion, and cross-theme transfer remain excluded. | edit_theme_options | write, create-only, not idempotent |
The Operation Ledger records at most 100 write operations with succeeded, failed, rejected, or recovery_required status in a bounded HMAC chain and can be reset only by administrators. It is not an authorization, verification, or approval mechanism. The connection setup card guides through the required local prerequisites and client configuration without exposing credentials.
Further tightly bounded provider paths
The following 25 abilities extend the previously documented 373-item catalog. They do not create a general provider write permission. Every surface is limited to its named provider contract.
| Ability | Purpose and hard boundary | Capability | Traits |
|---|---|---|---|
get-oceanwp-footer-customizer | Reads modelled free footer-widget and copyright values from OceanWP 4.2.2. | manage_options | read, idempotent |
get-oceanwp-blog-customizer | Reads modelled archive and single-post values from OceanWP 4.2.2. | manage_options | read, idempotent |
get-oceanwp-woocommerce-customizer | Reads modelled shop and product-view values from OceanWP 4.2.2. | manage_options | read, idempotent |
list-oceanwp-free-hooks | Lists ten verified Ocean Extra shortcode positions. It neither executes shortcodes nor returns their content. | edit_posts | read, idempotent |
get-oceanwp-post-free-overrides | Reads bounded layout, visibility, and hook assignments for one post. | edit_posts + edit_post | read, idempotent |
export-spectra-one-design-snapshot | Exports only typed global-style tokens, owned Site Editor resources, and block navigations from Spectra One 1.2.3. Raw markup and theme files are excluded. | edit_theme_options | read, idempotent |
import-spectra-one-design-snapshot | Imports selected snapshot components only as new native resources. It checks blog, theme, hash, lock, and permission state. It is not a portable two-site transfer. | edit_theme_options | write, non-destructive, not idempotent |
get-spectra-blocks-provider | Confirms the exactly bound Spectra Blocks installation, absence of Pro, and available read surfaces. | manage_options | read, idempotent |
list-spectra-blocks-catalog | Lists live-registered Spectra Blocks with provider-resolved enabled state. | manage_options | read, idempotent |
get-spectra-blocks-settings | Reads only selected non-secret Spectra Blocks toggles. Credentials and CAPTCHA data are excluded. | manage_options | read, idempotent |
get-spectra-blocks-global-styles | Reads bounded metadata and safe color tokens. Raw CSS, declaration values, and unknown entries are excluded. | manage_options | read, idempotent |
get-spectra-blocks-popup | Reads one popup only after CPT, metadata, wrapper, size, and block-tree checks. | manage_options + read_post | read, idempotent |
get-spectra-editor-settings | Reads selected non-secret Spectra editor toggles and bounded Google Font configuration for Spectra 2.20.1. The separate candidate writer is documented above. | manage_options | read, idempotent |
preview-elementor-v3-v4-migration | Analyses an Elementor document read-only for the checked Elementor 4.2.1 target contract. It never writes, imports templates, or simulates Pro features. | edit_posts + edit_post | read, idempotent |
snapshot-content-model | Reads a bounded ACF, Pods, ACPT Lite, or Meta Box model as a strict, site- and provider-bound snapshot with a closed schema and snapshot hash. | manage_options | read, idempotent |
compare-content-model-snapshots | Compares two integrity-checked snapshots and reports additions, removals, compatible changes, and losses. Each entry's before and after values are closed, integrity-bound {json,sha256,bytes} envelopes. An oversized or invalid value fails the whole response closed rather than being truncated. It writes nothing. | manage_options | read, idempotent |
migrate-content-model | Migrates only the verified lossless definition intersection from a persistent ACF field group to a new ACPT Lite meta group. Field values and existing targets are excluded. | manage_options | write, non-destructive, idempotent |
list-pods-settings | Lists native Pods settings definitions without option values. | manage_options | read, idempotent |
get-pods-settings | Reads one native Pods settings definition with a bounded field list, but no saved settings or option values. | manage_options | read, idempotent |
list-pods-field-groups | Lists native Pods field groups and bounded definitions. Field values, relationships, and media data are excluded. | manage_options | read, idempotent |
get-pods-field-group | Reads one native Pods field group with bounded field definitions and a conflict hash. Field values are excluded. | manage_options | read, idempotent |
list-pods-object-extensions | Lists definition data for native Pods extensions of WordPress objects, not object or field values. | manage_options | read, idempotent |
get-pods-object-extension | Reads one native Pods object extension. Field values and unsupported relationship and media values are excluded. | manage_options | read, idempotent |
list-acpt-woocommerce-product-data | Lists existing safe ACPT Lite 2.0.11 product-data groups with Text, Number, and Select fields. Unsafe groups are skipped. | ACPT Lite product-data management permission | read, idempotent |
update-acpt-woocommerce-product-data | Changes only defaults, descriptions, required state, and UI visibility on an existing safe ACPT Lite 2.0.11 group. Content, groups, options, and field structure remain unchanged. | ACPT Lite product-data management permission | write, conflict-protected, idempotent |
The roadmap records the source contract for Companion 0.4.121, Power 0.6.38, and CLI and Skills 0.4.91, alongside later gaps. The public Polar and plugin status is tracked separately. Code Snippets single use and any Pods or provider lifecycle beyond the documented ACPT Product Data fields remain explicitly outside the current contract: roadmap.
Further tightly bounded design paths
The four Companion abilities added after the previous source state remain deliberately narrow:
- Admin and Site Enhancements Free 9.0.0 adds
get-ase-free-generator-tagandupdate-ase-free-generator-tag. They read or change only the documented switch that removes the WordPress generator meta tag. The parent ASE group must be enabled manually. The change uses blog binding, atomic comparison, a renewable lock, and complete provider read-back. - Spectra Blocks 1.0.4 adds
get-spectra-blocks-separatorandupdate-spectra-blocks-separator. They read or change only the style, alignment, width, height, and color of an exactly shaped, server-registeredspectra/separator. The write path uses a document hash, revision, byte-exact CAS, render and provider read-back, and the existing recovery path.
Further tightly bounded builder and model paths
The 16 Companion abilities added after the previous catalog remain deliberately narrow:
- Beaver Builder adds the seven abilities
list-beaver-user-templates,get-beaver-user-template,save-beaver-user-template,save-beaver-node-template,delete-beaver-user-template,get-beaver-global-settings, andsave-beaver-global-settings. Beaver Lite does not expose the native user-template registration. Those five template paths therefore fail closed as unavailable there; they never simulate or persist substitute templates. The primitive global-settings map remains a separate real provider path. - Pods adds
get-pods-field-valuesandupdate-pods-field-valuesfor existing, supported fields. Unmodelled field shapes, table configurations, and unsafe provider state stay closed. - ACPT adds
list-acpt-meta-groups,get-acpt-meta-group,create-acpt-meta-group,update-acpt-meta-group,delete-acpt-meta-group,get-acpt-field-values, andupdate-acpt-field-values. They use the native provider path and accept only the modelled persistent meta group or supported field values.
The GenerateBlocks write path remains limited to its allowlisted structural Query and pagination attributes. It writes neither rich text nor arbitrary plain text. The commercial Meta Box Settings Pages runtime for values remains externally uncertified until a legally licensed practical fixture exists. Further licensed or proprietary provider surfaces remain outside this contract.