Каркас сторінки: блоки та включення
Як сторінка успадковує спільний каркас, де перевизначати заголовок і вміст та як виносити повторювані шматки.
На цій сторінці
Сторінка вітрини не повторює шапку і підвал — вона успадковує загальний каркас і
заповнює в ньому блоки. Каркас лежить у layout.html, сторінки успадковують його
тегом {extends}.
{extends file="layout.html"}
{block name="title"}{$product.name} — {$storefront.name}{/block}
{block name="content"}
<h1>{$product.name}</h1>
{/block}
Успадкування — ваше рішення, а не вимога магазину: сторінка може бути і
самостійним файлом із власним <html>. Але повторювати шапку у двадцяти
файлах ніхто не стане, тому каркас є в усіх тем.
Що зобов'язане бути в каркасі
<!DOCTYPE html>
<html lang="{$storefront.locale}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{block name="title"}{if $seo.title}{$seo.title}{else}{$storefront.name}{/if}{/block}</title>
{block name="meta"}
{if $seo.description}<meta name="description" content="{$seo.description|escape}">{/if}
{if $seo.canonical}<link rel="canonical" href="{$seo.canonical}">{/if}
{foreach $seo.hreflang as $code => $href}
<link rel="alternate" hreflang="{$code}" href="{$href}">
{/foreach}
{/block}
{block name="page_assets"}{/block}
{assets_head}
{hook name="storefront.head"}
</head>
<body class="page-{$action}" data-action="{$action}">
{hook name="storefront.body.start"}
{include file="partials/header.html"}
<main>{block name="content"}{/block}</main>
{include file="partials/footer.html"}
{assets_footer}
{hook name="storefront.body.end"}
</body>
</html>
Розберемо те, без чого магазин працювати не буде.
<meta name="csrf-token"> — без нього не пройде жодна форма і жоден
запит із браузера: додавання в кошик, перерахунок оформлення, надсилання відгуку.
Рядок виглядає необов'язковим, а без нього покупець не зможе нічого купити.
Адреси дій на <body> — за ними магазин знаходить, куди звертатися при
додаванні в кошик, зміні кількості, додаванні в обране і порівняння,
надсиланні відгуку і запитання. Повний список і що станеться без кожного з них — на
сторінці Атрибути data-*.
{assets_head} і {assets_footer} — сюди виводяться стилі і скрипти: і ваші,
і ті, що магазин підключає сам, і ті, що додають доповнення. Без них
вітрина залишиться без оформлення і без поведінки.
{block name="page_assets"} стоїть до {assets_head}. Порядок тут важливий:
усе, що зареєстроване після {assets_head}, у шапку вже не потрапить.
Сторінка оголошує свої файли в блоці page_assets, а вивід зібраного списку
йде слідом.
$action — ім'я поточного розділу вітрини: default на головній, далі
category, product, search, checkout/cart. Зручно і для класу на
<body>, і для підсвічування активного пункту меню.
Блоки
Блок — це іменоване місце в каркасі, яке сторінка може заповнити своїм вмістом. У базовій темі їх чотири:
| Блок | Для чого |
|---|---|
title |
заголовок вкладки |
meta |
мета-теги: опис, canonical, Open Graph |
page_assets |
стилі і скрипти, потрібні тільки цій сторінці |
content |
сам вміст сторінки |
Заводьте свої, якщо вони вам потрібні, — наприклад окремий блок під клас на
<body> або під хлібні крихти. Блок, який сторінка не перевизначила,
виводить те, що написано в каркасі.
{* у layout.html *}
{block name="breadcrumbs"}{include file="partials/breadcrumbs.html"}{/block}
{* у home.html — на головній крихти не потрібні *}
{block name="breadcrumbs"}{/block}
Включення
Шматок розмітки, який потрібен на кількох сторінках, виноситься в partials/ і
включається:
{include file="partials/product-card.html" product=$item}
Усе, що передано параметрами, доступне всередині включеного файлу як звичайні
змінні: {$product.name}. Дані сторінки там теж видно — передавати
$storefront або $shop не потрібно.
Включення особливо окупається на лістингу: категорія, пошук, бренд і мітка отримують однаковий набір даних, тому список товарів, фільтри і посторінкова навігація пишуться один раз.
{* category.html, search.html, brand.html, tag.html — одне й те саме *}
{include file="partials/filters.html"}
{foreach $products as $product}
{include file="partials/product-card.html" product=$product}
{/foreach}
{include file="partials/pagination.html"}
Умови і цикли
{if $product.preorder}
Під замовлення
{elseif $product.is_available}
В наявності
{else}
Немає в наявності
{/if}
{foreach $products as $product}
{$product@index} порядковий номер з нуля
{$product@iteration} він же з одиниці
{$product@first} перший у списку
{$product@last} останній
{foreachelse}
Товарів немає
{/foreach}
{foreachelse} спрацьовує, коли список порожній, — зручно, щоб не писати
окрему перевірку.
Коментарі
{* цей текст не потрапить у розмітку сторінки *}
Звичайний HTML-коментар <!-- … --> покупець побачить у вихідному коді;
{* … *} вирізається при збиранні шаблону.
Чого в шаблоні не можна
Шаблон працює в пісочниці. Заборонені {php}, {eval}, {fetch},
{include_php}, звернення до класів магазину і читання файлів із диска. Написали
{App\Models\User::count()} — отримаєте помилку і білий екран, а не дані.
Це не недоробка, а захист: тема правиться з панелі, і файл теми не повинен
перетворюватися на спосіб виконати на сервері що завгодно. Усе, що темі потрібно, вона
бере у помічника $shop і з
даних сторінки.
Що буває, коли файлу немає
| Що сталося | Що побачить покупець |
|---|---|
| немає шаблону сторінки | помилка на цій сторінці, решта працюють |
{extends} посилається на неіснуючий файл |
те саме |
{include} посилається на неіснуючий файл |
те саме |
немає 404.html |
стандартна сторінка «не знайдено», без вашої шапки і підвалу |
незнайомий одиночний тег {unknown} |
нічого, сторінка живе |
незнайомий парний тег {foo}…{/foo} |
помилка збирання шаблону |
| незнайомий обробник значення | значення виводиться як є, у журнал іде попередження |
Друкарська помилка в імені файлу — єдина з цих помилок, через яку покупець бачить помилку замість сторінки. Тому після перейменування шаблону варто пройтися по вітрині очима.