Claude Skill

rankmath-schema-integration

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 Prod

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download lonsdale201-wp-agent-skills-rankmath_rankmath-schema-integration-52f6020.zip · 4 KB
Part of lonsdale201/wp-agent-skills — 226 skills

Install

skills CLI npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/rankmath/rankmath-schema-integration
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
Git git clone https://github.com/Lonsdale201/wp-agent-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lonsdale201/wp-agent-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

Rank Math Schema integration

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

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 @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

Files (wp-agent-skills)
  • agents
    • openai.yaml 232 B
      interface:
        display_name: "Rank Math Schema Integration"
        short_description: "Extend Rank Math JSON-LD schema safely"
        default_prompt: "Use $rankmath-schema-integration to add or modify Rank Math JSON-LD schema for this plugin."
      
  • SKILL.md 9.6 KB
    ---
    name: rankmath-schema-integration
    description: >-
      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.
    metadata:
      wp-skills-author: "Soczó Kristóf"
      wp-skills-contact: "mailto:lonsdale201@hotmail.com"
      wp-skills-plugin: "seo-by-rank-math"
      wp-skills-plugin-version-tested: "1.0.273"
      wp-skills-wp-version-tested: "7.0.1"
      wp-skills-php-min: "7.4"
      wp-skills-last-updated: "2026-07-13"
    ---
    
    # Rank Math Schema integration
    
    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
    
    | 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
    
    ```php
    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:
    
    ```php
    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
    
    - 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.php`
      - `includes/modules/schema/class-frontend.php`
      - `includes/modules/schema/class-db.php`
      - `includes/modules/schema/snippets/`
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related