Перейти к содержанию

Отображение контента Flex

Когда тип Flex определён и его директория включена, следующий шаг — вывести эти объекты на фронтенд. Grav даёт три дополняющих друг друга способа, каждый под свою задачу:

  1. Шорткод [flex-objects] — безопасный для песочницы способ вставить коллекцию прямо в контент страницы.
  2. Тип страницы flex-objects — страница, которая рендерит директорию (или отдельный объект) по параметрам URL.
  3. Twig в шаблонах темы, где тег render и поиск шаблонов Flex дают полный контроль.

Их можно свободно сочетать. Лендинг может использовать шорткод для быстрого списка, а отдельный шаблон темы — выводить подробный вид одного объекта.

Шорткод [flex-objects]

Шорткод [flex-objects] (псевдоним [flex]) рендерит коллекцию Flex прямо там, где обрабатывается контент страницы. Это рекомендуемый способ показать данные Flex внутри контента, потому что он не требует открывать Twig в контенте.

Почему не просто Twig?

В Grav 2.0 окружение Twig фронтенда работает внутри песочницы. Песочница блокирует привилегированные вызовы, которые понадобились бы, чтобы получить коллекцию Flex из контента, например:

{% render grav.get('flex').collection('people').select([...]) %}

Этот вызов по умолчанию запрещён, и на то есть причина: авторы контента не должны иметь доступ к произвольным внутренностям фреймворка из тела страницы. Шорткод решает это аккуратно. Обработчик выполняется на сервере с полными правами, поэтому редакторы набирают только безопасный и ограниченный синтаксис шорткода, а сам рендеринг 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 /]
Выбранные ключи
[flex-objects collection=people select=a131e8aa65,d46e15eaf5,987691a5c3 /]
Макет, лимит, сортировка
[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
  list:
  - contacts
  - services
---

# Directories

Либо можно передать отдельную конфигурацию для каждой директории:

---
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 вашей темы (или плагина). У каждого типа есть две подпапки: одна для рендеринга коллекции, другая для рендеринга отдельного объекта:

templates/
  flex/
    contacts/
      collection/
        default.html.twig
      object/
        default.html.twig

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.