Drupal 8 Tour API позволяет создавать интерактивные туры по административным страницам, предоставляя редакторам наглядные обучающие подсказки.
В Drupal 8 появился новый Tour API. Это совершенно новый функционал для Drupal, следовательно, в 7-й версии его не было, но были варианты реализации с помощью контрибов, но их подход в корне отличается от того что мы видем в 8-ке.
Tour API - это небольшой фукнционал для создания "туров" по страницам, в основном административным. Другими словами, этот API позволяет нам создавать обучающие подсказки на необходимых страницах, тем самым избавляя от необходимости где-то указывать это отдельно, если это можно описать в двух словах. Это и наглядно, и быстро. При этом не нужно искать в интернете, достаточно нажать соответствующую кнопку.
Вот пример тура из Views.
Сделано это всё при помощи jQuery плагина под названием Joyride. Но вся прелесть в том, что нам не нужно использовать его API, подключать js и т.д. Библиотека находится в ядре друпала и обёрнута в соответствующий API, который и называется Tour. Всё это смешали с повсеместным использованием yaml файлов, и получилось достаточно просто и удобно. Создать свои туры можно совершенно не владея навыками программирования, достаточно лишь следовать инструкции и немного понимать устройство HTML (что такое id).
Теория
Как я уже сказал выше, туры объявляются в yaml файлах и конфигурации данного API
имеют следующий паттерн: module.type.id.yml
. Стоит обратить внимание, что это
паттерн Tour, а не вашего модуля, следовательно название файла тура должно быть
следующим: tour.tour.MY-CUSTOM-TOUR-NAME.yml
. Т.е. мы лишь указываем название
нашего тура, и всё, этого достаточно. Особое внимание обратите на то, что
допускаются дифисы, но не нижнее подчеркивание.
Листинг у туров следующий:
# Идентификатор тура.
id: MY-CUSTOM-TOUR-NAME
# Модуль, который объявляет тур.
module: mymodule
# Небольшой заголовок (название) нашего тура. Фигуриует лишь в данном файле.
# В дальнейшем планируется появление Tour UI, следовательно там оно будет
# задействовано.
label: 'My custom tour'
# Язык тура. В случае 'en' всё содержимое шагов тура будет переводимо.
langcode: en
# Маршруты на которых будет доступен наш тур.
routes:
- route_name: mymodule.foo
- route_name: mymodule.bar
# Зависимости. Здесь указываются модули которые необходимы для данного тура.
dependencies:
module:
- myanothermodule
# Непосредственно наши подсказки.
tips:
# Уникальный идентификатор подсказки в пределах данного тура.
my-tip-1:
# То же самое что и выше, дублируется.
id: my-tip-1
# Указывает на то, что данная подсказка имеет тип "текст" (html).
# В ядре находится только данный тип подсказки, но по всей видимости оно
# расширяется или будет расширяться через кастом.
plugin: text
# Заголовок для подсказки. Будет выведено в виде h3 элемента подсказки.
# Обратите внимание что строковые значения оборачиваются одинарными (!)
# кавычками, а также то, что эта строка будет переводима, не нужно писать
# на русском языке, или укажите langcode: ru.
label: 'My custom tip'
# Содержимое подсказки. Не нужно оборачивать его тегом <p>, так как он
# добавляется автоматически и вложенность может вызывать проблемы с
# отображением.
body: 'Hello <strong>World</strong>!'
# Позиция подсказки относительно элемента к которому применяется.
# Доступные значения: left, right, top, bottom (по-умолчанию bottom)
location: left
# Вес подсказки. Так как они выводятся поочередно, то вес и создает данную
# очередь.
weight: 1
# Аттрибуты подсказки. В базовом плагине имеются всего два аттрибута:
# data-id и data-class, они отвечают за выборку для тултипа. Если ни один
# из них не указать (т.е. вообще не указывать attributes), то будет показана
# модальная подсказка (по центру страницы).
attributes:
# HTML ID элемента к которому будет применена подсказка, знак #
# опускается. В данном случае подсказка будет показана к элементу
# id="edit-button".
data-id: edit-button
# То же самое что и с id. Единственное отличие, что тут допустм ввод
# более сложных селекторов, например a[href^="google"]
data-class: my-button-class
my-tip-2:
...
my-tip-3:
...
Практика
Чтобы нам особо не мучиться с подготовкой, давайте возьмем заготовку для модуля, который будет добавлять тур на страницу '/admin/config/system/site-information' (Информация о сайте). Эта страничка из ядра, и на ней достаточно обьемная форма, поэтому она удачно сойдет за пример, так как на ней отсутствует тур.
Всё что нам нужно, это модуль в базовой реализации, и файлик тура. Файлы туров
являются yml файлами, и по сути конфигурациями, поэтому они должны находиться в
папке config, и в подпапке optional. Там существуют разные категории
конфигураций, install, schema, optional, но в данном случае нам нужен именно
optional (эта инфа уже не из даной темы, если интересно можете погуглить
Configuration API, об этом я напишу позже). И в этой папке мы создаём файл тура
по следующему шаблону: tour.tour.[tour-name].yml
. Допустим наш тур будет
называться site-information-help, следотвательно, должна получиться такая
структура:
helloworld (модуль)
- config
-- optional
--- tour.tour.site-information-help.yml
Далее дело за малым, написать наш тур.
id: site-information-help
module: helloworld
# Обратите внимание как нужно выводить ' внутри строки.
label: 'Site''s information tour'
# В данном случае мы используем русский чтобы писать подсказки сразу ну русском
# в случае с языком en они станут переводимы - и надо будет писать на
# английском.
langcode: ru
routes:
# /admin/config/system/site-information
- route_name: system.site_information_settings
# Так как эту страницу добавляет модуль system (там же я и посмотрел название
# роута для страницы), то нам надо установить зависимость.
dependencies:
module:
- system
tips:
greetings:
id: greetings
plugin: text
label: 'Привет! Это настройки сайта.'
body: 'В данном разделе вы можете изменить базовые настройки сайта.'
weight: 1
site-name:
id: site-name
plugin: text
label: 'Название сайта'
body: 'В данном поле вы указываете название вашего сайта, оно будет выводиться в шапке сайта, а также в заголовке окна браузера.'
weight: 2
attributes:
data-id: edit-site-name
site-slogan:
id: site-slogan
plugin: text
label: 'Слоган сайта'
body: 'В данном поле можно написать как слоган сайта, так и слоган компании. Поведение данного поля зависит от темы.'
weight: 3
attributes:
data-id: edit-site-slogan
site-mail:
id: site-mail
plugin: text
label: 'E-mail адрес сайта'
body: 'Данный электронный адрес будет использоваться в качестве отправителя всех писем с сайта по умолчанию. Также, на этот адрес будут высылаться оповещения об обновлениях и прочие письма.'
weight: 4
attributes:
data-id: edit-site-mail
site-frontpage:
id: site-frontpage
plugin: text
label: 'Главная страница сайта'
body: 'В данном поле вы можете указать относительный путь до страницы, которая будет использоваться в качестве главной. Вы также можете оставить данное поле пустым, чтобы главная страница была стандартной.'
weight: 5
attributes:
data-id: edit-site-frontpage
error-pages:
id: error-pages
plugin: text
label: 'Страницы об ошибках'
body: 'В этом разделе настраиваются страницы об ошибках 403 и 404. Если указаны пути, то на них будет произвдена переадресация в случае конкретной ошибки.'
weight: 6
attributes:
data-id: edit-error-page
save:
id: save
plugin: text
label: 'Сохранение настроек'
body: 'Если вы внесли какие-либо изменения на данной странице, вам необходимо сохранить их используя данную кнопку.'
weight: 7
attributes:
data-id: edit-submit
goodbye:
id: goodbye
plugin: text
label: 'Спасибо за внимание'
body: 'На этом тур завершен, спасибо за внимание.'
weight: 8
Теперь нам надо включить наш модуль. В случае, если всё сделали правильно, на странице настроек сайта появиться кнопка тура:
Ну и при нажатии у нас запуститься наш тур:
Вот так просто делаются туры без единой строчки кода.
Возможные проблемы
Всё бы хорошо, но файл тура является конфигурацией, а следовательно это может доставить некоторые неудобства в процессе создания тура. Проблема в том, что файлы конфигурации импортируются единожды (!) при активации модуля. Т.е. если вы сделали данный тур, включили модуль, а затем добавили еще 1 пункт, то он не появится. Самое первое что придет на ум, это деинсталировать модуль с туром и активировать заного. Но это может поавлечь за собой иные проблемы и не является правильным решением.
Решение всё же имеется - Configuration Manager. Оно не идеальное, но работает. Для этого нам надо активировать наш модуль чтобы тур импортировался успешно и был внесен в конфигурации. Далее заходим на страницу экспорта одиночной (! admin/config/development/configuration/single/export) конфигурации (не всех что есть на сайте) и выбираем наш тур:
Ниже появиться экспорт нашего тура. Копируем содержимое. Оно отличается от оригинального только тем, что там добавлен UUID, поэтому удалять его не стоит. Затем правим наш тур в любом удобном редакторе, копируем содержимое файла (а не сам файл) и импортируем:
И когда всё доделаете, изменения переносим уже в оригинальный конфиг файл из config/optional.
Да, это не очень удобно, поэтому делается Tour UI. Но и надо заметить, делать туры не так сложно, и постоянно проверять что получилось тоже нет смысла. Поэтому их можно написать с первого раза и такие пляски вовсе не потребуются. Разве что на первое время, чтобы понять как это устроено.
На drupal.org был еще метод через синхронизацию конфигураций, но он не работает. Почему-то не распознает конфигурацию, даже с UUID меткой.
На этом всё, спасибо за внимание.
Удобно использовать для апдейта конфігов - https://www.drupal.org/project/config_update