Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Templates

A template is a file with the .phtml extension where HTML is mixed with short PHP inserts. A template belongs to a block: the layout says where the block stands, and the template says what it looks like.

Where templates live

Storefront templates are in the module's view/frontend/templates folder, admin templates in view/adminhtml/templates. The file is created by hand. In a layout a template is referenced as Acme_Hello::greeting.phtml; a nested folder goes after the colons: Acme_Hello::review/list.phtml.

A simple template

Replace the contents of the file from the previous lesson:

<!-- app/code/Acme/Hello/view/frontend/templates/greeting.phtml -->
<div class="hello-greeting">
    <h2><?= $escaper->escapeHtml(__('Hello!')) ?></h2>
</div>

The heading "Hello!" appears on the /hello page. The <?= ... ?> construct prints a value, the __() function makes a string translatable, and $escaper->escapeHtml() neutralises HTML special characters.

Template variables

Every Magento template already has two variables:

VariableWhat it is
$blockThe block the template belongs to
$escaperAn object for safe output

For the code editor to suggest methods, type comments are written at the top of a template:

<!-- app/code/Acme/Hello/view/frontend/templates/greeting.phtml -->
<?php
/** @var \Magento\Framework\View\Element\Template $block */
/** @var \Magento\Framework\Escaper $escaper */
?>

Values from the layout

A block can receive a value right in the layout — in the arguments section:

<!-- app/code/Acme/Hello/view/frontend/layout/hello_index_index.xml -->
<block name="hello.greeting" template="Acme_Hello::greeting.phtml">
    <arguments>
        <argument name="shop_name" xsi:type="string">Acme</argument>
    </arguments>
</block>

In the template the value is read with the getData() method:

<!-- app/code/Acme/Hello/view/frontend/templates/greeting.phtml -->
<h2><?= $escaper->escapeHtml(__('Welcome to %1!', $block->getData('shop_name'))) ?></h2>

After bin/magento cache:clean the heading becomes "Welcome to Acme!". The %1, %2 placeholders in __() are replaced with the following arguments.

Conditions and loops

Templates use the colon syntax:

<!-- app/code/Acme/Hello/view/frontend/templates/greeting.phtml -->
<?php $benefits = ['Delivery in 2 days', '30-day returns']; ?>
 
<?php if ($benefits): ?>
    <ul>
        <?php foreach ($benefits as $benefit): ?>
            <li><?= $escaper->escapeHtml($benefit) ?></li>
        <?php endforeach; ?>
    </ul>
<?php endif; ?>

The template prints a list of two items. In the next lesson the array moves from the template into a separate class.

Escaping

Everything printed to the page goes through $escaper:

MethodWhere to use it
escapeHtml()Text between tags
escapeHtmlAttr()An attribute value
escapeUrl()A URL in href and src
escapeJs()A string inside JavaScript
<!-- app/code/Acme/Hello/view/frontend/templates/greeting.phtml -->
<a href="<?= $escaper->escapeUrl($block->getUrl('hello/index/status')) ?>">
    <?= $escaper->escapeHtml(__('Status')) ?>
</a>
 
<?= $block->getChildHtml('hello.extra') ?>

The getUrl() method builds a page URL, and getChildHtml() prints a block nested into the current one in the layout. Its result is not escaped — it is already finished HTML.

Common mistake

A value is printed without escaping: <?= $review->getAuthor() ?>. If a customer typed a script tag into the name field, it runs in other visitors' browsers. Print any data from the database or the request only through the $escaper methods.

Thanks for reading!

Donate to the site — we work hard for you.