Fix for WooCommerce schema data missing brand and mpn

Fix for WooCommerce schema data missing brand and mpn

UPDATED 25/10/2021 to comply with latest google changes.

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.

Leave a Reply

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

65 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.

  11. Manish

    where I paste this code in theme editor

  12. Watkins

    This method is no longer working. Now Google won’t detect them when the fields are blank.
    The code just adds “brand”:””,”mpn”:”” at the end of schema so brand and mpn are still detected as inactive.

    • Hi, appears to still be working for me. You need to edit the code to provide the data for each field based on how your website is setup, MPN should pull from the products SKU if its set in your admin.

      As for the brand field, there is no default brand logic build into WooCommerce and in the example I use product attributes, but there is many ways you could implement brands into a woocommerce store and you will need to modify this code to pull in the data using the method you have used.

  13. Rmx

    So good, and so simple!
    Many thanks!!

  14. Hello! I would like to get brand from you plugin into Yoast structured data with hook custom_woocommerce_structured_data_product. I used to use it with regular attributs in Woocommerce and it worked: $data[‘brand’] = $product->get_attribute(‘pa_NAM_OF_ATTRIBUTE’) Can you tell me please what shouls I have to write into these brackets? Thank you

    • Hi, if you want to modify the Yoast strcuted data you will need to change the filter from “woocommerce_structured_data_product” to the relevent filter Yoast uses and then modify the function code to edit the Yoast strucutred code format, which I believe is JSON. I believe the filter is called “wpseo_json_ld_output”, you can find the Yoast SEO API here.

      https://developer.yoast.com/features/schema/api/

  15. Stanislav

    This is perfect and works like a charm! Thank you!

  16. Hi Im a startup and dont have the money to blow on GS1 BS at this point, so with Woo, Rank Math and WP I use the snippet below to get rid of this MPN warning?
    My shop pages are indexed but no reviews and this missing identifier Im know are hurting me.
    So I wanted to use the SKU as the MPN (since thats really what it is) and as Ill never be sold on Amazon etc I dont see the point for GS1 UPCs
    Please let me know as this has been bugging me for a while

    • Yes this should help, you may want to remove the $data[‘brand’] line if you are using a brand plugin or you could change this to hard coded text if you are just dealing with a single brand. Hope that is helpful.

      • Thanks Shane
        I used your snippet added Brand like the herbalist (I have a few Google doesn’t like for brand)
        did the same for reviews
        I resubmitted my site map yesterday so need to see how it works
        You are a champion, everyone’s so busy flogging their plugins for $50+ a year, you are helping us poor slobs trying to get ahead
        Will report back
        Thanks again
        Darren

      • Shane,
        Ok I put this snippet in but have pages that it still wont validate (wont get past the first 2)
        They have sku’s, https://twinspringcoupling.com/tsc300-ag/ is an example
        the sku is TSC300Ag, another is https://twinspringcoupling.com/tsc500-industrial/ which has TSC500Ind as an sku.
        This is the snippet I used, as I have the MPN error (have the brand in Rank Math also) and aggregated rating, so I have a large number of my products not listed (crawled but not indexed)
        What am I doing wrong, is the SKU not long enough? Ratings I have no idea.

        function custom_woocommerce_structured_data_product ($data) {
        global $product;

        $data[‘brand’] = ‘Twin Spring Coupling’;
        $data[‘mpn’] = $product->get_sku() ?? null;
        $data[‘review’] = $product->get_review_count() ?? null;
        $data[‘aggregateRating’] = $product->get_average_rating() ?? null;
        return $data;
        }
        add_filter( ‘woocommerce_structured_data_product’, ‘custom_woocommerce_structured_data_product’ );

      • Top Errors
        Errors can prevent your page or feature from appearing in Search results. The following errors were found on your site:
        Missing field “author”
        Missing field “ratingValue”
        Either “ratingCount” or “reviewCount” should be specified
        Top Warnings
        Warnings are suggestions for improvement. Some warnings can affect your appearance on Search; some might be reclassified as errors in the future. The following warnings were found on your site:
        Invalid value type for field “aggregateRating”
        Invalid value type for field “review”

        No idea what happened here, looks like they have changed the algorithm, Ill have to scrap this review/ratings piece and do something else

  17. Anthony

    Hi,

    I try to follow by adding your code and It works

    /*
    * Rich Snippet Data
    * Add missing Schema Not Provided by WooCommerce
    */
    function custom_woocommerce_structured_data_product ($data) {
    global $product;
    $data[‘brand’] = ‘name of company’;
    return $data;
    }
    add_filter( ‘woocommerce_structured_data_product’, ‘custom_woocommerce_structured_data_product’ );

    I’ve got an issue which tells me “Invalid object type for the “brand” field”
    Is it because I use Yoast.
    How can I fix this issue ?

    • Google have changed the structure of the brand property since I posted this, I have edited the code example to fix this issue.

      • Anthony

        Hey Shane,

        Sorry I’m not a developper. I don’t really understand.

        What do I need to change compared to what I put ?

        $data[‘brand’] = $data[‘myCompanyBrand’] ?

        thank you

        • Change line 8 to the following.

          $data[‘brand’] = $data[‘brand’] = [‘@type’ => ‘Brand’, ‘name’ => ‘My Company Brand’];

          • Anhony

            Hi Shane,

            Thank you, it works.
            I’ve got the same issue about the review, I put : $data[‘review’] = $product->get_review_count() ?? null;
            I’ve got a notice which is “Invalid object type for the “review” field”

            How to solve this issue ?
            Thank you

          • If you remove the $data[‘review’] line, WooCommerce will now add that value it self once there is real product reviews. Previously it moaned if it was missing, however know they dont like it present if its 0.

  18. Sharon

    I’ve just tried this after reading through above and all the comments as it sounded simple enough. I’ve tried with both my brand and without. But after installing the updated code above in my child theme functions.php, it is breaking my site and returning this error on the ‘brand’ line;

    An error of type E_PARSE was caused in line 34 of the file functions.php. Error message: syntax error, unexpected ‘@’, expecting ‘]’

    I’m using the free YOAST SEO plugin, so not sure if causes an issue.

  19. Hello,

    I’m wondering if the current version of the code is still valid. I added it to my functions.php file to no avail. Still getting the message:

    “No global identifier provided (e.g., gtin, mpn, isbn) (optional)”

    Here is my code:

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

    $data[‘brand’] = $data[‘brand’] = [‘@type’ => ‘Brand’, ‘name’ => ‘Victory Tractor Implements’];
    $data[‘mpn’] = $product->get_sku() ?? null;

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

    Thanks in advance

    • Have you added SKU against each of your products in WooCommerce? If you look in the raw HTML of the product page and make sure the MPN field is populated.

      • Ryan

        Yes, all products have SKUs associated with them. I ended up using a plugin called SmartCrawl Pro which was able to resolve the issue. Still not sure what the conflict was on my end with your script since it seemed to work for everyone else. Nonetheless I appreciate what you do.

  20. Hi,
    i have different values for sku and mpn because they are two different codes.
    I try to add mpn by editing your code:
    $data[‘mpn’] = $product->get_sku() ?? null;
    into
    $data[‘mpn’] = $product->get_mpn() ?? null;

    but I get “Fatal error”.

    I have MPN added to the page’s attributes and meta tags.

    I know it can be done, but it’s hard to find a specific answer from the suppliers ..
    I will be grateful for the tips.

    ps. I was about to give up this scam which is wordpress + woocommerce, but I found your help at the last moment: P
    This is the worst option for webpage anyway! If you want to learn something, do something, it’s best to do worpress format right now and their plugins!

    • The $product is part of WC_Product class (https://woocommerce.github.io/code-reference/classes/WC-Product.html), which does not contain a method called “get_mpn”. I am guessing this is a field added manually or as a part of another plugin? If that is the case it would be a meta value, so you would need to do somthing like “$product->get_meta(“_mpn”, true)”. You need to find out what the meta key is called.