Drupal 8: Программное создание хлебных крошек

Статья о том, как самостоятельно создавать хлебные крошки в Drupal 8.

02.09.2016
13 комментариев
5 мин.

В Drupal 8 хлебные крошки из коробки покрывают, наверное, 99% необходимого. Я даже не смог придумать нормального примера для гайда, так как все разруливали хлебные крошки из ядра самостоятельно. Если кому интересно, этим занимается PathBasedBreadcrumbBuilder. Иными словами, если вы будете генерировать URL для всего на сайте иерархические /category-name/content-name, то Drupal сам разрулит и установит хлебные крошки. В иных случаях можно написать свои, и делается это легче простого.

Хлебные крошки в D8 - это сервис, который, в свою очередь, является классом, у которого всего 2 метода applies() и build(). Звучит знакомо? А то как же, программное переключение темы работает по тому же принципу. Первый отвечает за простую логику, должен текущий сервис хлебных крошек работать на данной странице или нет, и если ответ положительный, то мы генерируем хлебные крошки.

Я не знаю даже что ещё тут рассказать, ибо всё настолько просто, что я просто приведу код с примером и небольшими комментариями. Напишу лишь небольшую заметку о том что он делает. У меня есть на сайте тип материала article, а также словарь таксономии с категориями. Соответственно у article есть поле field_category, которое ссылается на нужную категорию. Данный код создает хлебные крошки следующего вида: Главная -> Категория. Этот код потребуется только если у вас не иерархические URL, или у материала адрес системного вида node/{NID}. Если бы был иерархический - то ничего бы писать и не пришлось.

Объявляем сервис dummy.service.yml
services:
  dummy.article_breadcrumb:
    class: Drupal\dummy\ArticleBreadcrumbBuilder
    arguments: []
    tags:
      - { name: breadcrumb_builder, priority: 10 }
Листинг /src/ArticleBreadcrumbBuilder.php
<?php

/**
 * @file
 * Contains Drupal\dummy\ArticleBreadcrumbBuilder.
 */

namespace Drupal\dummy;

use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Link;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\node\NodeInterface;
use Drupal\taxonomy\Entity\Term;

/**
 * Class ArticleBreadcrumbBuilder.
 */
class ArticleBreadcrumbBuilder implements BreadcrumbBuilderInterface {
  # Необходимо чтобы использовать $this->t().
  use StringTranslationTrait;

  /**
   * {@inheritdoc}
   */
  public function applies(RouteMatchInterface $route_match) {
    $node = $route_match->getParameter('node');
    # Только если мы находимся на странице сущности node типа article.
    return $node instanceof NodeInterface && $node->getType() == 'article';
  }

  /**
   * {@inheritdoc}
   */
  public function build(RouteMatchInterface $route_match) {
    $breadcrumb = new Breadcrumb();
    $node = $route_match->getParameter('node');
    # Добавляем первую крошку на главную страницу.
    $links = [Link::createFromRoute($this->t('Home'), '<front>')];
    # Вторую крошку добавляем если категория задана в поле field_category.
    if (!$node->field_category->isEmpty()) {
      $tid = $node->field_category->target_id;
      $category_term = Term::load($tid);
      # Добавляем хлебную крошку на страницу термина.
      $links[] = Link::createFromRoute($category_term->name->value, 'entity.taxonomy_term.canonical', ['taxonomy_term' => $tid]);
    }
    # Указываем контекст для кэширования данной хлебной крошки. В нашем случае
    # будет кэшироваться только для текущего адреса url.
    $breadcrumb->addCacheContexts(['url.path']);
    return $breadcrumb->setLinks($links);
  }
}
Результат данных хлебных крошек.

P.s. В Drupal 8, получается, что задавать хлебные крошки особо то и не придется, только для очень специфичных случаев. А я боялся, как же я буду жить без замечательного модуля Path Breadcrumbs, а оно вон как :) Он даже по факту и не нужен уже.

Код прилагаю.

Прикрепленные файлы
Кастомные хлебные крошки. — dummy.tar.gz, 1.33 КБ
Drupal
Drupal 8
хлебные крошки

Комментарии

Александр   пт, 09/09/2016 - 12:33

Как у тебя работают крошки из коробки? Что то писал под них или где то задавал? Какая версия Drupal? А то у меня что то не работают

Niklan   пт, 09/09/2016 - 13:37

Drupal 8 из коробки крошки составляются по адресу. Как я и указал в статье, там используется PathBasedBreadcrumbBuilder

Он составляет хлебные крошки на основе адреса текущего пути.

/catalog/category-name/product-name

Следовательно друпал постепенно соберет крошки из пути:

  • Главная - по дефолту.
  • /catalog - добавит крошку на данный адрес + заголовок данной страницы
  • /catalog/category-name - ссылка на страницу + её заголовок.

На текущую не ссылается. Для этого достаточно pathauto или руками проконтролировать иерархию путей.

Василий   чт, 18/05/2017 - 14:01

Столкнулся с тем, что views с аргументами не умеют нормально крошки выводить. Увы.

Алексей   пн, 28/08/2017 - 16:10

Добрый день! Подскажите пожалуйста, а возможно ли сделать так, чтобы показывался title текущей страницы в хлебных крошках? (в виде текста, не ссылки)

Niklan   вт, 29/08/2017 - 09:54

Не пробовал, но попробуйте вместо ссылки просто строку передать и посмотрите что будет.

Boolboost   пт, 26/01/2018 - 14:02

Срезало текст, пробелы перед и после "<", ">" нужно удалить.

С route "< none >" выводит чисто текст без ссылки.

$links[] = Link::createFromRoute($title, '< none >');

Влад   пн, 10/06/2019 - 15:04

Спасибо,твой комментарий помог добавить обычный текст :)

Boris   вт, 12/09/2017 - 12:15

Добрый день! Ваш модуль хорошо работает. Сейчас выводится только один термин из field_category. У меня это самый последний дочерний в иерархии таксономии. А как вывести еще и все родительские термины в хлебных крошках?

Dmitry   вт, 16/04/2019 - 11:58

В смысле пример не придумать? Банальная ситуация – Views выводит на страницу материалы, с этих материалов нужно вернуться на страницу представления. Список проектов, документов, партнеров – вся вот эта чепуха, которая есть на каждом корпоративном сайте.

Виталий   вт, 23/02/2021 - 00:36

Спасибо за статью. Все нормально работает если сайт одноязычный. Если сайт мультиязычный (русский -основной, англ -вторым), то при переключении на английский, хлебные крошки выводятся в виде: home/ категория (на русском)/node page (название страницы на транслите/английском). Не подскажите, как сделать, чтобы категория была тоже на англ. языке В любом случае, спасибо. PS переводы включены, справочник Ктагории переведен

Niklan   ср, 24/02/2021 - 08:34

Не имел дела с кастомными мультиязычными крошками, но если сущность получается из $route_match, то, вероятнее всего, нужно предварительно получить нужный перевод этой сущности при помощи ::getTranslation(), а уже из сущности перевода генерировать ссылку для крошки.

Виталий   ср, 24/02/2021 - 19:09

Спасибо! Немного изменил Ваш код в public function build:

if (!$node->field_product_category->isEmpty()) {
      $tid = $node->field_product_category->target_id;
      $category_term = Term::load($tid);
      $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
      $translation = $category_term->getTranslation($langcode);
      # Добавляем хлебную крошку на страницу термина.
      $links[] = Link::createFromRoute($translation->name->value, 'entity.taxonomy_term.canonical', ['taxonomy_term' => $tid]);
    }

и все стало ок.