Adding Google, Bing, Yandex, and Pinterest Verification Meta Tags to Magento

Meta tags are an easy way to add verification to your Magento store for Google Webmaster Tools, Bing Webmaster Tools, Yandex.Webmaster, and Pinterest for Business accounts. In this article, we’ll go over two easy ways to add these tags to your Magento store.

Magento Tricks by Traffic Motion

One alternative to adding meta tags is to upload a file from each of these sites to your site’s root directory. Unfortunately, when developers, IT, and version control systems are involved, this can be a much longer process than it should be. Instead of taking a few seconds, it may take days or even weeks just to get a new file (let alone four) uploaded to the root directory of your store.

Thankfully, Magento provides a couple of workaround for this, one that is extremely simple, and one that is a little more sophisticaned but cleaner and easier to read and maintain. We’ll start with the simpler method.

Miscellaneous Head Scripts

Log in to the admin section of your store, and navigate to System > Configuration > Design > HTML Head > Miscellaneous Scripts, and simply copy-paste the verification code there.

The code for our TrafficMotion website would look like this:

<meta name="msvalidate.01" content="14B60B177AD73A9CB88E52E10DE81E9F" />
<meta name="google-site-verification" content="Y0KjL1s3sCz5_RnzmBPdNIiMKE7n-iPy3OzjlRlPvdI" />
<meta name="p:domain_verify" content="8c5c5b782d04896448cc802df0e4e97b" />
<meta name='yandex-verification' content='7754504dbf4109f0' />

Easy, right? So what’s the problem with this method?

There really isn’t one, but the scripts are added to the <head> of every page of your site, where Google, Bing, Yandex, and Pinterest only require it on the home page.

To put it simply, why clutter up every page of your site, when you don’t need to? Google or Bing aren’t going to bother verifying the tag on every single page of your store, so why bother including it? It’s just extraneous code for the vast, vast majority of your pages.

So let’s add these pieces of code a different way, and just get them on the home page.

Block & Layout Update

First, navigate to System > Configuration > General > Content Management > WYSIWYG Options. We’re going to change the setting for “Enable WYSIWYG Editor” to “Disabled by Default.” If we don’t do that, Magento’s WYSIWYG editor will strip out the meta tags we’ll be adding to a new static block.

Adding a New CMS Static Block

Once you’ve done that, go to CMS > Static Blocks > Add New Block. You can name it anything you want, but we’ll give it the Block Title of “Validation Codes” and the Identifier of “html_validation_codes” for the purposes of this tutorial.

Then, in the Content, copy-paste in your meta tag verification codes. Now, we just have to get that block into our home page.

Adding the Validation Codes Block to the Home Page

Now, go to CMS > Pages > Home page, and hit the Design Tab under Page Information. This is the part where it can get tricky for new store owners, but it’s really not too difficult.

There may already be some code in the Layout Update XML field if you’re using the base default theme, or it may be empty. In either event, we’re going to add a little snippet of code to reference our Validation Codes static block. Here’s what you would include if you’ve followed along so far:

<reference name="head">
<block type="cms/block" name="validation_code">
    <action method="setBlockId"><block_id>html_validation_codes</block_id></action> 
</block>
</reference>

Wrapping Up Validation Codes

Now, check the Page Source of your Magento store home page, and you should see the block of code just under our customized Google Analytics code. It looks just like this:

<!-- END GOOGLE ANALYTICS CODE -->
<meta name="msvalidate.01" content="14B60B177AD73A9CB88E52E10DE81E9F" />
<meta name="google-site-verification" content="Y0KjL1s3sCz5_RnzmBPdNIiMKE7n-iPy3OzjlRlPvdI" />
<meta name="p:domain_verify" content="8c5c5b782d04896448cc802df0e4e97b" />
<meta name='yandex-verification' content='7754504dbf4109f0' />
<script type="text/javascript">//<![CDATA[
        var Translator = new Translate([]);
        //]]></script></head>

Then, you can check for the code on any other page of your website, and it won’t be there! It’s not a huge savings in terms of the amount of HTML on the page, but it does keep a few lines of extraneous code off of them. No website would pay much attention to those meta tags if they were on every page anyway, so let’s keep the category, CMS, and product pages a little cleaner.

Fixing Magento’s Breadcrumbs – Cache and Microdata

Magento has a nice, built-in breadcrumbs feature, where breadcrumbs can appear on any type of page: static CMS page, product listings, or catalog product pages.

Picture of chocolate crumbs to illustrate breadcrumbs
I prefer chocolate over bread anyway. More paleo. So we’re going with chocolate crumbs in this article.

Frustratingly, though, Magento has not added in RDFa microdata to breadcrumbs by default, leaving it up to store owners to utilize this type of semantic markup or not.

There is also the problem of the breadcrumbs completely disappearing when the Full Page Cache is enabled! It would be especially annoying to add the microdata, but not have it be read by search engines when they crawl pages with the breadcrumbs completely missing.

So, in this article, we’ll dress up the default Magento breadcrumbs, adding RDFa markup and making sure the Full Page Cache remembers to grab and display them.

RDFa for Breadcrumbs

We’ll work with the base package and default theme in the basic Magento 1.8.1.0 installation. If you have your own package and theme, though, it would make more sense just to copy over this base theme file into your own theme and modify it from there. Here’s the file in its original status:

<?php if($crumbs && is_array($crumbs)): ?>
<div class="breadcrumbs">
    <ul>
        <?php foreach($crumbs as $_crumbName=>$_crumbInfo): ?>
            <li class="<?php echo $_crumbName ?>">
            <?php if($_crumbInfo['link']): ?>
                <a href="<?php echo $_crumbInfo['link'] ?>" title="<?php echo $this->escapeHtml($_crumbInfo['title']) ?>"><?php echo $this->escapeHtml($_crumbInfo['label']) ?></a>
            <?php elseif($_crumbInfo['last']): ?>
                <strong><?php echo $this->escapeHtml($_crumbInfo['label']) ?></strong>
            <?php else: ?>
                <?php echo $this->escapeHtml($_crumbInfo['label']) ?>
            <?php endif; ?>
            <?php if(!$_crumbInfo['last']): ?>
                <span>/ </span>
            <?php endif; ?>
            </li>
        <?php endforeach; ?>
    </ul>
</div>
<?php endif; ?>

And here’s all we have to do to make the breadcrumbs more friendly to Google and other search engine robots that visit our store. Check out the added code to the <ul> and <li> lines, as well as the <a> and <strong> tags.

<?php if($crumbs && is_array($crumbs)): ?>
<div class="breadcrumbs">
    <ul xmlns:v="http://rdf.data-vocabulary.org/#">
        <?php foreach($crumbs as $_crumbName=>$_crumbInfo): ?>
            <li class="<?php echo $_crumbName ?>" typeof="v:Breadcrumb">
            <?php if($_crumbInfo['link']): ?>
                <a href="<?php echo $_crumbInfo['link'] ?>" title="<?php echo $this->escapeHtml($_crumbInfo['title']) ?>" rel="v:url" property="v:title"><?php echo $this->escapeHtml($_crumbInfo['label']) ?></a>
            <?php elseif($_crumbInfo['last']): ?>
                <strong rel="v:url" property="v:title"><?php echo $this->escapeHtml($_crumbInfo['label']) ?></strong>
            <?php else: ?>
                <?php echo $this->escapeHtml($_crumbInfo['label']) ?>
            <?php endif; ?>
            <?php if(!$_crumbInfo['last']): ?>
                <span>/ </span>
            <?php endif; ?>
            </li>
        <?php endforeach; ?>
    </ul>
</div>
<?php endif; ?>

That’s it for the breadcrumbs! Now, you can copy the code from a product page on your development site (or live site) into the Google Webmaster Tools Structured Data Testing Tool and see how your pages may appear in search results.

That is, IF Google can read the breadcrumbs. Which it can’t do if the Full Page Cache disappears them.

Make Magento Cache the Breadcrumbs

Full credit for this fix goes to Luis Tineo of the “Memoir of a Magento Developer” website, who figured out how to fix the problem of Magento not caching breadcrumbs.

The fix is deceptively simple. In any of your modules (or you can create one if you want), just add a cache.xml file with the following code in it:

<?xml version="1.0" encoding="UTF-8"?>
<config>
	<placeholders>
		<catalog_breadcrumbs>
			<block>page/html_breadcrumbs</block>
			<name>breadcrumbs</name>
			<placeholder>CONTAINER_BREADCRUMBS</placeholder>
			<container>Enterprise_PageCache_Model_Container_Breadcrumbs</container>
			<cache_lifetime>86400</cache_lifetime>
		</catalog_breadcrumbs>
	</placeholders>
</config>

Read Luis’ site for the full details of why Magento fails to cache the breadcrumbs, but this fix rewrites the placeholder for the cache so that the breadcrumbs will be included on cached pages.

Wrapping Up Magento Breadcrumbs Debug & Upgrade

So with these two easy fixes, we now have Magento caching breadcrumbs, and giving Google more information on the structure of your store’s category and product pages.

Add Google AdWords Dynamic Remarketing Code to Magento Product Pages

Google AdWords Dynamic Remarketing is an excellent way to entice customers back to your store, and one of the most effective uses of your pay per click budget. You can market the very products to them that they were considering while on your website. Get them there through ecommerce SEO or traditional search/display network Google/Bing ads or social media, and them continue to advertise to them through this channel with ads tailored to their personal tastes.

Integrate Google Dynamic Remarketing in Magento

However, the main sticking point is that the dynamic remarketing code needs to be added only to your product pages in your Magento store, as the code looks for the ecommerce product ID (ecomm_prodid), page type (ecomm_pagetype), and total value (ecomm_totalvalue). Also, the code needs to go before the closing <body> tag on these pages.

This means that simply adding the code in the backend of your Magento store is out, as the “Miscellaneous Scripts” section adds code right before the closing <head> tag. So let’s make a simply layout update to our Magento theme to get the Dynamic Remarketing code to show up on product display pages before the closing <body> tag.

Creating or Adding to the local.xml File

First, we need to open (or create, if it’s not there already) the local.xml file located in the magentoroot/app/design/frontend/base/default/layout/ folder, and add the following code to it:

<?xml version="1.0" encoding="UTF-8"?>
<!-- other code -->
<layout>
<!-- other layout code -->
	<catalog_product_view>
		<reference name="before_body_end">
			<block type="catalog/product_view" name="trafficmotion.remarketing">
				<action method="setTemplate">
					<template>trafficmotion/remarketing/code.phtml</template>
				</action>
			</block>
		</reference>
	</catalog_product_view>
</layout>

This adds the layout update to the product pages and references the file that will insert the code into the pages (, as well as tells Magento where to put it (before_body_end).

Directory Structure for AdWords Dynamic Remarketing Code Layout

Next, we create the folders that are referenced in the layout.xml file, so Magento finds what it’s looking for in the place we told it to look. Create these folders:

  • magentoroot/app/design/frontend/base/default/template/trafficmotion/
  • magentoroot/app/design/frontend/base/default/template/trafficmotion/remarketing/

If you read some of my earlier articles on integrating Open Graph and Twitter Cards into Magento, you should already have the /trafficmotion/ folder, so all you’d have to do is create the /remarketing/ folder.

Creating the code.phtml File

Now, finally, we can insert the dynamic remarketing code into Magento. You’ll need to grab this code snippet from your AdWords account. Set up at least one remarketing campaign, and then you can grab the code there, or grab it from the “Shared Library” link in your list of AdWords Campaigns.

Either way, the raw code from Google will look something like this, which we’ll have to modify a bit.

<script type="text/javascript">
var google_tag_params = {
ecomm_prodid: 'REPLACE_WITH_VALUE',
ecomm_pagetype: 'REPLACE_WITH_VALUE',
ecomm_totalvalue: 'REPLACE_WITH_VALUE'
};
</script>
<script type="text/javascript">
/* <![CDATA[ */
var google_conversion_id = XXXXXXXXXX;
var google_conversion_label = "YYYYYYYYYY";
var google_custom_params = window.google_tag_params;
var google_remarketing_only = true;
/* ]]> */
</script>
<script type="text/javascript" src="//www.googleadservices.com/pagead/conversion.js">
</script>
<noscript>
<div style="display:inline;">
<img height="1" width="1" style="border-style:none;" alt="" src="//googleads.g.doubleclick.net/pagead/viewthroughconversion/XXXXXXXXXX/?value=0&amp;label=YYYYYYYYYY&amp;guid=ON&amp;script=0"/>
</div>
</noscript>

Take that code, and create a code.phtml file. Inside of it, modify the lines for the ecomm_prodid, ecomm_pagetype, and ecomm_totalvalue so that the values will be inserted dynamically on different product pages.

BUG FIX – in the prior version of this code, we were echoing the currency before including it before the getFinalPrice call. Turns out, AdWords doesn’t need the currency, so we’re just going to take that out of it. Here’s the updated version of the code.phtml file.

<?php
$_helper = $this->helper('catalog/output');
$_product = $this->getProduct();
$currency = Mage::app()->getLocale()->currency(Mage::app()->getStore()->getCurrentCurrencyCode())->getSymbol();
if($_product):
?>

<!-- Begin Google Code for Remarketing Tag -->
<script type="text/javascript">
var google_tag_params = {
ecomm_prodid: '<?php echo $_product->getSku() ?>',
ecomm_pagetype: 'product',
ecomm_totalvalue: '<?php echo Mage::helper('tax')->getPrice($_product, $_product->getFinalPrice(), true); ?>',
};
</script>
<script type="text/javascript">
/* <![CDATA[ */
var google_conversion_id = XXXXXXXXXX;
var google_custom_params = window.google_tag_params;
var google_remarketing_only = true;
/* ]]> */
</script>
<script type="text/javascript" src="//www.googleadservices.com/pagead/conversion.js">
</script>
<noscript>
<div style="display:inline;">
<img height="1" width="1" style="border-style:none;" alt="" src="//googleads.g.doubleclick.net/pagead/viewthroughconversion/XXXXXXXXXX/?value=0&amp;guid=ON&amp;script=0"/>
</div>
</noscript>
<!-- End Google Code for Remarketing -->
<?php endif; ?>

Wrapping Up Dynamic Remarketing Integration

And that’s all! However, remember to match up your product ID with whatever you’re sending Google in your product feed. If you’re sending the SKU, make sure that’s what you’re grabbing from Magento. Also remember to make the page type ‘product’ and make sure that your code is showing your actual account number, rather than all those XXXXXX lines in the sample code.

In any event, if you did everything correctly, you can go to any of the product pages in your store, and see this before the end of the page. We’ll look at the Nokia 2610 page from the default Magento 1.8.1.0 install with the sample data. It looks like this, including some of the last bits of the footer:

<p class="bugs">Help Us to Keep Magento Healthy - <a href="http://www.magentocommerce.com/bug-tracking" onclick="this.target='_blank'"><strong>Report All Bugs</strong></a> (ver. 1.8.1.0)</p>
        <address>&copy; 2013 Magento Demo Store. All Rights Reserved.</address>
    </div>
</div>
                
<!-- Begin Google Code for Remarketing Tag -->
<script type="text/javascript">
var google_tag_params = {
ecomm_prodid: 'asc',
ecomm_pagetype: 'product',
ecomm_totalvalue: '134.99',
};
</script>
<script type="text/javascript">
/* <![CDATA[ */
var google_conversion_id = XXXXXXXXXX;
var google_custom_params = window.google_tag_params;
var google_remarketing_only = true;
/* ]]> */
</script>
<script type="text/javascript" src="//www.googleadservices.com/pagead/conversion.js">
</script>
<noscript>
<div style="display:inline;">
<img height="1" width="1" style="border-style:none;" alt="" src="//googleads.g.doubleclick.net/pagead/viewthroughconversion/XXXXXXXXXX/?value=0&amp;guid=ON&amp;script=0"/>
</div>
</noscript>
<!-- End Google Code for Remarketing -->
    </div>
</div>
</body>
</html>

Magento Google AdWords Dynamic Remarketing Tutorials

How to Add Open Graph Cards for Products to Magento

In our last article, we looked at adding Twitter Cards to our Magento store, and specifically Twitter Product Cards. The next step is to integrate the Open Graph protocol, which is used by Google+, Facebook, and Pinterest, to name a social networks.

Open Graph Integration with Magento Product Pages

If you were able to follow along in adding Twitter Cards to your Magento store, then adding Open Graph cards will be a breeze. Essentially, we’ll be following the same exact process, targeting the Catalog Product View, and adding a new template file to the <head> section of the document, then inserting the Open Graph meta data for that particular product.

So, without further ado, let’s get started adding Facebook, Google+, and Pinterest integration to our Magento store! And then let us never speak of Magento layout updates again, shall we?

Creating or Adding to the local.xml File

Navigate to your theme’s local.xml file. For the vanilla Magento install with the base theme, the location is magentoroot/app/design/frontend/base/default/layout/local.xml

We’ll be adding the following code to this file:

<?xml version="1.0" encoding="UTF-8"?>
<!-- other code -->
<layout>
<!-- other layout code -->
	<catalog_product_view>
		<reference name="head">
			<block type="catalog/product_view" name="trafficmotion.opengraph">
 				<action method="setTemplate">
					<template>trafficmotion/social/opengraph.phtml</template>
				</action>
			</block>
		</reference>
	</catalog_product_view>
</layout>

Remember, if you went through our tutorial on the Twitter Card integration, you should already have some of this code. In particular, you’ll have the xml doctype declaration, the opening and closing <layout> tags, and the opening and closing <catalog_product_view> tags. You can just insert the above code that is applicable.

If you didn’t follow the Twitter Card integration, and you don’t have a local.xml file, then you’ll have to create one and all of the above code.

Directory Structure for Open Graph Layout

Next up, let’s set up a couple of new folders so we can add the actual Open Graph meta data. Create this directory structure:

  • magentoroot/app/design/frontend/base/default/template/trafficmotion/
  • magentoroot/app/design/frontend/base/default/template/trafficmotion/social/

If you followed along in our article on adding Twitter Card support, you should already have the /trafficmotion/ and /social/ folders, so you would not need to create them here. Now that the folders are there, we just have to add one file to the /social/ folder.

Creating the opengraph.phtml File

Our last step is another easy one, just copying and pasting in some PHP and HTML code. Create a file named opengraph.phtml and place it in the magentoroot/app/design/frontend/base/default/template/trafficmotion/social/ directory. Then, include the following code in the opengraph.phtml file:

<?php
$_helper = $this->helper('catalog/output');
$_product = $this->getProduct();
$currency = Mage::app()->getLocale()->currency(Mage::app()->getStore()->getCurrentCurrencyCode())->getSymbol();
if($_product):
?>
<!-- BEGIN OPEN GRAPH CARDS -->
<meta property="og:site_name" content="<?php echo Mage::app()->getStore()->getName(); ?>" />
<meta property="og:type" content="og:product" />
<meta property="og:title" content="<?php echo $_product->getName() ?>" />
<meta property="og:image" content="<?php echo $_product->getImageUrl() ?>" />
<meta property="og:description" content="<?php echo $this->htmlEscape($_helper->productAttribute($_product, nl2br($_product->getShortDescription()), 'short_description')) ?>" />
<meta property="og:url" content="<?php echo $_product->getUrlModel()->getUrl($_product, array('_ignore_category' => true)) ?>" />
<meta property="og:price:amount" content="<?php echo Mage::helper('tax')->getPrice($_product, $_product->getFinalPrice(), true); ?>" />
<meta property="og:price:currency" content="<?php echo Mage::app()->getStore()->getCurrentCurrencyCode() ?>" />
<meta property="og:availability" content="<?php echo ($_product->isAvailable() ? 'in stock' : 'out of stock') ?>" />
<!-- END OPEN GRAPH CARDS -->
<?php endif; ?>

Wrapping Up Open Graph Integration

That’s all there is to it! Open a product page in your Magento store frontend, and take a look at the Page Source. You should see something like the following code.

<!-- BEGIN OPEN GRAPH CARDS -->
<meta property="og:site_name" content="English" />
<meta property="og:type" content="og:product" />
<meta property="og:title" content=" Olympus Stylus 750 7.1MP Digital Camera" />
<meta property="og:image" content="http://localhost/mage-test/media/catalog/product/cache/1/image/265x/9df78eab33525d08d6e5fb8d27136e95/o/l/olympus-stylus-750-7-1mp-digital-camera-2.jpg" />
<meta property="og:description" content="A technically sophisticated point-and-shoot camera offering a number of pioneering technologies such as Dual Image Stabilization, Bright Capture Technology, and TruePic Turbo, as well as a powerful 5x optical zoom." />
<meta property="og:url" content="http://localhost/mage-test/olympus-stylus-750-7-1mp-digital-camera" />
<meta property="og:price:amount" content="161.94" />
<meta property="og:price:currency" content="USD" />
<meta property="og:availability" content="in stock" />
<!-- END OPEN GRAPH CARDS -->

How to Add Twitter Cards for Products to Magento

With social media signals becoming an increasingly important factor in search engine optimization, being able to share your products properly on Twitter, Facebook, Google+, Pinterest, and other social networks is imperative for Magento store owners. In this article, we’ll look at adding Twitter Product Cards to product display pages.

Integrating Twitter Cards into Magento

First of all, what are Twitter cards? Twitter has developed their own meta tag vocabulary to help websites share information on the popular microblogging platform. Read up on Twitter cards at the Twitter Developers website, or check out the specifications for Product Cards.

In a previous article here on TrafficMotion, I wrote about the importance of social signals, but didn’t go into how to do it specifically for WordPress, Magento, or other CMS platforms. If you’re just starting with social signals for SEO, read that article first and them come back here.

For Magento, let’s start with setting up the local.xml file, and then we’ll create a file just for Twitter Cards. In our next article, we’ll look at Open Graph integration, which is used by Facebook, Google+, and Pinterest. But first, Magento.

Creating or Adding to the local.xml File

I’ll be using the base/default template of the vanilla Magento install for this tutorial, so I start by going to the magentoroot/app/design/frontend/base/default/ folder and looking for the /layout/ directory. If it’s not there, I create it.

Next, we have to create or add to the local.xml file, and add the following information to it:

<?xml version="1.0" encoding="UTF-8"?>
<!-- other code -->
<layout>
<!-- other layout code -->
	<catalog_product_view>
	    <reference name="head">
	        <block type="catalog/product_view" name="trafficmotion.twitter">
	            <action method="setTemplate">
	                    <template>trafficmotion/social/twitter.phtml</template>
	            </action>
	        </block>         
	    </reference>
	</catalog_product_view>
</layout>

Directory Structure for Twitter Card Layout

Now, we have to set up the folder and file structure for our layout update. Create the following directory structure:

  • magentoroot/app/design/frontend/base/default/template/trafficmotion/
  • magentoroot/app/design/frontend/base/default/template/trafficmotion/social/

Creating the twitter.phtml File

Our last step is to set up the file that will include the Twitter Card data in the <head> section of each product display page.

Create a file called twitter.phtml in the magentoroot/app/design/frontend/base/default/template/trafficmotion/social/ folder, and include the following code in that file:

<?php
$_helper = $this->helper('catalog/output');
$_product = $this->getProduct();
$currency = Mage::app()->getLocale()->currency(Mage::app()->getStore()->getCurrentCurrencyCode())->getSymbol();
if($_product):
?>
<!-- BEGIN TWITTER PRODUCT CARDS -->
<meta name="twitter:card" content="product" />
<meta name="twitter:domain" content="<?php echo Mage::getBaseUrl() ?>" />
<meta name="twitter:site" content="@yourtwitterhandle" />
<meta name="twitter:creator" content="@yourtwitterhandle" />
<meta name="twitter:title" content="<?php echo $_product->getName() ?>" />
<meta name="twitter:description" content="<?php echo $this->htmlEscape($_helper->productAttribute($_product, nl2br($_product->getShortDescription()), 'short_description')) ?>" />
<meta name="twitter:image" content="<?php echo $_product->getImageUrl() ?>" />
<meta name="twitter:data1" content="<?php echo $currency ?><?php echo Mage::helper('tax')->getPrice($_product, $_product->getFinalPrice(), true); ?>" />
<meta name="twitter:label1" content="PRICE" />
<meta name="twitter:data2" content="<?php echo Mage::getStoreConfig('shipping/origin/country_id') ?>" />
<meta name="twitter:label2" content="LOCATION" />
<!-- END TWITTER PRODUCT CARDS -->
<?php endif; ?>

Remember to update the “yourtwitterhandle” lines to your actual site and creator Twitter accounts.

Wrapping Up Twitter Card Integration

That’s all there is to it — even easier than adding a custom module, and possibly more useful. Here’s how it looks in the Page Source of the default store with example data. Also check out the working 10% Google Site Speed Sample Rate, which we set up in a previous article.

<!-- BEGIN TWITTER PRODUCT CARDS -->
<meta name="twitter:card" content="product" />
<meta name="twitter:domain" content="http://localhost/mage-test/" />
<meta name="twitter:site" content="@trafficmotion" />
<meta name="twitter:creator" content="@trafficmotion" />
<meta name="twitter:title" content=" Olympus Stylus 750 7.1MP Digital Camera" />
<meta name="twitter:description" content="A technically sophisticated point-and-shoot camera offering a number of pioneering technologies such as Dual Image Stabilization, Bright Capture Technology, and TruePic Turbo, as well as a powerful 5x optical zoom." />
<meta name="twitter:image" content="http://localhost/mage-test/media/catalog/product/cache/1/image/265x/9df78eab33525d08d6e5fb8d27136e95/o/l/olympus-stylus-750-7-1mp-digital-camera-2.jpg" />
<meta name="twitter:data1" content="$161.94" />
<meta name="twitter:label1" content="PRICE" />
<meta name="twitter:data2" content="US" />
<meta name="twitter:label2" content="LOCATION" />
<!-- END TWITTER PRODUCT CARDS -->

The one question you might have is why not put the Open Graph and Twitter Cards in the same layout.xml tag and same socialtags.phtml file? That’s a very good idea, and you can definitely do that if you want.

However, it is likely that Twitter and Open Graph will continue to evolve in separate directions, so it will be easier in the future to go in and change the file that only deals with one type of social sharing, depending on the changes made.

For your next project, take a look at our Magento Open Graph protocol integration, used by Facebook, Google+, and Pinterest!

Setting the Google Analytics Site Speed Sample Rate to 10% in Magento

I’ve written before about how slow Magento can be, even with a moderately-sized store, only a handful of customizations, and all of the cache settings enabled. Following some of the steps in that previous article can increase site speed, but how can we get a better measurement of this vital metric?

Magento Tricks by Traffic Motion

Google Analytics has a report on Site Speed under Behavior > Site Speed > Overview, but the problem is that, by default, the analytics tracking code samples only 1% of pageviews. This is woefully underpowered for small and medium sized businesses, who may only get several dozen page timings per day. In a store with several thousand products (and double that number of duplicate pages that Magento will construct), this would mean that some very fast or very slow load speeds could throw off your measurements, making it difficult to determine if your site is performing adequately for visitors.

The solution is to set the Google Analytics page time setting to sample 10% of pageviews. Before we look at how to do it, here is the actual code that needs to be placed in the GA Tracking Code snippet, and what the GATC should look like once it is inserted.

_gaq.push(['_setSiteSpeedSampleRate', 10]); // line we need to add to the Google Tracking Code

_gaq.push(['_setAccount', 'UA-12345678-1']);
_gaq.push(['_setSiteSpeedSampleRate', 10]);
_gaq.push(['_trackPageview']);

// code needs to be inserted BEFORE _trackPageview is called

Here’s how to do it a couple of different ways.

Just Modify the Core — Bad!

We could, of course, just go into magentoroot/app/code/core/Mage/GoogleAnalytics/Block/Ga.php and add the line. That’s one option, and here’s what it looks like:

// Original Code

_gaq.push(['_setAccount', '{$this->jsQuoteEscape($accountId)}']);
" . $this->_getAnonymizationCode() . "
_gaq.push(['_trackPageview'{$optPageURL}]);

// Modified Code

_gaq.push(['_setAccount', '{$this->jsQuoteEscape($accountId)}']);
" . $this->_getAnonymizationCode() . "
_gaq.push(['_setSiteSpeedSampleRate', 10]);
_gaq.push(['_trackPageview'{$optPageURL}]);

That’ll work, and functions just fine by enabling Google Analytics in the backend of the Magento store. But hacking the core is a big no-no both in WordPress and Magento. So let’s look at a different method of setting the site speed sample rate to 10%.

Custom Module — Good!

Trafficmotion_GoogleAnalytics.xml File

First, let’s activate the module and let Magento know it’s there. We’ll call this module Trafficmotion_GoogleAnalytics, and create a Trafficmotion_GoogleAnalytics.xml file to put in our magentoroot/app/etc/modules folder. Here’s the simple code for this file:

<?xml version="1.0"?>
<config>
    <modules>
        <Trafficmotion_GoogleAnalytics>
            <active>true</active>
            <codePool>local</codePool>
        </Trafficmotion_GoogleAnalytics>
    </modules>
</config>

Module Directory Structure

Easy, right? Now, let’s set up our directory structure for this module. Create these folders:

  • magentoroot/app/code/local/Trafficmotion/GoogleAnalytics/
  • magentoroot/app/code/local/Trafficmotion/GoogleAnalytics/etc/
  • magentoroot/app/code/local/Trafficmotion/GoogleAnalytics/Block/

etc/config.xml File

Next, we’ll create the config.xml file in the magentoroot/app/code/local/Trafficmotion/GoogleAnalytics/etc/ folder. Here’s the code for that one:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <modules>
        <Trafficmotion_GoogleAnalytics>
            <version>0.1.0</version>
        </Trafficmotion_GoogleAnalytics>
    </modules>
    <global>
        <blocks>
            <googleanalytics>
                <rewrite>
                    <ga>Trafficmotion_GoogleAnalytics_Block_Ga</ga>
                </rewrite>
            </googleanalytics>
        </blocks>
    </global>
</config>

Another easy file, right? Now, all we have left is to create the block that’s going to be rewritten to include the site speed sample rate update.

Block/Ga.php file

Create a file called Ga.php and put it in the magentoroot/app/code/local/Trafficmotion/GoogleAnalytics/Block/ directory. And here’s the code to make it work:

<?php

class Trafficmotion_GoogleAnalytics_Block_Ga extends Mage_GoogleAnalytics_Block_Ga
{
    /**
     * Render regular page tracking javascript code
     * The custom "page name" may be set from layout or somewhere else. It must start from slash.
     *
     * @link http://code.google.com/apis/analytics/docs/gaJS/gaJSApiBasicConfiguration.html#_gat.GA_Tracker_._trackPageview
     * @link http://code.google.com/apis/analytics/docs/gaJS/gaJSApi_gaq.html
     * @param string $accountId
     * @return string
     */
    protected function _getPageTrackingCode($accountId)
    {
        $pageName   = trim($this->getPageName());
        $optPageURL = '';
        if ($pageName && preg_match('/^/.*/i', $pageName)) {
            $optPageURL = ", '{$this->jsQuoteEscape($pageName)}'";
        }
        return "
_gaq.push(['_setAccount', '{$this->jsQuoteEscape($accountId)}']);
_gaq.push(['_setSiteSpeedSampleRate', 10]);
_gaq.push(['_trackPageview'{$optPageURL}]);
";
    }

}

Wrapping Up the Custom Module

And that’s it! You’ve achieved the same same result as hacking the core, and all you had to do was create three new files, and a varying number of new directories.

Now, if you have Google Analytics enabled on your store, you should see something like the following by viewing the Page Source, with your own Google Analytics account number instead of “12345678.”

<!-- BEGIN GOOGLE ANALYTICS CODE -->
<script type="text/javascript">
//<![CDATA[
    var _gaq = _gaq || [];
    
_gaq.push(['_setAccount', '12345678']);
_gaq.push(['_setSiteSpeedSampleRate', 10]);
_gaq.push(['_trackPageview']);
    
    (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
 
//]]>
</script>
<!-- END GOOGLE ANALYTICS CODE -->

NoIndexing Filtered Product Listings in Magento

If you run a Magento website, you’re probably used to seeing at least 10-20,000 more pages indexed by Google than you have products in your store. The main problem is pages being indexed when visitors use your filtered navigation on product listing pages.

Magento Tricks by Traffic MotionYou can see this problem in the default Magento installation with sample data. On the Mens – Shoes – Apparel page, filter by Shoe Type: Running, and check out the Page Source. The meta robots tag will still be set to “INDEX, FOLLOW,” telling Google, Bing, and other search engines to index the page.

We don’t want those pages indexed. We want category and products and listing pages indexed, but not filtered views. Setting up your robots.txt file won’t help with this, because Disallowing the filters will only prevent them from being crawled — not from being indexed! Furthermore, Google Webmaster Tool’s URL Parameters tool is spotty at best in removing pages, in my experience.

So let’s get rid of these pages by setting the meta robots tag to NOINDEX, FOLLOW on product listings if there is a filter activated. Almost all of this code comes from Robert Kent’s book Magento Search Engine Optimization, but I’m going to take it a step further and explain exactly how to set up this amazingly simply custom module from scratch. If you want copy-and-paste code for this module, register your email at PacktPub and download the code package for this book for free.

We’ll be using the Namespace of Trafficmotion and Module name of Robots for this article.

Activating the Module

First, navigate to the magentoroot/app/etc/modules folder, and set up a file named Trafficmotion_Robots.xml with the following content:

<?xml version="1.0"?>
<config>
	<modules>
		<Trafficmotion_Robots>
			<active>true</active>
			<codePool>local</codePool>
		</Trafficmotion_Robots>
	</modules>
</config>

Working With the Module

Module Folder Structure

Next, we have to set up the module itself in the magentoroot/app/code/local/ folder. Make new folder for the following:

  • magentoroot/app/code/local/Trafficmotion/
  • magentoroot/app/code/local/Trafficmotion/Robots/
  • magentoroot/app/code/local/Trafficmotion/Robots/etc/
  • magentoroot/app/code/local/Trafficmotion/Robots/Model/

Module Config.xml File

Our next step is creating the config.xml file to go in magentoroot/app/code/local/Trafficmotion/Robots/etc/ so add this code to the new file.

<?xml version="1.0" encoding="UTF-8"?>
<config>
	<modules>
		<Trafficmotion_Robots>
			<version>0.1.0</version>
		</Trafficmotion_Robots>
	</modules>
	<global>
		<models>
			<robots>
				<class>Trafficmotion_Robots_Model</class>
			</robots>
		</models>
	</global>
	<frontend>
		<events>
			<controller_action_layout_generate_xml_before>
				<observers>
					<noindex>
						<type>singleton</type>
						<class>robots/observer</class>
						<method>changeRobots</method>
					</noindex>
				</observers>
			</controller_action_layout_generate_xml_before>
		</events>
	</frontend>
</config>

This code both creates the module (the previous file activated it and told Magento it was there, now this one actually creates it), as well as tells Magento what to do with the module. In a nutshell, Magento will look for the observer file before generating the page layout, and if the observer finds the event it’s looking for, will make a change to the page.

Module Observer.php

Finally, the last file we need to set up. Create a file named Observer.php and put it in the magentoroot/app/code/local/Trafficmotion/Robots/Model/ folder. Use this code snippet in it:

<?php

class Trafficmotion_Robots_Model_Observer
{
    public function changeRobots($observer)
    {
        if($observer->getEvent()->getAction()->getFullActionName() == 'catalog_category_view')
        {
            $uri = $observer->getEvent()->getAction()->getRequest()->getRequestUri();
            if(stristr($uri,"?")): // looks for a ? in the URL of the page
                $layout       = $observer->getEvent()->getLayout();
                $product_info = $layout->getBlock('head');
                $layout->getUpdate()->addUpdate('<reference name="head"><action method="setRobots"><value>NOINDEX,FOLLOW</value></action></reference>');
                $layout->generateXml();
            endif;
        }
        return $this;
    }
}

Wrapping Up the Module

That’s all! Now, do the filtered navigation again for Running Shoes, and check out the page source. The meta robots will be the following:

<meta name="robots" content="NOINDEX,FOLLOW" />

Essential .htaccess Modifications for Speeding Up Your Website

One of the largest concerns for website owners should be the speed of their sites. While Google does not actively penalize slow sites, there is a definite opportunity cost of having pages that take too long to download. This comes mainly in the form of Google and other search engines not crawling your site as deeply or as frequently as they otherwise would.

Picture of snail
This snail is tired of waiting for your store website to load
For ecommerce websites, this means that it can take weeks instead of days for Google to crawl new products, even after being made aware of them through the XML sitemap. With new products hitting the market every day, site speed can mean the difference between being on the search engine today or in two weeks, and the commensurate loss of income due to having a slow site.

While there are many factors out of the control of site owners, .htaccess modifications is one that is relatively easy to manipulate. The modifications in this article will work for any site on an Apache server — Magento, WordPress, or plain old HTML — but we’ll focus on Magento right now.

I’ve been writing a lot about Magento lately, and a default Magento install references several Apache server modules natively in its .htaccess file. Problem is, they’re either commented out or not filled in properly.

So let’s remedy that situation by fixing up the default Magento .htaccess file.

mod_deflate

Let’s start with mod_deflate located on Line 74 of the Magento 1.8.1.0 .htaccess located in the root directory of the install. The basic file looks like this.

<IfModule mod_deflate.c>

############################################
## enable apache served files compression
## http://developer.yahoo.com/performance/rules.html#gzip

    # Insert filter on all content
    ###SetOutputFilter DEFLATE
    # Insert filter on selected content types only
    #AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript

    # Netscape 4.x has some problems...
    #BrowserMatch ^Mozilla/4 gzip-only-text/html

    # Netscape 4.06-4.08 have some more problems
    #BrowserMatch ^Mozilla/4.0[678] no-gzip

    # MSIE masquerades as Netscape, but it is fine
    #BrowserMatch bMSIE !no-gzip !gzip-only-text/html

    # Don't compress images
    #SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary

    # Make sure proxies don't deliver the wrong content
    #Header append Vary User-Agent env=!dont-vary

</IfModule>

To get this module working, all we have to do is remove some of the # comments from certain lines. Removing some of the extraneous comments, the modified version would look like this:

<IfModule mod_deflate.c>
        SetOutputFilter DEFLATE
        BrowserMatch ^Mozilla/4 gzip-only-text/html
        BrowserMatch ^Mozilla/4.0[678] no-gzip
        BrowserMatch bMSIE !no-gzip !gzip-only-text/html
        SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary
        Header append Vary User-Agent env=!dont-vary
</IfModule>

mod_gzip

A default install of Magento makes no mention of mod_gzip in its .htaccess, so that’s our next step. Add these files to take advantage of this compression module in your .htaccess.

<IfModule mod_gzip.c>
    mod_gzip_on Yes
    mod_gzip_dechunk Yes
    mod_gzip_item_include file .(html?|txt|css|js|php|pl)$
    mod_gzip_item_include handler ^cgi-script$
    mod_gzip_item_include mime ^text/.*
    mod_gzip_item_include mime ^application/x-javascript.*
    mod_gzip_item_exclude mime ^image/.*
    mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.* 
</IfModule>

mod_expires

Finally, Magento has some mention of mod_expires but it is just a default expiry date of “access plus 1 year,” which is not very helpful or specific for store owners who may update some files (CSS tweaks, for example) on a continuing basis, while rarely touching others (images, for instance). Here is what Magento 1.8.1.0 includes by default:

<IfModule mod_expires.c>

############################################
## Add default Expires header
## http://developer.yahoo.com/performance/rules.html#expires

    ExpiresDefault "access plus 1 year"

</IfModule>

Not much to it, right? Let’s beef it up a little bit by making it more specific. Change these expires headers time periods according to your own site’s development process:

<IfModule mod_expires.c>
        ExpiresActive On
        ExpiresDefault "access plus 1 days"
        ExpiresByType text/html "access plus 1 days"
        ExpiresByType image/gif "access plus 90 days"
        ExpiresByType image/jpeg "access plus 60 days"
        ExpiresByType image/png "access plus 90 days"
        ExpiresByType text/css "access plus 14 days"
        ExpiresByType text/javascript "access plus 7 days"
        ExpiresByType application/x-javascript "access plus 7 days"
</IfModule>

That’s all there is to it. Just edit the code in your favorite code editor, upload the new version of the .htaccess file, and enjoy a faster Magento (or WordPress or other) website!

Adding jQuery to Your Magento Theme

jQuery is one of the most popular JavaScript libraries out there, but Magento (as of 1.8.1.0) doesn’t have it installed natively. Instead, Magento comes packaged with the Prototype JS library. What’s a jQuery developer to do? Add it to Magento, of course!

Magento Tricks by Traffic MotionThankfully, this is an easy fix for Magento (relatively speaking at least), with the addition of just a couple of files and adding a minimum of six lines of code to your layout/local.xml file. If you have access to your code yourself, you can probably get it done in 5-15 minutes of work, rather than paying a developer 4-5 hours to do this at an hourly rate of $60-$100.

Step 1.

Go to the jQuery site and download the version of it that you want to use, either the uncompressed development version or the compressed production version. Rename the file to jquery.js

Step 2.

Because jQuery and Prototype both use the $ symbol, we’ll need to create a noconflict file for jQuery. Create a file called jquery.noconflict.js and add the following code to it.

[crayon]
$.noConflict();
[/crayon]

Step 3.

Navigate to the [magento root]/js folder and create a new folder called jquery. Drop the jquery.js and jquery.noconflict.js files into that folder.

Step 4.

Go to app/design/frontend/[yourpackage]/[yourtheme]/layout/local.xml and add the following code to the file.

<?xml version="1.0" encoding="UTF-8"?>
<layout>
	<default>
		<reference name="head">
			<action method="addJs">
				<js>jquery/jquery.js</js>
			</action>
			<action method="addJs">
				<js>jquery/jquery.noconflict.js</js>
			</action>
		</reference>
	</default>
</layout>

Step 5.

Clear the cache if enabled, and reload your Magento store, and check the Page Source to see the code.
Showing where jQuery code shows up after adding to Magento store

And that’s it! You should now be able to use jQuery in Magento, as long as you use jQuery rather than $ when calling jQuery.

Increase Magento Store Speed From the Admin

One of the biggest knocks against Magento as an ecommerce CMS platform is its slow speed. While there are numerous extensions to help with speeding up your site, it makes more sense to start looking at the backend of the Magento site itself and getting the configuration settings correct.

Magento Tricks by Traffic MotionUnfortunately, Magento installs with a lot of these settings configured to “slow,” rather than fast, and the poor documentation of the platform does not help store owners optimize their sites very easily. Combine that with Magento developers usually going straight for extensions in order to drive up their hourly charges, and it’s no wonder Magento has a reputation for unnecessary complexity, high costs to configure, and slow running speeds.

But what can we do right in the admin panel of the website to get our stores running faster? Let’s take a look at some of the easier settings to reduce the running speed of the site.

Magento System > Configuration

All of these first settings can be found in the System > Configuration menu of your store’s admin section.

Catalog > Catalog > Frontend

The Magento User Guide suggests using the Flat Catalog Category and Flat Catalog Product settings to be enabled. This is specifically for increased frontend performance, and one of the easiest settings to adjust. Do it to flatten the product and catalog tables so Magento can load data faster.

Expected performance increase: moderate

Advanced > Developer > Log Settings

If you have a developer working on your site, you may not be able to Disable the Debug logging, but you can probably Disable System and Exception logging with little to no negative consequences. Ask if anyone in your company is actually using those logs, and if they aren’t — Disable away!

Expected performance increase: minimal

Advanced > Developer > JavaScript Settings

This setting and the next one are related to merging JS and CSS files.

If you have a lot of JavaScript files running on your site, merging them can increase the load time of the frontend. Some stores are running 10-30 JS files per page loaded, so merging them into one can decrease requests to the server at the very least.

Expected performance increase: depends on the amount of JS files running per site/page

Advanced > Developer > CSS Settings

Again, merging multiple CSS files can reduce requests to the server, thereby speeding up a site. There are usually fewer stylesheets being loaded than there are JavaScript files, but every millisecond counts with Magento stores.

Expected performance increase: minimal

Advanced > System > Full Page Cache Auto Generation

Full Page Caching is a feature of Magento Enterprise Edition and is specifically designed to speed up a site. However, if you have thousands or tens of thousands of products, pages may not be viewed enough for many new visitors to see the same pages as others. Therefore, Auto Generation.

Check your server settings before going ahead with FPC Auto Generation, though. You don’t want it taking 2-3 days to complete the generation of the cache, just to have to reindex or flush the cache because you’ve made significant changes to the website.

Expected performance increase: can be significant

Magento System > Tools

Compilation

If your store has Compilation Enabled, you can just go to the compiler and hit the Run Compilation Process button and go from there. If it doesn’t work, you may have to play with the /includes/ directory and the /includes/config.php file to make sure that they are both writable. We may look at how to do this in a future article on the compiler itself.

Making Good Decisions

Category Thumbnail Image and Image

For each category, you can define both a “Thumbnail Image” and an “Image” to represent that category.

Ideally, use the Thumbnail Image only for navigation if you include the images in your top-level nav bar. That way, you can make them as small as possible to reduce the page load speed.

One developer I know used the Thumbnail Image on Subcategory pages and made them close to 200x200px, and also used them in the navigation dropdown for the site. The images were 200px on the category pages, but resized down to 75x75px in the navigation, a huge difference in load times for these images!

Thus, if you’re going to do anything fancy with your category images throughout the site, make sure to use the Thumbnail Image only in places where it can be small! Loading 50+ 200px images on each page will reduce page speeds, so consider image optimization during the site design and development process.

Closing Thoughts

A brand new Magento site, even with caching enabled, can be a slow, lumbering beast of a CMS platform. While too many site owners immediately start looking for extensions to help them out, these quick admin and design fixes can reduce the page load speed to an acceptable level. At that point, more complicated solutions such as Redis/Varnish cache extensions and htaccess modification can be considered. But start with the easy stuff, since there’s so little of it when dealing with Magento sites.