The Story Behind This Case Study
As part of my role as an Ecommerce SEO consultant, I have been working with Heritage Parts Centre who are a global supplier of spare parts and accessories for classic VW and Porsche cars. Their website stores operate in the UK, US, Australia, Germany, Spain, and Italy, as well as an EU store for all other European countries. They have over 60,000 parts and accessories across over 40 models – resulting in an XML sitemap containing 250k pages.
In summary: It is a big site.
I came on board following a migration (following a rebrand) from Magento 1 to Magento 2 where traffic had been lost. Following the initial audit, the priority was to resolve all the redirects from the old site to ensure that they used 301 redirects, and that accurate mappings were in place across 57k old URLs, matching up product IDs, categories, and regions.
Following this, several opportunities were identified to enhance on page optimisation across the site – one of which being product page optimisation.
It is possible to set up title tag and meta description templates within M2 admin for product meta data such as adding suffixes and prefixes, but any truly bespoke formatting requires developer implementation. This in turn tends to take some time to get implemented as a ticket is raised, placed in a queue and you then you just wait. Very often, developers have much bigger tasks to get stuck into functionality wise than tweaking meta data.
Whilst not a criticism of developers, this is a common frustration for SEOs, and it is not a particularly agile way to go about meta data optimisation, because you may want to test/tweak/refine your meta data following regular analysis, and implementation via the database across 250k pages can be a bit on the server intensive side of things.
For me, this is where Google Tag Manager comes into its own – it makes it very easy to amend meta data at scale and quickly. Using custom variables, triggers, tags, and custom HTML & JavaScript, it is possible to make every product URL’s meta data on the site unique and, more importantly in this case, fully translated.
With that in mind, we set about an international SEO strategy to optimise all the product pages across all regions.
How To Implement Alternate Language Tags in Magento
Whilst this can, in some instances, be carried out via GTM in this case it wasn’t necessary as the site uses the Alternate Language Tags plugin by Magmodules – and very good it is too:
The Pre-Optimisation Meta Data
The following examples of titles and descriptions are for a product not on special offer, and one which is. Default regional suffixes had already been set up for each region, but as with many ecommerce stores, the default meta description was unoptimized and in some cases included HTML due to being pulled in from the page content.
Product Not On Offer – Fuel Tank
https://www.heritagepartscentre.com/uk/170201075j-fuel-tank.html
Region | Title | Description |
AU | Fuel Tank | Heritage Parts Centre AU | Fuel tank<br> |
DE | Kraftstofftank | Heritage Parts Centre DE | Wir haben unsere Marke umbenannt, liefern aber immer noch eine große Auswahl an Teilen und Zubehör für klassische VW- und Porsche-Modelle |
ES | Deposito de combustible | Heritage Parts Centre ES | Hemos cambiado de marca, pero aún almacenamos y suministramos una amplia gama de piezas y accesorios para los modelos clásicos de VW y Porsche. |
EU | Fuel Tank | Heritage Parts Centre EU | Fuel tank<br> |
IT | Serbatoio carburante | Heritage Parts Centre IT | Abbiamo rinominato ma ancora immagazziniamo e forniamo una vasta gamma di parti e accessori per i modelli classici VW e Porsche |
UK | Fuel Tank | Heritage Parts Centre UK | Fuel tank<br> |
US | Fuel Tank | Heritage Parts Center US | Fuel tank<br> |
Product On offer – Door Hinge Kit for Left or Right
https://www.heritagepartscentre.com/uk/90153103120-door-hinge-kit-for-left-or-right.html
Region | Title | Description |
AU | Door Hinge Kit for Left or Right | Heritage Parts Centre AU | <p>Door hinge kit for left or right.</p><p><br>Set includes both hinges for one door, does not include mounting bolts.</p> |
DE | Türscharnier-Set, ohne Schrauben/Bolzen, pro Tür | Heritage Parts Centre DE | Türscharnierset zur Montage an der linken oder rechten Tür. Der Satz enthält alle Scharniere mit Ausnahme der Bolzen zum Aufhängen der Tür.</div> |
ES | Kit bisagra puerta. Para 1 puerta | Heritage Parts Centre ES | <p>Kit bisagra puerta para lado derecho o izquierdo.</p><p><br></p><p>El kit incluye todas los herrajes excepto los tornillos para colgar la puerta.<br></p><p><br></p><p><br></p> |
EU | Door Hinge Kit for Left or Right | Heritage Parts Centre EU | <p>Door hinge kit for left or right. Set includes both hinges for one door, does not include mounting bolts.</p> |
IT | Kit cerniere porta per guida a dx | Heritage Parts Centre IT | Abbiamo rinominato ma ancora immagazziniamo e forniamo una vasta gamma di parti e accessori per i modelli classici VW e Porsche |
UK | Door Hinge Kit for Left or Right | Heritage Parts Centre UK | <p>Door hinge kit for left or right. Set includes both hinges for one door, does not include mounting bolts.</p> |
US | Door Hinge Kit Excluding bolts to Hang One Door | Heritage Parts Center US | <p>Door hinge kit to fit the left or right door.<br>Set includes all hinges excluding bolts to hang one door.</P> |
Product Meta Data Requirements
After reviewing existing product pages, the following list of requirements was drawn up.
- Title tags to be unique across all regions
- Meta data to include the original and a formatted version of the product SKU as users tend to search both with and without hyphens and slashes
- Descriptions to be bespoke in terms of:
- Fully translated, including differing sentence structure per language
- Specify whether the product is on offer or not
- Include the relevant USP for each region
Using Custom Variables to Populate Data
From this, it was determined we would need the following variables to construct the meta data:
- Store region
- Product name
- Product SKU
- Formatted product SKU
- Current price
- Old & new price if on offer
- USP unique to store region
These were then set as follows:
How To Configure Store Region
Whilst the regions are already in the title tags, as we are creating new titles, and for other purposes, we wanted to set a custom variable that captured the region. As each store is within a subfolder named for that region – e.g. /uk/ – we can do this by extracting it from the URL.
To do this we configure a URL of type “Custom JavaScript” that gets the current URL and splits it into an array via the slashes – and we know the region will always be in the 3rd array element:
So on this URL:
https://www.heritagepartscentre.com/uk/170201075j-fuel-tank.html
the region is set as follows:
Whilst we could just use a JavaScript function to convert this to uppercase, we used a lookup table based up the variable to set the region, as this will give us greater flexibility further down the line if we wish to amend the region name in the title tag – e.g. USA instead of US
Which is then set as follows on the above URL:
This can now be used in our tags and triggers by referring to {{Title Tag Region}}
How To Configure Product Name
All the product data we need is within the page content, so we can use CSS selectors to pull in each variable:
So in this case, we grab the contents of .page-title .base
Which we can refer to using {{Product Name}}:
How To Configure Product SKU
Like above, the SKU is also in a uniquely named div:
So, the variable is set as follows:
Which we can refer to using {{Product SKU}}
How To Configure A Formatted Product SKU
By default, the SKU contains / and – for example:
170-201-075/J
Some users will search with these characters, some without – so we wanted to include both. By using a custom JavaScript variable, we can pass the SKU then remove the / and – and return the formatted SKU.
I apologise for what looks like horribly inefficient code, but the replace function wasn’t working how I anticipated, so I just hacked this together to remove up to 4 instances of each character:
As you can see, it passes in the previously captured SKU, works its “magic”, then sends back a nicely formatted SKU:
Again, sorry about that code, but anyway, we can now refer to this using {{Product SKU Formatted}}
How To Configure Current Price
If the product is not on offer, the price can be found here:
Again, we use a CSS selector to grab this value:
And this is called using {{Product Price}}
How To Check If On Offer And Configure Old & New Price
If a product is on offer, the prices appear as follows:
These appear in the classes .old-price and .special-price
So, we set them accordingly:
As the .special-price only appears on product pages which are on offer, we can set a variable called “Product On Offer” of type “Element Visibility” which is set to true or false depending on if this element is on the page:
We then have 3 more potential variables we can use:
{{Product On Offer}}
{{Product Old Price}}
{{Product New Price}}
If the product is not on offer, we see:
Whereas if it is, these are populated accordingly:
(I am not sure why they appear as “null” and “false”, when they should be “false” and “true” – I must look into this)
How To Configure USP Unique To Store Region
We want to include a USP within the meta to encourage the click through from the SERPs. The delivery price is different in each region whilst DE, IT and ES need to be translated. As we already have the region as a variable, the USP can be set via a look up table taking {{Store Region}} as the input:
This is called using {{Product USP}}
Summary Of Configured Variables
For each product we now have a set of variables we can use to create our unique meta data:
https://www.heritagepartscentre.com/uk/170201075j-fuel-tank.html
https://www.heritagepartscentre.com/es/90153103120-kit-bisagra-puerta-para-1-puerta.html
How To Create A Product Page Trigger
Before we create our custom tag, we need a trigger that will allow us to identify if we are on a product page, or not.
There are several variables available to us, so we chose {{Product SKU}} – if this is not null, we know we are on a product page, so set up the trigger accordingly:
How To Create Custom HTML Tag For Dynamic Meta Data
Finally, on to the good stuff.
For this we use a custom HTML tag that will contain JavaScript and utilise jQuery to manipulate the key elements within the page.
First, we need to create the variables we will use and set these according to the custom variables set up previously:
var p_name = "{{Product Name}}";
var p_sku = "{{Product SKU}}";
var p_sku_formatted = "{{Product SKU Formatted}}";
var p_region = "{{Title Tag Region}}";
var p_on_offer = "{{Product On Offer}}";
var p_price = "{{Product Price}}";
var p_old_price = "{{Product Old Price}}";
var p_new_price = "{{Product New Price}}";
var p_product_usp = "{{Product USP}}";
To set the title tag, we want to append the product name, formatted SKU and insert the brand followed by the region:
var p_title = p_name + ": " + p_sku_formatted + " | Heritage Parts Centre " + p_region;
We then use jquery to remove the existing title tag, and create a new one populated with the text above:
jQuery('title').remove();
var p_title_tag = document.createElement('title');
p_title_tag.text = p_title;
jQuery('head').append(p_title_tag);
Whilst I prefer the syntax of JQuery, the following more efficient code wil also work and supports sites that don’t utilise JQeuery:
document.title = p_title;
For the meta description, we have differing formats depending on whether the product is on offer, and then different languages depending on the region. We will translate for DE, IT and ES, whilst AU, US, EU and UK will all use the same text.
The format we decided on in English was:
Buy the product_name (product_SKU) online for product_price. Product_usp
e.g.
Buy the Fuel Tank (170-201-075/J) online for £236.95. Free delivery on orders over £50, express next day delivery available.
If the product is on offer, the wording is as follows:
Buy the product_name (product_SKU) online. Was old_price, now new_price. Product_usp
e.g.
Buy the Door Hinge Kit for Left or Right (901-531-031-20) online. Was £102.95, now £92.95. Free delivery on orders over £50, express next day delivery available.
We also have the flexibility to change the structure of the sentences depending on the language.
To do this, we used the following code which utilises and if statement to determine if the product is on offer, and then switch statements to set to description according to the region – DE, ES and IT, or default English for AU, EU, UK and US – if we want to have specific descritpions for any English regions at any point, we just add in a further case:
if (p_on_offer == "null")
{
switch(p_region)
{
case "DE":
var p_desc = "Bestellen Sie " + p_name + " (" + p_sku + ") auf unserer Webseite für " + p_price + ". " + p_product_usp;
break;
case "ES":
var p_desc = p_name + " (" + p_sku + ") disponible en línea por " + p_price + ". " + p_product_usp;
break;
case "IT":
var p_desc = "Acquista " + p_name + " (" + p_sku + ") online per " + p_price + ". " + p_product_usp;
break;
default:
var p_desc = "Buy the " + p_name + " (" + p_sku + ") online for " + p_price + ". " + p_product_usp;
}
}
else
{
switch(p_region)
{
case "DE":
var p_desc = "Bestellen Sie " + p_name + " (" + p_sku + ") auf unserer Webseite. Regulärer Preis " + p_old_price + " - Sonderpreis " + p_new_price + ". " + p_product_usp;
break;
case "ES":
var p_desc = p_name + " (" + p_sku + ") disponible en línea. Precio inicial " + p_old_price + " - Precio rebajado " + p_new_price + ". " + p_product_usp;
break;
case "IT":
var p_desc = "Acquista " + p_name + " (" + p_sku + ") online. Prezzo originale " + p_old_price + " - Prezzo scontato " + p_new_price + ". " + p_product_usp;
break;
default:
var p_desc = "Buy the " + p_name + " (" + p_sku + ") online. Was " + p_old_price + " - Now " + p_new_price + ". " + p_product_usp;
}
}
And add this to the page as follows:
jQuery('meta[name="description"]').remove();
var p_meta_desc = document.createElement('meta');
p_meta_desc.name = 'description';
p_meta_desc.content = p_desc;
jQuery('head').append(p_meta_desc);
Or, again, without JQuery go with:
document.getElementsByTagName('meta')["description"].content = p_desc;
And that is it – the Custom HTML tag is set up containing the code above to be fired by the product page trigger:
And the good news is, the dynamically generated code is crawled, parsed and indexed by Google. Bing doesn’t. But so what.
We can see this using the site query operator to look for the SKU:
How To Analyse Product Page Performance
The amends had a significant impact on the organic visibility and traffic generated by the product pages on the site.
It’s easy to just say that, but, in the name of a comprehensive case study, I’m going to prove it.
Whilst one of my favourite SEO tools, the performance data in Google Search Console is limited to 1000 pages at a time, however, there are ways of getting a more definitive overview of your site’s search data.
For those with budget, I highly recommend Ryte which has a comprehensive Search Success module which allows you to see ALL your site’s URL search data within any given time frame:
Or, if on a budget and you want the same thing for free, Alyeda Solis has created a Google Data Studio Dashboard that basically does the same thing, that being, the ability to download all your search data.
Once we had this data month by month, we then used Screaming Frog SEO Spider and it’s custom extraction tool to crawl the URLs and identify which were products via the SKU code being in place on the page.
To do this, right click on the SKU in the web page and select “Inspect”:
Then, from within the code, select the element containing the text you want to extract and right click then select “Copy -> Copy Selector” to get the CSS path:
Which gives you the following:
#maincontent > div.columns > div > div.full-width.top.wrapper > div.product-info-main > div.product.attribute.sku > div
Within Screaming Frog, we can then paste in all the URLs into list mode after we’ve set “Configuration -> Custom -> Extraction” and set this to your CSS path:
This will then crawl all your URLs and where the SKU is in place, this will be flagged in the custom extractor field:
If Screaming Frog isn’t your thing, you can also use Sitebulb for website content extraction.
Either way, export the data, put the original search console export data in one excel tab, your crawl data in another, use a VLOOKUP to match and flag the product URLs with an SKU in place, which you then filter to obtain just product page data:
Optimisation work began on the site on October covering fundmental tech SEO actions such as crawl rate optimisation and breadcrumb schema optimisation – this had a positive impact, but more so on the category landing pages across the site. The product meta optimisation described above was implemented in December, and as you can see, it did good in terms of unique product pages and keyword generating impressions, clicks and click through rate:
OCT | NOV | DEC | JAN | FEB | MAR | |
Unique Pages | 14,448 | 15,414 | 16,033 | 21,750 | 32,996 | 34,113 |
Unique Keywords | 34,898 | 39,008 | 35,969 | 35,073 | 50,428 | 49,572 |
Total Impressions | 224,703 | 239,396 | 241,611 | 218,841 | 324,858 | 354,877 |
Total Clicks | 2,580 | 2,976 | 2,768 | 3,028 | 3,585 | 5,150 |
Click Through Rate | 1.15% | 1.24% | 1.14% | 1.38% | 1.10% | 1.45% |
The same data, but in a graph:
Whilst Ryte allows us to see new keywords this year to date which includes a lot of product part IDs due to them now being in the title tag and meta description:
The End Result
Enhanced Visibilty = More Long Tail Organic Traffic = More Reveune = Happy Client
But don’t just take my word for it:
“Heritage Parts Centre started working with Dave at Organic Digital mid-2020, presenting to him a number of challenges following a website migration earlier in the year. What Dave provided saw a number of quick wins (that quickly and drastically stabilised our organic traffic), and subsequently worked through some more strategic technical SEO optimisations that has seen a tremendous improvement in our SEO performance. It has been refreshing to work with Dave who have been genuinely excited by the unique challenges that our market presents, and look forward to continue our work with him. His direct, professional, pragmatic and creative problem solving and optimisation methods continue to make a positive difference to our business, and I recommend him highly.”
Rob Tickner
Head of Technology
“Have been working with Dave for 6 months now and very impressed with the technical SEO work that he has carried out particularly around GTM. His reports and roadmap are clear and concise and the work is returning good results.”
Barney Dines
Managing Director
About The Author - Dave Ashworth
I would describe myself as an SEO Expert and a specialist in technical optimisation with a professional approach to making websites better for people and better for search engines.
When I'm not blogging, I deliver website optimisation consultancy and organic SEO solutions by addressing a website's technical issues and identifying opportunities for growth