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.
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.
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());
}
}
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();
}
}
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>
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"}}
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.
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.