Skip to content

Instantly share code, notes, and snippets.

@yoanmarchal
Last active February 21, 2022 22:19
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save yoanmarchal/eeb267a08664987bf86949beafd64fe9 to your computer and use it in GitHub Desktop.
Save yoanmarchal/eeb267a08664987bf86949beafd64fe9 to your computer and use it in GitHub Desktop.
{* Structured Data Json - LD Microdata for Prestashop 1.6.X & 1.7
*
* Add this code in your smarty global.tpl/header.tpl file to show Organization, WebPage, Website and Product Microdata in ld+json format.
* Requires Prestashop 'productcomments' module for review stars ratings.
* by Ruben Divall @rubendivall http://www.rubendivall.com
* Module by @atomiksoft: https://addons.prestashop.com/en/seo-natural-search-engine-optimization/24511-microformats-in-ldjson.html
*}
<script type="application/ld+json">
{
"@context" : "http://schema.org",
"@type" : "Organization",
"name" : "{$shop_name|escape:'html':'UTF-8'}",
"url" : "{$link->getPageLink('index', true)|escape:'html':'UTF-8'}",
"logo" : {
"@type":"ImageObject",
"url":"{$logo_url|escape:'html':'UTF-8'}"
}
}
</script>
<script type="application/ld+json">
{
"@context":"http://schema.org",
"@type":"WebPage",
"isPartOf": {
"@type":"WebSite",
"url": "{$link->getPageLink('index', true)|escape:'html':'UTF-8'}",
"name": "{$shop_name|escape:'html':'UTF-8'}"
},
"name": "{$meta_title|escape:'html':'UTF-8'}",
"url": "{if isset($force_ssl) && $force_ssl}{$base_dir_ssl|escape:'html':'UTF-8'}{trim($smarty.server.REQUEST_URI,'/')|escape:'html':'UTF-8'}{else}{$base_dir|escape:'html':'UTF-8'}{trim($smarty.server.REQUEST_URI,'/')|escape:'html':'UTF-8'}{/if}"
}
</script>
{if $page_name =='index'}
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "WebSite",
"url": "{$link->getPageLink('index', true)|escape:'html':'UTF-8'}",
"image": {
"@type": "ImageObject",
"url": "{$logo_url|escape:'html':'UTF-8'}"
},
"potentialAction": {
"@type": "SearchAction",
"target": "{'--search_term_string--'|str_replace:'{search_term_string}':$link->getPageLink('search',true,null,['search_query'=>'--search_term_string--'])}",
"query-input": "required name=search_term_string"
}
}
</script>
{/if}
{if $page_name == 'product'}
<script type="application/ld+json">
{
"@context": "http://schema.org/",
"@type": "Product",
"name": "{$product->name|escape:'html':'UTF-8'}",
"description": "{$product->description_short|strip_tags|escape:'html':'UTF-8'}",
{if $product->reference}"mpn": "{$product->id|escape:'html':'UTF-8'}",{/if}
{if $product_manufacturer->name}"brand": {
"@type": "Thing",
"name": "{$product_manufacturer->name|escape:'html':'UTF-8'}"
},{/if}
{if isset($nbComments) && $nbComments && $ratings.avg}"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": "{$ratings.avg|round:1|escape:'html':'UTF-8'}",
"reviewCount": "{$nbComments|escape:'html':'UTF-8'}"
},{/if}
{if empty($combinations)}
"offers": {
"@type": "Offer",
"priceCurrency": "{$currency->iso_code|escape:'html':'UTF-8'}",
"name": "{$product->name|escape:'html':'UTF-8'}",
"price": "{$product->getPrice(true, $smarty.const.NULL, 2)|round:'2'|escape:'html':'UTF-8'}",
"image": "{$link->getImageLink($product->link_rewrite, $cover.id_image, 'home_default')|escape:'html':'UTF-8'}",
{if $product->ean13}
"gtin13": "{$product->ean13|escape:'html':'UTF-8'}",
{else if $product->upc}
"gtin13": "0{$product->upc|escape:'html':'UTF-8'}",
{/if}
"sku": "{$product->reference}",
{if $product->condition == 'new'}"itemCondition": "http://schema.org/NewCondition",{/if}
{if $product->condition == 'used'}"itemCondition": "http://schema.org/UsedCondition",{/if}
{if $product->condition == 'refurbished'}"itemCondition": "http://schema.org/RefurbishedCondition",{/if}
"availability":{if $product->quantity > 0} "http://schema.org/InStock"{else} "http://schema.org/OutOfStock"{/if},
"seller": {
"@type": "Organization",
"name": "{$shop_name|escape:'html':'UTF-8'}"
}
}
{else}
"offers": [
{foreach key=atomik item=combination from=$combinations}
{
"@type": "Offer",
"name": "{$product->name|escape:'html':'UTF-8'} - {$combination.reference}",
"priceCurrency": "{$currency->iso_code|escape:'html':'UTF-8'}",
"price": "{$combination.finalprice|round:'2'}",
"image": "{if $combination.id_image > 0}{$link->getImageLink($product->link_rewrite, $combination.id_image, 'home_default')|escape:'html':'UTF-8'}{else}{$link->getImageLink($product->link_rewrite, $cover.id_image, 'home_default')|escape:'html':'UTF-8'}{/if}",
{if $combination.ean13}
"gtin13": "{$combination.ean13|escape:'html':'UTF-8'}",
{else if $combination.upc}
"gtin13": "0{$combination.upc|escape:'html':'UTF-8'}",
{/if}
"sku": "{$combination.reference}",
{if $combination.condition == 'new'}"itemCondition": "http://schema.org/NewCondition",{/if}
{if $combination.condition == 'used'}"itemCondition": "http://schema.org/UsedCondition",{/if}
{if $combination.condition == 'refurbished'}"itemCondition": "http://schema.org/RefurbishedCondition",{/if}
"availability": {if $combination.quantity > 0}"http://schema.org/InStock"{else}"http://schema.org/OutOfStock"{/if},
"seller": {
"@type": "Organization",
"name": "{$shop_name|escape:'html':'UTF-8'}"}
} {if !$combination@last},{/if}
{/foreach}
]
{/if}
}
</script>
{/if}
{** End of Structured Data Json - LD Microdata for Prestashop 1.6.X **}
@mikesp007
Copy link

mikesp007 commented Jul 14, 2016

Hi Yoan,

This code works very nicely with prestashop 1.6.1.0, kept as a standard version. I succesfully implemented it for the product.tpl page.

However...

In the prestashop backoffice you can add GTIN-codes (ean13) to your products via two methods:

Method 1)
A general GTIN-13 number for products without attributes - via the button 'information' (eg. catalog/products/product1)

Method 2)
A specific >GTIN-13 number for products with different attributes - via the button 'combinations' (for example a stock volkswagen polo in blue or in yellow would require different Gtin number although the cars are technically identical)

Click below for a screenshot of the backoffice image for reference:

https://app.box.com/s/3ly4sn72eg530c9u7l9t26k8pbkdbn2r

When using Method 1, your json code above works like a charm, but with method 2 it fails to display any GTIN information when checking through the sdtt tool from google:

https://search.google.com/structured-data/testing-tool#url=https%3A%2F%2Fwww.mediaelectronics.com%2Fbe%2Fvloerstaande-luidspreker%2F37-klipsch-reference-premiere-rp-280f.html

The specific GTIN-codes show correctly on the pages for the users (visually) after implemeting the code which is sadly missing from Prestashop following this tutorial:

https://www.prestashop.com/forums/topic/184552-how-to-display-upc-code-on-product-page/

As a test we have added the Gtin codes to this page only, no other products were altered :
https://www.mediaelectronics.com/be/vloerstaande-luidspreker/37-klipsch-reference-premiere-rp-280f.html

You will see when clicking the color that the correct GTIN is applied and changes accordingly.

Adding microdata just to alleviate the Gtin-13 data that the above Json-ld script fails to show does not solve the problem because in Google's SDTT-tool two references of product show up instead of one that combines all data.

On another note, I see that your JSON-LD script above covers all pages (index, product.tpl) is there a reason why product-list was omitted?
Yes, we have also read that Google guidelines (https://developers.google.com/search/docs/data-types/products) specifiy that :

Use markup for a specific product, not a category or list of products. For example, “shoes in our shop” is not a specific product. See also our structured data policies for multiple entities on the same page.

However, the crawler doesn't seem to mind top pick up the relevant page as seen in the screenshot below:
https://app.box.com/s/fd0bot0ahizgdybkxvfw670vz3j4bsl4
The schema markup (in microdata) is present in the standard Prestashop product-list.tpl, and all the information that can be crawled by google on the individual products pages is also present per product on the list page.

Below find a zip file which contains our header.tpl, product.tpl and product-list.tpl as we currently use it.
https://app.box.com/s/s8pm0izv54d2pxmqr1vd9uv8j0h84v47

Could you give us directions or ammend your json-ld in order for it to work with the second GTIN method please ?

Kind regards,

Mike

@rubendivall
Copy link

Hi Yoan, there new changes at https://github.com/rubendivall/PrestaShop-SEO-Snippets/blob/master/microdata-json.tpl

Now add stock, and ean or (0+UPC as EAN) for each attribute combination.

@yoanmarchal
Copy link
Author

thanks, i had update this gist

@Mychela
Copy link

Mychela commented May 26, 2017

This code will work if I will add in Google Tag Manager as a tag?

@hakeryk2
Copy link

hakeryk2 commented Sep 27, 2018

From where did You get $combinations.finalprice? It is not available in $combinations array. Is it some modification to the ProductController.php?

Edit: Ok, I made it with editing protected function assignAttributesGroups in ProductController. I added

$combinations[$row['id_product_attribute']]['finalprice'] = Product::getPriceStatic((int)$this->product->id, true, $row['id_product_attribute'], 6, null, false, false, 1, false, null, null, null, $combination_specific_price);

after this:
$combinations[$row['id_product_attribute']]['price'] = (float)Tools::convertPriceFull($row['price'], null, Context::getContext()->currency, false);

@Marwazeinoo88
Copy link

Does it work for prestashop 1.7.3.0 Multishop mode?

@Marwazeinoo88
Copy link

Une réponse SVP ?

@Aldegunde
Copy link

Hello,

could someone help me checking if this code is working properlly on may page https://www.delica-te-zen.com/ ?
I placed exact code on the theme template but when see the html source code it appears on the top but not as HTML but the scrip coding.
Thanks in advance for confirmation. BR

@Aldegunde
Copy link

Hi all, asking for help,
Not usre why code do not works showing the brand on product pages:
https://www.delica-te-zen.com/comprar-te-verde-online/11-te-verde-templo-del-cielo.html

I understand that part of the code doing that is:

    {if $product_manufacturer->name}"brand": {
        "@type": "Thing",
        "name": "{$product_manufacturer->name|escape:'html':'UTF-8'}"
    }

But no sucess showing the brand. Shop is 1.6, any idea?

Thanks in advance. BR

@tripats
Copy link

tripats commented Sep 20, 2019

Maybe I am wrong but I noticed a lot of crawling anomalies I could not explain in webmaster tools. The problem is imo related to if for example a product is disalbled it can not load the product object therefore a "Uncaught Error: Call to a member function getPrice() on null " is thrown and google will reject the page as crawling anomaly which might be not really good after all. So be careful and habe a look at your webmaster stats if anything strange happen.

@vit2010
Copy link

vit2010 commented Sep 20, 2019

Hello Yoan.
I ask for help in upgrading this code.
Tell me how to use tag values
aggregateRating, ratingValue, reviewCount when using the gsnippetsreviev module?
With best regards, Vladimir.

@surffari
Copy link

I managed to fix all the product related structured data on a 1.7 shop after tinkering with it sometime and acquited knowledge about the schema and structured data itself.

However, I'm working on a another shop whichi has most of the products configured with 4 variants (same product, differet weight/packsize) where each combination has diffrent EAN, price etc. Took me a while to figure out why I'mnot getting the EAN code out of teh product when I realized I have to pull it from $attributesCombinations for each variant.

I put this code to the header and started debugging, Seems my Presta instance (1.7.5.0) for some reason sprinkles the combination data to $combinations and $attributesCombination. For example, the GTIN, SKU is put into the latter hence why this code by default does not find it.
Has Prestashop changed this behaviour since this code was updated or is my instance outdated compared to his code.

Also, all combinations here are defined as an Offer of one product. I'm trying to find what is the correct schema.org way to define the combinations? I found productModel which could be the answer, but has anyone figured this out?

Otherwise, this code is much cleaner solution than fixing and figuring out the microdate sprinkled all over the files by default.

@evamariamontero
Copy link

Hi guys!

Thank you for the contribution. But I added the code first to global.tpl, then to header.tpl (1.6.1.24), without effect on the search console errors related to Either "offers", "review", or "aggregateRating", "ratingCount", "reviewCount" or "ratingValue".

Any hint on how to solve it?

Thank you so much!

@yoanmarchal
Copy link
Author

i found that https://gist.github.com/sen0rxol0/1b411bccfc643dc87f551c2f8578bb94 by looking at fork of this gist

@evamariamontero
Copy link

Hi Yoan,

Thank you for your help. I followed your link and tested the modifications without effect. Everything works fine for microdata but not for ld+json, where "offers", "review", or "aggregateRating", "ratingCount", "reviewCount" or "ratingValue" errors still persist.

By the way, the Google Structured Data Testing Tool results are far away from the Google Search Console results (these are plenty of errors when the others are mostly clean).

If anyone has any idea, I'll be very happy to read it and help

@DennisSuitters
Copy link

@evamariamontero from what I was able to find, there is some suggestion to omit those parts of the Schema if there are no values to add. For e.g. if a product has no reviews, simply don't have it in the Schema. However, I have seen Google people working on the Schema implementation comment on some places, to use a null value, but I am yet to try, or see an example of how to properly add those.

@Aldegunde
Copy link

Hi all, asking for help,
Not usre why code do not works showing the brand on product pages:
https://delica-te-zen.com/te-verde/te-verde-gunpowder-templo-del-cielo

I understand that part of the code doing that is:

{if $product_manufacturer->name}"brand": {
    "@type": "Thing",
    "name": "{$product_manufacturer->name|escape:'html':'UTF-8'}"
}

But no sucess showing the brand. Shop is 1.7, any idea?

Thanks in advance. BR

@yoanmarchal
Copy link
Author

@Aldegunde is your $product_manufacturer variable is available in this context ?
is your product manufacturer is set on the back office ?
FYI i'm not sure this code is able to work on 1.7 since it's a convenient fork of code taken from

@Aldegunde
Copy link

Hi @yoanmarchal if I analyse the page on google search, there is an error on brand, but on the code I can see that content is clearly visible. Not sure why it is not shown.

<label

Thanks for oyur comments

@Aldegunde
Copy link

<meta itemprop="brand" content="Delica-Té-Zen (A)"><div class="product-manufacturer "> <label class="label">Marca</label> <span> <a href="https://delica-te-zen.com/brand/delica-te-zen-a">Delica-Té-Zen (A)</a> </span></div><div class="product-reference"> <label

@Aldegunde
Copy link

Sorry @yoanmarchal, definetly I was doing something worng, sorry for that. I was looking on worng place...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment