WooCommerce product and review schema
- Schema type
ProductOfferAggregateRatingReview- Checked against
- WooCommerce 11.2.2 source code and Google Search Central product documentation, read November 2026
- Author
- The wprichsnippets.com editors
- Published
- Updated
WooCommerce prints Product markup on single product pages: name, image, SKU, price offers, stock status and, when reviews exist, an aggregate rating and up to five reviews. The usual gaps are brand, GTIN, shipping and return details. Fill them in product data or through the woocommerce_structured_data_product filter, then retest the live product URL.

01What does WooCommerce add by default?
WooCommerce rich snippets start with markup the plugin already writes. WooCommerce product schema is the Product JSON-LD that WooCommerce core generates for each single product page, printed once as a script block near the end of the page by the WC_Structured_Data class. In the WooCommerce 11.2.2 source for that class, it builds Product, Review, BreadcrumbList and WebSite data and prints it on the wp_footer hook.
For a product, the class collects these properties, as of November 2026:
name,url,description(the short description, or the full description when there is no short one) and the mainimage.sku, which falls back to the product ID when no SKU is set.gtin, only when the product's global unique ID holds 8, 12, 13 or 14 digits after non-digits are stripped.offers: a single Offer, or an AggregateOffer price range when a variable product's variations differ in price, with currency,priceValidUntil,availabilityand the shop asseller.aggregateRatingwithratingValueandreviewCount, when the product has ratings and star ratings are enabled.review: the five most recent approved reviews that carry a star rating, each with the commenter's name as the author.
If a product has no offer, no rating and no review, the class returns without printing Product markup for it. That matters for catalogue-only shops that hide prices: their product pages get breadcrumbs and little else.
02Which properties does Google want that WooCommerce leaves out?
Google documents two shopping rich results. A product snippet is the richer listing, with ratings or price, that any page about a product can earn; a merchant listing is the shopping result for a page where you sell the product yourself. Google's product snippet documentation requires a name plus one of review, aggregateRating or offers, so WooCommerce's default output meets that bar for any product with a price.
Merchant listings ask for more. The merchant listing documentation requires a name, an image and an Offer, and recommends properties such as brand.name, a GTIN, shipping details and a return policy. It also states that merchant listings need an Offer rather than an AggregateOffer, which matters for variable products whose variations have different prices.
| Property | WooCommerce default | How to fill the gap |
|---|---|---|
| name, image, offers | Printed | Keep the main product image crawlable |
| brand | Printed only when a brand term is assigned in WooCommerce Brands | Assign one brand to every product, or add it through the filter |
| gtin | Printed when the global unique ID is a valid 8, 12, 13 or 14 digit number | Enter the full barcode number for each product or variation |
| Offer on variable products | AggregateOffer when variation prices differ | Accept product snippets for the parent, or link shoppers to variation URLs |
| review author | The commenter's display name | Moderate names that are not real names |
| shippingDetails | Not printed | Add through the filter, using the values the shop shows |
| hasMerchantReturnPolicy | Not printed on the product | Add through the filter, matching the published returns page |
The brand row needs care. WooCommerce's own Brands code in version 11.2.2 adds a Brand object, taking the first brand assigned to the product, through the same Product filter WooCommerce exposes to everyone. Products without a brand term ship without one, and the merchant listing guidance asks for at most one brand name anyway.
Review authors are the quiet gap. The product snippet documentation says that if you add a review, the reviewer's name must be a valid name for a Person or Team. WooCommerce copies whatever name the commenter typed, so moderating names is a content job, not a code job.
03How do you fix the gaps without touching the theme?
A filter is a WordPress hook that lets code change a value before it is used. WooCommerce passes the finished Product array through woocommerce_structured_data_product just before storing it, so a few lines in an mu-plugin can add properties without editing templates or overriding theme files.
- Create a file such as
wp-content/mu-plugins/shop-schema.php, so the change survives theme updates and cannot be switched off by accident. - Hook a function to
woocommerce_structured_data_productthat accepts two arguments: the markup array and the product object. - Read the value you need from the product, for example a custom field with
$product->get_meta(), and add the property only when the value exists. - Return the array. Never echo from the filter; WooCommerce prints the result itself.
- Clear any page cache and retest a live product URL.
1<?php2/**3 * Plugin Name: Example shop schema additions4 * Description: Adds brand and MPN to WooCommerce Product markup.5 */67add_filter( 'woocommerce_structured_data_product', 'example_shop_schema', 30, 2 );189function example_shop_schema( $markup, $product ) {10 if ( ! $product instanceof WC_Product ) {11 return $markup;12 }1314 $mpn = $product->get_meta( 'example_mpn' );15 if ( '' !== $mpn && empty( $markup['mpn'] ) ) {16 $markup['mpn'] = sanitize_text_field( $mpn );17 }1819 if ( empty( $markup['brand'] ) ) {220 $brand = $product->get_meta( 'example_brand' );21 if ( '' !== $brand ) {22 $markup['brand'] = array(23 '@type' => 'Brand',24 'name' => sanitize_text_field( $brand ),325 );26 }27 }2829 return $markup;30}The same filter can carry shipping and return details, but only add values the shop actually publishes. Markup that promises free returns the returns page does not offer is a mismatch, whatever the test says.
If a plugin also prints Product markup, check afterwards that one Product node remains per page with one price and one rating. The schema plugin audit shows how to tell which component printed which block and how to switch the duplicate off.
04Why don't review stars show on product pages?
Review stars on a product page come from the aggregateRating WooCommerce prints when a product has ratings. Two shop settings control whether that exists: product reviews must be enabled, and star ratings on reviews must be enabled. The WooCommerce source checks wc_review_ratings_enabled() before it adds the rating.
Even with a valid rating, stars are not guaranteed. The product snippet documentation points both aggregateRating and review at Google's review snippet guidelines, so the ratings must be genuine reviews of the product on the page. Eligibility is a floor, not a promise.
One detail is worth knowing: WooCommerce marks up only the five most recent rated reviews, while a product page may display many more. The aggregate rating still covers all of them, because ratingValue is the product's average rating and reviewCount is its full review count.
The same Product node is the machine-readable summary other systems can parse, which is why the guide to product schema for rich results and AI shopping answers treats it as the foundation for shopping answers as well as rich results.
05Testing WooCommerce rich snippets
Test a live product URL, not pasted code, because WooCommerce builds the markup at request time and prints it in the footer. Run at least three kinds of product: a simple product with a price, a variable product, and a product with reviews. Each exercises a different branch of the output.
- Product snippets, and merchant listings where you sell directly, appear as detected items.
- Exactly one Product item is detected per page.
- The offer price and stock status match what the page shows.
- A GTIN appears for every product that has a barcode.
- Brand appears once, with a single name.
Our guide to testing structured data covers the Rich Results Test, the Schema Markup Validator and Search Console's Shopping reports, and how to read their warnings. For the other WordPress how-tos, start at the WordPress section, or browse the full handbook for schema types and AI answers.
06Questions
Q1Does WooCommerce add schema markup by default?
Yes. WooCommerce core prints Product JSON-LD on single product pages, plus breadcrumb and website data, as long as the product has a price, a rating or a review. You do not need a plugin for basic product snippets, but merchant listing properties such as shipping and returns are not in the default output.
Q2Why is brand missing from my WooCommerce product schema?
WooCommerce adds a brand only when the product has a term assigned in its Brands taxonomy. Assign a brand to each product, or add one from a custom field through the woocommerce_structured_data_product filter. Include at most one brand name, as Google's merchant listing documentation asks.
Q3Where does the WooCommerce GTIN come from?
From the product's global unique ID field. WooCommerce strips everything except digits and prints the value as gtin only when it is 8, 12, 13 or 14 digits long, so a mistyped or partial barcode is silently left out of the markup rather than flagged.
Q4Should I disable WooCommerce's markup when I use an SEO plugin?
Only if the plugin replaces it completely. What matters is the result: one Product node per product page with consistent price, availability and rating. Test a product URL after any change and remove whichever source duplicates the other.
07Sources
- woocommerce/includes/class-wc-structured-data.php at 11.2.2WooCommerce on GitHub
- woocommerce/includes/class-wc-brands.php at 11.2.2WooCommerce on GitHub
- Product snippet (Product, Review, Offer) structured dataGoogle Search Central
- Merchant listing (Product, Offer) structured dataGoogle Search Central



