Rank Math Schema integration

SkillAI & models

Add, 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.

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

  1. Define the eligible WordPress query and authoritative data source.
  2. Inspect the graph Rank Math already generates for that query.
  3. Decide whether to extend an existing entity, add a connected entity, or remove an entity. Prefer extension over duplication.
  4. Register a narrowly scoped filter and preserve the graph on every early return.
  5. Validate semantic requirements, references, dates, URLs, and duplicate types.
  6. Compare the rendered JSON-LD with and without the integration.

Choose the correct hook

NeedHookGuidance
inspect or change the complete graphrank_math/json_lduse priority 100 after built-ins
modify a stored schema entity by typerank_math/snippet/rich_snippet_{type}_entityreceives one entity
replace Rank Math's stored type processingrank_math/snippet/rich_snippet_{type}short-circuit contract; avoid unless necessary
final post-validation cleanuprank_math/schema/validated_datapreserve an array; validation already ran
breadcrumb entity onlyrank_math/snippet/breadcrumbreturn the entity array
disable breadcrumb Schemarank_math/json_ld/breadcrumbs_enabledreturn false, scoped if needed
control taxonomy graphrank_math/snippet/remove_taxonomy_databoolean 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 @context only 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 @id when available. Do not guess /#organization if 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 only meta_key.
  • its editor stores metadata and shortcode relationships with additional semantics;
  • RankMath\Schema\DB uses 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 @id values, and resolvable internal @id references.
  • Test missing optional meta, malformed dates, password-protected posts, drafts/previews, pagination, and a different post type.
  • Check that disabling the rich-snippet module 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-compatibility for bootstrap, title, robots, canonical, social metadata, and editor analysis.
  • Use rankmath-sitemap-integration to align canonical/indexability decisions with XML sitemap entries.
  • Use wp-metadata-api if 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

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