WP Manifestindependent plugin directory
manifest / seo / rankmath-rest-bridge

SEO Control Layer self-updates

WordPress REST API plugin for SEO Remediation Agent — RankMath meta, snippet injection, cache purge, auto-update

by AMS · github.com/penzenmaster/rankmath-rest-bridge

0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/penzenmaster/rankmath-rest-bridge/archive/refs/heads/main.zip

Ships its own WordPress updater (Plugin Update Checker), so new versions show up under Dashboard → Updates.

RankRocket SEO Control Layer

WordPress plugin that is the native SEO control layer for the RankRocket remediation pipeline. Manages title/meta, schema injection, image ALT text, llms.txt, XML sitemap, robots.txt, cache purge, and self-updates. RankMath is not required; rank_math_* post-meta is read as a migration fallback.

  • REST namespace: rankrocket-seo/v1
  • Requires: PHP 7.4+, WordPress 5.9+
  • Auth: All write endpoints require manage_options capability via WordPress Application Passwords.

Caching Compatibility

If your host runs a persistent page or object cache (SiteGround SuperCacher, Redis Object Cache, W3 Total Cache, WP Rocket, LiteSpeed Cache), you must exclude the REST API path from full-page caching to avoid stale GET responses after writes:

SiteGround SuperCacher: Exclude /wp-json/ from Dynamic Cache. WP Rocket: Add /wp-json/(.*) to the "Never Cache URL(s)" list. W3 Total Cache / LiteSpeed / Breeze: Exclude /wp-json/ from page cache rules.

POST /cache/purge flushes the WordPress object cache and all detected plugin-level caches. Call it after any bulk operation if you need read-after-write consistency without a page reload.


REST API — Key Endpoints

All examples use:

BASE="https://example.com/wp-json/rankrocket-seo/v1"
CRED="admin:APP_PASSWORD"

SEO Meta

POST /update — write or clear SEO meta for a post or term

Accepts a post_id that resolves to either a post/page or a taxonomy term. The plugin detects the type automatically and writes to post meta or term meta accordingly.

# Write title + description to a post
curl -X POST "$BASE/update" -u "$CRED" \
  -H "Content-Type: application/json" \
  -d '{"post_id": 123, "title": "New Title", "description": "New description."}'

# Write term meta to a taxonomy term
curl -X POST "$BASE/update" -u "$CRED" \
  -H "Content-Type: application/json" \
  -d '{"post_id": 21, "title": "Category Title", "description": "Category description."}'

Response includes object_type: "post" or object_type: "term" so callers know which path was taken.

Clearing fields with unset_fields

To delete a previously-stored meta value, pass its name in the unset_fields array. Sending an empty string ("title": "") is intentionally a no-op — empty strings are skipped so that pipeline templates that render a blank value for a missing field don't accidentally wipe live SEO data. Use unset_fields for explicit, deliberate deletion.

curl -X POST "$BASE/update" -u "$CRED" \
  -H "Content-Type: application/json" \
  -d '{"post_id": 123, "unset_fields": ["title", "og_image"]}'

Valid field names: title, description, focus_keyword, robots, og_title, og_description, og_image, canonical, twitter_card, twitter_title, twitter_description, twitter_image.

Returns 422 invalid_unset_field for unrecognised names (includes valid_fields array). Returns 422 unset_write_conflict if the same field appears in both write params and unset_fields.

GET /get/{id} — read SEO meta

curl "$BASE/get/123" -u "$CRED"

POST /preview-update — dry-run diff (posts only)

Returns what would change without writing. Returns 422 term_not_supported for term IDs — use POST /update directly for term meta writes.


Schema (JSON-LD)

GET /schema/{post_id} — read the stored JSON-LD schema

curl "$BASE/schema/123" -u "$CRED"

Returns whatever was stored: a single node object, or a @graph envelope for multi-node writes. schema: null if nothing has been written yet.

POST /schema/{post_id} — validate and store JSON-LD schema

Accepts any of three shapes in the schema field. All three validate each node's @type against the allowed list and normalize to a canonical @graph envelope on write, except a single node, which is stored exactly as received.

1. Single node (unchanged since v3.0.0):

curl -X POST "$BASE/schema/123" -u "$CRED" \
  -H "Content-Type: application/json" \
  -d '{"schema": {"@context": "https://schema.org", "@type": "Service", "name": "Bookkeeping"}}'

2. Bare array of nodes — wrapped into a @graph envelope with @context defaulted to https://schema.org:

curl -X POST "$BASE/schema/123" -u "$CRED" \
  -H "Content-Type: application/json" \
  -d '{"schema": [
        {"@type": "Service", "name": "Bookkeeping"},
        {"@type": "BreadcrumbList", "itemListElement": []}
      ]}'

3. @graph envelope (preferred canonical form for multi-node writes):

curl -X POST "$BASE/schema/123" -u "$CRED" \
  -H "Content-Type: application/json" \
  -d '{"schema": {
        "@context": "https://schema.org",
        "@graph": [
          {"@type": "Service", "name": "Bookkeeping"},
          {"@type": "FAQPage", "mainEntity": []}
        ]
      }}'

Provider references between nodes (e.g. Service.provider -> a LocalBusiness.@id on another page) are stored verbatim — the caller is responsible for keeping @id values consistent across nodes and pages.

Optional dry_run: true validates without writing.

Errors:

  • 422 validation_failed — a node's @type isn't in the allowed list, a required field is missing, or a @graph array is empty. The errors array is per-node for multi-node payloads (e.g. schema: @graph[1] @type 'Widget' not allowed. Allowed: ...).
  • 413 validation_failed — more than 20 nodes in one graph (raise via the rrseo_schema_graph_max_nodes filter).

The wp_head emitter (priority 5) outputs whatever is stored verbatim in one `