В этой статье мы расскажем, как вывести любой блок с помощью подстановки токена в текстовое поле. В итоге у нас получится готовый модуль для 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.

Добавить комментарий