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
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 type | Typical schema | Where it usually comes from |
|---|---|---|
| Home | WebSite + Organization | SEO plugin |
| Blog post | Article or BlogPosting | SEO plugin |
| Service page | Service (optional) | Custom JSON-LD or plugin custom schema |
| Contact page | LocalBusiness (optional) | Custom JSON-LD (careful with NAP consistency) |
| FAQ section | FAQPage | SEO plugin blocks or dedicated FAQ output |
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.
<?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.
Use condition rules (or WordPress conditionals like is_front_page()) so schema appears only where it is correct.
Validation Workflow
The fastest loop is:
- View the HTML source for the page
- Find the
<script type="application/ld+json">block - Validate using a structured data testing tool
On the server, you can at least confirm the JSON-LD exists:
PAGE_URL="https://example.com/"
curl -sL "$PAGE_URL" | rg -n "application/ld\+json" -n
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Multiple Organization schemas | Plugin + custom code | Keep plugin or custom, not both |
| Breadcrumb schema duplicates | Theme hook + plugin breadcrumbs | Disable one breadcrumb source |
| Missing required fields | Minimal schema object | Add required properties for that type; keep values accurate |
| Errors only on some pages | Conditional logic too broad | Tighten conditions (post type, template, taxonomy) |
Hands-On: Add Schema to a Single Service Page
Goal: add a small Service schema to exactly one page.
- Identify the page slug (e.g.,
/services/wordpress-maintenance/). - Add a conditional block in your child theme or Hook Element.
- Output JSON-LD for that page only.
- Confirm it appears only on that URL.
<?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
- Next: Accessibility Standards