Отображение контента Flex¶
Когда тип Flex определён и его директория включена, следующий шаг — вывести эти объекты на фронтенд. Grav даёт три дополняющих друг друга способа, каждый под свою задачу:
- Шорткод [flex-objects] — безопасный для песочницы способ вставить коллекцию прямо в контент страницы.
- Тип страницы flex-objects — страница, которая рендерит директорию (или отдельный объект) по параметрам URL.
- Twig в шаблонах темы, где тег
renderи поиск шаблонов Flex дают полный контроль.
Их можно свободно сочетать. Лендинг может использовать шорткод для быстрого списка, а отдельный шаблон темы — выводить подробный вид одного объекта.
Шорткод [flex-objects]¶
Шорткод [flex-objects] (псевдоним [flex]) рендерит коллекцию Flex прямо там, где обрабатывается контент страницы. Это рекомендуемый способ показать данные Flex внутри контента, потому что он не требует открывать Twig в контенте.
Почему не просто Twig?¶
В Grav 2.0 окружение Twig фронтенда работает внутри песочницы. Песочница блокирует привилегированные вызовы, которые понадобились бы, чтобы получить коллекцию Flex из контента, например:
Этот вызов по умолчанию запрещён, и на то есть причина: авторы контента не должны иметь доступ к произвольным внутренностям фреймворка из тела страницы. Шорткод решает это аккуратно. Обработчик выполняется на сервере с полными правами, поэтому редакторы набирают только безопасный и ограниченный синтаксис шорткода, а сам рендеринг Flex происходит в PHP. Вы получаете динамический вывод Flex в контенте, не ослабляя песочницу.
Принимаемые параметры¶
Шорткод читает следующие параметры:
| Параметр | Описание |
|---|---|
collection |
Тип Flex (директория) для рендеринга, например people. Можно также использовать type= как псевдоним или форму bbcode [flex-objects=people]. Это единственное обязательное значение. |
select |
Список ключей объектов через запятую. Сужает коллекцию до этих объектов, сохраняя порядок, в котором вы их перечислили. |
sort |
Поле для сортировки. Используйте sort="field" для сортировки по возрастанию либо sort="field|asc" / sort="field|desc", чтобы задать направление явно. order= принимается как псевдоним. |
limit |
Положительное целое число. Рендерит только первые N объектов. |
layout |
Макет коллекции. Если опущено, используется default. |
Примеры¶
[flex-objects collection=people layout=cards limit=10 sort="last_name|asc" /]
Коллекция рендерится через свой шаблон Flex — точно так же, как это сделал бы {% render %}, поэтому любой уже имеющийся у вас макет коллекции продолжит работать. О том, как разрешаются эти макеты, см. раздел Twig в шаблонах темы ниже.
Предупреждение
Шорткод может рендерить любую зарегистрированную директорию, в том числе такую, объекты которой вы не собирались публиковать. Поскольку авторы контента могут указать любое значение collection=, осознанно подходите к тому, какие директории можно рендерить на публичных страницах. Считайте шорткод публичным путём чтения этих данных и не полагайтесь на него, чтобы скрыть что-то конфиденциальное. Если директория никогда не должна появляться на фронтенде, не включайте её на публичном сайте и опирайтесь на флаги публикации отдельных объектов в своих макетах (например, фильтруя по полю published).
Тип страницы flex-objects¶
Второй механизм — отдельный тип страницы. Страница становится страницей Flex одним из двух способов: задайте в её заголовке блок flex, где directory указывает на тип, либо установите template страницы в flex-objects. После этого страница рендерит список директории или отдельный объект по параметрам URL.
По умолчанию страница flex-objects принимает два параметра URL: directory и id. Они используются для навигации по директориям.
Вывод нескольких директорий на странице directories/flex-objects.md:
Либо можно передать отдельную конфигурацию для каждой директории:
---
title: Directories
flex:
layout: default
directories:
contacts:
collection:
title: '{{ directory.title }}'
layout: default
object:
layout: list-default
object:
title: 'Contact: {{ object.first_name }} {{ object.last_name }}'
layout: default
services:
---
# Directories
Вывод одной директории на странице contacts/flex-objects.md:
---
title: Contacts
flex:
directory: contacts
collection:
title: '{{ directory.title }}'
layout: default
object:
layout: list-default
object:
title: 'Contact: {{ object.first_name }} {{ object.last_name }}'
layout: default
---
# Contacts
Вывод одного объекта на странице my-contact/flex-objects.md:
---
title: Contact
flex:
directory: contacts
id: ki2ts4cbivggmtlj
object:
title: 'Contact: {{ object.first_name }} {{ object.last_name }}'
layout: default
---
# Contacts
Примеры URL для таких страниц выглядят так:
https://www.example.com/directories/directory:contacts/id:ki2ts4cbivggmtlj
https://www.example.com/contacts/id:ki2ts4cbivggmtlj
Когда страница получает параметр id, она рендерит этот отдельный объект; без него — список коллекции. Параметр directory выбирает, какой тип показывать, если страница ещё не закреплена за одним типом в своём заголовке.
Совет
В блок flex можно передать собственные параметры и использовать их в файлах шаблонов коллекции и объекта, так что заголовок страницы заодно служит местом настройки собственных макетов.
Twig в шаблонах темы¶
Для полного контроля вы рендерите коллекции и объекты Flex прямо из Twig в своей теме с помощью тега render. И коллекции, и объекты поддерживают рендеринг в HTML, а вывод можно настроить двумя аргументами: layout и context. Макет выбирает файл шаблона (так у вас может быть компактный список карточек и более подробный вид), а контекст передаёт в шаблон дополнительные переменные.
{% render collection layout: 'custom' with { context_variable: true } %}
{% render object layout: 'custom' with { context_variable: true } %}
Поиск шаблонов¶
Шаблоны Flex лежат в папке templates/flex вашей темы (или плагина). У каждого типа есть две подпапки: одна для рендеринга коллекции, другая для рендеринга отдельного объекта:
Grav находит шаблон по типу и имени макета:
- Коллекции загружаются из
flex/{TYPE}/collection/{LAYOUT}.html.twig - Объекты загружаются из
flex/{TYPE}/object/{LAYOUT}.html.twig
Сегмент {LAYOUT} — это layout:, который вы передаёте в render (по умолчанию default), а имя файла без расширения и есть имя макета. В примере выше у нас есть макет default и для коллекции, и для объекта.
Шаблон коллекции¶
Шаблон коллекции отвечает за рендеринг всех объектов коллекции. Отрендеренный вывод по умолчанию кэшируется; ключ кэша выводится из коллекции и контекста, переданного в метод render().
Примечание
Если контекст содержит нескалярные значения, кэширование отключается. Держите контекст как можно проще.
Вот пример шаблона коллекции:
<div id="flex-objects">
<div class="text-center">
<input class="form-input search" type="text" placeholder="Search by name, email, etc" />
<button class="button button-primary sort asc" data-sort="name">
Sort by Name
</button>
</div>
<ul class="list">
{% for object in collection.filterBy({ published: true }) %}
<li>
{% render object layout: layout with { options: options } %}
</li>
{% endfor %}
</ul>
</div>
Примечание
Если отрендеренный HTML содержит динамический контент, кэш рендеринга можно отключить из шаблона Twig с помощью {% do block.disableCache() %}.
Шаблон объекта¶
Шаблон объекта рендерит один объект. Его вывод тоже по умолчанию кэшируется, ключ строится по объекту и контексту, переданному в render().
Примечание
Если контекст содержит нескалярные значения, кэширование отключается. Держите контекст как можно проще.
Вот пример шаблона объекта:
<div class="entry-details">
{% if object.website %}
<a href="{{ object.website|e }}"><span class="name">{{ object.last_name|e }}, {{ object.first_name|e }}</span></a>
{% else %}
<span class="name">{{ object.last_name|e }}, {{ object.first_name|e }}</span>
{% endif %}
{% if object.email %}
<p><a href="mailto:{{ object.email|e }}" class="email">{{ object.email|e }}</a></p>
{% endif %}
</div>
<div class="entry-extra">
{% for tag in object.tags %}
<span>{{ tag|e }}</span>
{% endfor %}
</div>
Собственные макеты¶
Собственные макеты позволяют сделать сколько угодно разных видов коллекций и объектов. Создайте макет, добавив новый файл рядом с default.html.twig; имя файла без расширения станет именем макета. Тогда рендеринг {% render collection layout: 'cards' %} загрузит flex/{TYPE}/collection/cards.html.twig.
Совет
В макетах коллекций лучше вызывать {% render object layout: 'xxx' %} для каждого элемента, а не выводить поля объекта напрямую в шаблоне коллекции. Так разметка отдельного объекта остаётся в одном месте и переиспользуется между макетами.
Что выбрать?¶
| Если вы хотите... | Используйте |
|---|---|
| Вставить список в контент страницы, не трогая тему | Шорткод [flex-objects] |
| Дать директории собственный URL на фронтенде со списком и подробностями | Тип страницы flex-objects |
| Полностью контролировать разметку и интегрироваться с темой | Twig render в шаблонах темы |
О способах работы с теми же данными через REST API и Admin Next см. раздел REST API Flex-объектов и разделы Admin Next.