Шаблоны Smarty
Собирать HTML строками в PHP неудобно и небезопасно. На витрине PrestaShop разметку пишут в шаблонах Smarty — файлах .tpl, где HTML перемешан с простыми командами в фигурных скобках. Модуль передаёт в шаблон переменные и получает готовую строку.
Где лежат шаблоны
Шаблоны модуля хранят в папке views/templates, шаблоны для хуков — в подпапке hook. Создайте файл вручную:
modules/acmehello/
├── acmehello.php
├── logo.png
└── views/
└── templates/
└── hook/
└── home.tplПервый шаблон
{* modules/acmehello/views/templates/hook/home.tpl *}
<section class="acme-hello">
<h2>{$greeting}</h2>
</section>Строка в {* *} — комментарий Smarty, в страницу он не попадает. {$greeting} выводит переменную.
Вывод шаблона из хука
// modules/acmehello/acmehello.php
public function hookDisplayHome(array $params): string
{
$this->context->smarty->assign([
'greeting' => 'Добро пожаловать!',
]);
return $this->fetch('module:acmehello/views/templates/hook/home.tpl');
}assign() передаёт переменные в шаблон, fetch() возвращает готовый HTML. Обновите главную страницу: приветствие теперь в заголовке h2. Сбрасывать модуль не нужно — подписка на хук не менялась.
Путь начинается с module: и имени модуля. Благодаря этому тема может подменить шаблон своим — об этом в уроке о темах.
Условия и циклы
Создайте второй шаблон — для блока отзывов на карточке товара:
{* modules/acmehello/views/templates/hook/product-reviews.tpl *}
<section class="acme-reviews">
<h3>Отзывы</h3>
{if $reviews}
<ul>
{foreach from=$reviews item=review}
<li>{$review.author}: {$review.rating} из 5</li>
{/foreach}
</ul>
{else}
<p>Отзывов пока нет.</p>
{/if}
</section>// modules/acmehello/acmehello.php
public function hookDisplayFooterProduct(array $params): string
{
$this->context->smarty->assign([
'reviews' => [
['author' => 'Анна', 'rating' => 5],
['author' => 'Борис', 'rating' => 4],
],
]);
return $this->fetch('module:acmehello/views/templates/hook/product-reviews.tpl');
}На странице любого товара появится список из двух отзывов. Пока они заданы массивом; в уроке о базе данных их заменит запрос.
Синтаксис
| Запись | Что делает |
|---|---|
{$name} | Выводит переменную |
{$review.author} | Элемент массива или свойство |
{if $a > 1}...{elseif ...}...{else}...{/if} | Условие |
{foreach from=$list item=row}...{foreachelse}...{/foreach} | Цикл; foreachelse — если список пуст |
{$text|truncate:100} | Модификатор: обрезать до 100 символов |
{$price|string_format:'%.2f'} | Модификатор: формат числа |
{include file='module:acmehello/views/templates/hook/stars.tpl'} | Вставить другой шаблон |
Готовые переменные
На витрине в любом шаблоне уже есть переменные движка: $customer, $cart, $currency, $language, $shop, $urls.
{if $customer.is_logged}
<p>Здравствуйте, {$customer.firstname}!</p>
{else}
<a href="{$urls.pages.authentication}">Войти</a>
{/if}Вошедший покупатель увидит своё имя, гость — ссылку на страницу входа.
Экранирование
На витрине Smarty настроен так, что каждая переменная при выводе экранируется: символы < и > превращаются в безопасные коды, и текст отзыва не может стать скриптом. Чтобы вывести переменную как HTML, добавляют nofilter:
<div class="acme-text">{$html nofilter}</div>Так выводят только HTML, который подготовили вы сами или ядро. В шаблонах панели управления автоматического экранирования нет — там пишут {$name|escape:'html':'UTF-8'}. В чужих модулях этот модификатор встречается и на витрине: он там безвреден.
Частая ошибка
Текст отзыва выводится с видимыми тегами, и чтобы «починить» это, к переменной дописывают nofilter. Теперь отзыв со скриптом выполнится у каждого посетителя — это уязвимость XSS. nofilter допустим только для содержимого, которое не вводил пользователь или которое прошло очистку.