Support / Royal MCP Pro / SEO Audit → Fix → Report

SEO Audit → Fix → Report Workflow

End-to-end agency workflow combining wp_audit_seo_bulk (the audit) with the four *_bulk_update_meta writers (the fix), then turning the audit's structured response into a client-facing report. Designed for the recurring rhythm most agencies run monthly against every portfolio site: scan for problems, fix in bulk, verify, hand the client a summary.

When to run this workflow
  • Monthly SEO health check across a portfolio of client sites
  • Onboarding a new site — establish a baseline of what needs fixing before the first content push
  • After a site migration or theme swap — surface anything that got dropped or broken
  • Post-content-audit follow-up — you know some pages have thin content; this quantifies which ones
  • Pre-launch cleanup — pair with Site Launch Readiness to catch the on-page issues that the composer's home-page-only check doesn't cover

Prerequisites

  • Royal MCP Pro installed and licensed (see Getting Started)
  • MCP client connected to your site
  • Cap: manage_options for the audit; manage_options + per-post edit_post for the bulk fix
  • An SEO plugin (Yoast, Rank Math, SEOPress, or All in One SEO) — the audit auto-detects which one is active. If none is active the audit falls back to reading WP native fields (post_title and post_excerpt), but the bulk-fix writers require the matching plugin to be active
  • Optional: SiteVault Pro (for the snapshot: true flag on the audit call to fire a pre-audit backup)

The workflow at a glance

  1. Optional pre-audit snapshot — SiteVault backup fires before any read so you have a known-good restore point.
  2. Run wp_audit_seo_bulk — scan the target post type, paginating through if needed. Response contains per-page findings + a rollup with issues_by_type and worst_offenders.
  3. Bucket the findings by issue key — group posts by issue so each bulk-fix call touches a homogeneous batch.
  4. Dry-run the bulk fix — call the plugin-specific writer with dry_run: true first. Review the diff. Commit with the returned commit_token within 5 minutes.
  5. Re-audit — run wp_audit_seo_bulk again on the same slice. Issue counts should drop to reflect what you just fixed.
  6. Format the report — the audit's structuredContent is your report data. Ask the AI to shape it into whatever the client wants.

Steps 2–6 are all MCP calls. Nothing in this workflow requires opening wp-admin unless you want to spot-check a fix visually.

Step 1: Optional pre-audit snapshot

The audit itself is read-only, but the bulk fixes that follow are not. If you want a fresh restore point from just before this workflow started:

Run wp_audit_seo_bulk on post_type "page" with snapshot=true.

The audit response will include a sitevault_snapshot object describing what happened:

  • status: ok with via and id — SiteVault fired and returned a backup ID
  • status: skipped with message: 'SiteVault not installed — snapshot skipped, audit proceeds against live state.' — no SiteVault detected; audit still runs

Snapshot failure never aborts the audit — the audit is safe to run without one. You get informed either way.

Step 2: Run wp_audit_seo_bulk

Basic call

Run wp_audit_seo_bulk on post_type "post".

Default: 100 posts per page, page 1, rollup on. If the post type has more than 100 posts you'll need to paginate (next section).

Response shape

Abbreviated to one representative page for readability:

{
  "isError": false,
  "content": [
    { "type": "text", "text": "SEO audit — 47 post audited. Top issues: 22× description_missing, 18× title_too_short, 9× no_featured_image. SEO plugin: yoast." }
  ],
  "structuredContent": {
    "post_type": "post",
    "pagination": { "page": 1, "per_page": 100, "total_pages": 1, "total_posts": 47 },
    "seo_plugin_detected": "yoast",
    "pages": [
      {
        "post_id": 128,
        "url": "https://example.com/why-half-of-your-plugins-are-eating-your-tttf/",
        "title":       { "value": "Why half of your plugins are eating your TTFB", "length": 47, "issue": null },
        "description": { "value": "",                                                "length": 0,  "issue": "missing" },
        "noindex": false,
        "h1_count": 1,
        "word_count": 942,
        "image_count": 4,
        "images_missing_alt": 2,
        "featured_image": true,
        "issues": [ "description_missing", "2_images_missing_alt" ]
      }
      // … 46 more page objects
    ],
    "sitevault_snapshot_id": null,
    "sitevault_snapshot": { "status": "skipped", "message": "…" },
    "rollup": {
      "total_pages_audited": 47,
      "issues_by_type": {
        "description_missing":  22,
        "title_too_short":      18,
        "no_featured_image":     9,
        "images_missing_alt":    7,
        "h1_missing":            3,
        "title_missing":         2
      },
      "worst_offenders": [
        { "post_id": 128, "issue_count": 5 },
        { "post_id":  91, "issue_count": 4 }
        // … up to 10 worst offenders
      ]
    }
  },
  "undo": { "token": "…", "expires_at": "…", "ttl_hours": 168, "summary": "SEO audit — read-only, undo is a no-op" }
}
About that undo token

The audit is read-only, but the response ships an undo token anyway for API consistency (so MCP clients that always look for one don't blow up). Redeeming it resolves to a no-op. The subsequent bulk-fix calls ship real undo tokens — those are the ones that matter.

Pagination

For post types with more than 100 posts (or if you want smaller page sizes for slower servers):

Run wp_audit_seo_bulk on post_type "post" with paginate={page:1, per_page:200}.

Pagination caps: per_page minimum 1, maximum 500 (enforced by the tool regardless of what the schema minimum suggests). Loop through pagination.total_pages to cover the full portfolio.

Statuses included

The audit queries posts in these statuses: publish, draft, pending, private, future. Trashed posts are intentionally excluded — they don't appear in SEO surfaces so scoring them would inflate issue counts against posts nobody sees.

Disable the rollup

If you only want the per-page findings (no aggregate):

Run wp_audit_seo_bulk on post_type "post" with rollup=false.

Response omits the rollup key. Useful when piping into your own aggregation script.

Step 3: Bucket the findings by issue key

Each per-page object has an issues array. Group posts by which issue is on their list so the fix batches are homogeneous — all title_too_short in one call, all description_missing in the next, etc.

The full issue-key catalog

Issue keyTriggerFixable via bulk_update_meta?
title_missingBoth SEO plugin title and post_title are emptyYes — pass a title value
title_too_shortTitle length < 30 charsYes — pass a longer title
title_too_longTitle length > 60 charsYes — pass a shorter title
description_missingBoth SEO plugin description and post_excerpt are emptyYes — pass a description value
description_too_shortDescription length < 120 charsYes — pass a longer description
description_too_longDescription length > 160 charsYes — pass a shorter description
noindex_truePost is set to noindexYes — pass noindex: false (see per-plugin notes below)
h1_missingNo <h1> in post_contentNo — edit the post content in the editor
h1_multipleMore than one <h1> in post_contentNo — edit the post content
no_featured_imagePost has no featured image setNo — set via wp_set_featured_image (Free tier) after uploading media
N_images_missing_altN images in post_content lack an alt attributeNo — edit each image's alt text in the Media Library or editor

Rollup bucketing: the rollup normalizes compound keys like 3_images_missing_alt into a single images_missing_alt bucket for counting purposes. The per-page objects still show the compound version so you know how many images per post need alt text.

Length thresholds (constants)

  • Title: 30–60 chars (min TITLE_MIN, max TITLE_MAX)
  • Description: 120–160 chars (min DESC_MIN, max DESC_MAX)

These match Yoast / Rank Math / SEOPress / AIOSEO / SEObolt's own default snippet-preview ranges. Not configurable via filter as of 1.0.2.

Step 4: Bulk-fix with the SEO-plugin-specific writer

Four writers, one per supported plugin. Pick the one that matches the value in the audit's seo_plugin_detected field:

  • yoast_bulk_update_meta
  • rankmath_bulk_update_meta
  • seopress_bulk_update_meta
  • aioseo_bulk_update_meta

All four share the same argument shape, two-step commit pattern, drift detection, and 168h undo TTL. See the SEO Agency Suite reference for the full argument grammar including the 3-state field model (OMIT / null / value) that keeps you from accidentally overwriting untouched fields.

Two-step commit walkthrough

Step 4a: Dry-run to preview

Call yoast_bulk_update_meta with dry_run=true and updates=[
  { post_id: 128, description: "Half the plugins on the average WordPress site are quietly eating your TTFB. Here's how to spot them, and what to swap them for." },
  { post_id: 91,  description: "A 12-minute walkthrough on turning a slow WooCommerce cart into a sub-second checkout." }
  // … up to 100 rows per call
].

Response includes a per-row preview showing what the value would change from and to, plus a commit_token to redeem in step 4b. Nothing is written yet.

Step 4b: Commit with the returned token

Call yoast_bulk_update_meta with commit_token="{token from step 4a}".

The tool re-reads the current values of every row and compares against what they were at dry-run time. Any post whose value changed between dry-run and commit gets skipped with a drift warning (someone else edited it in that 5-minute window). The rest apply.

Commit tokens have a 5-minute TTL and are one-shot

If you take more than 5 minutes between dry-run and commit, the token expires — you'll need to re-dry-run. Tokens also can't be redeemed twice; a successful commit invalidates the token immediately.

Row cap

Each call handles up to 100 rows. For portfolio-wide fixes, chunk your buckets into calls of 100 or fewer.

The noindex quirks

SEOPress noindex has no explicit-index option

On Yoast, Rank Math, and AIOSEO, passing noindex: false explicitly sets the post to index. On SEOPress, both noindex: false and noindex: null delete the meta row (reverting to the site default). SEOPress just doesn't have a "force index" concept — if the site default is index-all, that's what you get; if it's noindex-all, you'd need to change the site default instead.

AIOSEO's dual-table quirk

AIOSEO writes to legacy post_meta AND to a custom wp_aioseo_posts table on modern versions. The writer dual-writes to keep both surfaces coherent. Posts that AIOSEO has never touched (no row in wp_aioseo_posts) surface in warnings — open them once in the AIOSEO editor first to seed a row, then re-run the bulk fix.

Step 5: Re-audit to verify

Run wp_audit_seo_bulk a second time on the same post type. Compare the two issues_by_type rollups:

Before:
  description_missing:  22
  title_too_short:      18

After (same 100-row batch fixed):
  description_missing:   0   ← fixed the 22, no new ones
  title_too_short:      18   ← untouched batch, still there

If a fixed issue count didn't drop as expected, likely causes:

  • Drift-detection skipped some rows — check the commit response's skipped array for post IDs that were touched during your 5-minute window
  • Wrong SEO plugin writer was called (audit detected Yoast, you called rankmath_bulk_update_meta) — check seo_plugin_detected in the audit response
  • A subset of your rows had a length that still hit the threshold (e.g. you set a description that's 118 chars — still under the 120-char DESC_MIN)

Step 6: Format the report

Royal MCP Pro doesn't ship a "generate a client PDF" button — the report data is the audit's structuredContent. The AI you're using is what formats it. Ask for whatever shape works for the client.

Executive summary shape

Take the two wp_audit_seo_bulk responses (before + after) and write me an
executive summary in 5 bullets for a non-technical client. Mention what
was audited, the top 3 issue types found, how many were fixed, and what's
left as a follow-up.

Punch-list shape (for the client's dev/content team)

From the after-fix audit response, list every page with remaining issues
grouped by URL. For each URL show which issues remain and what needs to
happen to close each one (edit content vs. edit meta vs. add featured image).

Trend-over-time shape (agency retention)

Log each month's issues_by_type rollup to a spreadsheet. Ask the AI to visualize the trend across 3–6 months so the client sees the graph go down over time.

The audit's plain-text content[0].text field

The audit's top-level content field always contains a single-sentence summary in the format: "SEO audit — {N} {post_type} audited. Top issues: {N× issue1, N× issue2, N× issue3}. SEO plugin: {detected}." Great as a one-line agency status update in Slack / Discord / email without any AI formatting.

Common scenarios

Monthly agency check across 20 portfolio sites

Same audit call on each site. Log issues_by_type rollups to a shared spreadsheet. The client sites where an issue count creeps up month over month are your action list.

New-site onboarding baseline

Run the audit on post and page post types (and any custom post types the site uses). The rollup is your first-month project scope. Fix the top-3 buckets in bulk, hand the client a before/after report at the end of month 1.

Post-migration cleanup

Migrations frequently lose SEO meta (theme change wipes theme-stored meta, migration tools skip custom fields, plugin swap doesn't map old-plugin keys to new-plugin keys). Run the audit right after migration; the resulting rollup shows exactly what got lost. Bulk-restore in one batch.

Thin-content follow-up

Content audit surfaces "these 40 pages have < 300 words." Cross-reference with wp_audit_seo_bulk's word_count field per page. Anything under 300 words AND with a no_featured_image or description_missing issue is a genuinely thin, un-loved page. Prioritize accordingly.

Still Stuck? Two-Step Support Path

If the audit or bulk-fix calls aren't producing what you expect, work through these two steps in order.

Step 1: Start with the Royal MCP Troubleshooting Guide

Royal MCP Troubleshooting — Start Here covers MCP-layer issues (connection, discovery, auth).

For Pro-specific patterns:

Step 2: Email priority support

If you've worked through Start Here and the relevant Pro-specific doc and the workflow still isn't working, email priority support from your purchase email address at support@royalplugins.com. Priority email support is included with your license — typical response within 24 hours. Never include your license key in email; we look it up from your purchase address.

What to include in your email
  • Your hosting provider
  • Royal MCP Pro version
  • Which SEO plugin is active + its version (the audit's seo_plugin_detected field answers this)
  • Which MCP client and how the call was phrased
  • Post type being audited + approximate total post count
  • The full audit response if you're reporting an audit issue, or the full dry-run + commit responses if you're reporting a bulk-fix issue
  • Any drift-warnings from the commit response if you're troubleshooting missed rows
  • Screenshot of the Pro tool row in Audit Log with View Details expanded