Magento – Block with Cachable=false not rendered on product view page

blockscachefull-page-cachelayoutmagento2

I am using magento2-1.0.0-beta4

I have copied the checkout.root block from app/code/Magento/Checkout/view/frontend/layout/checkout_index_index.xml to the product page.

Everything is working fine, until I enable the page_cache. That block is having cacheable="false" in the Layout XML.

Now when I open my product page, the block does not get rendered at all.

If I understood the page cache correctly, it should load such blocks via an AJAX call. But there does not seem to happen such an AJAX call as my break point in \Magento\PageCache\Controller\Block\Render::execute is never hit.

When opening /checkout/ or /checkout/cart/ everything works. But there also does not seem to happen an AJAX call. Instead the whole page does not seem to be rendered from the cache, which makes sense for the cart.

So should I simply exclude the product view page from the page_cache?
But I did not find a way to do so?

Best Answer

This issue is still reproducible on Magento 2.0.0 Stable.

There is a feature in Magento 2 exception handling, which prevents rendering of broken blocks while all other blocks are still rendered. In developer mode it is disabled and all exceptions are displayed right in browser. In default and production modes, if exception occurs during block rendering, the block will just be removed from the output (corresponding exception is still logged to var/log/system.log). See \Magento\Framework\View\Layout::renderNonCachedElement().

Following exception occurs during checkout block rendering on product page and that is why this block is missing: main.CRITICAL: No such entity with customerId = [] [].

The reason for this exception is that customer data in session storage is in inconsistent state (customerLoggedIn == true and customer data is missing) after \Magento\PageCache\Model\Layout\DepersonalizePlugin::afterGenerateXml() execution. This plugin closes current PHP session and thus removes customer data from session storage. This happens only if page is fully cacheable (and it actually is).

Page is considered to be cacheable by page cache module only if its layout does not contain blocks with cacheable="false". Adding this attribute will not make this block loaded by Ajax (as assumed in the question). To have some block being loaded by Ajax, this block should have declared property _isScopePrivate which is set to true, moreover, there should be no blocks with cacheable="false" on the page. See \Magento\PageCache\Observer\ProcessLayoutRenderElement::execute() and mage.pageCache._replacePlaceholder() in Magento/PageCache/view/frontend/web/js/page-cache.js. Also check high-level docs in page cache module readme

Product page should not be cacheable since cacheable="false" is set for checkout block, however it is, due to known issue Uncacheable blocks being cached. Until this issue is resolved, the following workaround may be used (don't ask me why it works, it is a long story):

  1. Go to \Magento\Framework\Pricing\Render\Layout::__construct
  2. Change ['cacheable' => $generalLayout->isCacheable()] to ['cacheable' => false]

This should not harm because product pages will not be cached anyway after adding checkout block

Another question is, do you really want to make product pages non-cacheable by built-in page cache or Varnish?

Related Topic