SEOPress
These abilities register when SEOPress is detected on the site and a Pro licence is active. If either is missing the module stays absent rather than failing at call time.
At a glance
SEOPress registers 16 abilities: 9 that only read, 6 that write, and 1 marked destructive. That split is the practical answer to how much of this module can run unattended. Reads cost nothing and are safe to repeat, so discovery is the part to be generous with; the writes are where review belongs, and the destructive calls stop for an explicit confirmation every single time regardless of which profile is active.
What this module is for
Operate SEOPress post and term metadata, structured-data fields and templates, redirects, schema type assignments, and settings.
Before you rely on it: Keep schema consistent with visible page content and test redirect behavior with a crawler.
Typical workflows
- Inspect schema templates before assigning a type
- Audit a redirect list for chains and stale destinations
- Update one page's metadata after evaluating its visible content
The SEOPress integration page covers the same module from the workflow side, with the capability map and the questions worth asking before a first write.
Availability on your site
The SEOPress module needs three things at once: WPPilot Free as the MCP foundation, an active Pro licence, and the companion plugin detected on the site. Miss any one and the module does not register, which is deliberate: an ability that appears in the tool list but fails at call time is worse than an ability that was never offered. What the connected agent can actually call is then narrowed twice more: by the safety profile active on the site, and by the WordPress capabilities of the user behind the credential. A read that succeeds for an administrator can be absent entirely for an editor.
Every write these abilities perform is recorded in the change ledger, and destructive calls can be routed through the approval queue so a person signs off before anything is applied. A successful tool result means the operation returned, not that the front end, the cache, and every dependent template are correct: that still needs a look.
Reads
Available in every safety profile, including Read Only. Inspection costs nothing and is not rate limited.
| Ability | What it does |
|---|---|
wppilot/seopress-check-setupCheck SeoPress Setup | Reports the SeoPress environment: whether SeoPress is active, its version, whether the Pro add-on is loaded (and, for info only, whether its license is valid), which Pro-gated surfaces are available (redirects and structured-data/schema need Pro), the enabled-module map (titles, social, XML sitemap, rich snippets, redirections, …), and the public post types and taxonomies whose SEO can be managed. Pro-gated abilities check this. Call this first before any other SeoPress ability. |
wppilot/seopress-get-post-schemaGet Post Schema (SeoPress) | Reads the MANUAL structured-data (rich snippets) attached to a single post or page (requires SeoPress Pro). SeoPress Pro stores manual schemas as a list of rows on the post — each row has a type (one of articles, localbusiness, recipes, jobs, videos, events, products, softwareapp, services, review, faq, howto, courses, custom) plus its _seopress_pro_rich_snippets_* field values. Returns a LEAN view: { post_id, schemas: [ { index, type, fields } ], disabled_all, rendering_enabled }, where fields holds ONLY the POPULATED (non-empty) keys of each row — a type can have dozens of possible keys, so empty ones are omitted to keep the output small. Use list-schema-fields(type) to see every possible key for a type. index is the row's position (0-based) and is the handle set-post-schema-type / edit-post-schema address. disabled_all (read-only) is the per-post kill switch (_seopress_pro_rich_snippets_disable_all) that disables the AUTOMATIC/template schemas. rendering_enabled (read-only) reflects the SITE-WIDE rich-snippets feature (seopress_pro_option_name[seopress_rich_snippets_enable]): when false, SeoPress will NOT emit JSON-LD for these manual rows even though they are stored — enable the rich-snippets feature in SeoPress (or via execute-php) for the schema to actually render. schemas is [] when the post has no manual rows. This reads ONLY the manual schemas — not the automatic-template override. Identify the post by post_id (alias: id). |
wppilot/seopress-get-post-seoGet Post SEO (SeoPress) | Reads the SeoPress metadata for a single post or page in one friendly shape: title and description (the per-post meta-title / meta-description templates, which may contain SeoPress %%dynamic_variables%%), robots (noindex, nofollow, nosnippet, noimageindex as explicit booleans, breadcrumbs_hide which is Pro-written/read-only, canonical URL, and an effective sub-block that resolves the global / per-post-type defaults so a globally-forced directive is not under-reported), target_keywords (the content-analysis keywords as a list), facebook (Open Graph) and twitter social previews (title, description, image, image_id), and redirect (the single-post redirection: enabled, type, value, logged_status). The top-level robots flags are the RAW per-post overrides: an empty string / false means "no override — SeoPress inherits the global or per-post-type default", NOT a stored blank; robots.effective is the resolved directive. Identify the post by post_id (alias: id). |
wppilot/seopress-get-redirectGet Redirect (SeoPress) | Reads one SeoPress Pro redirect / monitored 404 by id (requires SeoPress Pro). Redirects AND 404s share ONE custom post type (seopress_404); the presence of an HTTP status (type) distinguishes a configured redirect from a bare 404 log entry. Returns the FULL row: id, origin (the source path / regex, stored as the post_title), destination (target URL), type (int HTTP status, or null for a 404), enabled, enabled_regex (origin is a regex), logged_status (both / only_logged_in / only_not_logged_in), param (exact_match / without_param / with_ignored_param), count (hit count), last_hit (unix timestamp or null), ua (last user agent), referer (last referer), and category_ids (the seopress_404_cat term ids). Identify the entry by id (the seopress_404 post id — get it from list-redirects). |
wppilot/seopress-get-settingsGet SeoPress Settings | Reads a curated, read-only snapshot of the site-wide SeoPress configuration. group selects the block(s) (default "all"): "titles" = the title separator, homepage title/description, site alternative name, global robots toggles (noindex/nofollow/nosnippet/noimageindex), archive noindex toggles, and the LISTS of post types / taxonomies that carry a per-type title override; "social" = Open Graph + Twitter/X card toggles, the default social images, and the linked social account URLs; "knowledge" = the Person/Organisation knowledge-graph identity (type, name, image, phone, email, legal name, founding date); "sitemap" = the XML sitemap enable flag, the LISTS of included post types / taxonomies, and the image/video/author/HTML toggles; "advanced" = category/product permalink stripping, attachment redirects, and the PUBLIC site-verification meta codes (Google/Bing/Yandex/Baidu/Pinterest); "analytics" = the Google Analytics / GA4 / Matomo / Microsoft Clarity public ids and enable flags. ALL secrets are REDACTED and never returned: the SeoPress Pro license key, the instant-indexing API keys, and any analytics auth token. Writing settings is NOT an ability — use wppilot/execute-php (e.g. update_option on the relevant seopress_*_option_name array) to change them. |
wppilot/seopress-get-term-seoGet Term SEO (SeoPress) | Reads the SeoPress metadata for a single taxonomy term (category, tag, or custom taxonomy term) in the same friendly shape as get-post-seo: title, description, robots (noindex, nofollow, nosnippet, noimageindex, canonical, and an effective sub-block resolving the global / per-taxonomy defaults), facebook and twitter social previews, and redirect. Term SEO is a FREE SeoPress feature and reuses the SAME _seopress_* keys as posts, only stored in term meta. The top-level robots flags are the RAW per-term overrides — an empty string / false means "inherit the per-taxonomy or global default"; robots.effective is the resolved directive. Identify the term by term_id AND taxonomy (both required). |
wppilot/seopress-list-redirectsList Redirects (SeoPress) | Lists the SeoPress Pro redirects and monitored 404s (requires SeoPress Pro). Redirects AND 404s share ONE custom post type (seopress_404); the PRESENCE of an HTTP status (type) distinguishes a configured redirect from a bare 404 log entry. Use view to pick which: "redirects" (default — has a type), "404" (logged 404s with no type yet), or "all". Returns compact rows {id, origin, destination, type (int|null — null for a 404), enabled, enabled_regex, logged_status, param, count, last_hit}, newest first. origin is the source path (a relative path like /old-page/ or a regex pattern); destination is the target URL. Filter with enabled (bool), type (int HTTP status), and search (matches the origin). Paginate with limit (default 100, max 500) and offset; total is the matching count (respects the filters) so you can page while offset + returned < total. The compact row omits user-agent and referer telemetry — use get-redirect for the full row including ua, referer and category_ids. Use the id with get-redirect. |
wppilot/seopress-list-schema-fieldsList Schema Fields (SeoPress) | Lists the manual structured-data (rich snippets) field keys for ONE SeoPress Pro schema type (requires SeoPress Pro). This is the FIELD-DISCOVERY VALVE for edit-post-schema: SeoPress stores per-post manual schemas as rows keyed by full _seopress_pro_rich_snippets_* meta keys, and the keys differ from the type value (a plural/singular quirk — e.g. type "articles" uses _seopress_pro_rich_snippets_article_* keys, type "products" uses _product_*). Call this with one type to learn exactly which keys edit-post-schema accepts, instead of carrying all 14 types' keys in every schema. Returns { type, fields: [{ key, format }] } where key is the FULL meta key and format is a coarse hint: string | url | date | time | number | repeater(array) | json-ld-script. type "custom" returns a single json-ld-script field (_seopress_pro_rich_snippets_custom — raw JSON-LD <script>); "faq" and the howto steps key are repeater(array). The 14 types: articles, localbusiness, recipes, jobs, videos, events, products, softwareapp, services, review, faq, howto, courses, custom. |
wppilot/seopress-list-schema-templatesList Schema Templates (SeoPress) | Lists SeoPress Pro's "automatic" structured-data templates (requires SeoPress Pro). These templates are the seopress_schemas custom post type: each one defines a schema.org type and a set of attach-RULES that decide which content it applies to (by post type, taxonomy or post id), so the schema is emitted automatically across matching pages — distinct from the MANUAL per-post schema you read with seopress-get-post-schema. This ability is a LEAN INDEX: it returns { templates: [ { id, title, type } ], total, limit, offset } where type is the template's schema.org type (_seopress_pro_rich_snippets_type, '' when unset). It deliberately does NOT return the attach-rules tree (a large nested blob) — use it to learn that the automatic/template system is present and what types are defined, not to edit it. To edit a template's type or rules, use wppilot/execute-php (update_post_meta on _seopress_pro_rich_snippets_type / _seopress_pro_rich_snippets_rules). Paginate with limit (default 100, max 500 — clamped) and offset; total is the full count so you can page while offset + returned < total. |
Writes
Gated by the active profile and your WordPress capabilities. Rate limited to 120 per minute per credential.
| Ability | What it does |
|---|---|
wppilot/seopress-create-redirectCreate Redirect (SeoPress) | Creates a new SeoPress Pro redirect (a seopress_404 custom post type — redirects and monitored 404s share it) (requires SeoPress Pro). REQUIRED: origin (the source path like /old-page/ or a regex pattern — stored as the post_title). Optional: destination (target URL — required in practice for a 301/302/307, omit for a 410/451 "gone" status), type (HTTP status, default 301, must be one of 301, 302, 307, 410, 451), enabled (default true), enabled_regex (origin is a regex, default false — NOTE SeoPress matches the regex against the request path WITH its leading slash, so anchor as "^/old-(.*)" or leave it unanchored; a start-anchored "^old-(.*)" never fires), logged_status (audience: both | only_logged_in | only_not_logged_in, default both), param (query-parameter mode: exact_match | without_param | with_ignored_param, default exact_match), category_ids (a list of seopress_404_cat term ids). A redirect only FIRES when it is enabled AND has a destination AND a valid type AND a logged_status — all defaulted here so a minimal {origin, destination} call works. NOT idempotent: every call mints a fresh redirect with a new auto-generated id, so re-running creates a duplicate — pre-check with list-redirects (search by origin) before creating. All provided fields are validated FIRST (seopress_invalid_input, 400) before anything is written. Returns the compact redirect row {id, origin, destination, type, enabled, enabled_regex, logged_status, param, count, last_hit}. |
wppilot/seopress-edit-post-schemaEdit Post Schema (SeoPress) | Partial-merges the FIELDS of one manual structured-data (rich snippets) row on a post or page (requires SeoPress Pro). The row at index (default 0) MUST already exist — set its type first with set-post-schema-type. fields is an object of full _seopress_pro_rich_snippets_* key → value; call list-schema-fields(type) to discover the exact keys for the row's type (the keys differ from the type value: articles → _article_*, products → _product_*). Every provided key is VALIDATED against the row's CURRENT type and an unknown key is rejected (seopress_invalid_input) — except _seopress_pro_rich_snippets_custom (raw JSON-LD <script>) which is allowed only on a custom row. CLEARING: a field whose value is "" DELETES that key from the row. Sanitisation mirrors SeoPress exactly: the custom JSON-LD via wp_kses (the <script type="application/ld+json"> tag is PRESERVED); array (repeater) values via map_deep + sanitize_text_field; everything else via sanitize_text_field. CURATED SCOPE: this ability is for the SCALAR fields and the custom JSON-LD. The deeply-nested repeaters (howto steps _seopress_pro_rich_snippets_how_to, faq _seopress_pro_rich_snippets_faq, course offers/instances, product positive/negative notes) accept an array value and are sanitised, but authoring those nested structures by hand is error-prone — prefer execute-php for them. Identify the post by post_id (alias: id). Returns the re-read schema view (same shape as get-post-schema). |
wppilot/seopress-edit-post-seoEdit Post SEO (SeoPress) | Updates the SeoPress metadata for a single post or page. Send ONLY the fields to change — it is a partial merge, and nested blocks (robots, facebook, twitter, redirect) merge field-by-field. CLEARING semantics: because SeoPress stores "no override" as an ABSENT row, passing an empty string (or false / empty array / 0) for a field DELETES it so the post inherits the global / per-post-type default — it never stores a blank. Fields: title (_seopress_titles_title, may contain %%dynamic_variables%%), description (_seopress_titles_desc — SeoPress stores it single-line, collapsing newlines to spaces on save), canonical (URL), robots {noindex, nofollow, nosnippet, noimageindex as booleans — true sets the override, false clears it; the key name is the NEGATIVE so noindex=true means "do not index"; breadcrumbs_hide is Pro-written and IGNORED on write}, target_keywords (a list of strings — SeoPress keeps ONE comma-joined row, so the whole list is rewritten and a keyword may NOT contain a comma (it would split into two; rejected with seopress_invalid_input); [] clears it), facebook / twitter {title, description, image, image_id} (clearing image also clears its attachment-id/width/height companions), redirect {enabled (bool), type (one of 301/302/307; 0 clears), value (URL), logged_status (both | only_logged_in | only_not_logged_in)}. All provided fields are validated FIRST and rejected together (seopress_invalid_input, 400) before anything is written. Identify the post by post_id (alias: id). Returns the full re-read SEO. |
wppilot/seopress-edit-redirectEdit Redirect (SeoPress) | Updates an existing SeoPress Pro redirect / monitored 404 (a seopress_404 custom post type) by id (requires SeoPress Pro). Send ONLY the fields to change — it is a partial merge. Identify the entry by id (the seopress_404 post id from list-redirects). Fields: origin (the source path or regex, stored as the post_title — cannot be blanked, a redirect always needs a source), destination (target URL; empty string clears it), type (HTTP status, must be one of 301, 302, 307, 410, 451; 0 clears the type and DEMOTES the entry back to a bare 404), enabled (bool; false stops it firing), enabled_regex (bool; origin is a regex), logged_status (both | only_logged_in | only_not_logged_in; empty clears it), param (exact_match | without_param | with_ignored_param; empty clears it), category_ids (a list of seopress_404_cat term ids — REPLACES the existing set; [] detaches all). This is also how a monitored 404 is PROMOTED to a redirect: give a bare 404 a type + destination (and it fires once enabled + logged_status are set). All provided fields are validated FIRST (seopress_invalid_input, 400) before anything is written. Returns the compact redirect row {id, origin, destination, type, enabled, enabled_regex, logged_status, param, count, last_hit}. |
wppilot/seopress-edit-term-seoEdit Term SEO (SeoPress) | Updates the SeoPress metadata for a single taxonomy term (category, tag, or custom-taxonomy term). Send ONLY the fields to change — it is a partial merge, and nested blocks (robots, facebook, twitter, redirect) merge field-by-field. CLEARING semantics: because SeoPress stores "no override" as an ABSENT row, passing an empty string (or false / empty array / 0) for a field DELETES it so the term inherits the per-taxonomy / global default — it never stores a blank. Fields: title (_seopress_titles_title, may contain %%dynamic_variables%%), description (_seopress_titles_desc — returned single-line: newlines collapse to spaces on read), canonical (URL), robots {noindex, nofollow, nosnippet, noimageindex as booleans — true sets the override, false clears it; the key name is the NEGATIVE so noindex=true means "do not index"; breadcrumbs_hide is Pro-written and IGNORED on write}, facebook / twitter {title, description, image, image_id} (clearing image also clears its attachment-id/width/height companions), redirect {enabled (bool), type (one of 301/302/307; 0 clears), value (URL), logged_status (both | only_logged_in | only_not_logged_in)}. There is NO target_keywords field — content-analysis keywords are post-only. All provided fields are validated FIRST and rejected together (seopress_invalid_input, 400) before anything is written. Term SEO is a FREE SeoPress feature (no Pro needed). Identify the term by term_id AND taxonomy (BOTH required). Returns the full re-read SEO. |
wppilot/seopress-set-post-schema-typeSet Post Schema Type (SeoPress) | Sets (PUT-style) the TYPE of one manual structured-data (rich snippets) row on a post or page (requires SeoPress Pro). SeoPress Pro stores manual schemas as a list of rows; this ability sets the row at index (default 0) to the given type. If no row exists at that index, it CREATES the row with just the type — then use edit-post-schema to fill in its _seopress_pro_rich_snippets_* fields (call list-schema-fields(type) to learn the keys). If a row already exists at that index with a DIFFERENT type, switching the type starts a CLEAN row of the new type: every foreign field key from the old type is DROPPED (only the type is kept) so the row never carries stale, wrong-type fields. Re-setting the SAME type is idempotent (no field loss). type must be one of: articles, localbusiness, recipes, jobs, videos, events, products, softwareapp, services, review, faq, howto, courses, custom. Note the type→key-stem quirk (articles → _article_* keys, products → _product_*) — list-schema-fields resolves it. Identify the post by post_id (alias: id). Returns the re-read schema view (same shape as get-post-schema). |
Destructive
Marked destructive in the source, so each call needs an explicit confirmation flag, every time.
| Ability | What it does |
|---|---|
wppilot/seopress-delete-redirectDelete Redirect (SeoPress) | PERMANENTLY deletes a SeoPress Pro redirect / monitored 404 (a seopress_404 custom post type) by id (requires SeoPress Pro). This is a HARD delete — the post is removed outright, NOT trashed, and cannot be undone (mirrors SeoPress's own behaviour). Use it to drop a redirect OR to clear a monitored 404 log entry (they share the seopress_404 CPT). Identify the entry by id (from list-redirects). SAFETY: if the id does not exist this is an idempotent no-op (returns {deleted: false, id} — already gone); if the id is a post of ANOTHER type it is REFUSED (seopress_invalid_input, 400) and nothing is deleted — this ability NEVER hard-deletes an arbitrary post. Returns {deleted: bool, id}. |