61

In Magento 1, as a module developer it's possible to change a block's template using layout XML code something like this

<reference name="block_to_change">
    <action method="setTemplate">
        <param>/path/to/template.phtml</param>
    </action>
</reference>

and then adding your template to the base theme.

app/design/frontend/base/default/template/path/to/template.phtml

Is it possible, as a module developer, to do something similar in Magento 2? Or would I need to use layout XML or PHP code to remove the block I'm interested in, and insert a new block with a different template (whose class extends the original block class's)

I know I could create a custom theme that replaces a template, but I'm interested in creating a module that changes the default template, but still allows a custom theme to then replace that template.

6 Answers 6

83

Of course, it is possible:

<referenceBlock name="copyright">
    <action method="setTemplate">
        <argument name="template" xsi:type="string">Dfr_Backend::page/copyright.phtml</argument>
    </action>
</referenceBlock>
4
  • Can you explain the steps how can i change the layout, Actually i want to update the add to addtocart.phtml file according to system configuration and also want to update this using custom module Nov 25, 2015 at 7:44
  • 5
    KAndy solution didn't work for me but this one yes
    – csmarvz
    Jan 26, 2016 at 16:09
  • I have changed the template of the block name "customer_account_dashboard_top"<body> <referenceBlock name="customer_account_dashboard_top"> <action method="setTemplate"> <argument name="template" xsi:type="string">Namespace_Modulename::order/recentorder.phtml</argument> </action> </referenceBlock> </body>" but its not getting work, kindly check and let me know your comments
    – senthil
    Apr 26, 2018 at 17:36
  • action is now deprecated.
    – Black
    Aug 7, 2020 at 9:08
51

Action node is deprecated, but you can use block arguments

<referenceBlock name="block_to_change">
    <arguments>
        <argument name="template" xsi:type="string">[Vendor]_[Module]::/path/to/template.phtml</argument>
    </arguments>
</referenceBlock>
9
  • Can you explain the steps how can i change the layout, Actually i want to update the add to addtocart.phtml file according to system configuration and also want to update this using custom module Nov 25, 2015 at 7:44
  • @KAndy would you mind clarifying where the statement "action node is deprecated is coming from" - after a quick search of the current core code base I found 4 uses with referenceBlock changing the template . All 4 of them use the action node to set a template and none this approach. Mar 9, 2016 at 10:18
  • 4
    Thanks - I'll just leave a reference to a bug report here github.com/magento/magento2/issues/3356 - the method posted in this answer, while possibly the future way of doing things, does not yet work as advertised Mar 21, 2016 at 10:27
  • 2
    @KAndy Is your code example 100% correct? I tried that and I can't get it to work in any way. The other answer from @Mage2.PRO (which uses <action method='setTemplate'>) works without problems. May 24, 2016 at 8:52
  • 2
    This doesn't work. Accepted answer does though. Aug 20, 2017 at 22:20
37

To understand the difference between <arguments> and <action> you must understand how the constructors of Magento 2 objects work. If you override a constructor in Magento, you'll always get a $data-parameter which is an array. This is the data as provided in the XML files and translated to the internal $_data-array of \Magento\Framework\DataObject:

<referenceBlock name="catalog.topnav">
    <arguments>
        <argument name="template" xsi:type="string">Foo_Bar::buzz.phtml</argument>
    </arguments>
</referenceBlock>    

...

public function __construct(array $data = [])
{
    // $_data is populated with the arguments from XML:
    // so $_data['template'] is now 'Foo_Bar::buzz.phtml'
    $this->_data = $data;
}

However, in the case of a template, if setTemplate() is used in the pseudo constructor (_construct(), single underscore), this means that the $data is overridden, no matter if it's set in the XML.

public function _construct()
{
    $this->setTemplate('foo/bar.phtml');
}

In that scenario, <action> is prefered, since this is executed after the constructor & pseudo constructor.

<referenceBlock name="catalog.topnav">
    <action method="setTemplate">
        <argument name="template" xsi:type="string">Foo_Bar::buzz.phtml</argument>
    </action>
</referenceBlock> 
19

The following worked for me in Magento EE 2.2.3

<?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="core.module.block.name" template="[Vendor]_[Module]::path/to/your/template.phtml" />
    </body>
</page>

Note: if you are using a custom module to change a core's template and you are going mad because the previous code snipped does not work, make sure your module is loaded after the core module you are trying to change (module.xml) and you executed bin/magento setup:upgrade :)

1
  • This is the cleanest way in my opinion.
    – Ben Crook
    May 25, 2018 at 16:02
8

I don't know why, but i find this way to be the best:

<referenceBlock name="sales.order.items.renderers.default" template="Foo_Bar::sales/order/items/renderer/default.phtml"/>
0
1
<referenceBlock name="sales.order.items.renderers.default" template="Foo_Bar::sales/order/items/renderer/default.phtml"/>

This will work only if your block wasn't overwritten before using setTemplate method. Magento 2.2.x and higher.

1

Your Answer

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

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