В этой статье мы расскажем, как вывести любой блок с помощью подстановки токена в текстовое поле. В итоге у нас получится готовый модуль для Drupal 8-9.
Создание модуля
Создадим директорию для модуля и назовем её, например: insert_block_token.
Добавим файл конфигурации модулю insert_block_token.info.yml и добавим в него конфигурации.
name: Insert Block Token
type: module
description: "Inserts the contents of a block into the text field using token."
package: custom
core_version_requirement: ^8 || ^9
dependencies:
- drupal:block
- drupal:filter
version: '8.x-1.0'
project: 'insert_block_token'
Для правильной работы нам потребуется сделать 2 зависимости от блока block и filter. Эти блоки являются частью ядра Drupal.
Название и описание можно использовать на ваш выбор.
Теперь нам потребуется файл с кодом модуля insert_block_token.module.
/**
* Implements hook_help().
*/
function insert_block_token_help($path, $arg) {
switch ($path) {
case 'admin/help#insert_block_token':
return t('Use special token to insert the contents of a block into a text field. ');
}
}
Вся работа модуля будет реализована в плагине для текстовых фильтров, поэтому в insert_block_token.module мы добавляем только справочную информацию.
Создание фильтра
Создадим плагин для фильтра, соблюдая правила структуры директорий src/Plugin/Filter/. В директорию Filter добавляем файл InsertBlockTokenFilter.php. Имя файла состоит из названия модуля в CamelCase и Filter <НазваниеМодуля>Filter.php. Так как это стандартный тип плагина, подключать или указывать не нужно — Drupal автоматически подключит его сразу после включения модуля.
Определим пространство имен и дополнительные классы в нашем фильтре.
namespace Drupal\insert_block_token\Plugin\Filter;
use Drupal\Core\Url;
use Drupal\Core\Form\FormStateInterface;
use Drupal\filter\Plugin\FilterBase;
use Drupal\filter\FilterProcessResult;
- Url — класс ссылки;
- FormStateInterface — интерфейс для $form_state;
- FilterBase — класс фильтра;
- FilterProcessResult — класс для вывода содержимого фильтра.
Добавим класс и наследуем его от FilterBase, также добавим обязательную аннотацию к фильтру.
/**
* Class InsertBlockTokenFilter.
*
* @package Drupal\insert_block_token\Plugin\Filter
*
* @Filter(
* id = "filter_insert_block_token",
* title = @Translation("Insert blocks"),
* description = @Translation("Inserts the contents of a block into a node using [block:block-entity-id] tags."),
* type = Drupal\filter\Plugin\FilterInterface::TYPE_MARKUP_LANGUAGE,
* )
*/
class InsertBlockTokenFilter extends FilterBase {
Переопределим метод tips. Он отвечает за отображение подсказок на странице описания фильтров filter/tips и краткого описания фильтров в поле ввода.
public function tips($long = FALSE) {
if ($long) {
return $this->t('You may use [block:block_entity_id] to display the contents of block.');
} else {
$tips_url = Url::fromRoute("filter.tips_all", [], ['fragment' => 'filter-insert_block_token']);
return $this->t('You may use [block:block_entity_id] to display the contents of block.', ["@insert_block_token_help" => $tips_url->toString()]);
}
}
Код работы фильтра пишем в методе process. Для начала добавим регулярное выражение, которое в содержимом будет находить наш токен. Далее из токена будем доставать id сущности блока.
public function process($text, $langcode) {
if (preg_match_all("/\[block:([^\]]+)+\]/", $text, $match)) {
$raw_tags = $repl = [];
foreach ($match[1] as $key => $value) {
$raw_tags[] = $match[0][$key];
if (strpos($value, '=') !== FALSE) {
$block_id_split = explode('=', $value); $block_id = $block_id_split[1];
} else {
$block_id = $value;
}
Теперь нам нужно добавить вызов блока. Добавим код для блоков и кастомных блоков (контентных, создаваемых в админке). Инициализируем переменную $replacement и положим в нее рендер блока.
$replacement = '';
// Render blocks in code.
if ($block = \Drupal::service('entity_type.manager')
->getStorage('block')
->load($block_id)) {
$block_view = \Drupal::service('entity_type.manager')
->getViewBuilder('block')
->view($block);
$replacement = \Drupal::service('renderer')->render($block_view);
}
// Render custom blocks.
if ($block = \Drupal::service('entity_type.manager')
->getStorage('block_content')
->load($block_id)) {
$block_view = \Drupal::service('entity_type.manager')
->getViewBuilder('block_content')
->view($block); $replacement = \Drupal::service('renderer')->render($block_view);
}
$repl[] = $replacement;
В заключении осталось только подменить наш токен в содержимом и передать измененное содержимое как результат работы фильтра на вывод.
$text = str_replace($raw_tags, $repl, $text);
}
return new FilterProcessResult($text);
Итог
Мы написали модуль и реализовали в нем подстановку блока по токену.
Код всего модуля: insert_block_token
Документация по классу FilterBase.
Добавить комментарий