Rank Math Schema integration
SkillAI & modelsAdd, extend, remove, or audit Schema.org JSON-LD generated by Rank Math from a third-party WordPress plugin. Use when code touches rank_math/json_ld, rank_math/schema/validated_data, rank_math/snippet/rich_snippet_*_entity, custom post types with structured data, WooCommerce Product schema extensions, entity @id links, schema duplication, or custom event, service, course, job, person, organization, FAQ, and breadcrumb entities. Covers final graph mutation, stable identifiers, entity relationships, execution order, module guards, validation, and duplicate avoidance; it does not cover XML sitemaps or general title/meta filters.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Rank Math Schema integration skill
What this skill tells your AI
The instructions your AI receives, as published by lonsdale201/wp-agent-skills in rankmath/rankmath-schema-integration/SKILL.md and read by ahel’s review.
Extend Rank Math's single JSON-LD @graph instead of printing a competing script. Preserve graph relationships, administrator-authored entities, and Rank Math's associative working keys.
Workflow
- Define the eligible WordPress query and authoritative data source.
- Inspect the graph Rank Math already generates for that query.
- Decide whether to extend an existing entity, add a connected entity, or remove an entity. Prefer extension over duplication.
- Register a narrowly scoped filter and preserve the graph on every early return.
- Validate semantic requirements, references, dates, URLs, and duplicate types.
- Compare the rendered JSON-LD with and without the integration.
Choose the correct hook
| Need | Hook | Guidance |
|---|---|---|
| inspect or change the complete graph | rank_math/json_ld | use priority 100 after built-ins |
| modify a stored schema entity by type | rank_math/snippet/rich_snippet_{type}_entity | receives one entity |
| replace Rank Math's stored type processing | rank_math/snippet/rich_snippet_{type} | short-circuit contract; avoid unless necessary |
| final post-validation cleanup | rank_math/schema/validated_data | preserve an array; validation already ran |
| breadcrumb entity only | rank_math/snippet/breadcrumb | return the entity array |
| disable breadcrumb Schema | rank_math/json_ld/breadcrumbs_enabled | return false, scoped if needed |
| control taxonomy graph | rank_math/snippet/remove_taxonomy_data | boolean plus taxonomy slug |
Rank Math collects the graph through rank_math/json_ld, validates it, applies rank_math/schema/validated_data, then serializes array_values( $data ) under one @context and @graph. Do not call array_values() in your filter: later callbacks use associative keys.
Add a connected entity
add_filter(
'rank_math/json_ld',
static function ( $data, $jsonld ) {
if ( ! is_array( $data ) || ! is_singular( 'acme_event' ) ) {
return $data;
}
$post_id = ! empty( $jsonld->post_id )
? (int) $jsonld->post_id
: get_queried_object_id();
$start = get_post_meta( $post_id, '_acme_start', true );
if ( ! $post_id || ! is_string( $start ) || '' === trim( $start ) ) {
return $data;
}
try {
$start_at = new \DateTimeImmutable( $start, wp_timezone() );
} catch ( \Exception $exception ) {
return $data;
}
$canonical = ! empty( $jsonld->parts['canonical'] )
? $jsonld->parts['canonical']
: get_permalink( $post_id );
if ( ! is_string( $canonical ) || '' === $canonical ) {
return $data;
}
$entity_id = strtok( (string) $canonical, '#' ) . '#acme-event';
$entity = [
'@type' => 'Event',
'@id' => esc_url_raw( $entity_id ),
'name' => wp_strip_all_tags( get_the_title( $post_id ) ),
'url' => esc_url_raw( (string) $canonical ),
'startDate' => $start_at->format( DATE_W3C ),
];
if ( ! empty( $data['WebPage']['@id'] ) ) {
$entity['mainEntityOfPage'] = [ '@id' => $data['WebPage']['@id'] ];
}
$data[ 'acme-event-' . $post_id ] = $entity;
return $data;
},
100,
2
);
Use a stable graph key and @id; do not use uniqid(), request time, array position, translated labels, or random UUIDs generated per render. Derive identifiers from the canonical resource and a stable fragment.
Extend an existing entity
Do not assume the associative key is Product, Article, or richSnippet. Stored schemas use keys derived from metadata IDs, and @type may be an array:
add_filter( 'rank_math/json_ld', static function ( array $data ): array {
if ( ! is_singular( 'product' ) ) {
return $data;
}
foreach ( $data as &$entity ) {
$types = isset( $entity['@type'] ) ? (array) $entity['@type'] : [];
if ( ! in_array( 'Product', $types, true ) ) {
continue;
}
$brand = get_post_meta( get_queried_object_id(), '_acme_brand', true );
if ( is_string( $brand ) && '' !== trim( $brand ) ) {
$entity['brand'] = [
'@type' => 'Brand',
'name' => wp_strip_all_tags( $brand ),
];
}
break;
}
unset( $entity );
return $data;
}, 100 );
Preserve an administrator's valid value unless the third-party plugin is explicitly authoritative. Do not add a second Product, Article, BreadcrumbList, Organization, WebSite, or WebPage merely because its expected key was not found.
Maintain graph integrity
- Add
@contextonly at the top-level output. Rank Math owns it; entities should not repeat it. - Reference entities with
['@id' => $id]; do not copy the full Organization, WebPage, Person, or ImageObject into every relation. - Reuse the actual existing entity
@idwhen available. Do not guess/#organizationif the graph says something else. - Keep URLs absolute and canonical. Strip fragments before adding your own stable fragment.
- Emit ISO 8601 dates with an explicit timezone. Reject unparseable dates instead of producing 1970 values.
- Omit unavailable optional properties. Never invent ratings, review counts, prices, availability, authors, addresses, or identifiers.
- Treat Schema.org vocabulary validity and Google rich-result eligibility as different checks. A valid Schema.org type may not qualify for a Google feature.
- Preserve zero and boolean values intentionally. Rank Math's validation removes empty strings, not every falsy value.
Respect execution order and caching
Use priority 100 on rank_math/json_ld when the integration needs the complete graph; Rank Math's entity connector runs at priority 99. Use a type-specific entity hook when only one stored entity should change.
Keep callbacks pure for the same query. Prime metadata or object caches before loops, avoid remote HTTP calls, and never perform writes from a frontend Schema filter. Full-page caches can retain old JSON-LD after source data changes; invalidate the page cache through the owning cache integration, not by disabling Rank Math Schema.
Avoid persistence traps
For runtime integration, filter the graph. Do not write rank_math_schema_* postmeta directly:
- Rank Math derives schema working keys from
meta_id, not onlymeta_key. - its editor stores metadata and shortcode relationships with additional semantics;
RankMath\Schema\DBuses static in-request caches;- direct SQL bypasses metadata caches and hooks.
If the requirement is to create editor-visible, administrator-editable persisted schemas, use the installed version's supported editor/REST workflow and test round-trip editing. Do not emulate it from inferred meta rows.
Security and privacy
- Build public Schema only from data allowed on the public page.
- Do not leak private post meta, email addresses, internal IDs, unpublished relations, capability-protected fields, or precise personal locations.
- Do not accept arbitrary caller-supplied JSON-LD and pass it through unchanged.
- Do not rely on Rank Math's final encoding as business-level validation. Validate types, URLs, dates, cardinality, and allowed properties at your boundary.
Verification
- Capture the
<script type="application/ld+json" class="rank-math-schema">block and decode it as JSON. - Assert one top-level
@context, one@graph, unique@idvalues, and resolvable internal@idreferences. - Test missing optional meta, malformed dates, password-protected posts, drafts/previews, pagination, and a different post type.
- Check that disabling the
rich-snippetmodule simply removes integration output without a fatal error. - Compare classic frontend and Rank Math headless output if headless support is enabled.
- Run a Schema.org validator and the relevant search-engine rich-result test; record warnings separately from errors.
Cross-references
- Use
rankmath-plugin-compatibilityfor bootstrap, title, robots, canonical, social metadata, and editor analysis. - Use
rankmath-sitemap-integrationto align canonical/indexability decisions with XML sitemap entries. - Use
wp-metadata-apiif the source data uses complex or multi-row WordPress metadata.
What this skill does not cover
- Rank Math PRO schema templates or PRO-only types without source and runtime verification.
- XML sitemap generation, IndexNow submission, or ranking strategy.
- Persisting undocumented Rank Math editor internals.
References
- Official documentation: https://rankmath.com/kb/filters-hooks-api-developer/
- Official documentation: https://schema.org/docs/schemas.html
- Official documentation: https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data
- Verified source paths:
includes/modules/schema/class-jsonld.phpincludes/modules/schema/class-frontend.phpincludes/modules/schema/class-db.phpincludes/modules/schema/snippets/
Signals
- GitHub stars
- 22
- Forks
- 2
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
rankmath-schema-integration- Source
- github.com/lonsdale201/wp-agent-skills