Skip to content

Instantly share code, notes, and snippets.

@jonpugh
Created May 5, 2016 00:28
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save jonpugh/ccaeb01e173abbc6c88f7a332d271e4a to your computer and use it in GitHub Desktop.
Save jonpugh/ccaeb01e173abbc6c88f7a332d271e4a to your computer and use it in GitHub Desktop.
Add Taxonomy Term to a Node's Breadcrumb in Drupal 8
<?php
// src/Breadcrumbs.php
namespace Drupal\modulename;
use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Link;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\node\NodeInterface;
/**
* Class Breadcrumbs.
*
* @package Drupal\modulename
*/
class Breadcrumbs implements BreadcrumbBuilderInterface {
use StringTranslationTrait;
/**
* {@inheritdoc}
*/
public function applies(RouteMatchInterface $route_match) {
return $route_match->getRouteName() == 'entity.node.canonical'
&& $route_match->getParameter('node') instanceof NodeInterface;;
}
/**
* {@inheritdoc}
*/
public function build(RouteMatchInterface $route_match) {
$node = $route_match->getParameter('node');
$breadcrumb = new Breadcrumb();
// 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->nid->value}"]);
// Add "Home" breadcrumb link.
$breadcrumb->addLink(Link::createFromRoute($this->t('Home'), '<front>'));
// Given we have a taxonomy term reference field named "field_section", and that field has data,
// Add that term as a breadcrumb link.
if (!empty($node->field_section->entity)) {
$breadcrumb->addLink($node->field_section->entity->toLink());
}
return $breadcrumb;
}
}
# modulename.services.yml
services:
modulename.breadcrumbs:
class: Drupal\modulename\Breadcrumbs
tags:
- { name: breadcrumb_builder, priority: 100 }
@jonpugh
Copy link
Author

jonpugh commented May 5, 2016

I needed to take a taxonomy term from a node and add it to the breadcrumbs.

After a painful crash course in Drupal 8 Services and BreadcrumbBuilder, along with an unexpected ride through learning cache contexts and tags, I finally got this to work properly... I think.

The trickiest parts were the caches stuff, so I made sure to add some comments to explain what I think is happening.

@olmas-git
Copy link

Hi, I am a new of drupal, how can I implement your code?

@RishiKulshreshtha
Copy link

RishiKulshreshtha commented Jun 19, 2017

@olmas-git, @jonpugh has already provided the whole module in this gist. In case if you need a ready made bundle you can use my module which is built using the same code or I would suggest you to go with HOOK_preprocess_breadcrumb

Add this in your YOURTHEME.theme

/**
 * Implements HOOK_preprocess_breadcrumb().
 */
function YOURTHEME_preprocess_breadcrumb(&$variables) {
  if (($node = \Drupal::routeMatch()->getParameter('node')) && $variables['breadcrumb']) {
    $breadcrumb = &$variables['breadcrumb'];
    if (!empty($node->field_tags->entity)) {
      $term_url = $node->field_tags->entity->toLink();
      $node_url = array_pop($breadcrumb);
      array_push($breadcrumb, $term_url);
      array_push($breadcrumb, $node_url);
      // Implementing Cache.
      $variables['#cache']['contexts'][] = "url.path";
      $variables['#cache']['tags'][] = "node:{$node->nid->value}";
    }
  }
}

For more information, follow https://drupal.stackexchange.com/a/239154/3808

@mfrosch
Copy link

mfrosch commented Jun 19, 2017

If you also want the parents you can replace

    if (!empty($node->field_section->entity)) {
      $breadcrumb->addLink($node->field_section->entity->toLink());
    }

with

    if (!empty($node->field_section->entity)) {
      $term = $node->field_section->entity;
      $storage = \Drupal::service('entity_type.manager')
        ->getStorage('taxonomy_term');
      $parents = $storage->loadParents($term->id());

      if (!empty($parents)) {
        foreach ($parents as $index => $parent) {
          $breadcrumb->addLink($parent->toLink());
        }
      }

      $breadcrumb->addLink($term->toLink());
    }

@int-ua
Copy link

int-ua commented Dec 3, 2020

Thank you all, here is a slightly more parametrized theme code version for non-node entities with taxonomy parents:

/**
 * Implements hook_system_breadcrumb_alter().
 */
function THEMENAME_preprocess_breadcrumb(array &$vars) {
  // proper taxonomy breadcrumbs for Commerce Products through field_category
  $entity_type = 'commerce_product'; // TODO: change or verify
  $taxonomy_field_name = 'field_category'; // TODO: change or verify

  if (($entity = \Drupal::routeMatch()->getParameter($entity_type)) && $vars['breadcrumb']) {
    $cache_tag = "{$entity_type}:{$entity->product_id->value}"; // TODO: change or verify

    $breadcrumb = &$vars['breadcrumb'];
    if (!empty($entity->$taxonomy_field_name->entity)) {
      $node_url = array_pop($breadcrumb);

      $term = $entity->$taxonomy_field_name->entity;
      $storage = \Drupal::service('entity_type.manager')
        ->getStorage('taxonomy_term');
      $parents = $storage->loadParents($term->id());
      if (!empty($parents)) {
        foreach ($parents as $index => $parent) {
          array_push($breadcrumb, $parent->toLink());
        }
      }
      array_push($breadcrumb, $term->toLink());

      array_push($breadcrumb, $node_url);

      // Implementing Cache.
      $vars['#cache']['contexts'][] = "url.path";
      $vars['#cache']['tags'][] = $cache_tag;
    }
  }
}

@bohotina
Copy link

bohotina commented Feb 6, 2021

If you also want the parents you can replace

    if (!empty($node->field_section->entity)) {
      $breadcrumb->addLink($node->field_section->entity->toLink());
    }

with

    if (!empty($node->field_section->entity)) {
      $term = $node->field_section->entity;
      $storage = \Drupal::service('entity_type.manager')
        ->getStorage('taxonomy_term');
      $parents = $storage->loadParents($term->id());

      if (!empty($parents)) {
        foreach ($parents as $index => $parent) {
          $breadcrumb->addLink($parent->toLink());
        }
      }

      $breadcrumb->addLink($term->toLink());
    }

How would can I implement this solution to show the parents but using the YOURTHEME.theme preprocess function instead of the module? Thank you in advance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment