Наші Drupal-розробники продовжують ділитися цінним знаннями про Drupal 8. Ви мали змогу оцінити статтю про конфігурацію в Drupal 8, загальні поради щодо розробки на Drupal 8, а також почитати про використання Twig у Drupal 8. Сьогоднішня стаття перекликатиметься з останньою, адже Twig знову буде в фокусі нашої уваги. Тож давайте зануримося в світ чіткої, точної та на 100% корисної інформації від розробників.
Drupal 8 набирає популярності ще з моменту виходу першої бета-версії і він приніс з собою чимало змін. Зокрема це стосується і темізації. Між темами у Drupal 7 і Drupal 8 є низка істотних відмінностей, з якими можна ознайомитися за цим посиланням. Загалом, .info файли змінилися на .yml, як і у модулів, функції темізації замінені Twig-кодом і тепер виконуються через файли шаблонів.
Оскільки Drupal 8 швидко змінюється, деякі деталі з цієї статті можуть виявитися застарілими на момент їхнього прочитання.
Створення теми у Drupal 8
Тему можна створювати з нуля, а можна взяти за основу готову тему і створити свою як підтему (sub-theme). Підтема відрізняється від основної теми тільки тим, що наслідує ресурси батьківської теми. Можна створювати довільні ланцюги підтем, кожна з яких буде наслідувати ресурси з батьківської. Це дає можливість не прописувати усе кастомно, а користуватися уже готовим (наприклад файлами css чи javascript), заміняючи усе, що потрібно, своїм.
За основу можна взяти тему classy. Вона використовується як базова для таких тем ядра, як bartik і seven, і забезпечує свої підтеми багатьма класами, які допомагають виводити елементи розмітки на сторінку.
Головним файлом теми є файл .info.yml, який задає всю базову інформацію. Це заміна .info файлів сьомого Друпала, їхнє використання дає більше можливостей і гнучкості у налаштуванні теми. Аналогічні файли створюються для модулів, тож важливо задати для ключа “type” значення “theme”. Підтема створюється як і будь-яка тема, лише додається ключ “base theme”.
Файл .info.yml повинен лежати у папці з темою і носити її ім’я (наприклад, my_theme/my_theme.info.yml). Приклад такого файлу:
name: My theme type: theme description: 'A custom theme based on Classy.' package: Custom base theme: classy core: 8.x version: 8.x-1.0 screenshot: my_theme.png libraries: - my_theme/globalstyling stylesheets-remove: - '@classy/css/layout.css' - core/assets/vendor/normalize-css/normalize.css regions: header: Header content: Content sidebar_first: 'Sidebar first' footer: Footer
Наступні ключі дають мета-інформацію про нашу тему і визначає базову функціональність:
name (обов’язково) - читабельне для людей (human-readable) ім’я теми, яке буде відображатися у списку тем на сторінці Appearance;
description (обов’язково) - опис, який буде так само висвітлюватися на сторінці Appearance;
package - назва групи, у яку згруповуватимуться теми з таким значення цього ключа;
type (обов’язково) - тип розширення, для тем завжди буде мати значення “theme”;
base theme - базова (батьківська) тема для даної, якщо ми створюємо підтему;
core (обов’язково) - версія Друпала, з якою наша тема сумісна;
version - версія модуля, якщо він розміщується на drupal.org;
screenshot - картинка (може бути скріншот), який відображатиметься на сторінці Appearance. Якщо не задати цього ключа, тоді Drupal шукатиме файл з іменем “screenshot.png” у папці з темою, щоб відобразити;
libraries - бібліотеки, які містять css і js файли, які будуть додаватися до усіх сторінок. Про додавання бібліотек є ціла стаття на drupal.org. Якщо коротко, то до теми додається додається ще один файл типу my_theme.libraries.yml, а в ньому прописується щось на зразок цього:
globalstyling:
globalstyling: version: 1.x css: theme: css/style.css: {} css/print.css: { media: print }
А це в кінцевому результаті рендериться як частина html-коду сторінки:
<link rel="stylesheet" href="css/style.css" media="all" /> <link rel="stylesheet" href="css/print.css" media="print" />
stylesheets-remove - видаляє посилання на css, додане іншою темою чи модулем. Тут потрібно вказувати повний шлях від директорії сайту. Можна також використати токен, позначений символом @;
regions - регіони теми. Більше про додавання регіонів тут.
Breakpoints
Breakpoints - це точки, у яких сайт змінює розташування елементів, залежно від ширини екрану, використовуючи media query в CSS. Брейкпоінти задаються у файлі .breakpoints.yml. Після задання їх у темі, до них будуть мати доступ різні модулі чи інші теми, які створюють функціональність, що залежить від брейкпоінтів.
Щоб задати налаштування брейкпонтів, потрібно створити файл типу my_theme.breakpoints.yml. Приклад вмісту такого файлу:
my_theme.mobile: label: mobile mediaQuery: '' weight: 2 multipliers: - 1x my_theme.narrow: label: narrow mediaQuery: 'all and (min-width: 560px) and (max-width: 850px)' weight: 1 multipliers: - 1x my_theme.wide: label: wide mediaQuery: 'all and (min-width: 851px)' weight: 0 multipliers: - 1x
Кожен фрагмент оголошує один брейкпоінт, який задається машинним ім’ям (наприклад, my_theme.mobile, my_theme.narrow, my_theme.wide) і такими параметрами:
label - читабельне ім’я (label) брейкпоінта; mediaQuery - синтаксис media query, який задає мінімальну і максимальну ширину екрану для брейкпоінта;
weight - порядок брейкпоінтів;
multipliers - підтримувані множники пікселів.
Множники - це міра роздільної здатності екрану пристрою. Визначається як відношення реального розміру пікселя активного пристрою і розміру пікселя, який не залежить від пристрою. Доступні значення: 1x, 1.5x, 2x.
Більше інформації про брейкпоінти можна знайти на drupal.org.
Файл .theme
Цей файл містить hook препроцеси, які вносять зміни до теми. Цей файл виконує ту ж роль, що й template.php у Drupal 7.
Функції темізації і шаблони (templates)
Drupal 8 використовує Twig. Це машина шаблонів (template engine) для PHP і є частиною фреймворка Symfony. Усі функції типу theme_* і файли *.tpl.php замінені twig-файлами *.html.twig.
Drupal 8 дозволяє перезаписувати (overriding) будь-які шаблони, що використовуються для генерації html-розмітки. Якщо потрібно перезаписати шаблон ядра чи іншої теми, потрібно у директорію templates, що лежить в директорії теми додати .html.twig файл з відповідним ім’ям. Можна скопіювати той файл з кодом, який потрібно замінити своїм. Після цього чистимо кеш і можемо редагувати свій файл. Тепер Drupal буде запускати наш файл, замість свого (замість файла ядра або теми). Важливо: не можна змінювати Twig-файли ядра, потрібно робити копії цих файлів у своїй темі чи модулі і там змінювати.
Якщо потрібно внести свої зміни не у всі сторінки, а лише в якісь більш конкретні, потрібно додати ще один файл (або скопіювати базовий) і змінити ім’я. Наприклад, якщо треба зробити шаблон для всіх нод типу article, копіюємо файл node.html.twig, даємо йому ім’я node--article.html.twig. Саме цей новий файл Drupal шукатиме в першу чергу, а якщо не знайде, буде використовувати базовий (тобто node.html.twig). Детальніше про іменування шаблонів тут. Процес коли Drupal визначає, які можливі імена файл шаблону може використовувати, називається theme hook suggestion. Щоб додавати чи змінювати suggestions, існують три хуки:
hook_theme_suggestions_HOOK(array $variables)
hook_theme_suggestions_alter(array &$suggestions, array $variables, $hook)
hook_theme_suggestions_HOOK_alter(array &$suggestions, array $variables)
Основи написання Twig-темплейтів
У восьмому Друпалі більше не використовується php код для написання темплейтів теми, лише Twig. Twig має окремий синтаксис. Файли .html.twig починаються з опису змінних, які використовуються у даному файлі. Далі йде html-розмітка зі вставками коду. Наприклад, код у файлі .tpl.php у Drupal 7 мав такий вигляд:
<?php if (!empty($page['preface_first'])): ?> <?php print render($page['preface_first']); ?> <?php endif; ?>
У Drupal 8 матиме такий:
{% if page.preface_first %} {{ page.preface_first }} {% endif %}
Змінні огортаються у подвійні фігурні дужки {{ variable }}, коментарі у фігурні дужки і знак хеш {# comment #}, конструкції у фігурні дужки і знак процента {% for item in items %} {% endfor %}.
Темплейти можна продебажити. Для цього для початку треба внести зміни у файл sites/default/services.yml:
parameters: twig.config: debug: true
Це дає доступ до кількох речей. Насамперед, у вихідному коді додаються коментарі з дебаг-інформацією, в тому числі вказівкою на Twig-файли, які використовуються:
Це дозволить використовувати функцію dump() для того, щоб дебажити змінні у файлі .html.twig. Як параметр можна передавати змінну, яку функція виведе на відповідній сторінці (наприклад, {{ dump(page) }}), а можна запускати без параметрів, тоді функція виведе всі доступні змінні:
Для кращої роботи з дебагом можна додати ще кілька налаштувань:
auto_reload: true
Тепер Twig темплейти будуть автоматично рекомпілюватися, якщо змінюється їх код.
cache: false
За замовчуванням Twig темплейти компілюються і зберігаються у файловій системі, щоб збільшити швидкодію. Відключення кешування Twig змусить темплейти компілюватися з коду кожен раз, коли вони використовуються. Звичайно, у живих проектах потрібно відключати дебаг мод.
Більше про роботу зі змінними у темплейтах можна дізнатися на сайті drupal.org.
Створення кастомної сторінки з використанням темплейта
Перейдемо від теорії до практики. Для початку нам потрібно у своєму кастомному модулі створити нову сторінку. Як взагалі створювати модулі у восьмому Друпалі, можна почитати тут. Свій модуль я назвав на свою честь shedow_module. Отже, оголошуємо нашу сторінку у файлі shedow_module.routing.yml:
shedow_module.theming_page: path: '/theming-page/{number}' defaults: _title: 'Shedow theming page' _controller: '\Drupal\shedow_module\Controller\ShedowController::themingPage' requirements: _permission: 'access content'
Другим елементом у шляху пропишемо number - яке-небудь число або слово, щоб продемонструвати, як його можна буде використовувати у темплейті. У файлі shedow_module.module оголосимо hook_theme:
function shedow_module_theme() { $theme['shedow_module_page_theme'] = array( 'variables' => array('number' => NULL), 'template' => 'shedow-theme-page', ); return $theme; }
Тут ми задаємо дефолтне значення для змінної number і вказуємо, який файл шаблону буде використовуватися для відображення цієї сторінки (а саме shedow-theme-page.html.twig). І тепер прив’язуємо тему нашої сторінки до самої сторінки у контролері (файл src/Controller/ShedowController.php):
namespace Drupal\shedow_module\Controller; use Drupal\Core\Controller\ControllerBase; class ShedowController extends ControllerBase { public function __construct() { } public function themingPage($number) { return array( '#theme' => 'shedow_module_page_theme', '#number' => $number, ); } }
Тут оголошуємо клас контролера, свій конструктор і функцію themingPage, яка приймає один параметр (число або слово з url). Функція вертає масив, де вказані: тема для сторінки (та сама, яку ми оголосили в hook_theme) і значення змінної number. Тепер лишилось створити файл темплейта і прописати у ньому все, що ми хочемо вивести на сторінці. Файл повинен лежати у нашому випадку у директорії “templates” у директорії модуля:
modules/shedow_module/templates/shedow-theme-page.html.twig:
<section> <h1> My theming page </h1> <p><em> This is my page #{{ number }} </em></p> </section>
Якщо другим параметром в url передати число 19 (theming-page/19), то виглядатиме це наступним чином:
Перший рядок - це тайтл, який ми задали у файлі shedow_module.routing.yml, все інше рендериться з нашого темплейта, в тому числі і наша змінна number. Якщо в нас включений дебаг, ми можемо побачити у вихідному коді, що використовується саме наш twig-файл:
Висновки
Основною відмінністю у темізації Drupal 8 від попередніх версій є Twig, який змінив базовану на php-темплейтах систему темізації Drupal 7 і старіших за нього. Twig дає можливість дизайнерам зі знанням html/css модифікувати розмітку сторінок, не будучи експертом у php. Наприклад, замість того щоб розуміти синтаксичну відмінність між багатовимірними масивами і об’єктами, і знати що де використовується, вони можуть юзати конструкцію {{ foo.bar }}, яка виконає дану роботу. Загалом, змін доволі багато, до них доведеться звикати. Але ж зміни - це рушій прогресу :)