Passing Data in Layout

The arguments node feeds data into a block from XML, so one class can serve two pages without a subclass.

Syntax<arguments><argument name="heading" xsi:type="string" translate="true">Delivery</argument></arguments>

A block needs data: a heading, a CSS class, a template path, a view model. The <arguments> node supplies it from layout XML. One block class can then behave differently on two pages, and a theme can change a value without any PHP.

How it works

Each <argument> has a name and an xsi:type. The value is set on the block instance before it renders, and the template reads it with $block->getData('heading') or the magic getter $block->getHeading(). Add translate="true" to a string and it goes through translation.

xsi:typeValue
string, boolean, number, nullText content of the node
array<item name="..." xsi:type="..."> children, nestable
objectA class name, instantiated by DI; it must implement Magento\Framework\View\Element\Block\ArgumentInterface
urlpath attribute, with optional <param name="..."> children
helperhelper="\Class\Name::methodName", called for its return value

Shorthand and longhand

template="Acme_Delivery::product/estimate.phtml"

<argument name="template" xsi:type="string">Acme_Delivery::product/estimate.phtml</argument>

The attribute and the argument are the same thing. Setting the template here instead of inside the block class is what lets one class render two layouts.

What trips people up

The same argument name set in two handles does not merge; the file merged later wins. After adding a class used by xsi:type="object", run bin/magento setup:di:compile in production mode, then bin/magento cache:flush.

Example

Example · xml
<!-- app/code/Acme/Delivery/view/frontend/layout/catalog_product_view.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="product.info.main">
            <block class="Magento\Framework\View\Element\Template"
                   name="acme.delivery.estimate"
                   after="product.price.tier">
                <arguments>
                    <argument name="template" xsi:type="string">Acme_Delivery::product/estimate.phtml</argument>
                    <argument name="heading" translate="true" xsi:type="string">Delivery estimate</argument>
                    <argument name="show_cutoff" xsi:type="boolean">true</argument>
                    <argument name="carriers" xsi:type="array">
                        <item name="standard" xsi:type="string">3-5 business days</item>
                        <item name="express" xsi:type="string">1 business day</item>
                    </argument>
                    <argument name="view_model" xsi:type="object">Acme\Delivery\ViewModel\Estimate</argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

When to use it

  • Reuse one template with a different heading on the cart and the product page.
  • Hand a view model to a template so no block subclass is needed.
  • Override a core block's CSS class from your own module.
  • Build a route URL in layout instead of hardcoding it in a template.

More examples

Reading the arguments in the template

$escaper is provided to every template by the framework, alongside $block. Each argument arrives as block data, and the object argument is reachable as $block->getViewModel() because the argument was named view_model. Every value printed goes through the escaper method that matches its context: escapeHtml inside an element, escapeHtmlAttr inside an attribute.

Example · php
<?php
// app/code/Acme/Delivery/view/frontend/templates/product/estimate.phtml
/** @var \Magento\Framework\View\Element\Template $block */
/** @var \Magento\Framework\Escaper $escaper */
$carriers = $block->getData('carriers') ?? [];
?>
<div class="acme-delivery">
    <strong><?= $escaper->escapeHtml($block->getData('heading')) ?></strong>
    <ul>
        <?php foreach ($carriers as $code => $label): ?>
            <li data-carrier="<?= $escaper->escapeHtmlAttr($code) ?>">
                <?= $escaper->escapeHtml($label) ?>
            </li>
        <?php endforeach; ?>
    </ul>
    <?php if ($block->getData('show_cutoff')): ?>
        <p><?= $escaper->escapeHtml($block->getViewModel()->getCutoffText()) ?></p>
    <?php endif; ?>
</div>

Changing an argument on a core block

Magento_Theme sets css_class on footer_links to "footer links". Because the same argument name does not merge, this replaces the value outright. It only wins if your file is merged after Magento_Theme's, so declare <sequence><module name="Magento_Theme"/></sequence> in your etc/module.xml, then run bin/magento setup:upgrade and bin/magento cache:flush.

Example · xml
<!-- app/code/Acme/Delivery/view/frontend/layout/default.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="footer_links">
            <arguments>
                <argument name="css_class" xsi:type="string">footer links acme-links</argument>
            </arguments>
        </referenceBlock>
    </body>
</page>

A URL argument built by the framework

The url type takes a route path and optional parameters, and the framework turns it into a full store URL with the correct base, store code and secure scheme. Use it instead of writing a literal URL in the template, which breaks on a second store view or on HTTPS. The template still escapes it with $escaper->escapeUrl().

Example · xml
<!-- app/code/Acme/Delivery/view/frontend/layout/checkout_cart_index.xml -->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="content">
            <block class="Magento\Framework\View\Element\Template"
                   name="acme.delivery.help"
                   template="Acme_Delivery::cart/help.phtml">
                <arguments>
                    <argument name="help_url" xsi:type="url" path="contact/index/index">
                        <param name="topic">delivery</param>
                    </argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

Discussion

  • Be the first to comment on this lesson.