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()
);
}
-
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– B00MER2016年10月09日 20:35:35 +00:00Commented Oct 9, 2016 at 20:35
-
I am only using standard magento caching. Aha I'll take a look at the pricing blocks.tread– tread2016年10月09日 20:47:02 +00:00Commented Oct 9, 2016 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 carefullyrajatsaurastri– rajatsaurastri2016年10月10日 06:44:57 +00:00Commented Oct 10, 2016 at 6:44
-
@rajatsaurastri The issue is accessing product from the block. I am not seeing a reference to that in the article.tread– tread2016年10月10日 07:02:10 +00:00Commented Oct 10, 2016 at 7:02
3 Answers 3
$this->getProduct()->getId()to thegetCacheKeyInfo()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:
use the stickers data for the cache key
\md5($this->getData('stickers')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());
}
-
Thanks, I have added my current block code. Please check and see if there are any red flags.tread– tread2016年10月10日 06:46:39 +00:00Commented Oct 10, 2016 at 6:46
-
I don't see anything product related. How do you access the product in the template?Fabian Schmengler– Fabian Schmengler2016年10月10日 06:54:44 +00:00Commented Oct 10, 2016 at 6:54
-
I am doing it incorrectly. I tried using
$this->getParent()->getProduct()->getId()but that also gave anullongetProduct. The parent class isMage_Catalog_Block_Product_Listtread– tread2016年10月10日 07:00:47 +00:00Commented Oct 10, 2016 at 7:00 -
Oh, I just use
setDatato 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()`tread– tread2016年10月10日 07:08:09 +00:00Commented Oct 10, 2016 at 7:08 -
I see. Please see my updateFabian Schmengler– Fabian Schmengler2016年10月10日 08:55:43 +00:00Commented Oct 10, 2016 at 8:55
- after instance this block, setProduct($product)(block extends Varien_Object)
- setCacheKey(),please ensure its unique(ex. MY_BLOCK_NAME . $product--getId());or, you can rewrite the function 'getCacheKeyInfo()'
I'm not sure if it's exactly what you're looking for but to cache custom block and then clean cache exactly for this block I use the next approach which works good to me:
Implement \Magento\Framework\DataObject\IdentityInterface and set your custom cache tag like
use Magento\Framework\DataObject\IdentityInterface; use Magento\Framework\View\Element\Template; use Magento\Framework\View\Element\Template\Context; ... class Block extends Template implements IdentityInterface { public const CACHE_TAG = 'custom_cache_tag'; public function __construct ( ... Context $context, array $data = [] ) { parent::__construct($context, $data); ... } public function getIdentities(): array { return [self::CACHE_TAG]; } ... }Use it to clean cache in a place you need
use Magento\Framework\App\CacheInterface; use Magento\PageCache\Model\Cache\Type; ... public function __construct ( ... private readonly CacheInterface $cache, private readonly Type $fullPageCache ) { } public function cleanBlockCache (): void { $tags = [Block::CACHE_TAG]; //tag from our custom block $this->cache->clean($tags); $this->fullPageCache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG,$tags); }