Recently viewed products with Magento, Turpentine, Varnish

So, we’ve a Magento EE 1.13 with multiple backend servers and Varnish cache server managed by Turpentine, pretty common setup in the Magento EE world.

Everybody knows that tracking what users does it’s really hard with this setup, cause we don’t want to have calls going to the backend servers (they’ll create a higher load) but Varnish is not going to tell Magento “hey this users just visited this product” thus a lot of features will not work anymore (at least recently viewed products and customer segmentation).To have at least part of the functionalities i thought that:

  • in every page we’ve an AJAX call to the backend servers to render the “flash messages” (like product was added to cart)
  • Varnish is not going to tell Magento “hey the customer just visited this product
  • we could use the AJAX call for the flash messages to track the user view

So I wanted to override Nexcessnet_Turpentine_Block_Core_Messages (it already overrides core/messages block) but to do that you’ll have to patch Nexcessnet_Turpentine_Model_Observer_Esi::addMessagesBlockRewrite() method, telling which block you want to istance instead of their own (actually you could patch Nexcessnet_Turpentine_Block_Core_Messages but that’s less good let’s say).

Then you create your own block extending Nexcessnet_Turpentine_Block_Core_Messages and overriding the _prepareLayout() method with this one:

public function _prepareLayout()
{
try {
if (isset($_SERVER["HTTP_REFERER"]) and $_SERVER["HTTP_REFERER"]) {
$vPath = $_SERVER["HTTP_REFERER"];
$vPath = basename($vPath, ".html");
$product_id = Mage::getModel('catalog/product')->getCollection()->addAttributeToFilter('url_key', $vPath)->getFirstItem()->getId();
if ($product_id) {
Mage::getModel('reports/product_index_viewed')
->setProductId($product_id)
->save()
->calculate();

$eventTypeId = Mage_Reports_Model_Event::EVENT_PRODUCT_VIEW;
$objectId = $product_id;
$subtype = 0;
if (Mage::getSingleton('customer/session')->isLoggedIn()) {
$customer = Mage::getSingleton('customer/session')->getCustomer();
$subjectId = $customer->getId();
Mage::getSingleton('enterprise_customersegment/customer')->processEvent("catalog_product_view", $customer, Mage::app()->getStore()->getWebsite());
}
else {
$subjectId = Mage::getSingleton('log/visitor')->getId();
$subtype = 1;
}

$eventModel = Mage::getModel('reports/event');
$storeId    = Mage::app()->getStore()->getId();
$eventModel
->setEventTypeId($eventTypeId)
->setObjectId($objectId)
->setSubjectId($subjectId)
->setSubtype($subtype)
->setStoreId($storeId);
$eventModel->save();
}
}
} catch (Exception $e) {}
return parent::_prepareLayout();
}

Some comments:

  • try/catch to avoid possible problems
  • we check for HTTP_REFERER cause that’s what we’ll have from Varnish
  • extract the product url_key (what we hope it’s going to be the product url_key)
  • use some code from the core (Mage_Reports_Model_Event_Observer::catalogProductView() and Enterprise_CustomerSegment_Model_Observer::processEvent()) to track the event and manage the segmentation
  • maybe I could call the core’s code instead of copying but I didn’t want to mess with all the dependancies those methods have

Don’t forget to remove the blocks you need to work depending on customer’s data (recently viewed) from the Varnish cache setting it’s ESI policy to private.

Leave a Reply

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