Skip to content

saswp custom schema

Some WordPress sites manage their structured data with saswp (“Schema & Structured Data for WP & AMP”) instead of, or alongside, RankMath. saswp emits its blocks with a tell-tale class:

<script type="application/ld+json" class="saswp-custom-schema-markup-output"></script>

saswp does not expose its custom-schema storage over the core WordPress REST API (/wp/v2/saswp returns 404, and its meta is not show_in_rest). The RankMath bridge cannot reach it either — they are different plugins writing different storage. The saswp bridge closes that gap.

When you need this: the schema you want to edit renders with the saswp-custom-schema-markup-output class. If the block is a rank-math-schema block instead, use RankMath SEO — not this. Check the page source (or diagnose_site) to see which provider is active.

saswp stores every Custom Schema entry’s raw JSON-LD in the postmeta key saswp_custom_schema_field — both for a global Custom Schema entry (a saswp post shown across many pages via its display rules) and for per-post custom markup. The bridge reads and writes that one field. Because a global entry is a single definition, editing it once updates every page its display rules already target — the “update everything at once” case.

Scope guardrail. The bridge only reads/writes the JSON-LD body. It never edits a Custom Schema’s display/target conditions (which pages it shows on) — those stay in the saswp admin UI — and it never deletes. Writes are gated behind an explicit confirm=true flag; without it you get a before/after preview and nothing changes.

  1. Download seo-navigator-saswp from wp-plugins/seo-navigator-saswp in the worker repo.
  2. Upload as a zip in wp-admin → Plugins → Add New → Upload Plugin, then activate it (saswp itself must already be installed + active).
  3. Confirm it answers on its status route:
Terminal window
curl https://<site>/wp-json/sn-saswp/v1/status
# → { "ok": true, "plugin": "seo-navigator-saswp", "saswp_active": true,
# "saswp_version": "1.61", "entry_count": 3 }

The plugin registers the REST namespace /wp-json/sn-saswp/v1/. Every route except /status is gated by the edit_posts capability — the same trust model as the RankMath bridge and the core meta channel.

RouteMethodPurpose
/sn-saswp/v1/statusGETBridge + saswp presence, version, custom-schema entry count. Public (used by diagnose_site).
/sn-saswp/v1/custom-schemaGETList every Custom Schema entry (post_id, post_type, title, value_type, value). ?id=N for one entry; ?needle=AutomotiveBusiness to filter by a substring of the JSON.
/sn-saswp/v1/custom-schemaPOSTUpdate one entry’s JSON-LD: { id, value, confirm }. Send value in the same shape (value_type) a GET returned — string JSON or array — so storage is never corrupted. Omit confirm for a dry-run preview.
1. GET /sn-saswp/v1/custom-schema?needle=AutomotiveBusiness
→ find the entry id + see value_type (e.g. "string") + current JSON
2. POST /sn-saswp/v1/custom-schema { id, value: <edited JSON>, confirm: false }
→ preview: returns { current, proposed }, changes nothing
3. POST /sn-saswp/v1/custom-schema { id, value: <edited JSON>, confirm: true }
→ writes saswp_custom_schema_field; returns the updated entry
4. Purge the site's page cache (and CDN) and re-check the front-end.

A string value is validated as JSON before saving (422 on malformed JSON), so you can’t write markup that would break the front-end output.

The bridge’s /status route is what diagnose_site probes. Target shape once worker support lands:

"saswp": {
"active": true,
"version": "1.61",
"bridge_installed": true,
"entry_count": 3
}

The plugin ships the REST surface above. The MCP worker still needs the matching pieces before Claude can call this end-to-end:

  1. A saswp probe in src/utils/diagnose.ts that fetches /wp-json/sn-saswp/v1/status (mirror the rankmath bridge probe).
  2. MCP tools — e.g. get_saswp_schema (GET) and set_saswp_schema (POST with the confirm gate) — in src/mcp/tools.ts, routed through the WordPress adapter to /sn-saswp/v1/custom-schema.
  3. Optional: a Danger-Zone-style flag if writes to live entries should be gated like allow_seo_on_published.

Until that lands, the bridge is reachable directly over REST (curl / any HTTP client) with an Application Password.

The RankMath bridge writes rank_math_schema_* postmeta — a different provider. On a saswp site, RankMath usually emits no schema at all, so routing schema through RankMath would (a) leave the saswp block (and any stale data in it) untouched, and (b) risk two competing schema blocks on the page. Edit schema in the provider that actually renders it.

Code / statusMeaning
sn_saswp_not_found (404)No saswp_custom_schema_field on that post id.
sn_saswp_bad_input (400)Missing id or value.
sn_saswp_bad_json (422)value is a string but not valid JSON.
rest_forbidden (401/403)The app-password user lacks edit_posts.