Creating breadcrumbs in Drupal 8
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.