Fix for WooCommerce schema data missing brand and mpn

Today I came across and issue where Google Search Console was complaning products “brand” and “mpn” where missing from the products schema / rich snippets data. You can checking using the rich snippet testing tool by Google found here.

https://search.google.com/structured-data/testing-tool

I fixed my issue by adding a WordPress filter using the “woocommerce_structured_data_product” filter option. This allows you to add new data to the already generated WooCommerce data.

This is an example. You will need to change for your implementation.

/*
 * Rich Snippet Data
 * Add missing data not handled by WooCommerce yet
 */
function custom_woocommerce_structured_data_product ($data) {
	global $product;
	
	$data['brand'] = $product->get_attribute('pa_manufacturer') ?? null;
	$data['mpn'] = $product->get_sku() ?? null;
	
	return $data;
}
add_filter( 'woocommerce_structured_data_product', 'custom_woocommerce_structured_data_product' );

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

39 Comments

  1. Awilkerson

    Nice, thanks, I’ll have to try this when I get time. Every little error in search console stresses me out these days so I need all the help I can get, thanks for sharing.

    • Glad it can be of help! I am the same, I have another project where it is complaining about comments / feedback not being provided so may update this code to fix that issue as well in the future.

  2. Great solution! I’m happy with using default woocommerce rich snippets. Thanks

  3. Sam

    In which theme file do I copy this code in? functions.php? header.php?

    • Code should always go into the functions.php file, you should never be adding action and hooks into any other file.

      • Sam

        Thank you. Worked like a charm. Did you find that fix for google’s warnings about products without reviews? Or should we just plainly disable reviews from our products?

        • No I never looked into it further, I do ignore them at the moment, its mainly moaning if there is no product reviews, once the product has reviews the warnings disappearing.

        • Rad little hack to fix the MPN issue…especially since I don’t have a GTIN or UPC code. Regarding the product review schema errors, the best way to fix that issue is to get reviews for your products! In the event you can’t, I suppose you could leverage the example given for the MPN code and swap it out for reviews and aggregateRatings errors you may be having. You could also manually add a review for each product from the product edit page.

          • Thanks, I think as long as you provide the reviews and aggregateRatings fields with 0 value it should remove the “warning” flag from Google. However adding manual / fake reviews againsts products I am not sure if thats the best solution, could upset people and if you have thousands of products its not ideal / quick fix.

  4. $data[‘brand’] = $product->get_attribute(‘pa_merk’) ?? null;
    $data[‘mpn’] = $product->get_sku() ?? null;
    $data[‘review’] = $product->get_wc_review_count() ?? null;
    $data[‘aggregateRating’] = $product->get_wc_average_rating() ?? null;

      • Hi!

        It fixes the errors but when later taking a closer look at the website… Not Good!
        As long as there is no price filled in with a product everything works fine but as soon as a product has a price set then it cuts off part of the website. Bsically, from where description should start there is no more code. Also no photos working.
        When price not filled in everything works.

        No idea why, too limited knowledge about coding to find out…

        • Are you running the code within the “woocommerce_structured_data_product” filter?

          If you put wordpress into debug mode, hopfully you should be able to see the PHP errors, I suspect a PHP error is being triggered.

          • When I delete my added 2 lines everything works fine with your code. (and both need to be deleted, tested each line of code individual)
            I add the 2 lines and the product has a price then wham, half website not generated.
            There were no php errors in my server logs…

          • The function names are wrong, try


            $data['review'] = $product->get_review_count() ?? null;
            $data['aggregateRating'] = $product->get_average_rating() ?? null;

          • Yeah well, site works but now Google says errors:
            0 (Google herkent de property ‘review’ niet voor een object van het type Product.)

            Google does not recognise the property “review” for an object of the type Product

          • [08-Dec-2019 16:36:58 UTC] PHP Warning: Use of undefined constant ‘review’ – assumed ‘‘review’’ (this will throw an Error in a future version of PHP) in /home/…/wordpress/wp-content/themes/storefront-child/functions.php on line 70
            [08-Dec-2019 16:36:58 UTC] PHP Warning: Use of undefined constant ‘aggregateRating’ – assumed ‘‘aggregateRating’’ (this will throw an Error in a future version of PHP) in /home/…/wordpress/wp-content/themes/storefront-child/functions.php on line 71

          • Fixed some ‘ issues, now Google says:
            0 (Er moet een waarde worden opgegeven in het veld author.)

            There must be a value assigned in the field author

  5. Hello,

    I was using your code (modified) for months and then suddent it stopped working, broke all my custom functions. I had to disable it.

    Can you please help me on this? (I tried your original code again but it didn’t work either btw)

      • Hi Shane,

        I’ve tried to apply your code again and it’s working now. My host downgraded my php version to 5.x without notifying me, maybe that was the reason of problem. Thanks anyway.

        • Weird for them to downgrade your PHP! The code uses the double question marks (“??”), which is only available in PHP 7+, this would be why you probably got errors after the PHP version was downgraded.

  6. Peter

    Nice post.

    Am I correct that these functions return null results ?

    We’re a manufacturer and trying to always set our brand to the same “name”, ie “Acme Rockets”

    We’d also like to set the MPN = SKU in each case….

    Is that possible ?

    • Hi, this code would set your MPD to SKU, if the SKU is missing it would fallback to null.

      • Peter

        Thank you Shane, how does it set Brand ?

        ‘pa_manufacturer’ is not known to me

        • Brand is not a default feature built into WooCommerce, the PA_ are attribute values, for example in that scenario I had a attribute assigned to each product called “Manufacturere”, pa_manufacturer is how you would have accessed that piece of data.

          You will need to sub that bit of code to however you are achieveing manufuacters on your site.

          • On my site we manufacture all of our own stuff so i would always want the brand to just be “HomeGrown Herbalist”

            I’m not a coder, but is there a way to modify this snippet:

            /*
            * Rich Snippet Data
            * Add missing data not handled by WooCommerce yet
            */
            function custom_woocommerce_structured_data_product ($data) {
            global $product;

            $data[‘brand’] = $product->get_attribute(‘pa_manufacturer’) ?? null;
            $data[‘mpn’] = $product->get_sku() ?? null;

            return $data;
            }
            add_filter( ‘woocommerce_structured_data_product’, ‘custom_woocommerce_structured_data_product’ );

            so that instead of returning ‘pa_manufacturer’ it would simply return the text “HomeGrown Herbalist” as the brand?

          • Hi, Update the following line

            $data[‘brand’] = $product->get_attribute(‘pa_manufacturer’) ?? null;

            to

            $data[‘brand’] = ‘HomeGrown Herbalist’;

  7. I spent a lot of time trying to find this. Thank you. This is of course exactly what I needed. Opens all the doors.
    This is the first time I have had all green in search console.
    Lonn

  8. Hello;

    If you can please help, I am here because I found the exact same issue you did. I am being told by both my SEO plugin with Yoast and Woocommerce that to fix my issue I can “pay” to have a plugin do it but to me this is not necessary because I have already added custom attributes as MPN UPC, etc. Where exactly are you adding this filter? Is this in the woocommerce template override? somewhere else? If you could please point me in the right direction that would be amazing.

    • Hi, You can add this as part of your themes function.php or wrap it into a plugin. Please make sure you use a child theme if it is not your theme, otherwise you will lose the changes when the theme is updated. Shane

  9. I would like to contribute my modifications for those who are wanting to add additional logic to determine correct GTIN(8,12,13, or 14 digit) based off in my case a single product attribute (that I call “UPC”). I am using online wordpress with woocommerce with custom attributes for Manufacturer, UPC. This filter as stated goes under my template theme functions.php; I am using a child theme

    //Add additional woocommerce product data to structured format
    /*
    * Rich Snippet Data
    * Add missing data not handled by WooCommerce yet
    */
    function custom_woocommerce_structured_data_product ($data) {
    global $product;

    $data[‘brand’] = $product->get_attribute(‘Manufacturer’) ?? null;
    $data[‘mpn’] = $product->get_sku() ?? null;

    //custom GTIN selection for gtin8, 12, 13, or 14
    //$working_gtin_len = $product->get_attribute(‘UPC’) ?? null;
    $working_gtin_name = $product->get_attribute(‘UPC’) ?? null;
    $num_length = strlen((string)$working_gtin_name);

    if ($num_length == 8){
    $data[‘gtin8’] = $product->get_attribute(‘UPC’);
    $data[‘gtin12’] = null;
    $data[‘gtin13’] = null;
    $data[‘gtin14’] = null;
    }elseif($num_length == 12){
    $data[‘gtin12’] = $product->get_attribute(‘UPC’);
    $data[‘gtin8’] = null;
    $data[‘gtin13’] = null;
    $data[‘gtin14’] = null;
    }elseif($num_length == 13){
    $data[‘gtin13’] = $product->get_attribute(‘UPC’);
    $data[‘gtin8’] = null;
    $data[‘gtin12’] = null;
    $data[‘gtin14’] = null;
    }elseif($num_length == 14){
    $data[‘gtin14’] = $product->get_attribute(‘UPC’);
    $data[‘gtin12’] = null;
    $data[‘gtin13’] = null;
    $data[‘gtin8’] = null;
    }else{
    $data[‘gtin14’] = null;
    $data[‘gtin12’] = null;
    $data[‘gtin13’] = null;
    $data[‘gtin8’] = null;
    }

    return $data;
    }
    add_filter( ‘woocommerce_structured_data_product’, ‘custom_woocommerce_structured_data_product’ );

    • Thanks for your input! A slightly modified version to so the codes a bit cleaner!

      /*
      * Rich Snippet Data
      * Add missing data not handled by WooCommerce yet
      */
      function custom_woocommerce_structured_data_product ($data) {
      global $product;

      $data[‘brand’] = $product->get_attribute(‘Manufacturer’) ?? null;
      $data[‘mpn’] = $product->get_sku() ?? null;

      // Custom GTIN selection for gtin8, 12, 13, or 14
      $upcValue = $product->get_attribute(‘UPC’) ?? null;
      $upcLength = strlen((string)$upcValue);

      // Default GTIN values
      $data[‘gtin8’] = null;
      $data[‘gtin12’] = null;
      $data[‘gtin13’] = null;
      $data[‘gtin14’] = null;

      // Set GTIN
      if ($upcLength == 8) {
      $data[‘gtin8’] = $upcValue;
      } elseif($upcLength == 12) {
      $data[‘gtin12’] = $upcValue;
      } elseif($upcLength == 13) {
      $data[‘gtin13’] = $upcValue;
      } elseif($upcLength == 14) {
      $data[‘gtin14’] = $upcValue;
      }

      return $data;
      }
      add_filter( ‘woocommerce_structured_data_product’, ‘custom_woocommerce_structured_data_product’ );

      • Yes perfect. I am mostly just dangerous with code But I know how to fumble around to make things work! I have to ask, how did you stumble upon this? I have had more than a few instances where I was jus trying to “locate” the data in general but didn’t even really know to start…. the woodommerce theme overrode? Lol. Anyways thanks for the script it does 100% of what I need; I’m tire of having to install woocomnerce plugins ! Haha

  10. Tim

    Wow! I didn’t know there was filter for this. Thank you so much. Saved me some major headaches.