Skip to main content

Schema Implementation

Schema is structured data that helps search engines understand what a page is (organization, article, product, FAQ) instead of guessing. In modern WordPress, the most practical format is JSON-LD placed in the page head.

The Big Rule: One Source of Truth

Most schema problems happen because multiple systems output similar JSON-LD:

  • An SEO plugin outputs Organization + WebSite + Article
  • A block plugin outputs FAQ schema
  • Custom code outputs another Organization schema
caution

Do not "stack" schema providers unless you understand exactly what each outputs. Duplicate Organization, WebSite, and BreadcrumbList types are common reasons for confusing test results.

Plugin vs Custom: A Practical Decision

flowchart TD
A[Do you need schema for standard pages/posts?] -->|Yes| B[Use an SEO plugin as primary schema source]
A -->|No, custom post types or special markup| C[Use plugin + small targeted custom JSON-LD]
B --> D[Disable any theme-level schema output]
C --> E[Add custom JSON-LD only where plugin does not cover]

Recommendation for most sites:

  • Use one SEO plugin for baseline schema
  • Add small custom schema only for special page types (e.g., LocalBusiness, Service, Course) and only if your plugin cannot represent it cleanly

What Schema Types You Will Commonly Use

Page typeTypical schemaWhere it usually comes from
HomeWebSite + OrganizationSEO plugin
Blog postArticle or BlogPostingSEO plugin
Service pageService (optional)Custom JSON-LD or plugin custom schema
Contact pageLocalBusiness (optional)Custom JSON-LD (careful with NAP consistency)
FAQ sectionFAQPageSEO plugin blocks or dedicated FAQ output
note

If you run WooCommerce, let WooCommerce + your SEO plugin handle Product schema unless you have a very specific reason to customize it.

Implementing JSON-LD in GeneratePress

GeneratePress itself is not an SEO plugin. The clean approach is to output JSON-LD using a hook that runs in the document head.

If you are using a child theme, place code in wp-content/themes/generatepress-child/functions.php.

Child theme: output Organization schema in wp_head
<?php
add_action( 'wp_head', function () {
// Example: output on the front page only.
if ( ! is_front_page() ) {
return;
}

$schema = [
'@context' => 'https://schema.org',
'@type' => 'Organization',
'name' => get_bloginfo( 'name' ),
'url' => home_url( '/' ),
];

echo "\n";
echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) . '</script>';
echo "\n";
} );

If you prefer the GeneratePress UI, you can put the same logic in a Hook Element (with PHP enabled). Treat Hook Elements like code: version them, document them, and keep them small.

tip

Use condition rules (or WordPress conditionals like is_front_page()) so schema appears only where it is correct.

Validation Workflow

The fastest loop is:

  1. View the HTML source for the page
  2. Find the <script type="application/ld+json"> block
  3. Validate using a structured data testing tool

On the server, you can at least confirm the JSON-LD exists:

Confirm JSON-LD exists on a page
PAGE_URL="https://example.com/"
curl -sL "$PAGE_URL" | rg -n "application/ld\+json" -n

Troubleshooting

SymptomLikely causeFix
Multiple Organization schemasPlugin + custom codeKeep plugin or custom, not both
Breadcrumb schema duplicatesTheme hook + plugin breadcrumbsDisable one breadcrumb source
Missing required fieldsMinimal schema objectAdd required properties for that type; keep values accurate
Errors only on some pagesConditional logic too broadTighten conditions (post type, template, taxonomy)

Hands-On: Add Schema to a Single Service Page

Goal: add a small Service schema to exactly one page.

  1. Identify the page slug (e.g., /services/wordpress-maintenance/).
  2. Add a conditional block in your child theme or Hook Element.
  3. Output JSON-LD for that page only.
  4. Confirm it appears only on that URL.
Target a specific page and output Service schema
<?php
add_action( 'wp_head', function () {
if ( ! is_page( 'wordpress-maintenance' ) ) {
return;
}

$schema = [
'@context' => 'https://schema.org',
'@type' => 'Service',
'name' => 'WordPress Maintenance',
'provider' => [
'@type' => 'Organization',
'name' => get_bloginfo( 'name' ),
'url' => home_url( '/' ),
],
'areaServed' => 'US',
];

echo "\n";
echo '<script type="application/ld+json">' . wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) . '</script>';
echo "\n";
} );

Quick Reference

  • Prefer one SEO plugin for baseline schema
  • Add custom JSON-LD only when you need it, scoped by conditions
  • Validate output and watch for duplicates

What's Next