Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Full Page Cache invalidation on cart (quote) change

Tags:

magento

I'm trying to add a block (button) to mini cart block: either to name="cart_sidebar" or preferably name="topCart.extra_actions" as it renders it's child block automatically being of core/text_list type

Everything works great except the block is not getting called on product pages due to FPC being in effect. I'm trying to extend my container from Enterprise_PageCache_Model_Container_Advanced_Quote class (tried Enterprise_PageCache_Model_Container_Abstract as well) however _renderBlock method is not called.

My cache.xml seems to be correct and valid:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <placeholders>
        <internationalcheckout_international>
            <block>internationalcheckout/international</block>
            <name>internationalcheckout_international</name>
            <placeholder>INT_CHECKOUT</placeholder>
            <container>GSX_InternationalCheckout_Model_Container_Button</container>
            <cache_lifetime>84600</cache_lifetime>
        </internationalcheckout_international>
    </placeholders>
</config>

Any help or hints are appreciated

like image 591
Zifius Avatar asked Nov 30 '22 04:11

Zifius


2 Answers

Nesting dynamic blocks

What you are attempting to do is nest dynamic blocks, that is the dynamic mini cart block should contain a nested dynamic block with type=internationalcheckout/international.

This does not work because of the way the FPC processor implements dynamic blocks (holepunching).

protected function _processContainers(&$content)
{
    $placeholders = array();
    preg_match_all(
        Enterprise_PageCache_Model_Container_Placeholder::HTML_NAME_PATTERN,
        $content, $placeholders, PREG_PATTERN_ORDER
    );

    // ...
    // ... if applyWithoutApp() on each placeholder then update content
    // ... else prepare data for applyWithApp()
    // ...

    }

FPC processing flow

Lets go through step by step what happens.

First, when the _processContainers() method is called, $content contains the cached page, including all placeholder tags. This also includes the nested block you defined.

Second, the method matches all placeholder tags. After this $placeholdersincludes the mini cart placeholder, and then also your nested placeholder definition.

Third, the found placeholders are processed in order. This means the mini cart placeholder will be processed before it processes the nested placeholder, because that is how preg_match_all() collects the matches.

Fourth, the mini-cart container is instantiated. It in turn instantiates the checkout/cart_sidebar block, initializes the renderers and calls toHtml() on it.

Fifth, the checkout/cart/cartheader.phtml template is rendered. When Magento reaches the call

<?php echo $this->getChildHtml('extra_actions') ?>

it won't render any content for it because during the processing of applyWithoutApp() and applyWithApp() no child blocks exist.

Sixth, the FPC processor replaces the complete content area marked by the mini cart placeholder tags with the rendered content returned by the mini cart container. The $content now contains the updated mini cart html.

Seventh, the FPC container attempts to process the placeholder of your nested block. But the $content no longer contains the placeholder tags for it. They have been removed by replacing the wrapping mini cart placeholder with the new generated content!

Summary

When the FPC is processing the content, no layout XML is loaded, and the regular block hierarchy isn't instantiated.
For dynamic ("holepunched") blocks, all output from child blocks will be removed, unless the block instance itself or the container takes care of instantiating them without the layout XML being loaded.
It would be a bad idea performance wise to load the layout XML and generate all blocks while the FPC is processing page content.

What this boils down to is that the topCart.extra_actions container block looks like a good idea, but it's not compatible with the FPC :(

You can't use child blocks within dynamic blocks.

To implement a workaround you will have to move your block outside of the cart_sidebar block.

like image 145
Vinai Avatar answered Dec 02 '22 18:12

Vinai


To anyone looking for a solution to the extra_actions PayPal button, there is a Magento patch fixing it (SUPEE-87_1.12.0.0_v1.patch).

Since it's a Magento patch, you can simply open the file "app/code/core/Enterprise/PageCache/Model/Container/Sidebar/Cart.php" and add these 2 functions after the _renderBlock function, which is exactly what the patch does:

    /**
 * Get Place Holder Block
 *
 * @return Mage_Core_Block_Abstract
 */
protected function _getPlaceHolderBlock()
{
    $block = parent::_getPlaceHolderBlock();
    $block->setChild('extra_actions', $this->_getExtraActionsChildBlock());
    return $block;
}

/**
 * Get child Block
 *
 * @return Mage_Core_Block_Abstract
 */
protected function _getExtraActionsChildBlock()
{
     $paypalShortcutBlock = Mage::app()->getLayout()->createBlock('paypal/express_shortcut');
     $paypalShortcutBlock->setTemplate('paypal/express/shortcut.phtml');
     $paypalShortcutBlock->setLayout(Mage::app()->getLayout());

     return $paypalShortcutBlock;
}

Understanding how this works can help for other similar problems.

Thanks Vinai by the way, very informative answer.

like image 38
user3112649 Avatar answered Dec 02 '22 17:12

user3112649