| name | wp-audit-seo-standards |
| description | Rank Math SEO configuration reference, schema JSON-LD templates, meta patterns, and SEO seeding commands |
| user-invocable | false |
SEO Standards — Rank Math Reference
This skill defines the SEO configuration standards, schema templates, and seeding commands for WordPress sites using Rank Math SEO as the primary SEO plugin.
1. Rank Math Plugin Detection
Before running any Rank Math commands, verify the plugin is active:
$WP eval "
if (defined('RANK_MATH_VERSION')) {
echo 'Rank Math v' . RANK_MATH_VERSION . ' is active.';
} else {
echo 'Rank Math is NOT active.';
}
"
2. Rank Math Modules Reference
| Module | Slug | Recommended | Notes |
|---|
| SEO Analysis | seo-analysis | Yes | On-page content scoring |
| Sitemap | sitemap | Yes | XML sitemap generation |
| Rich Snippets | rich-snippet | Yes | JSON-LD structured data |
| Breadcrumbs | breadcrumbs | Yes | Breadcrumb trail + schema |
| 404 Monitor | 404-monitor | Yes | Track broken links |
| Redirections | redirections | Yes | 301/302 redirect manager |
| Local SEO | local-seo | Yes (business sites) | LocalBusiness schema |
| Image SEO | image-seo | Yes | Auto alt/title attributes |
| Instant Indexing | instant-indexing | Yes | IndexNow / Bing |
| Link Counter | link-counter | Yes | Internal/external link audit |
Enable All Recommended Modules
$WP eval "
\$modules = get_option('rank_math_modules', []);
\$enable = ['seo-analysis','sitemap','rich-snippet','breadcrumbs','404-monitor','redirections','local-seo','image-seo','instant-indexing','link-counter'];
foreach (\$enable as \$mod) { if (!in_array(\$mod, \$modules)) { \$modules[] = \$mod; } }
update_option('rank_math_modules', \$modules);
echo 'Enabled modules: ' . implode(', ', \$modules);
"
3. Rank Math Option Keys
| Option | Purpose |
|---|
rank_math_modules | Array of active module slugs |
rank-math-options-general | Breadcrumbs, links, image SEO, strip category base |
rank-math-options-titles | Title templates, schema type, social profiles, noindex rules |
rank-math-options-sitemap | Sitemap inclusions, ping settings |
rank-math-options-instant-indexing | IndexNow configuration |
Reading Options
$WP eval "print_r(get_option('rank-math-options-general'));"
$WP eval "print_r(get_option('rank-math-options-titles'));"
$WP eval "print_r(get_option('rank_math_modules'));"
Writing Options
Rank Math stores options as serialized arrays. Always merge rather than overwrite:
$WP eval "
\$opts = (array) get_option('rank-math-options-general', []);
\$opts['breadcrumbs'] = 'on';
\$opts['strip_category_base'] = 'on';
\$opts['nofollow_external_links'] = 'on';
\$opts['new_window_external_links'] = 'on';
\$opts['add_img_alt'] = 'on';
\$opts['add_img_title'] = 'on';
update_option('rank-math-options-general', \$opts);
echo 'General options updated.';
"
4. Rank Math Post Meta Keys
| Meta Key | Purpose | Example Value |
|---|
rank_math_title | SEO title template | %title% %sep% %sitename% |
rank_math_description | Meta description | Free text, 150-160 chars |
rank_math_focus_keyword | Focus keyword(s) | keyword1,keyword2 |
rank_math_robots | Robots directives | ["index","follow"] |
rank_math_canonical_url | Canonical URL override | https://... |
rank_math_facebook_title | OG title | Free text |
rank_math_facebook_description | OG description | Free text |
rank_math_facebook_image | OG image URL | https://... |
rank_math_facebook_image_id | OG image attachment ID | 42 |
rank_math_twitter_card_type | Twitter card type | summary_large_image |
rank_math_twitter_title | Twitter title | Free text |
rank_math_twitter_description | Twitter description | Free text |
rank_math_schema_Article | Article schema | Serialized array |
rank_math_schema_FAQPage | FAQ schema | Serialized array |
rank_math_breadcrumb_title | Breadcrumb label override | Free text |
rank_math_pillar_content | Pillar content flag | on |
Seeding Post Meta via WP-CLI
$WP eval "
\$post_id = 42;
update_post_meta(\$post_id, 'rank_math_title', '%title% %sep% %sitename%');
update_post_meta(\$post_id, 'rank_math_description', 'Your meta description here.');
update_post_meta(\$post_id, 'rank_math_focus_keyword', 'primary keyword');
update_post_meta(\$post_id, 'rank_math_robots', ['index','follow']);
update_post_meta(\$post_id, 'rank_math_twitter_card_type', 'summary_large_image');
echo 'SEO meta set for post ' . \$post_id;
"
Bulk-Seed Meta Descriptions from Content
$WP eval "
\$posts = get_posts(['post_type' => ['post','page'], 'posts_per_page' => -1, 'post_status' => 'publish']);
foreach (\$posts as \$p) {
\$existing = get_post_meta(\$p->ID, 'rank_math_description', true);
if (!empty(\$existing)) continue;
\$text = wp_strip_all_tags(\$p->post_excerpt ?: \$p->post_content);
\$desc = mb_substr(trim(preg_replace('/\s+/', ' ', \$text)), 0, 155);
if (mb_strlen(\$desc) > 10) {
update_post_meta(\$p->ID, 'rank_math_description', \$desc);
echo 'Set description for: ' . \$p->post_title . PHP_EOL;
}
}
"
5. Schema JSON-LD Templates
Organization
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "",
"url": "",
"logo": {
"@type": "ImageObject",
"url": ""
},
"sameAs": [
"https://www.facebook.com/PROFILE",
"https://www.instagram.com/PROFILE",
"https://x.com/PROFILE",
"https://www.linkedin.com/company/PROFILE"
]
}
LocalBusiness
{
"@context": "https://schema.org",
"@type": "LocalBusiness",
"name": "",
"url": "",
"image": "",
"telephone": "",
"email": "",
"address": {
"@type": "PostalAddress",
"streetAddress": "",
"addressLocality": "",
"addressRegion": "",
"postalCode": "",
"addressCountry": ""
},
"geo": {
"@type": "GeoCoordinates",
"latitude": "",
"longitude": ""
},
"openingHoursSpecification": [
{
"@type": "OpeningHoursSpecification",
"dayOfWeek": ["Monday","Tuesday","Wednesday","Thursday","Friday"],
"opens": "09:00",
"closes": "17:00"
}
],
"sameAs": []
}
FAQPage
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "What is the question?",
"acceptedAnswer": {
"@type": "Answer",
"text": "The answer to the question."
}
},
{
"@type": "Question",
"name": "Another question?",
"acceptedAnswer": {
"@type": "Answer",
"text": "Another answer."
}
}
]
}
BreadcrumbList
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Home",
"item": "https://example.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "Category",
"item": "https://example.com/category/"
},
{
"@type": "ListItem",
"position": 3,
"name": "Current Page"
}
]
}
Article
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "",
"author": {
"@type": "Person",
"name": "",
"url": ""
},
"datePublished": "2025-01-01T00:00:00+00:00",
"dateModified": "2025-01-01T00:00:00+00:00",
"image": {
"@type": "ImageObject",
"url": "",
"width": 1200,
"height": 630
},
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://example.com/post-slug/"
},
"publisher": {
"@type": "Organization",
"name": "",
"logo": {
"@type": "ImageObject",
"url": ""
}
}
}
6. Meta Title Formulas by Page Type
| Page Type | Formula |
|---|
| Homepage | %sitename% %sep% %sitedesc% |
| Page | %title% %sep% %sitename% |
| Blog Post | %title% %sep% %sitename% |
| Category | %term% %sep% %sitename% %page% |
| Search | Search: %searchphrase% %sep% %sitename% |
| 404 | Page Not Found %sep% %sitename% |
| Author | %name% %sep% %sitename% |
Available Variables
%title% — Post/page title
%sitename% — Site name from Settings > General
%sitedesc% — Site tagline
%sep% — Separator character (default: -)
%term% — Category/tag name
%searchphrase% — Current search query
%page% — Page number (blank on page 1)
%name% — Author display name
%date% — Post publication date
%excerpt% — Post excerpt
Seed Title Templates via WP-CLI
$WP eval "
\$opts = (array) get_option('rank-math-options-titles', []);
\$opts['homepage_title'] = '%sitename% %sep% %sitedesc%';
\$opts['pt_post_title'] = '%title% %sep% %sitename%';
\$opts['pt_page_title'] = '%title% %sep% %sitename%';
\$opts['tax_category_title'] = '%term% %sep% %sitename% %page%';
\$opts['search_title'] = 'Search: %searchphrase% %sep% %sitename%';
\$opts['404_title'] = 'Page Not Found %sep% %sitename%';
\$opts['author_archive_title'] = '%name% %sep% %sitename%';
update_option('rank-math-options-titles', \$opts);
echo 'Title templates updated.';
"
7. Meta Description Generation
Priority Order
- Manual —
rank_math_description post meta (highest priority)
- Excerpt — Post excerpt if set
- First paragraph — First
<p> block in post content
- Trimmed content — First 155 characters of stripped content
Target length: 150–160 characters.
Auto-Generate Description Function
function prefix_auto_meta_description( $post_id ) {
$existing = get_post_meta( $post_id, 'rank_math_description', true );
if ( ! empty( $existing ) ) {
return $existing;
}
$post = get_post( $post_id );
if ( ! $post ) {
return '';
}
if ( ! empty( $post->post_excerpt ) ) {
$text = $post->post_excerpt;
} else {
$content = $post->post_content;
if ( preg_match( '/<p[^>]*>(.*?)<\/p>/is', $content, $matches ) ) {
$text = $matches[1];
} else {
$text = $content;
}
}
$text = wp_strip_all_tags( $text );
$text = trim( preg_replace( '/\s+/', ' ', $text ) );
$desc = mb_substr( $text, 0, 155 );
if ( mb_strlen( $text ) > 155 ) {
$desc = mb_substr( $desc, 0, mb_strrpos( $desc, ' ' ) );
$desc .= '...';
}
return $desc;
}
Bulk Seed via WP-CLI
$WP eval "
\$posts = get_posts(['post_type' => ['post','page'], 'posts_per_page' => -1, 'post_status' => 'publish']);
\$count = 0;
foreach (\$posts as \$p) {
\$existing = get_post_meta(\$p->ID, 'rank_math_description', true);
if (!empty(\$existing)) continue;
\$text = wp_strip_all_tags(\$p->post_excerpt ?: \$p->post_content);
\$text = trim(preg_replace('/\s+/', ' ', \$text));
\$desc = mb_substr(\$text, 0, 155);
if (mb_strlen(\$text) > 155) {
\$desc = mb_substr(\$desc, 0, mb_strrpos(\$desc, ' '));
}
if (mb_strlen(\$desc) > 10) {
update_post_meta(\$p->ID, 'rank_math_description', \$desc);
\$count++;
}
}
echo \"Seeded \$count meta descriptions.\";
"
8. llms.txt Template
# {Site Name}
> {Site Description}
## Pages
- [Page Title](url): excerpt or first 20 words
## Blog Posts
- [Post Title](url): excerpt
## Contact
- Website: {home_url}
Generate llms.txt via WP-CLI
$WP eval "
\$name = get_bloginfo('name');
\$desc = get_bloginfo('description');
\$home = home_url('/');
\$out = \"# \$name\n\n> \$desc\n\n\";
// Pages
\$out .= \"## Pages\n\";
\$pages = get_posts(['post_type' => 'page', 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'menu_order', 'order' => 'ASC']);
foreach (\$pages as \$p) {
\$url = get_permalink(\$p->ID);
\$excerpt = \$p->post_excerpt ?: wp_trim_words(wp_strip_all_tags(\$p->post_content), 20, '...');
\$out .= \"- [\$p->post_title](\$url): \$excerpt\n\";
}
// Blog posts
\$out .= \"\n## Blog Posts\n\";
\$posts = get_posts(['post_type' => 'post', 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'date', 'order' => 'DESC']);
foreach (\$posts as \$p) {
\$url = get_permalink(\$p->ID);
\$excerpt = \$p->post_excerpt ?: wp_trim_words(wp_strip_all_tags(\$p->post_content), 20, '...');
\$out .= \"- [\$p->post_title](\$url): \$excerpt\n\";
}
// Contact
\$out .= \"\n## Contact\n\";
\$out .= \"- Website: \$home\n\";
file_put_contents(ABSPATH . 'llms.txt', \$out);
echo 'Generated llms.txt at ' . ABSPATH . 'llms.txt';
echo PHP_EOL . '---' . PHP_EOL . \$out;
"
9. robots.txt Template
# robots.txt for WordPress
User-agent: *
Allow: /
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php
Disallow: /wp-includes/
Disallow: /wp-content/plugins/
Disallow: /readme.html
Disallow: /license.txt
Disallow: /?s=
Disallow: /search/
Disallow: /cgi-bin/
Disallow: /trackback/
# AI Crawlers — Allow by default (confirm with user before changing)
User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: CCBot
Allow: /
User-agent: Bytespider
Disallow: /
# Sitemap
Sitemap: {home_url}/sitemap_index.xml
Note: AI crawler policy (Allow vs Disallow) should be confirmed with the site owner before writing. The defaults above allow all major AI crawlers except Bytespider.
Generate robots.txt via WP-CLI
$WP eval "
\$home = home_url('/');
\$robots = 'User-agent: *
Allow: /
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php
Disallow: /wp-includes/
Disallow: /wp-content/plugins/
Disallow: /readme.html
Disallow: /license.txt
Disallow: /?s=
Disallow: /search/
Disallow: /cgi-bin/
Disallow: /trackback/
# AI Crawlers
User-agent: GPTBot
Allow: /
User-agent: ClaudeBot
Allow: /
User-agent: Google-Extended
Allow: /
User-agent: PerplexityBot
Allow: /
User-agent: CCBot
Allow: /
User-agent: Bytespider
Disallow: /
Sitemap: ' . \$home . 'sitemap_index.xml
';
file_put_contents(ABSPATH . 'robots.txt', \$robots);
echo 'Generated robots.txt at ' . ABSPATH . 'robots.txt';
"
10. Breadcrumb Integration Code
PHP Function
function prefix_breadcrumbs() {
if (is_front_page()) return;
echo '<nav class="breadcrumbs" aria-label="Breadcrumb">';
if (function_exists('rank_math_the_breadcrumbs')) {
rank_math_the_breadcrumbs();
} else {
echo '<a href="' . esc_url(home_url('/')) . '">Home</a>';
echo ' » ';
if (is_singular()) { the_title(); }
elseif (is_archive()) { the_archive_title(); }
elseif (is_search()) { echo 'Search results'; }
elseif (is_404()) { echo 'Page Not Found'; }
}
echo '</nav>';
}
Breadcrumb CSS
.breadcrumbs {
padding: 12px 0;
font-size: 0.875rem;
color: #6b7280;
}
.breadcrumbs a {
color: #3b82f6;
text-decoration: none;
}
.breadcrumbs a:hover {
text-decoration: underline;
}
.breadcrumbs .separator {
margin: 0 0.5rem;
color: #9ca3af;
}
Enable Breadcrumbs in Rank Math
$WP eval "
\$opts = (array) get_option('rank-math-options-general', []);
\$opts['breadcrumbs'] = 'on';
update_option('rank-math-options-general', \$opts);
echo 'Breadcrumbs enabled.';
"
11. FAQ Detection Patterns
FAQ content can appear in several forms. Detect and convert to JSON-LD schema automatically.
Detection Sources
- ACF repeater fields — field names:
faq_items, faqs, faq_cards, faq
<details>/<summary> HTML — accordion-style FAQ in content
- H2/H3 headings ending with
? — followed by <p> answer content
FAQ Auto-Detection and JSON-LD Generator
function prefix_detect_faq_jsonld( $post_id ) {
$faqs = [];
$acf_names = ['faq_items', 'faqs', 'faq_cards', 'faq'];
foreach ( $acf_names as $field_name ) {
if ( function_exists('have_rows') && have_rows( $field_name, $post_id ) ) {
while ( have_rows( $field_name, $post_id ) ) {
the_row();
$q = get_sub_field('question') ?: get_sub_field('title');
$a = get_sub_field('answer') ?: get_sub_field('content') ?: get_sub_field('text');
if ( $q && $a ) {
$faqs[] = [ 'q' => wp_strip_all_tags($q), 'a' => wp_strip_all_tags($a) ];
}
}
}
}
$content = get_post_field('post_content', $post_id);
if ( preg_match_all('/<summary[^>]*>(.*?)<\/summary>\s*(.*?)<\/details>/is', $content, $matches, PREG_SET_ORDER) ) {
foreach ( $matches as $m ) {
$q = wp_strip_all_tags( $m[1] );
$a = wp_strip_all_tags( $m[2] );
if ( $q && $a ) {
$faqs[] = [ 'q' => $q, 'a' => $a ];
}
}
}
if ( preg_match_all('/<h[23][^>]*>(.*?\?)<\/h[23]>\s*<p>(.*?)<\/p>/is', $content, $matches, PREG_SET_ORDER) ) {
foreach ( $matches as $m ) {
$q = wp_strip_all_tags( $m[1] );
$a = wp_strip_all_tags( $m[2] );
if ( $q && $a ) {
$faqs[] = [ 'q' => $q, 'a' => $a ];
}
}
}
if ( empty( $faqs ) ) {
return '';
}
$schema = [
'@context' => 'https://schema.org',
'@type' => 'FAQPage',
'mainEntity' => [],
];
foreach ( $faqs as $faq ) {
$schema['mainEntity'][] = [
'@type' => 'Question',
'name' => $faq['q'],
'acceptedAnswer' => [
'@type' => 'Answer',
'text' => $faq['a'],
],
];
}
return '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT ) . '</script>';
}
Inject FAQ Schema into Head
add_action('wp_head', function() {
if ( is_singular() ) {
$jsonld = prefix_detect_faq_jsonld( get_the_ID() );
if ( $jsonld ) {
echo $jsonld;
}
}
});
12. SEO Seeding Sequence
Recommended order for bulk SEO setup on a new or existing site:
- Install + activate Rank Math —
$WP plugin install seo-by-rank-math --activate
- Enable modules — activate all recommended modules (Section 2)
- Configure general settings — breadcrumbs, link behavior, image SEO (Section 3)
- Configure title templates — set formulas per page type (Section 6)
- Configure sitemap — set post types and taxonomies to include
- Set Organization / LocalBusiness schema — configure site-wide schema (Section 5)
- Configure OG / Social defaults — set default OG image, social profiles
- Enable IndexNow — activate instant indexing for Bing / Yandex
- Seed per-page SEO meta —
rank_math_title, rank_math_focus_keyword, robots (Section 4)
- Seed meta descriptions — auto-generate from excerpt/content (Section 7)
- Set image alt texts — bulk update missing alt attributes
- Generate robots.txt — write optimized robots.txt (Section 9)
- Generate llms.txt — write AI-readable site summary (Section 8)
- Flush sitemap cache + rewrite rules — finalize:
$WP eval "
if (class_exists('RankMath')) {
// Trigger sitemap regeneration
delete_transient('rank_math_sitemap_cache');
\RankMath\Sitemap\Cache::invalidate_storage();
}
"
$WP rewrite flush
Verification Checklist
After seeding, verify:
$WP eval "print_r(get_option('rank-math-options-titles'));"
$WP eval "
global \$wpdb;
\$count = \$wpdb->get_var(\"SELECT COUNT(*) FROM \$wpdb->postmeta WHERE meta_key = 'rank_math_description' AND meta_value != ''\");
echo \"Posts with meta descriptions: \$count\";
"
$WP eval "echo home_url('/sitemap_index.xml');"
$WP eval "echo file_exists(ABSPATH . 'robots.txt') ? 'robots.txt exists' : 'robots.txt missing';"
$WP eval "echo file_exists(ABSPATH . 'llms.txt') ? 'llms.txt exists' : 'llms.txt missing';"