Your WordPress site looks fine to a human. To Google, it's half-invisible. The difference is structured data — the microdata and JSON-LD markup that tells a search engine what each page actually is, not just what it says. That gap between "looks fine" and "is machine-readable" is where most sites leave visibility on the table. This is the checklist I run through on every WordPress build, based on what's actually paid off in Search Console over the years.
Start with the schema types that apply to you
Google's documentation covers dozens of schema.org types, but most sites only need a handful. Before touching code, match your actual page types to real schema:
- Organization or Person — homepage, once, identifying who's behind the site.
- WebSite — homepage, enables sitelinks search box eligibility.
- Article or BlogPosting — every blog post or news page.
- BreadcrumbList — every page below the homepage, matching your actual navigation path.
- Product and Review — only on real product/review pages, with real prices and real reviews.
- LocalBusiness — only if you have a physical address or service area customers visit.
Resist the urge to add every type "just in case." Google's guidelines are explicit that structured data must describe content actually present and visible on the page. Marking up data that isn't there is treated as spam, not enthusiasm.
Where to add JSON-LD in WordPress
Google supports JSON-LD, Microdata, and RDFa, but recommends JSON-LD because it lives in a single script block instead of being woven through your HTML. That means your theme's markup can change without breaking your schema. In a WordPress context, there are three practical ways to add it:
1. An SEO plugin
Fine for standard types (Article, Organization, BreadcrumbList) and the fastest way to get baseline coverage. The trade-off is limited control over edge cases and the risk of duplicate markup if you later add your own.
2. A small functions.php snippet
For anything the plugin doesn't cover well, hook into wp_head directly:
function nb_person_schema() {
if ( ! is_front_page() ) return;
$schema = array(
'@context' => 'https://schema.org',
'@type' => 'Person',
'name' => get_bloginfo( 'name' ),
'url' => home_url( '/' ),
);
echo '<script type="application/ld+json">'
. wp_json_encode( $schema )
. '</script>';
}
add_action( 'wp_head', 'nb_person_schema' );
3. Native block theme support
If you're on a full-site-editing block theme, template parts can output JSON-LD conditionally per template — useful when different post types need genuinely different schema rather than one generic block. If you're migrating into FSE specifically, I've written about the real problems you'll hit moving a static site into Full Site Editing, including how structured data fits into the new theme structure.
WooCommerce structured data: the gaps that cost you
WooCommerce outputs Product schema out of the box, but it's shallow by default — often missing brand, gtin, or a proper aggregateRating, which is the single most common reason a WooCommerce store's rich results get stripped in Search Console. If you see "structured data missing name" warnings on WooCommerce product pages, that's usually the name field not matching the visible product title, or a product with no price set. Run each product page through the Rich Results Test individually rather than trusting the bulk report. For aggregateRating, only include it if you have real reviews — Google will penalise fabricated ratings, and WooCommerce's default setup doesn't generate reviews on its own.
JSON-LD vs HTML microdata: which to use
Google recommends JSON-LD, but HTML microdata — the itemscope, itemtype, and itemprop attributes woven directly into your markup — still works and is what many older WordPress themes and plugins output. The practical difference: JSON-LD lives in <head> and is easy to audit and update; microdata is coupled to your HTML, so it breaks if the markup changes. If you're stuck with a theme that outputs microdata and can't rewrite it, don't panic — Google parses both. But if you're building fresh, use JSON-LD. Running both side by side on the same page is where duplication warnings come from, not the format choice itself.
A practical page-by-page checklist
- Homepage: Organization/Person + WebSite
- Every page: BreadcrumbList matching the real nav hierarchy
- Blog posts: Article, with
datePublished,dateModified, andauthorfilled in from real post data, not hardcoded - Shop/product pages: Product + aggregateRating, only where real reviews exist
- FAQ content: FAQPage, only if the questions are genuinely visible as content on the page
Common mistakes worth avoiding
The most frequent issue isn't missing schema, it's schema that's gone stale. Because JSON-LD lives in the page's <head>, it's easy to update the visible content and forget the structured data underneath it, which leaves you describing a page that no longer exists. The fix is boring but effective: pull schema values from the same post fields that render on the page, so they can't drift apart.
The second most common issue is duplication: a plugin outputs Organization schema, and a theme or custom snippet outputs it again. Search Console's Enhancements reports will flag this, but it's worth checking manually after any theme or plugin change.
How to verify it actually worked
Two checks, every time. Run the page through Google's Rich Results Test to confirm the markup parses and is eligible for the enhancement you're targeting, then watch the relevant report under Search Console's Enhancements section over the following days to confirm Google is picking it up at crawl time. Validation and real indexing aren't the same thing, and only the second one moves the needle.