Ubercart and Google Merchant Integration

We recently integrated a client's Drupal 6.x / Ubercart 2.x web site with Google Merchant Services (formerly Google Base) AKA Google Shopping.  The motivation for this was to get on the Google Shopping results pages, and hopefully to gain some ground in natural language search engine results as well.  As the best path to accomplish this was not obvoius, I thought that I'd share the various options that are available, and what we determined to be the best path.

There are a couple of Drupal modules that seek to meet this need.  Unfortuately at the time of writing this neither is being actively maintained.  Couple that with the fact that Google likes to add new features and/or change their requirements from time to time, and utilizing a module that isn't actively maintained was a no go.  We did not want to charge the client for the work and then find out in September the rules have changed, the module needs a re-write, and the maintainers aren't able to provide one.

When in doubt I always ask myself this question "Could I do that in Views?"  In this case the answer was yes.

I'm not going to go into all of the details of how to accomplish this, but rather offer an overview of the pieces.  First off, our views setup is Views 3, with Views Bonus Pack, and the Views XML Export enabled.

There are 2 pieces to this equation.

  1. Create an XML view with the data that Google requires
  2. Override that XML view's default rendering at the theme layer to make it conform to Google's XML standard for Google Merchant Services

For the view, you want to create a node type view with a Feed Display.  The Style under 'Style Settings' should be 'XML file'.  You are going to want to add filters to narrow down your result set to published products, and then add your fields.  You can reference the Google Merchant Products Feed Specification here: http://www.google.com/support/merchants/bin/answer.py?answer=188494

When adding fields, make the label for the field the XML tag, for instance g:id fo the unique identifier.  Go through the list of fields in the specification that I referenced earlier and add in all the required fields.  You now have an XML feed or file (depending on your choice) that has the data that you need. 

This file however doesn't conform to the Google Product Feed standard as is, so we need to alter it in the theme layer.  You are going to create a file in the /sites/all/themes/your_theme_name directory and name that file:

views-bonus-export-xml--[view-name].tpl.php.  

You want to put your view's machine name in place of [view-name] in the example.  Now for a caveat - that is how it is supposed to work.  In my case it didn't.  For unknow reasons, this theme files was not being called when the view was served, so I resorted to overriding all XML export views by naming the file views-bonus-export-xml.tpl.php instead.

In that file you simply want to override the XML formatting for the file to make it conform to the Google Product Feed Specification, which has the following format:

<?php if (!function_exists(filterCharacter)){ function filterCharacter($text){ return google_base_xml_sanitizer(substr($text,0,10000)); } function google_base_xml_sanitizer($str, $cdata = false) { $_strip_search = array("![\t ]+$|^[\t ]+!m",'%[\r\n]+%m'); // remove CRs and newlines $_strip_replace = array('',' '); $_cleaner_array = array("Ö" => "O", ">" => "> ", "&reg;" => "", "®" => "", "“" => "&quot;", "\"" => "&quot;", "&trade;" => "", "™" => "", "\t" => "");//, " " => ""); $str = html_entity_decode($str); $str = strtr($str, $_cleaner_array); $str = preg_replace($_strip_search, $_strip_replace, $str); $str = strip_tags($str); $str = eregi_replace("[^[:alnum:][:space:].,!()'-_/+=?äÂÄöÖüÜß]", "", $str); $str = utf8_encode(htmlentities($str)); $str = str_replace('&amp;amp;', '&amp;', $str); $str = preg_replace('/\s+/', ' ', $str); $str = trim($str); if ($cdata) { $str = '<![CDATA[' . $str . ']]>'; } return $str; } } ?> <?php print '<?xml version="1.0" encoding="UTF-8"?>'; $host = 'http://'.$_SERVER['HTTP_HOST'].'/'; ?> <rss version="2.0" xmlns:g="http://base.google.com/ns/1.0"> <channel> <title>Store Name</title> <link>http://www.storeurl.com</link> <description>Store Description.</description> <?php foreach ($themed_rows as $count => $row): ?> <item> <?php foreach ($row as $field => $content): $label = $header[$field] ? $header[$field] : $field; ?> <<?php print $label; ?>><?php print filterCharacter($content); ?></<?php print $label; ?>> <?php endforeach; ?> </item> <?php endforeach; ?> </channel> </rss>

The real benefit of this approach is that as the Google standard changes, you can easily change the views output to comply.

If you have any questions, post a comment or contact us

The article by dzieyzone was helpful to me in working out this approach. Although this implementation is different, the filterCharacter function was a life saver!