[Solved] Magento2: Conditionally replace block template and class the right way

Riccardo Baral Asks: Magento2: Conditionally replace block template and class the right way
This rather trivial requirement turns out 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 with 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 MagentoFrameworkViewElementTemplate.


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:

Code:
<referenceBlock name="top.search" class="TestMyAppBlockMySearch">
    <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​

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

  $newBlock = $layout->createBlock('TestMyAppBlockMySearch', '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?

Ten-tools.com may not be responsible for the answers or solutions given to any question asked by the users. All Answers or responses are user generated answers and we do not have proof of its validity or correctness. Please vote for the answer that helped you in order to help others find out which is the most helpful answer. Questions labeled as solved may be solved or may not be solved depending on the type of question and the date posted for some posts may be scheduled to be deleted periodically. Do not hesitate to share your response here to help other visitors like you. Thank you, Ten-tools.