1

I'm trying to customize the breadcrumb of drupal 8 to get something like this:

Home > category >article-title.

I wrote this and I wrote the code below.

namespace Drupal\module_demo\Breadcrumb;

use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Link;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\taxonomy\Entity\Term;

class ArticleBreadcrumbBuilder implements BreadcrumbBuilderInterface {

    public function applies(RouteMatchInterface $route_match) {
        $parameters = $route_match->getParameters()->all();
        if(isset($parameters['node'])) {
            return $parameters['node']->getType() === 'article';
        }

    }

    public function build(RouteMatchInterface $route_match) {

        $breadcrumb = new Breadcrumb();

        $term = $route_match->getParameter('taxonomy_term');

        $breadcrumb->addCacheContexts(["url"]);

        $breadcrumb->addLink(Link::createFromRoute(t('Home'), '<front>'));

        $breadcrumb->addLink(Link::createFromRoute(t('Articles'), '<none>'));

        $breadcrumb->addLink(Link::createFromRoute($term->getName(), 'entity.taxonomy_term.canonical', ['taxonomy_term' => $term->id()]));

        $request = \Drupal::request();
        $route_match = \Drupal::routeMatch();
        $page_title = \Drupal::service('title_resolver')->getTitle($request, $route_match->getRouteObject());
        if (!empty($page_title)) {
            $breadcrumb->addLink(Link::createFromRoute($page_title, '<none>'));
        }

        return $breadcrumb;
    }
}

but I have the error below.

The website encountered an unexpected error. Please try again later. Error: Call to a member function getName() on null in Drupal\module_demo\Breadcrumb\ArticleBreadcrumbBuilder->build() (line 34 of modules/custom/module_demo/src/Breadcrumb/ArticleBreadcrumbBuilder.php).

Apparently the problem is with getName() and id().

Can someone tell me where the mistake is?

3

You can also use hook_system_breadcrumb_alter to achieve this:
Try this:

/**
 * Implements hook_system_breadcrumb_alter().
 */
function MyModule_system_breadcrumb_alter(\Drupal\Core\Breadcrumb\Breadcrumb &$breadcrumb, \Drupal\Core\Routing\RouteMatchInterface $route_match, array $context) {
  $node = \Drupal::request()->attributes->get('node');
  if ($node && $node instanceof Drupal\node\Entity\Node) {
    if ($node->bundle() == 'article') {
      // Add Articles item.
      $breadcrumb->addLink(Link::createFromRoute(t('Articles'), '<none>'));
      // Add category term item to breadcrumb.
      // Change here the field_tags with your taxonomy you want to add to breadcrumb.
      $term_id = $node->field_tags->getValue()[0]['target_id'];
      $term = Term::load($term_id);
      $breadcrumb->addLink(Link::createFromRoute($term->getName(), 'entity.taxonomy_term.canonical', ['taxonomy_term' => $term->id()]));
      // Add title as breadcrumb item.
      $request = \Drupal::request();
      $route_match = \Drupal::routeMatch();
      $page_title = \Drupal::service('title_resolver')
        ->getTitle($request, $route_match->getRouteObject());
      if (!empty($page_title)) {
        $breadcrumb->addLink(Link::createFromRoute($page_title, '<none>'));
      }
    }
  }
}

Update: To fix the error.
Update the applies method to apply your breadcrumb only on articles as it mentioned in @Jdrupal answer:

  public function applies(RouteMatchInterface $route_match) {
    $parameters = $route_match->getParameters()->all();
    if (isset($parameters['node'])) {
      return $parameters['node']->getType() === 'article';
    }
    if (isset($parameters['term'])) {
      return TRUE;
    }
  }

The error comes from the line:

$term = $route_match->getParameter('taxonomy_term');

$term equal NULL its normal, you are in node page so the taxonomy_term param always null, so try to get your term from the node object something like:

 $node = \Drupal::request()->attributes->get('node');
 // Change the field_tags with your filed.
 $term_id = $node->field_tags->getValue()[0]['target_id'];
 $term = Term::load($term_id);
  • Hi @berramou, Thank you. Your solution works perfectly. Thank you very much. – Worksfather Nov 24 '19 at 21:03
  • But tell me please. I was talking about taxonomy term. It's rather the vocabulary I want. Can you tell me how to get in the code that you put the vocabulary instead of the taxonomy term. – Worksfather Nov 24 '19 at 21:11
  • I don't understand what you want to achieve exactly but if you want to get a vocabulary you can use something like $vocabulary = \Drupal\taxonomy\Entity\Vocabulary::load('tags'); $vocab_name = $vocabulary->get('name'); – berramou Nov 24 '19 at 21:23
  • Excuse me very much. I'm new and I think I'm mixing up the brushes. In fact, the code you made works perfectly. But after putting it on, I noticed that it was the first term of the tags that appeared (I finally understood by looking at the code). But in fact, I created in drupal two vocabularies called "Articles category" and which contain 2 terms (vocab1, vocab2). It is these terms that I want breadcrumb to display (not the name of the vocabulary itself). – Worksfather Nov 24 '19 at 21:51
  • It's okay, i get now, you want to display all terms of a vocabulary right? – berramou Nov 24 '19 at 21:57
2

The problem is that you try to get the term from the route, but in your applies() method you have restricted the breadcrumb to apply only on pages where you can get the node from the route.

If you want your breadcrumb to apply for taxonomy term pages as well your applies() function must look like this:

public function applies(RouteMatchInterface $route_match) {
  $parameters = $route_match->getParameters()->all();
  if (isset($parameters['node'])) {
    return $parameters['node']->getType() === 'article';
  }
  if (isset($parameters['term'])) {
    return TRUE;
  }
}

Otherwise you have to remove $term->getName() from your build() method.

UPDATE: Since you mention you only want to display the breadcrumb on article pages, you must fetch the term from the node.

Replace this line:

$term = $route_match->getParameter('taxonomy_term');

With:

$term = $route_match->getParameter('node')->field_term->first()->entity;

Then you can call $term->label().

  • Hi @Jdrupal. I don't know if I don't understand what you said. But what I want is to display the breadcrumb for only article type nodes. But in the breadcrumb I want the category to appear. As Home > Category > title-article – Worksfather Nov 24 '19 at 13:29
  • Hi, I have updated my answer. – user72672 Nov 24 '19 at 13:52
  • I just tried. The problem persists. – Worksfather Nov 24 '19 at 14:17
  • Try label() instead. Remember you have to replace field_term with the fieldname of your term field. – user72672 Nov 24 '19 at 14:19
0

Your applies() checks for a node-route while your build() wants a taxonomy-route. That's why $term is null here. You have to fetch your $term object from the corresponding node field.

  • Thank you @Rainer. I tried to do it, but it still doesn't work. I'm new to Drupal. Can you tell me exactly what part of my code I need to change please? – Worksfather Nov 24 '19 at 13:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.