wprichsnippets
Guide · WordPress · How-tosCERT No. WP 0001

WooCommerce product and review schema

Schema type
Product Offer AggregateRating Review
Checked against
WooCommerce 11.2.2 source code and Google Search Central product documentation, read November 2026
Author
The wprichsnippets.com editors
Published
Updated
Direct answerField 01

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.

56 wordsUpdated November 8, 2026
FeatureFig. 01
A white shopping bag with a blank card clipped on and a stack of slips
WooCommerce builds one Product node per product page from data the shop already holds.

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 main image.
  • 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, availability and the shop as seller.
  • aggregateRating with ratingValue and reviewCount, 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.

WooCommerce 11.2.2 default output against Google's merchant listing properties
PropertyWooCommerce defaultHow to fill the gap
name, image, offersPrintedKeep the main product image crawlable
brandPrinted only when a brand term is assigned in WooCommerce BrandsAssign one brand to every product, or add it through the filter
gtinPrinted when the global unique ID is a valid 8, 12, 13 or 14 digit numberEnter the full barcode number for each product or variation
Offer on variable productsAggregateOffer when variation prices differAccept product snippets for the parent, or link shoppers to variation URLs
review authorThe commenter's display nameModerate names that are not real names
shippingDetailsNot printedAdd through the filter, using the values the shop shows
hasMerchantReturnPolicyNot printed on the productAdd 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.

  1. 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.
  2. Hook a function to woocommerce_structured_data_product that accepts two arguments: the markup array and the product object.
  3. 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.
  4. Return the array. Never echo from the filter; WooCommerce prints the result itself.
  5. Clear any page cache and retest a live product URL.
Example 1 · PHP: adding brand and MPN through the WooCommerce Product filterPHPDisplay only
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}
  1. 1Line 7Priority 30 runs after the WooCommerce Brands filter, which uses priority 20, so an assigned brand term wins.
  2. 2Line 19Only fills brand when WooCommerce did not already set one.
  3. 3Line 24Plain text only; the array is JSON-encoded by WooCommerce when printed.

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