How To Modify Google Feed Format in AbleCommerce

Google Data feeds are a convenient way to create multiple items in Google Base. Feeds are assigned an item type, which classifies the feed according to what sort of items it contains. AbleCommerce 7.0.x fully supports Google Data Feed genearation directly from within AbleCommerce admin interface (Administration > Marketing > Feeds > Google Base).

By default AbleCommerce generates Google Feed file (GoogleBaseData.txt) in the following tab-delimited feed format:

description    id    link    price    title    brand    condition    image_link    mpn    upc   product_type

Based on the type of products and your marketing objectives you may need to submit to Google feed format specific to your business.

Full description of all Google Feed attributes defined by Google Base is available at: Google Base Attribute List 

In AbleCommerce 7.0.x Google Feed file generation is being implemented in CommerceBuilder.DataFeeds namespce located in CommerceBuilder.dll assembly.

If you have not purchased AbleCommerce CommerceBuilder source code and do not have access to CommerceBuilder code it may not be possible to change data feed format directly.

It still possible however to replace GoogleBase class with your own custom data feed format implementation with no additional code changes and no CommerceBuilder.dll recompile.

Step 1: Create a new C# file GoogleBaseCustom.cs under your site App_Code folder

Step2: Modify example code listed below with custom fields specific to your site. In most cases only GetHeaderRow() and GetFeedData() methods need to be modified.

Code example listed below will generate Google Data Feed in the following format:

title description link id image_link price condition brand product_type mpn weight length height width

using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using CommerceBuilder.Common;
using CommerceBuilder.Catalog;
using CommerceBuilder.Products;
using CommerceBuilder.Utility;

namespace CommerceBuilder.DataFeeds
{
    public class GoogleBaseCustom : FeedProviderBase
    {
		public GoogleBaseCustom()
      {
			this.FeedOperationStatus = new FeedOperationStatus();
		}

		protected override string GetHeaderRow()
		{
			// title description link id image_link price condition brand product_type mpn weight length height width 
			StringBuilder feedLine = new StringBuilder();
			feedLine.Append("title\t");
			feedLine.Append("description\t");
			feedLine.Append("link\t");
			feedLine.Append("id\t");
			feedLine.Append("image_link\t");
			feedLine.Append("price\t");
			feedLine.Append("condition\t");
			feedLine.Append("brand\t");
			feedLine.Append("product_type\t");
			feedLine.Append("mpn\t");
			feedLine.Append("weight\t");
			feedLine.Append("length\t");
			feedLine.Append("height\t");
			feedLine.Append("width\t");

			feedLine.Append("\r\n");
			return feedLine.ToString();
		}

		protected override string GetFeedData(ProductCollection products)
      {
			StringWriter feedWriter = new StringWriter();
			StringBuilder feedLine;

			string storeUrl = Token.Instance.Store.StoreUrl;
			storeUrl = storeUrl + (storeUrl.EndsWith("/") ? "" : "/");

			//title description link id image_link price condition brand product_type mpn weight length height width 
			string title, desc, url, id, imgurl, price, condition, brand, prod_type, mpn, weight,length,height, width;

			foreach (Product product in products)
			{
				 //url
				 url = product.NavigateUrl;

				 if (url.StartsWith("~/"))
				 {
					  url = url.Substring(2);
				 }

				 url = storeUrl + url;

				 //title
				 title = StringHelper.CleanupSpecialChars(product.Name);

				 //desc
				 desc = StringHelper.CleanupSpecialChars(product.Description);
				 desc = this.RemoveHtmlTags(desc);

				 //imgurl
				 imgurl = product.ImageUrl;

				 if (!string.IsNullOrEmpty(imgurl) && !IsAbsoluteURL(imgurl))
				 {
					  if (imgurl.StartsWith("~/"))
					  {
							imgurl = imgurl.Substring(2);
					  }

					  imgurl = storeUrl + imgurl;
				 }

				 //id
				 id = product.ProductId.ToString();

				 //price
				 price = string.Format("{0:F2}", product.Price);

				 //condition
				 condition = "New";

				 //brand
				 brand = product.Manufacturer != null ? product.Manufacturer.Name : "";

				 //prod_type
				 var prod_type_t = new StringBuilder("Type > ");
				 prod_type_t.Append(GetProductType(product));
				 prod_type = prod_type_t.ToString();

				 //mpn
				 mpn = product.ModelNumber;

				 //weight
				 weight = string.Format("{0:F2}", product.Weight);

				 //length
				 length = string.Format("{0:F2}", product.Length);

				 //height
				 height = string.Format("{0:F2}", product.Height);

				 //width
				 width = string.Format("{0:F2}", product.Width);

				 feedLine = new StringBuilder();
				 feedLine.Append(title + "\t" + desc + "\t" + url + "\t" + id + "\t" + imgurl + "\t" + price + "\t" + condition + 
                                                           "\t" + brand + "\t" + prod_type + "\t" + mpn + "\t" + weight + "\t" + length + "\t" + height + "\t" + width + "\t");

				 feedWriter.WriteLine(feedLine.ToString());
			}

			string returnData = feedWriter.ToString();
			feedWriter.Close();

			return returnData;
		}

		private string GetProductType(Product product)
		{
			if (product.Categories.Count > 0)
			{
				 List<CatalogPathNode> pathNodes = CatalogDataSource.GetPath(product.Categories[0], false);
				 List<string> categoryNames = new List<string>();

				 foreach (CatalogPathNode node in pathNodes)
				 {
					  categoryNames.Add(node.Name);
				 }

				 return string.Join(" > ", categoryNames.ToArray());
			}

			return string.Empty;
		}

		private string RemoveHtmlTags(string text)
      {
			var notags = Regex.Replace(text, "<(.|\n)*?>", String.Empty);
			var sb = new StringBuilder(notags);

			var replaceItems = new[] { """, " " , "®"};

			foreach (var replace in replaceItems)
			{
				 sb.Replace(replace, String.Empty);
			}

			return sb.ToString();
		}
	}

}

Step 3: Open the following file located under your AbleCommerce site folder: Admin\Marketing\Feeds\GoogleBase.aspx.cs

Step 4: Find all GoogleFeed object instances “feedProvider” and change instance object type to your custom feed class : GoogleBaseCustom feedProvider

Step 5: Save GoogleBase.aspx.cs file

Now if you go back to your AbleCommerce admin site and generate Google Feed file, the new file should have data feed format based on the new fileds from GoogleBaseCustom.cs