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.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/* * 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' => $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' ); |
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.
Shane Rutter
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.
Deniz
Great solution! I’m happy with using default woocommerce rich snippets. Thanks
Shane Rutter
Glad it can be of help!
Sam
In which theme file do I copy this code in? functions.php? header.php?
Shane Rutter
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?
Shane Rutter
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.
Tom
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.
Shane Rutter
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.
ckhatton
This is amazing!! Thank you so much!
Shane Rutter
Glad it could help!
Pascal
$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;
Shane Rutter
Thanks I havent tested, but it looks more or less correct!
Pascal
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…
Shane Rutter
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.
Pascal
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…
Shane Rutter
The function names are wrong, try
$data['review'] = $product->get_review_count() ?? null;
$data['aggregateRating'] = $product->get_average_rating() ?? null;
Pascal
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
Pascal
[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
Pascal
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
Deniz Akay
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)
Shane Rutter
Hi, what error messages you getting in PHP logs? Can you share the code?
Deniz
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.
Shane Rutter
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.
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 ?
Shane Rutter
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
Shane Rutter
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.
Evan Jones
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?
Shane Rutter
Hi, Update the following line
$data[‘brand’] = $product->get_attribute(‘pa_manufacturer’) ?? null;
to
$data[‘brand’] = ‘HomeGrown Herbalist’;
Lonn Holiday
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
Shane Rutter
Glad it was of help!
PLC Exchange
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.
Shane Rutter
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
PLC Exchange
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’ );
Shane Rutter
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’ );
PLC Exchange
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
Tim
Wow! I didn’t know there was filter for this. Thank you so much. Saved me some major headaches.
Manish
where I paste this code in theme editor
Shane Rutter
It needs to go into your themes function.php file.
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.
Shane Rutter
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.
Rmx
So good, and so simple!
Many thanks!!
Andrej Laciak
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
Shane Rutter
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/
Stanislav
This is perfect and works like a charm! Thank you!
Darren Finch
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
Shane Rutter
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.
Darren Finch
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
Darren Finch
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’ );
Darren Finch
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
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 ?
Shane Rutter
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
Shane Rutter
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
Shane Rutter
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.
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.
Shane Rutter
This could be your PHP version, are you using 7.4+?
Ryan
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
Shane Rutter
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.
Arkadiusz
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!
Shane Rutter
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.