19 Sep.2018

Drupal 8 & 9: How create a simple custom module for breadcrumbs: Example #2

Own custom breadcrumb

In the previous article "How to create a simple custom module for breadcrumbs", I wrote how to make a custom module for breadcrumbs. This article extends the code shown in the previous example. Below is an example of how you can do it yourself.

Of course, this code does not have an admin interface and is not configurable. However, as practice shows, this is enough for most and easily editable at any time.

I tried to leave the necessary comments in the code. I hope this will help anyone :-)

File
easydrupal_breadcrumb.services.yml
services:
  easydrupal_breadcrumb.breadcrumb_nodes:
    class: Drupal\easydrupal_breadcrumb\Breadcrumb\BreadcrumbNodesBuilder
    tags:
     - { name: breadcrumb_builder, priority: 100 }
  easydrupal_breadcrumb.breadcrumb_views:
    class: Drupal\easydrupal_breadcrumb\Breadcrumb\BreadcrumbViewsBuilder
    tags:
     - { name: breadcrumb_builder, priority: 100 }
File
/src/Breadcrumb/BreadcrumbNodesBuilder.php
<?php
 
namespace Drupal\easydrupal_breadcrumb\Breadcrumb;
 
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Link;
use Drupal\node\NodeInterface;
 
class BreadcrumbNodesBuilder implements BreadcrumbBuilderInterface {
 
  /**
   * {@inheritdoc}
   */
  public function applies(RouteMatchInterface $attributes) {
    $parameters = $attributes->getParameters()->all();
    if (isset($parameters['node']) && $parameters['node'] instanceof NodeInterface) {
      return TRUE;
    }
  }
 
  /**
   * {@inheritdoc}
   */
  public function build(RouteMatchInterface $route_match) {
    $breadcrumb = new Breadcrumb();
 
    $node = \Drupal::routeMatch()->getParameter('node');
    $node_type = $node->bundle();
 
    switch ($node_type) {
 
      // If node type is "article".
      // I want to add as parent of breadcrumb my summary articles view.
      case 'article':
        $breadcrumb->addLink(Link::createFromRoute('Home', '<front>'));
        $breadcrumb->addLink(Link::createFromRoute('News', 'entity.node.canonical', ['node' => '10360']));
 
        break;
 
      // If node type is "event"
      // I want to add as parent of breadcrumb my summary event view.
      case 'event':
        $breadcrumb->addLink(Link::createFromRoute('Home', '<front>'));
        $breadcrumb->addLink(Link::createFromRoute('Events', 'entity.node.canonical', ['node' => '8085']));
 
        break;
 
      // If node type is "location / venue"
      // I want to add as parent of breadcrumb my Campus Map page.
      case 'location':
        $breadcrumb->addLink(Link::createFromRoute('Home', '<front>'));
        $breadcrumb->addLink(Link::createFromRoute('Campus Map', 'entity.node.canonical', ['node' => '6']));
 
        break;
 
      // If node type is "person"
      // I want to add as parent of breadcrumb my Directory page.
      case 'person':
        $breadcrumb->addLink(Link::createFromRoute('Home', '<front>'));
        $breadcrumb->addLink(Link::createFromRoute('Directory', 'view.a_z.page_1'));
 
        break;
      // If node type is "page"
      // I want to add custom breadcrumbs for few pages.
      case 'page':
 
        // Apply the custom breadcrumbs for News page.
        if ($node->id() == '10360') {
          $breadcrumb->addLink(Link::createFromRoute('Home', '<front>'));
          $breadcrumb->addLink(Link::createFromRoute('About', 'entity.node.canonical', ['node' => '15220']));
        }
 
        break;
 
      default:
        $breadcrumb->addLink(Link::createFromRoute('Home', '<front>'));
 
        break;
 
    }
 
    // Don't forget to add cache control,otherwise you will surprised,
    // all breadcrumb will be the same for all pages.
    // By setting a "cache context" to the "url", each requested URL gets it's
    // own cache. This way a single breadcrumb isn't cached for all pages on the
    // site.
    $breadcrumb->addCacheContexts(['url']);
 
    // By adding "cache tags" for this specific node, the cache is invalidated
    // when the node is edited.
    $breadcrumb->addCacheTags(["node:{$node->id()}"]);
 
    return $breadcrumb;
  }
 
}
File
src/Breadcrumb/BreadcrumbViewsBuilder.php
<?php
 
namespace Drupal\easydrupal_breadcrumb\Breadcrumb;
 
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Link;
 
class BreadcrumbViewsBuilder implements BreadcrumbBuilderInterface {
 
  /**
   * {@inheritdoc}
   */
  public function applies(RouteMatchInterface $attributes) {
    $parameters = $attributes->getParameters()->all();
    // I need my breadcrumbs for a few views ONLY.
    if (isset($parameters['view_id']) && !empty($parameters['view_id'])) {
      return TRUE;
    }
  }
 
  /**
   * {@inheritdoc}
   */
  public function build(RouteMatchInterface $route_match) {
    $breadcrumb = new Breadcrumb();
 
    $view_name = \Drupal::routeMatch()->getParameter('view_id');
 
    switch ($view_name) {
 
      case 'glossary':
        $breadcrumb->addLink(Link::createFromRoute('Home', '<front>'));
        $breadcrumb->addLink(Link::createFromRoute('A-Z Index', '<nolink>'));
 
        break;
 
    }
 
    // Don't forget to add cache control by a route, otherwise you will surprised,
    // all breadcrumb will be the same for all pages.
    $breadcrumb->addCacheContexts(['route']);
 
    return $breadcrumb;
  }
 
}
Conclusion

I hope the information in this article helpful. And of course, I would happy if you can provide the own solution in a comment below.

Ruslan Piskarov

Ukraine
PHP/WEB Developer / Drupal Expert. More than 11 years of experience delivering Drupal based General Purpose solutions for different sectors such as Job Boards, Product Portfolios, Geo Coding, Real Estate solutions, E-Commerce, Classifieds, Corporate and online Magazines/Newspapers.

Versions