Categories


Archives


Recent Posts


Categories


Why you Can’t Remove the product_list_toolbar Block

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

Over in my Patreon slack, a patron came to me with the following layout handle XML chunk.

This block of XML would successfully remove the block named breadcrumbs, but it would not successfully remove the block named product_list_toolbar.

This is one of those places where Magento’s lack of documentation and/or a cogent systems philosophy really bites practitioners in the butt. Even as an experienced M2 developer, my mind came up with multiple possible causes

Worse – because Magento 2’s layout loading is much more complicated that it was in M1, even someone like me isn’t sure where to start debugging. There are too many layers where the remove instruction might get, um, removed. This makes it impossible to point a user-programmer to the right place for some debugging code.

Fortunately, my patron was also a Commerce Bug user – using the Layout tab’s View Page/Request button we were able to view the final layout XML Magento uses to instantiated blocks. We examined the layout loading order, and searched for conflicting rules. Everything seemed fine – except we noticed a small bit of weirdness in the initial product_list_toolbar code

#File: vendor/magento/module-catalog/view/frontend/layout/catalog_category_view.xml
<block class="MagentoCatalogBlockProductListProduct" name="category.products.list" as="product_list" template="Magento_Catalog::product/list.phtml">
    <!-- ... -->
    <block class="MagentoCatalogBlockProductProductListToolbar" name="product_list_toolbar" template="Magento_Catalog::product/list/toolbar.phtml">
        <block class="MagentoThemeBlockHtmlPager" name="product_list_toolbar_pager"/>
    </block>
    <action method="setToolbarBlockName">
        <argument name="name" xsi:type="string">product_list_toolbar</argument>
    </action>
</block>

For reasons that weren’t immediately apparent, Magento’s core code calls the setToolbarBlockName method on the parent MagentoCatalogBlockProductListProduct block. This was curious enough to warrant an investigation of what was happening in that parent block’s source. This, in turn, revealed the problem.

For reasons known only to those behind the wall of corporate and historic fog, the parent block object does some weird monkey business with the toolbar in the _beforeHtml method (called right before the block’s HTML renders)

#File: vendor/magento/module-catalog/Block/Product/ListProduct.php
protected function _beforeToHtml()
{
    $toolbar = $this->getToolbarBlock();

    /* ... monkey business ... */

    $this->setChild('toolbar', $toolbar);

    /* more monkey business */

    return parent::_beforeToHtml();
}

By itself, this code isn’t damning – but if we look at the getToolbarBlock method

#File: vendor/magento/module-catalog/Block/Product/ListProduct.php
public function getToolbarBlock()
{
    $blockName = $this->getToolbarBlockName();
    if ($blockName) {
        $block = $this->getLayout()->getBlock($blockName);
        if ($block) {
            return $block;
        }
    }
    $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, uniqid(microtime()));
    return $block;
}

We see that, if Magento can’t fetch toolbar block, it instantiates a new one via code.

#File: vendor/magento/module-catalog/Block/Product/ListProduct.php
$block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, uniqid(microtime()));

For my Patron? This meant their remove=true attribute was working. The product_list_toolbar block was removed from the layout. However, during render, Magento just re-instantiated the toolbar block and stuck it back in the layout.

This sort of thing isn’t exactly new in Magento – in fact this specific problem goes back to Magento 1

#File: app/code/core/Mage/Catalog/Block/Product/List.php
public function getToolbarBlock()
{
    if ($blockName = $this->getToolbarBlockName()) {
        if ($block = $this->getLayout()->getBlock($blockName)) {
            return $block;
        }
    }
    $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, microtime());
    return $block;
}

This, more than anything, is a nice example of the big challenge Magento faces w/r/t developer uptake. After 5+ years of development, Magento 2 still presents the same set of challenges as Magento 1. It also presents a whole new slew of challenges introduced by Magento 2. It also shows no signs, as an organization (hello hard working individuals fighting the good fight!), of realizing this and making the necessary adjustments.

All of this won’t prevent Magento from being a financial success – but it’s created a new platform where even its die-hard advocates are taking hard looks at other options.

Copyright © Alana Storm 1975 – 2023 All Rights Reserved

Originally Posted: 26th April 2017

email hidden; JavaScript is required