Creating breadcrumbs in Drupal 8

A really easy to use API

This article was originally posted at Medium

A breadcrumb or breadcrumb trail is a graphical control element frequently used as a navigational aid in user interfaces and on web pages. (Wikipedia)

Breadcrumbs have become a service in Drupal 8; so, in order to customize the breadcrumbs programatically, you need to create a breadcrumb_builder service and define when your service class applies to create the breadcrumbs and actually build the breadcrumbs using the interfaces and functions provided by the API.

Assuming you have a content type named blog and a taxonomy vocabulary named category, you want all blog post to have a breadcrumb like this: Home -> Category -> Blog Title. Let's do it! We'll use a module named demo_module

The first thing you need to do is to define the service. In order to do this, you need a demo_module.services.yml file with a content like this:

services:
  demo_module.breadcrumbs:
    class: Drupal\demo_module\BreadcrumbsBuilder
    arguments: ['@current_user', '@access_manager']
    tags:
      - { name: breadcrumb_builder, priority: 100 }

The only other thing that you need to create is obviously the BreadcrumbsBuilder class. Given the class name we gave in the service definition, you need a file named BreadcrumbsBuilder.php under src folder with content like this:

<?php
namespace Drupal\demo_module;
use Drupal\Core\Access\AccessManagerInterface;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Link;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
class BreadcrumbsBuilder implements BreadcrumbBuilderInterface {
  use StringTranslationTrait;
  /**
   * The access manager.
   *
   * @var \Drupal\Core\Access\AccessManagerInterface
   */
  protected $accessManager;
  /**
   * The user currently logged in.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;
  /**
   * {@inheritdoc}
   */
  public function __construct(AccountInterface $current_user, AccessManagerInterface $access_manager) {
    $this->currentUser = $current_user;
    $this->accessManager = $access_manager;
  }
  public function applies(RouteMatchInterface $route_match) {
    if ($node = $route_match->getParameter('node')) {
      return TRUE;
    }
    return FALSE;
  }
  public function build(RouteMatchInterface $route_match) {
    $breadcrumb = new Breadcrumb();
    $access = $this->accessManager->check($route_match, $this->currentUser, NULL, TRUE);
    $breadcrumb->addCacheableDependency($access);
    $breadcrumb->addCacheContexts(['url.path']);
    $node = $route_match->getParameter('node');
    $links = [];
    $links[] = Link::createFromRoute($node->label(), '<none>');
    $term = $node->field_category->entity;
    $links[] = Link::createFromRoute($term->label(), 'entity.taxonomy_term.canonical', ['taxonomy_term' => $term->id()]);
    $links[] = Link::createFromRoute($this->t('Home'), '<front>');
    return $breadcrumb->setLinks(array_reverse($links));
  }
}

Besides constructor (where you do all the usual handle of dependency injection), you have two important functions: applies and build.

In applies() you should return a boolean indicating whether your breadcrumb builder applies or not to the given context. In our case, it applies to all nodes in our installation (let's assume it's a very small site only used as a blog).

In build(), you need to create the breadcrumb. It's recommended to add cache metadata (we do that in first lines in the function). Then, you should create a links array and set those links to the created Breadcrumb object using the function setLinks (we use array_reverse to have the breadcrumbs in the expected order).

And that's all! Enjoy your breadcrumbs by placing the breadcrumbs block in your site.

Tags:
Submitted by kporras07 on