12

This rather trivial requirement turns out to be quite a pain for us in recent days, as we couldn't find a satisfying existing solution, yet. The Task

We are trying to replace certain blocks with a custom template accompanied by a custom block class. Our extension has a system configuration with a couple of boolean inputs (Yes/No) if certain predefined custom blocks should be used. Each custom block replaces one or more default blocks.

If the Merchant selects "No", nothing should happen to these default blocks.

Example

The search box in the container header-wrapper in the Luma theme has a block named top.search. We wand to replace this block with the my-search.phtml template and the MySearch block class, which inherits from the default search block class. In this case \Magento\Framework\View\Element\Template.


Current solutions

A) Using deprecated <action>-Tag with ifconfig-Attribute

My most favorable way was using layout xml files with basic layout definitions to fix our problem. We altered the layout as follows:

<referenceBlock name="top.search" class="Test\MyApp\Block\MySearch">
    <action ifconfig="myapp/components/searchbox" method="setTemplate">
        <argument name="template" xsi:type="string">Test_MyApp::my-search.phtml</argument>
    </action>
</referenceBlock>

Disadvantage: Magento2 documentation discourages from using <action>-Tag. If the search box feature is not used, it still overwrites the default block class.

B) Event-based block exchange using ObserverInterface

Disadvantage: It seems a bit hacky to me to use the event system in Magento2 to replace blocks on a certain condition. I get the feeling that this might also impact the performance if a lot of blocks need to be replaced.

C) Insert a new and invisible block on every page that replaces default blocks on demand

// pseudocode
$layout = $this->getLayout();
$block = $layout->getBlock('top.search');
if ($block) {
  // todo only unset on condition
  $layout->unsetElement('top.search');

  $newBlock = $layout->createBlock('Test\MyApp\Block\MySearch', 'top.search', []);
  $layout->setBlock('top.search', $newBlock);
}

Disadvantage: Possible (unverified) performance and caching issues in the future. Similar to solution B.


The last solution (C) resembles our current pick. However, we are looking for a satisfying solution that works without using any PHP and is written in the Magento2 layout definition (XML). Any ideas?

2
  • Did you find a solution on this or just go with answer c)? Commented May 28, 2019 at 20:55
  • No, we kept using this method. Commented May 29, 2019 at 21:27

2 Answers 2

1

I'd probably go for option B in this case, the performance impact is probably not that significant in the grand scheme of things, especially if you're simply adding layout handles before the layout has loaded. For example, you could add an observer on the event layout_load_before, something like:

public function execute(Observer $observer) : void
{
    $layout = $observer->getEvent()->getData('layout');
    if (!$layout instanceof LayoutInterface) {
        return;
    }

    if (/** Some sort of condition based on your "Yes/No" inputs **/) {
        $layout->getUpdate()->addHandle('custom_layout_handle_for_the_specific_input'); 
    }
}

And then in your custom_layout_handle_for_the_specific_input.xml:

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="top.search" template="Vendor_Module::my/template/override/for/top/search.phtml"/>
    </body>
</page>

To me, this seems like the cleanest solution. The other solution on this post suggests plugging into getTemplate, however you'd need to plug into every block you'd want to replace and might not have the flexibility of being able to manipulate things with a layout... However it might work for your needs.

0

You can create a plugin for getTemplate() method for the desired block.

1
  • 2
    explain please with some code
    – Waqar Ali
    Commented Dec 6, 2019 at 11:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.