How to Exclude Block from the Full Page Cache
Igor Furseev Avatar

Magento Enterprise Edition Full Page Cache is a great feature that significantly improves the frontend performance. Nevertheless, it is causing the troubles with the customisations that require the dynamic content output. As you may know, the customer and cart information custom outputs are the first “victims” there, especially, if you migrated your Magento store from Community to Enterprise Edition. Some of the custom solutions, as well as the Mage Store modules, may not be ready for such migration. This brief article will not only show how to avoid a separate block caching in FPC, but also uncover the way how it works.

First of all, let’s check how FPC works. If you try to inspect the page code that is under FPC, you will find that some of the items are wrapped in the strange commented lines. Here is an example of the cart sidebar if you inspect it:

<!--{CART_SIDEBAR_9g2f8f44f7829dc0accf6ce90381157a}-->
<div class="some-class">
...block content goes here...
</div>
<!--/{CART_SIDEBAR_9g2f8f44f7829dc0accf6ce90381157a}-->

That is the wrapper – CART_SIDEBAR ,in our example, is called placeholder, and 9g2f8f44f7829dc0accf6ce90381157a is a cache key.

We won’t provide you with the Enterprise Edition code here, but if you inspect Enterprise_PageCache_RequestController  in your copy of Magento Enterprise Edition, you will see that $content and $containers variables in a single action. This controller and this action override all the frontend controllers and actions if the page was cached. If you try to debug it, you will see that $content  is storing the entire page’s content, but the excluded from the cache blocks will look like this (it should be one line, but we’ve made it three for your convenience):

<!--{MY_PLACEHOLDER_NAME container="Mycompany_Mymodule_Model_Container_Blockname" 
block="Mycompany_Mymodule_Block_Blockname" cache_id="207cac56684bdad153b84fc222b34171fb9e72d1" 
cache_lifetime="86400" template="mycompany/mymodule/blockname-template.phtml"}-->

And before $content  is set as an action response body – every container of the $containers  gets processed on it. In general, each of the containers is searching for its own MY_PLACEHOLDER_NAME in the content, checks if the cache is invalidated and, if so, renders a new block content. Afterwards, it replaces the commented information above with the block content.

So, what do we need to make it work for our extension? First of all, we should let Magento know that we have own placeholder. We will do this by creating the cache.xml file in the etc directory of our extension. The corresponding content of cache.xml for the block in the example above should have the following look:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <placeholders>
        <my_placeholder_identifier>
            <block>mycompany_mymodule/blockname</block>
            <placeholder>MY_PLACEHOLDER_NAME</placeholder>
            <container>Mycompany_Mymodule_Model_Container_Blockname</container>
            <cache_lifetime>86400</cache_lifetime>
        </my_placeholder_identifier>
    </placeholders>
</config>

Let’s assume that the block has been created before, it already has a template and you also have a model declaration in your extension’s config.xml . Then, we just need to create the container model, like here is:

<?php

class Mycompany_Mymodule_Model_Container_Blockname extends Enterprise_PageCache_Model_Container_Abstract
{
    public $childBlocks = array(
        'mycompany.smymodule.blockname.child1',
        'mycompany.smymodule.blockname.child2',
        'mycompany.smymodule.blockname.child3',
    );

    /**
     * Render block content
     *
     * @return string
     */
    protected function _renderBlock()
    {
        $block = $this->_getPlaceHolderBlock();
        foreach($this->childBlocks as $child) {
            $block->setChild($child, $this->_getChildBlock($child));
        }

        return $block->toHtml();
    }

    /**
     * Get child Block
     *
     * @return Mage_Core_Block_Abstract
     */
    protected function _getChildBlock($name)
    {
        return $this->_getLayout()->getBlock($name);
    }

    protected function _saveCache($data, $id, $tags = array(), $lifetime = null) { return false;}

}

Please note that our block has three child blocks in the layout and checks the way how we render them. The easier way, in our opinion, is to add those child blocks to the __construct method of Mycompany_Mymodule_Block_Blockname. And you can do it, especially if your block has also, for example, item renderers.

So, that is all information that we need to exclude our block (and all its child elements) from the full page caching. We hope these tips will simplify your work with Magento Enterprise Edition Full Page Cache.