16

What would be the easiest way to create a FPC hole punch for static block (cms block)?

Let's say I have a static block that calls another block inside that has behaviour I want to be dynamic on every page load.

10

The easiest way I've found to holepunch CMS blocks in Magento Enterprise's Full Page Caching module has a few steps:

First, let's look at the directory structure required:

BranchLabs/CacheBuster/
    Block/Cms.php         # We inherit almost all functions from the Mage CMS
                            block, only overriding the "getCacheKeyInfo" function.
                            We do this to set the CMS block ID for later use by
                            our placeholder model.
    etc/cache.xml         # Here we target our module's version of the CMS block
                            and set their cache lifetimes to 0.
    Model/Placeholder.php # This module is responsible for freshly rendering our
                            CMS blocks every time they're requested.

With that top-down understanding in mind here's how to fill those files out.

  1. Create your own block class that extends the built in Magento CMS block. You'll need to override the "getCacheKeyInfo" function as follows too:

    <?php
    // BranchLabs/CacheBuster/Block/Cms.php
    class BranchLabs_CacheBuster_Block_Cms extends Mage_Cms_Block_Block {
    
        // Used to set the cache placeholder attribute definitions, required in
        // the placeholder's "_renderBlock" function.
        public function getCacheKeyInfo() {
            return array('block_id' => $this->getBlockId());
        }
    
    }
    
  2. Set up the placeholder model that is responsible for rendering out our CMS block without applying the cache.

    <?php
    // BranchLabs/CacheBuster/Model/Placeholder.php
    class BranchLabs_CacheBuster_Model_Placeholder extends Enterprise_PageCache_Model_Container_Abstract {
    
        public function applyWithoutApp(&$content)
        {
            return false;
        }
    
        protected function _getCacheId()
        {
            $id = 'CACHEBUSTER_HOLEPUNCH_' . microtime() . '_' . rand(0,99);
            return $id;
        }
    
        /**
         * CacheBuster doesn't cache data! Do nothing.
         */
        protected function  _saveCache($data, $id, $tags = array(), $lifetime = null)
        {
            return $this;
        }
    
        /**
         * Render fresh block content.
         *
         * @return false|string
         */
        protected function _renderBlock()
        {
            $block = $this->_placeholder->getAttribute('block');
            $block = new $block;
            // Get the block_id attribute we originally set in our CMS block's
            // getCacheKeyInfo function.
            $block_id = $this->_placeholder->getAttribute('block_id');
            $block->setBlockId($block_id);
            $block->setLayout(Mage::app()->getLayout());
            return $block->toHtml();
        }
    }
    
  3. Set up cache.xml to target our newly created CMS block and render using our newly created placeholder.

    <!-- BranchLabs/CacheBuster/etc/cache.xml -->
    <?xml version="1.0" encoding="UTF-8"?>
    <config>
      <placeholders>
        <arbitrary_unique_identifier>
          <block>cachebuster/cms</block>
          <placeholder>ARBITRARY_UNIQUE_IDENTIFIER</placeholder>
          <container>BranchLabs_CacheBuster_Model_Placeholder</container>
          <cache_lifetime>0</cache_lifetime>
        </arbitrary_unique_identifier>
      </placeholders>
    </config>
    
  4. In the CMS, replace the block types for the blocks you're trying render outside the cache with our newly minted CMS-proof block: {{block type="cachebuster/cms" block_id="cacheproof"}}

  • Thanks Graham, I'll give it a try and let you know how it went. – LDusan Sep 12 '14 at 7:01
  • Did this solve your problem for you @LDusan? – Graham Sep 29 '14 at 22:30
  • Did not try it yet, I'll let you know :) – LDusan Sep 30 '14 at 20:44
  • Graham I think this works, the only drawback is that you would have to change the existing cms block classes if you want them not cached, but regardless it's a good solution. Thanks. – LDusan Oct 12 '14 at 12:29
3

The problem is that Magento core team forgot to cache static blocks and what is not cached individually can't be hole-punched.

So the solution is to fix caching first.

1

Indeed, the solution would be to change the way caching is done.

Lesti's FPC is doing this right in my souvenir, and it's free. It only lacks the multiple websites support, but it's perfect for 1 website anjd you'll be able to specify the blocks that must be dynamically hole-punched.

I also tried Amasty's FPC, you'll have to pay for it and it's not the perfect caching solution for CE I guess, but it's working well, you can specify caching of blocks / pages or both. You can also set the compression rate of the cached objects and store them in Db / Filesystem (slow) or memcached.

Wish you luck.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.