Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Свой блок

Блок — кусок страницы, который администратор размещает в областях темы: в шапке, боковой колонке, подвале. Модуль может добавить свой блок — например, «Свежие статьи». Для этого нужен один класс в определённой папке.

Где лежит блок

Класс блока кладут в папку src/Plugin/Block модуля. Путь важен: Drupal ищет блоки именно там. Создайте папки и файл вручную или командой drush generate plugin:block.

Простой блок

// web/modules/custom/blog/src/Plugin/Block/LatestArticlesBlock.php
namespace Drupal\blog\Plugin\Block;
 
use Drupal\Core\Block\Attribute\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;
 
#[Block(
    id: 'blog_latest_articles',
    admin_label: new TranslatableMarkup('Свежие статьи'),
    category: new TranslatableMarkup('Blog'),
)]
class LatestArticlesBlock extends BlockBase
{
    public function build(): array
    {
        return [
            '#markup' => $this->t('Здесь будут свежие статьи.'),
        ];
    }
}

Запись #[Block(...)] над классом — атрибут PHP: по нему Drupal узнаёт машинное имя блока и название для панели. Метод build() возвращает массив вывода — такой же, как в контроллере.

Размещение

Выполните drush cr и откройте «Структура → Схема блоков», адрес /admin/structure/block. Рядом с нужной областью нажмите «Разместить блок», найдите «Свежие статьи» и сохраните. Блок появится на страницах сайта в выбранной области. В форме размещения можно задать заголовок и ограничить показ отдельными страницами или ролями.

Блок с данными

Выведем настоящие статьи. Сервисы блок получает через create(), но у блоков этот метод принимает больше аргументов, и класс должен объявить интерфейс ContainerFactoryPluginInterface:

// web/modules/custom/blog/src/Plugin/Block/LatestArticlesBlock.php
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
 
class LatestArticlesBlock extends BlockBase implements ContainerFactoryPluginInterface
{
    public function __construct(
        array $configuration,
        $plugin_id,
        $plugin_definition,
        private EntityTypeManagerInterface $entityTypeManager,
    ) {
        parent::__construct($configuration, $plugin_id, $plugin_definition);
    }
 
    public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static
    {
        return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity_type.manager'));
    }
 
    public function build(): array
    {
        $storage = $this->entityTypeManager->getStorage('node');
 
        $ids = $storage->getQuery()
            ->accessCheck(TRUE)
            ->condition('type', 'article')
            ->condition('status', 1)
            ->sort('created', 'DESC')
            ->range(0, 5)
            ->execute();
 
        $links = [];
 
        foreach ($storage->loadMultiple($ids) as $node) {
            $links[] = $node->toLink()->toRenderable();
        }
 
        return [
            '#theme' => 'item_list',
            '#items' => $links,
            '#cache' => ['tags' => ['node_list:article']],
        ];
    }
}

Атрибут #[Block] остаётся над классом, как в первом примере. Блок выведет список из пяти ссылок на свежие статьи. Свойство #cache сообщает, что блок нужно построить заново, когда создаётся или меняется статья, — о кеше есть отдельный урок.

Настройки блока

Чтобы число статей выбирал администратор, добавьте в класс три метода:

// web/modules/custom/blog/src/Plugin/Block/LatestArticlesBlock.php
use Drupal\Core\Form\FormStateInterface;
 
public function defaultConfiguration(): array
{
    return ['count' => 5];
}
 
public function blockForm($form, FormStateInterface $form_state): array
{
    $form['count'] = [
        '#type' => 'number',
        '#title' => $this->t('Сколько статей показывать'),
        '#default_value' => $this->configuration['count'],
        '#min' => 1,
        '#max' => 20,
    ];
 
    return $form;
}
 
public function blockSubmit($form, FormStateInterface $form_state): void
{
    $this->configuration['count'] = (int) $form_state->getValue('count');
}

Поле появится в форме размещения блока. В build() замените range(0, 5) на range(0, $this->configuration['count']). Один блок можно разместить несколько раз с разными настройками.

Частая ошибка

Блок не появляется в списке «Разместить блок». Проверьте по порядку: файл лежит в src/Plugin/Block, namespace равен Drupal\blog\Plugin\Block, над классом стоит атрибут с уникальным id, а после добавления файла выполнен drush cr. Ошибка в любом из пунктов не даёт сообщения — блок молча отсутствует.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.