Add Google Rich Snippets Breadcrumbs to Prestashop

In this tutorial we will see how to add Google Rich Snippets Breadcrumbs to a Prestashop website, by modifying a small portion of the template and using a lightweight override.

  • Version used: Prestashop 1.5.6.2

Two types of markup

Google supports the following types of data for the breadcrumbs rich snippets:

  • Microdata
  • RDFa

Microdata is the one we used in the previous tutorial on how to add Google Rich Snippets to your Prestashop store, and the basic markup consists in adding itemprops and scopes to single html entities

On the other hand, RDFa adds a set of attributes and extensions to html using xml properties. You can read more about it here: RDFa Wiki.

I will use the latter in this demonstration, but either will do, so feel free to use the one you prefer in the end. You can visit the official Google Documentation on Breadcrumbs Rich Snippets if you want to get more info about the implementation.

Adding Google Rich Snippets Breadcrumbs to Prestashop – The tpl

First things first, we must hardcode a small portion of code inside breadcrumb.tpl. Open up the file located in your theme’s folder. It will look approximately like this (default theme):

<!-- Breadcrumb -->
{if isset($smarty.capture.path)}{assign var='path' value=$smarty.capture.path}{/if}
<div class="breadcrumb">
	<a href="{$base_dir}" title="{l s='Return to Home'}"><img src="{$img_dir}icon/home.gif" height="26" width="26" alt="{l s='Home'}" /></a>
	{if isset($path) AND $path}
		<span class="navigation-pipe" {if isset($category) && isset($category->id_category) && $category->id_category == 1}style="display:none;"{/if}>{$navigationPipe|escape:html:'UTF-8'}</span>
		{if !$path|strpos:'span'}
			<span class="navigation_page">{$path}</span>
		{else}
			{$path}
		{/if}
	{/if}
</div>
<!-- /Breadcrumb -->

Edit as follows:

<!-- Breadcrumb -->
{if isset($smarty.capture.path)}{assign var='path' value=$smarty.capture.path}{/if}
<div class="breadcrumb" xmlns:v="http://rdf.data-vocabulary.org/#">
	<span typeof="v:Breadcrumb"><a href="{$base_dir}" rel="v:url" property="v:title" title="{l s='Return to Home'}"><img src="{$img_dir}icon/home.gif" height="26" width="26" alt="{l s='Home'}" /></a></span>
	{if isset($path) AND $path}
		<span class="navigation-pipe" {if isset($category) && isset($category->id_category) && $category->id_category == 1}style="display:none;"{/if}>{$navigationPipe|escape:html:'UTF-8'}</span>
		{if !$path|strpos:'span'}
			<span typeof="v:Breadcrumb">
				<span property="v:title" class="navigation_page">{$path}</span>
			</span>
		{else}
			{$path}
		{/if}
	{/if}
</div>
<!-- /Breadcrumb -->

Explanation: First, we told Google that the .breadcrumb div is our breadcrumb container. Then, we added a span around the homepage link, with typeof=”v:Breadcrumb” so that it know it’s dealing with part of the breadcrumb. Lastly, we added a rel and property attribute to the link pointing to the homepage. Then, we added the breadcrumb object and title property to the last item

At this point, we must use an override as Prestashop builds breadcrumbs in the Tools::getPath() method!

Adding Google Rich Snippets Breadcrumbs to Prestashop – The override

Create a new override in override/classes and call it Tools.php. Add some regular override markup inside:


class Tools extends ToolsCore
{

}

We need to override the getPath method, so open the original Tools.php class file that you find in your classes/ directory, copy the whole getPath() method, and paste it inside the new override as follows:


class Tools extends ToolsCore
{
	public static function getPath($id_category, $path = '', $link_on_the_item = false, $category_type = 'products', Context $context = null)
	{
		if (!$context)
			$context = Context::getContext();

		$id_category = (int)$id_category;
		if ($id_category == 1)
			return '<span class="navigation_end">'.$path.'</span>';

		$pipe = Configuration::get('PS_NAVIGATION_PIPE');
		if (empty($pipe))
			$pipe = '>';

		$full_path = '';
		if ($category_type === 'products')
		{
			$interval = Category::getInterval($id_category);
			$id_root_category = $context->shop->getCategory();
			$interval_root = Category::getInterval($id_root_category);
			if ($interval)
			{
				$sql = 'SELECT c.id_category, cl.name, cl.link_rewrite
						FROM '._DB_PREFIX_.'category c
						LEFT JOIN '._DB_PREFIX_.'category_lang cl ON (cl.id_category = c.id_category'.Shop::addSqlRestrictionOnLang('cl').')
						WHERE c.nleft <= '.$interval['nleft'].'
							AND c.nright >= '.$interval['nright'].'
							AND c.nleft >= '.$interval_root['nleft'].'
							AND c.nright <= '.$interval_root['nright'].'
							AND cl.id_lang = '.(int)$context->language->id.'
							AND c.active = 1
							AND c.level_depth > '.(int)$interval_root['level_depth'].'
						ORDER BY c.level_depth ASC';
				$categories = Db::getInstance()->executeS($sql);

				$n = 1;
				$n_categories = count($categories);
				foreach ($categories as $category)
				{
					$full_path .=
					(($n < $n_categories || $link_on_the_item) ? '<a href="'.Tools::safeOutput($context->link->getCategoryLink((int)$category['id_category'], $category['link_rewrite'])).'" title="'.htmlentities($category['name'], ENT_NOQUOTES, 'UTF-8').'">' : '').
					htmlentities($category['name'], ENT_NOQUOTES, 'UTF-8').
					(($n < $n_categories || $link_on_the_item) ? '</a>' : '').
					(($n++ != $n_categories || !empty($path)) ? '<span class="navigation-pipe">'.$pipe.'</span>' : '');
				}

				return $full_path.$path;
			}
		}
		else if ($category_type === 'CMS')
		{
			$category = new CMSCategory($id_category, $context->language->id);
			if (!Validate::isLoadedObject($category))
				die(Tools::displayError());
			$category_link = $context->link->getCMSCategoryLink($category);

			if ($path != $category->name)
				$full_path .= '<a href="'.Tools::safeOutput($category_link).'">'.htmlentities($category->name, ENT_NOQUOTES, 'UTF-8').'</a><span class="navigation-pipe">'.$pipe.'</span>'.$path;
			else
				$full_path = ($link_on_the_item ? '<a href="'.Tools::safeOutput($category_link).'">' : '').htmlentities($path, ENT_NOQUOTES, 'UTF-8').($link_on_the_item ? '</a>' : '');

			return Tools::getPath($category->id_parent, $full_path, $link_on_the_item, $category_type);
		}
	}
}

We can now modify the code snippets that generate links. First off, locate:

		if (!$context)
			$context = Context::getContext();

Right after it, add

	$path = '<span typeof="v:Breadcrumb"><span property="v:title">'.$path.'</span></span>';

This way we label the current page name as title in the breadcrumbs. Then:

					$full_path .=
					(($n < $n_categories || $link_on_the_item) ? '<a href="'.Tools::safeOutput($context->link->getCategoryLink((int)$category['id_category'], $category['link_rewrite'])).'" title="'.htmlentities($category['name'], ENT_NOQUOTES, 'UTF-8').'">' : '').
					htmlentities($category['name'], ENT_NOQUOTES, 'UTF-8').
					(($n < $n_categories || $link_on_the_item) ? '</a>' : '').

Edit as follows

					$full_path .=
					(($n < $n_categories || $link_on_the_item) ? '<span typeof="v:Breadcrumb"> <a rel="v:url" property="v:title" href="'.Tools::safeOutput($context->link->getCategoryLink((int)$category['id_category'], $category['link_rewrite'])).'" title="'.htmlentities($category['name'], ENT_NOQUOTES, 'UTF-8').'">' : '').
					htmlentities($category['name'], ENT_NOQUOTES, 'UTF-8').
					(($n < $n_categories || $link_on_the_item) ? '</a> </span>' : '').

Explanation: as we did previously, we added a span around the link, and assigned a rel and property attributes to the inner link. Remember to close the span at the end!.

Lastly, let’s account for cms pages as well, find:

			if ($path != $category->name)
				$full_path .= '<a href="'.Tools::safeOutput($category_link).'">'.htmlentities($category->name, ENT_NOQUOTES, 'UTF-8').'</a><span class="navigation-pipe">'.$pipe.'</span>'.$path;
			else
				$full_path = ($link_on_the_item ? '<a href="'.Tools::safeOutput($category_link).'">' : '').htmlentities($path, ENT_NOQUOTES, 'UTF-8').($link_on_the_item ? '</a>' : '');

And change it to:

			if ($path != $category->name)
				$full_path .= '<span typeof="v:Breadcrumb"> <a rel="v:url" property="v:title" href="'.Tools::safeOutput($category_link).'">'.htmlentities($category->name, ENT_NOQUOTES, 'UTF-8').'</a> </span> <span class="navigation-pipe"> '.$pipe.' </span> '.$path;
			else
				$full_path = ($link_on_the_item ? '<span typeof="v:Breadcrumb"> <a rel="v:url" property="v:title"  <a href="'.Tools::safeOutput($category_link).'">' : '').htmlentities($path, ENT_NOQUOTES, 'UTF-8').($link_on_the_item ? '</a> <span>' : '');

We are done! Save, clear smarty cache/force compile so that changes take effect, then go to cache/ and erase class_index.php so that the override can take place!

The final override:


class Tools extends ToolsCore
{

	public static function getPath($id_category, $path = '', $link_on_the_item = false, $category_type = 'products', Context $context = null)
	{
		if (!$context)
			$context = Context::getContext();

		$path = '<span typeof="v:Breadcrumb"><span property="v:title">'.$path.'</span></span>';

		$id_category = (int)$id_category;
		if ($id_category == 1)
			return '<span class="navigation_end">'.$path.'</span>';

		$pipe = Configuration::get('PS_NAVIGATION_PIPE');
		if (empty($pipe))
			$pipe = '>';

		$full_path = '';
		if ($category_type === 'products')
		{
			$interval = Category::getInterval($id_category);
			$id_root_category = $context->shop->getCategory();
			$interval_root = Category::getInterval($id_root_category);
			if ($interval)
			{
				$sql = 'SELECT c.id_category, cl.name, cl.link_rewrite
						FROM '._DB_PREFIX_.'category c
						LEFT JOIN '._DB_PREFIX_.'category_lang cl ON (cl.id_category = c.id_category'.Shop::addSqlRestrictionOnLang('cl').')
						WHERE c.nleft <= '.$interval['nleft'].'
							AND c.nright >= '.$interval['nright'].'
							AND c.nleft >= '.$interval_root['nleft'].'
							AND c.nright <= '.$interval_root['nright'].'
							AND cl.id_lang = '.(int)$context->language->id.'
							AND c.active = 1
							AND c.level_depth > '.(int)$interval_root['level_depth'].'
						ORDER BY c.level_depth ASC';
				$categories = Db::getInstance()->executeS($sql);

				$n = 1;
				$n_categories = count($categories);
				foreach ($categories as $category)
				{
					$full_path .=
					(($n < $n_categories || $link_on_the_item) ? '<span typeof="v:Breadcrumb"> <a rel="v:url" property="v:title" href="'.Tools::safeOutput($context->link->getCategoryLink((int)$category['id_category'], $category['link_rewrite'])).'" title="'.htmlentities($category['name'], ENT_NOQUOTES, 'UTF-8').'">' : '').
					htmlentities($category['name'], ENT_NOQUOTES, 'UTF-8').
					(($n < $n_categories || $link_on_the_item) ? '</a> </span>' : '').
					(($n++ != $n_categories || !empty($path)) ? ' <span class="navigation-pipe"> '.$pipe.' </span> ' : '');
				}

				return $full_path.$path;
			}
		}
		else if ($category_type === 'CMS')
		{
			$category = new CMSCategory($id_category, $context->language->id);
			if (!Validate::isLoadedObject($category))
				die(Tools::displayError());
			$category_link = $context->link->getCMSCategoryLink($category);

			if ($path != $category->name)
				$full_path .= '<span typeof="v:Breadcrumb"> <a rel="v:url" property="v:title" href="'.Tools::safeOutput($category_link).'">'.htmlentities($category->name, ENT_NOQUOTES, 'UTF-8').'</a> </span> <span class="navigation-pipe"> '.$pipe.' </span> '.$path;
			else
				$full_path = ($link_on_the_item ? '<span typeof="v:Breadcrumb"> <a rel="v:url" property="v:title"  <a href="'.Tools::safeOutput($category_link).'">' : '').htmlentities($path, ENT_NOQUOTES, 'UTF-8').($link_on_the_item ? '</a> <span>' : '');

			return Tools::getPath($category->id_parent, $full_path, $link_on_the_item, $category_type);
		}
	}

}

Time to test your page now! Here is one from my Prestashop modules store: Prestashop SEO Booster example

Need Prestashop Modules? Have a look at my Prestashop Addons Store!

Looking for quality PrestaShop Web Hosting? Look no further than Arvixe Web Hosting!

Tags: , , , , , , , , , , | Posted under PrestaShop | RSS 2.0

Author Spotlight

Fabio Porta

Fabio Porta

Fabio has been involved in web development and design since 2005, when launched his first website at the age of 16. He’s now highly skilled in both client and server side development, along with design, and since August 2012 runs a successful website about PrestaShop tutorials and Prestashop Modules called Nemo’s Post Scriptum, at http://nemops.com

Leave a Reply

Your email address will not be published. Required fields are marked *


+ 9 = 13

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>