Implement Product Schema in WooCommerce Without Duplicates
By Holifan, approved 2026-09-19. Drafted with AI from the sources listed below, checked against them automatically, with code examples tested, and approved by the site owner.
This guide is for WooCommerce store owners and developers who need to implement product structured data without duplicate JSON-LD. You’ll learn what WooCommerce already outputs on product pages, how to customize that markup with filters, how the Rich Snippets plugin adds other schema types, and how to verify the results.
Default Product Structured Data in WooCommerce
WooCommerce outputs structured data for products automatically on single product pages in JSON-LD format. According to Google, this markup is suitable for single product pages. The generated Product markup includes properties such as @id, name, image, description, sku, and offers.
Here is an example of the JSON-LD that WooCommerce can generate on a product page:
{
"@context": "https://schema.org/",
"@type": "Product",
"@id": "http://local.wordpress.test/product/wordpress-pennant/#product",
"name": "WordPress Pennant",
"image": "http://local.wordpress.test/wp-content/uploads/2019/02/pennant-1.jpg",
"description": "This is an external product.",
"sku": "wp-pennant",
"offers": [
{
"@type": "Offer",
"price": "11.05",
"priceSpecification": {
"price": "11.05",
"priceCurrency": "USD",
"valueAddedTaxIncluded": "true"
},
"priceCurrency": "USD",
"availability": "https://schema.org/InStock",
"url": "http://local.wordpress.test/product/wordpress-pennant/",
"seller": {
"@type": "Organization",
"name": "Test",
"url": "http://local.wordpress.test"
}
}
]
}
The @id uses the product permalink with #product appended to differentiate it from the BreadcrumbList @id. The image is included when the product has one, description uses the product’s short description (falling back to the full description) with HTML removed, and sku comes from the product’s SKU. Offers are marked up with price, currency, availability, and seller information.
WooCommerce no longer outputs product structured data on archive or category pages. Prior to version 3.5.6, limited data was sometimes output to archives; this is no longer the case because only visible data should be marked up, and archives that link out to individual pages should not be marked up. The same application/ld+json script may include breadcrumbs, products, and other relevant structured data.
Customizing Product Markup with Filters
Two filters control the markup for products:
woocommerce_structured_data_product_offermarks up prices as offers. The format of this varies depending on the product type, and the filter passes an array of data for offers.woocommerce_structured_data_productcontrols the full set of data for the product and passes an array of data.
Use woocommerce_structured_data_product to change or add values without adding a separate Product schema. The filter receives all values that will be output, so you can modify the existing $markup array.
For example, if you don’t use SKUs and want to output the product ID instead, add this code to your theme’s functions.php or a custom plugin:
add_filter( 'woocommerce_structured_data_product', function( $markup, $product ) {
$markup['sku'] = $product->get_id(); // Set sku to product id.
return $markup;
}, 10, 2 ); // 10 = priority, 2 = the callback accepts both arguments.
After adding this code, the resulting structured data includes the product ID as sku.
The WC_Structured_Data class generates product data on the woocommerce_single_product_summary hook and outputs it on wp_footer. This is how WooCommerce injects the final JSON-LD into your page. Understanding these hooks helps you debug missing or duplicated markup.
If you need to generate product data on archive pages, WooCommerce provides an action, but using it contradicts Google guidelines and can lead to duplicate or invalid markup. The code is:
add_action( 'woocommerce_shop_loop', array( wc()->structured_data, 'generate_product_data' ), 10 );
Avoid this unless you have a specific reason and understand the risks.
Using the Rich Snippets Plugin for Additional Schema Types
The WooCommerce Rich Snippets plugin adds structured data and is configured at WooCommerce > Settings > Rich Snippets. The plugin provides 9 types of schemas: organizational schema, breadcrumb list, product schema, book schema, recipe schema, carousel schema, article schema, course schema, and FAQ schema.
When you enable product schema in the plugin’s general settings, it is also enabled at the product level. Product-level schema settings take priority over general settings. This means you can override general product schema settings for individual products.
To enable product schema with the Rich Snippets plugin, go to the general settings, check the product schema option, and then adjust the individual settings such as store name, product name, description, price, SKU, availability, rating, and reviews. At the product level, the same settings are available, and those product-level values take precedence.
If you use the Rich Snippets plugin to add product schema, remember that WooCommerce core already outputs product schema on single product pages. Adding a second product schema through a plugin or custom code can create duplicate markup. Instead, use the woocommerce_structured_data_product filter described earlier to modify the core markup, or ensure the plugin’s product schema output replaces the core output and does not duplicate it.
Common Mistakes That Cause Duplicate or Invalid Markup
Follow these rules to avoid problems:
- Do not add structured data about information that is not visible to the user, even if the information is accurate.
- Do not create blank or empty pages just to hold structured data.
- Do not output product structured data on archive pages that link to individual product pages.
- Do not add a separate Product schema when WooCommerce already outputs one. Use the
woocommerce_structured_data_productfilter to modify the existing markup instead of adding a second JSON-LD block.
WooCommerce’s structured data generation hooks into woocommerce_single_product_summary and outputs on wp_footer, so any theme or plugin that duplicates those hooks can also cause duplicate markup. Check your final page source if you see more than one Product type.
How to Verify Your Product Structured Data
You can verify your structured data in several ways:
- View the page source of a product page and search for
application/ld+json. This script contains all structured data for the page, including breadcrumbs and products. The same script can contain several entities, such as aBreadcrumbListand aProduct. TwoProductnodes for the same product mean the markup is duplicated. - Test the page with the Schema Markup Validator (
https://validator.schema.org/) and Google’s Rich Results Test (https://search.google.com/test/rich-results). The comments in theWC_Structured_Datasource code recommend testing generated markup with the Schema Markup Validator and Google Search Console.
If you find duplicate Product schema, inspect the page source to see where each application/ld+json block comes from. Common sources include your theme, other plugins, or custom code. Remove or disable the extra output and rely on WooCommerce’s built-in schema, customizing it with filters as needed.
Sources
- https://github.com/woocommerce/woocommerce/wiki/Structured-data-for-products
- https://woocommerce.com/document/rich-snippets/
- https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/plugins/woocommerce/includes/class-wc-structured-data.php
- https://developers.google.com/search/docs/appearance/structured-data/product
Check your own site with the Structured Data Validator.