As we keep improving JewelsBoutique.com to bring faster browsing experience to our visitors, recently we’ve made another step, to use Magento cache aggressively to speed up page processing at backend(server side).
Background
By studying the traffic and visit statistics, we found that many of our visitors were landing on static CMS pages, so keeping these pages fast can make our visitors feel good at the first impression, rather than experiencing a slow page then leave. Originally we thought Magento could cache the CMS pages & blocks if we enable the cache in Admin Panel, but that’s not true after digging into the code. So we planned to change this and make those frequently-visited blocks to be cacheable to accelerate the response speed.
Finding solution
In Magento wiki, there is a tutorial introduces the regular way of using block cache. To make one block cacheable, you just need add the code for the block class like below:
protected function _construct() { $this->addData(array( 'cache_lifetime' => 3600, 'cache_tags' => 'Cache tags for this block', 'cache_key' =>' Cache key for this block' )); }
If choosing this way, we need to edit every block class to use cache, this requires certain code change which is not effective yet. Is there a better way? Yes! Because we have Magento Events. After looking into the core module, we found that before getting block output Magento will dispatch an Event (core_block_abstract_to_html_before), this is a good place to inject our cache setting for any block we want rather than editing each block independently.
Implementation
1. Add a new module or editing an existing module’s config.xml, add the following event listening setting:
<frontend> <events> <core_block_abstract_to_html_before> <observers> <cacheBlock> <type>singleton</type> <class>{your_module}/observer</class> <method>customBlockCache</method> </cacheBlock> </observers> </core_block_abstract_to_html_before> </events> </frontend>
2. Add the implementation of event handler:
class {your_company}_{your_module}_Model_Observer{ //you can make this to be configurable at Admin Panel const CUSTOM_CACHE_LIFETIME = 3600; //the non-CMS Block you want to cache private $cacheableBlocks = array('Block_Class_A', 'Block_Class_B', ...); public function customBlockCache(Varien_Event_Observer $observer){ try { $event = $observer->getEvent(); $block = $event->getBlock(); $class = get_class($block); if (('Mage_Cms_Block_Block' == $class) && $block->getBlockId()) { $block->setData('cache_lifetime', self::CUSTOM_CACHE_LIFETIME); $block->setData('cache_key', 'cms_block_' . $block->getBlockId()); $block->setData('cache_tags', array(Mage_Core_Model_Store::CACHE_TAG, $block->getBlockId())); } elseif (('Mage_Cms_Block_Page' == $class) && $block->getPage()->getIdentifier()) { $block->setData('cache_lifetime', self::CUSTOM_CACHE_LIFETIME); $block->setData('cache_key', 'cms_page_' . $block->getPage()->getIdentifier()); $block->setData('cache_tags', array(Mage_Core_Model_Store::CACHE_TAG, $block->getPage()->getIdentifier())); } elseif (in_array($class, $this->cacheableBlocks)) { $block->setData('cache_lifetime', self::CUSTOM_CACHE_LIFETIME); $block->setData('cache_key', 'block_' . $class); $block->setData('cache_tags', array(Mage_Core_Model_Store::CACHE_TAG, $class)); } } catch (Exception $e) { Mage::logException(e); } } }
3. Now we are done, pretty easy, right?
Further tuning
Soon after we rolled out the code, we met several problems that required code enhancement:
- For some CMS pages or static blocks, they might embed other dynamic blocks which shouldn’t be cached, so you may need use a ignore-list of CMS page id or static block id in the event handler, and skip the cache setting if the block is in the ignore-list.
- If your site has HTTPS enabled, you’d better use current protocol(Mage::app()->getStore()->isCurrentlySecure()) as a part of the cache_key in case the cache is mixed under certain case.



