5

I would like to add caching for a block on a per product basis.

I tried just adding:

protected function _construct()
{
    //cache for half a day
    $this->setCacheLifetime(43200);
}

The problem is a single cache entry is used for every product. So if I load the first page with products that has specific html in it. Then on all other products the same html is shown.

So it is caching the entire block using a default block tag.

How would I cache the block for the page/url as well as per product?

Update:

$this->getProduct()->getId() to the getCacheKeyInfo() function I get the following error:

PHP Fatal error:  Call to a member function getId() on null

Update: Add Block Code

class Module_Sticker_Block_Badge extends Mage_Core_Block_Template
{

    protected function _construct()
    {
        //cache the stickers for half a day
        $this->setCacheLifetime(43200);

        // Add cache tags
        // cache tags are used as handles for clearing certain caches
        $this->setCacheTag(array(
            Mage_Core_Model_Store::CACHE_TAG,
            Mage_Cms_Model_Block::CACHE_TAG,
            Tengisa_Sticker_Model_Sticker::CACHE_TAG
        ));
    }

    // Cache key is unique per bit of HTML
    public function getCacheKeyInfo()
    {
        return array(
            Module_Sticker_Model_Sticker::CACHE_TAG,
            $this->getNameInLayout(),
            Mage::app()->getStore()->getId(),
            Mage::getDesign()->getPackageName(),
            Mage::getDesign()->getTheme('template'),
            //Product id
            // $this->getParentBlock()->getProduct()->getId()
            // Mage::registry('product')->getId()
            $this->getProduct()->getId()
        );
    }
4
  • Are you currently using an FPC/Varnish or particularly interested in the block caching layer? Also what version of Magento are you using? I would take a look at pricing blocks on category pages to help understand how it is implemented. Also AOE_TemplateHints github.com/AOEpeople/Aoe_TemplateHints will show you cache details of each block, even color coding states.
    – B00MER
    Oct 9 '16 at 20:35
  • I am only using standard magento caching. Aha I'll take a look at the pricing blocks.
    – stephen
    Oct 9 '16 at 20:47
  • I will suggest you to follow up the article explained by alanstorm - alanstorm.com/magento_listener_lifecycle_block You will get you answer if you follow it carefully Oct 10 '16 at 6:44
  • @rajatsaurastri The issue is accessing product from the block. I am not seeing a reference to that in the article.
    – stephen
    Oct 10 '16 at 7:02
6
+50

$this->getProduct()->getId() to the getCacheKeyInfo() function I get the following error:

PHP Fatal error:  Call to a member function getId() on null

Adding the product ID to getCacheKeyInfo() is the right thing to do. But it looks like at least in some cases your block does not have the product available with getProduct(). Make sure that getProduct() is implemented and actually returns a product instance.


How would I cache the block for the page/url as well as per product?

You were talking about category pages, so I assume there are multiple different instances of your block on one page. In this case I don't see sense in using the URL for the cache key.

On product pages you could use Mage::registry('current_product') to refer the current product and on category pages, the same with "current_category".

I cannot tell, if any of these make sense to you. If you need more concrete help, please update the question with relevant code of your custom block.


Update based on comment

I just use setData to set the data I need in the template: <?php echo $this->getChild('badge')->setData('stickers', $_product->getStickers())->toHtml(); ?> and then access in the template with: $this->getStickers()

In this case, the block has no access to the product id. Now you have two possible ways to solve it:

  1. use the stickers data for the cache key

    \md5($this->getData('stickers')
    
  2. additionally pass the product id

    $this->getChild('badge')->setData('product_id', $_product->getId());
    

    and then use it for the cache key

    $this->getData('product_id')
    

Note that you pass generated HTML (product->getStickers()->toHtml()) from outside, so it is generated every time even if the block itself is cached.

To optimize this, you should move this HTML generation into the block so that is is only executed if the block is not already cached.

The parent template then should look like this:

$this->getChild('badge')->setData('product', $_product);

The additional data for the cache key:

$this->getData('product')->getId()

And the blocks _beforeToHtml() method (which is only called if the block was not cached):

protected function _beforeToHtml()
{
     parent::_beforeToHtml();
     $this->setData('stickers', $this->getData('product')->getStickers()->toHtml());
}
9
  • Thanks, I have added my current block code. Please check and see if there are any red flags.
    – stephen
    Oct 10 '16 at 6:46
  • I don't see anything product related. How do you access the product in the template? Oct 10 '16 at 6:54
  • I am doing it incorrectly. I tried using $this->getParent()->getProduct()->getId() but that also gave a null on getProduct. The parent class is Mage_Catalog_Block_Product_List
    – stephen
    Oct 10 '16 at 7:00
  • Oh, I just use setData to set the data I need in the template: <?php echo $this->getChild('badge')->setData('stickers', $_product->getStickers())->toHtml(); ?> and then access in the template with: ` $this->getStickers()`
    – stephen
    Oct 10 '16 at 7:08
  • I see. Please see my update Oct 10 '16 at 8:55
0
  1. after instance this block, setProduct($product)(block extends Varien_Object)
  2. setCacheKey(),please ensure its unique(ex. MY_BLOCK_NAME . $product--getId());or, you can rewrite the function 'getCacheKeyInfo()'

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.