5

I'm trying to get the title into my breadcrumb path without using a preprocess function. Drupal 8 Add the current title to the breadcrumb shows how to do it with preprocess function which is not what I'm trying to do.

I want my output be like this:

enter image description here

Here is what have been trying and have not work yet.

breadcrumb.html.twig

{#
/**
 * @file
 * Theme override for a breadcrumb trail.
 *
 * Available variables:
 * - breadcrumb: Breadcrumb trail items.
 */
#}
{% if breadcrumb %}
    <nav class="breadcrumb" role="navigation" aria-labelledby="system-breadcrumb">
        <h2 id="system-breadcrumb" class="visually-hidden">{{ 'Breadcrumb'|t }}</h2>
        <ol>{{ 'You are here:'|t }}
            {% for item in breadcrumb %}
                <li>
                    {% if item.url %}

                        <a href="{{ item.url }}">{{ item.text }}</a>
                    {% else %}
                        {{ item.text }}
                    {% endif %}
                </li>
                {{ '>'|t }} {{title}}
            {% endfor %}
        </ol>
    </nav>
{% endif %}

And this is what I'm getting:

enter image description here

For some reason the title is not been display when I use {{ title }}.

What am I doing wrong?

Why is my title not being displayed on my breadcrumb title?

1
  • 1
    I wouldn't say it's bad practice to use preprocess in D8, I think it would be more accurate and reasonable to say something like: "Adding classes to your markup via preprocess functions in D8 is discouraged." As the others are saying, if you need a variable that's not in the template then you likely need to add a preprocess to create/populate that variable.
    – star-szr
    Commented Nov 6, 2015 at 2:42

7 Answers 7

8

There is also an alter hook for breadcrumbs, where you can alter them in a non-theme specific way, in case the breadcrumbs are also used somewhere else.

I've implemented this in a project:

/**
 * Implements hook_system_breadcrumb_alter().
 */
function yourmodule_system_breadcrumb_alter(array &$breadcrumb, RouteMatchInterface $route_match, array $context) {
  // Append the current page title to the breadcrumb for non-admin routes.
  if ($breadcrumb && !\Drupal::service('router.admin_context')->isAdminRoute()) {

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

EDIT for Drupal 8.2.x

I add a lot of error with this code, which I believe is the best approach for altering the breadcrumb has seen on Drupal API. So here is the code for Drupal 8.2.x

/**
 * Implements hook_system_breadcrumb_alter().
 */
function YOURMODULE_system_breadcrumb_alter(\Drupal\Core\Breadcrumb\Breadcrumb &$breadcrumb, \Drupal\Core\Routing\RouteMatchInterface $route_match, array $context) {
  // Append the current page title to the breadcrumb for non-admin routes.
  if ($breadcrumb && !\Drupal::service('router.admin_context')->isAdminRoute()) {

    $title = \Drupal::service('title_resolver')->getTitle(\Drupal::request(), $route_match->getRouteObject());
    if (!empty($title)) {
      $breadcrumb->addLink(\Drupal\Core\Link::createFromRoute($title, '<none>'));
    }
  }
}
3
  • 1
    It's a nice implementation but I just want to point out to others that it will only work in a module, not a theme. See @cmsbots.com answer for one that works in a theme. Commented Apr 3, 2016 at 8:37
  • Well lets comment, my edit was rejected by reviewers... There is 2 main concerns about this code, after Drupal 8.0 release &$breadcrumb is a Object not an array, to correct, change to Breadcrumb &$breadcrumb and $request variable is not defined in code, change to \Drupal::request(). Minor mistake breadcrumb->addLink... misspell $. Just for future reference, like pointed by Mark, this is not exactly what OP asks for, but there is more up votes than correct answer...
    – Vagner
    Commented Aug 15, 2016 at 21:10
  • 1
    since 8.4.x (drupal.org/node/2891075) you would need to add $breadcrumb->addCacheContexts(['url.path']); to the code, otherwise you will run into caching issues, for example if you have multiple menu items with same parent. Commented Aug 14, 2019 at 4:47
6

By default, the variable {{title}} will not avaliable to breadcrumb.html.twig. You have to to use HOOK_preprocess_breadcrumb in your .theme file.

P.S: In D8, it is bad practice only if you try to display the data from preprocesser function. It is nothing wrong of you try to add extra variable in preprocesser. Here more clarification https://www.drupal.org/node/1920746

In YOUYTHEME.theme file

function YOURTHEME_preprocess_breadcrumb(&$variables) {
  $request = \Drupal::request();
  $route_match = \Drupal::routeMatch();
  $page_title = \Drupal::service('title_resolver')->getTitle($request, $route_match->getRouteObject());

  //this variable will avaliable in twig file. 
  $variables['breadcrumb'][] = array(
    'text' => $page_title
  );
}
1
  • Any example on how I can pass the {{title}}? Commented Nov 6, 2015 at 1:48
2

No matter what I will need to use preprocess function because {{title}} was not part of the breadcrumb.html.twig. I ended up doing this to achieve this my output:

mytheme.theme

<?php

function mytheme_preprocess_breadcrumb(&$variables){

        if(($node = \Drupal::routeMatch()->getParameter('node')) && $variables['breadcrumb']){
    // Adding the a divider of between home an the title of the page.
            $variables['breadcrumb'][] = array(
                'text' => '>'
            );
    // Adding the title of the page in the breadcrumb
            $variables['breadcrumb'][] = array(
                'text' => $node->getTitle(),
                'url' => $node->URL()
            );

        }
    }

breadcrumb.html.twig

{#
/**
 * @file
 * Theme override for a breadcrumb trail.
 *
 * Available variables:
 * - breadcrumb: Breadcrumb trail items.
 */
#}
{% if breadcrumb %}
    <nav class="breadcrumb" role="navigation" aria-labelledby="system-breadcrumb">
        <h2 id="system-breadcrumb" class="visually-hidden">{{ 'Breadcrumb'|t }}</h2>
        {{ 'You are here:'|t }}
        <div class="breadcrumb">
            {% for item in breadcrumb %}
                <span>
                    {% if item.url %}
                            <a href="{{ item.url }}">{{ item.text }}</a>
                    {% else %}
                        {{ item.text }}
                    {% endif %}
                </span>
            {% endfor %}
        </div>
    </nav>
{% endif %}

For more information about my solving this issue you can visit - Light Skeleton - Breadcrumb D8 Port

2
  • This method only adds node title to breadcrumb. If i want to add all page title to breadcrumb, then how can do this?
    – Guru
    Commented Jan 18, 2016 at 10:52
  • darol100 - it is for nodes solution only. What about another types of pages?
    – user61877
    Commented Jun 20, 2016 at 14:27
2

Some of the suggested solutions may have troubles with cache because the logic happens in the preprocess (YOURTHEME_preprocess_breadcrumb(&$variables)). I would recommend using some contrib modules or implement their solutions:

Easy breadcrumbs: Replaces core breadcrumbs with configurable breadcrumbs that follow Breadcrumb best-practices.

Current page crumb: Extends the Drupal 8 core system breadcrumbs to append the current page title as a text only breadcrumb.

1
2

There is a new module called Current Page Crumb that can help you.

Current Page Crumb extends the Drupal 8 core system breadcrumbs to append the current page title as a text only breadcrumb. Admin paths are left unmodified. The module has no configuration.

And the author has made a blog post talking about the solution.

0
1

The preprocess function for breadcrumbs in core is:

function template_preprocess_breadcrumb(&$variables) {
  $variables['breadcrumb'] = array();
  /** @var \Drupal\Core\Link $link */
  foreach ($variables['links'] as $key => $link) {
    $variables['breadcrumb'][$key] = array('text' => $link->getText(), 'url' => $link->getUrl()->toString());
  }
}

It only provides the breadcrumbs, nothing else. So if you want to use other variables, you have to put them into the variables array in your own preprocess function.

1
  • Any example on how I can pass the {{title}}? Commented Nov 6, 2015 at 1:48
0

To achieve this, use below code in your custom module or create a new custom module. I assume you already have understanding on how to create a custom module for Drupal 8/9. Create your services file mymodule.services.yml and add below code,

  mymodule.breadcrumb_nodes:
    class: Drupal\mymodule\Breadcrumb\MyModuleBreadcrumbBuilder
    tags:
      - { name: breadcrumb_builder, priority: 10001 }

You could set key as above like breadcrumb_nodes or breadcrumb or breadcrumb_terms etc as per your needs. Then create breadcrumb builder file under mymodule/src/Breadcrumb/ directory named as MyModuleBreadcrumbBuilder.php and add below code

<?php

namespace Drupal\mymodule\Breadcrumb;

use Drupal;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Link;
use Drupal\Core\Routing\RouteMatchInterface;

class MyModuleBreadcrumbBuilder implements BreadcrumbBuilderInterface {

  /**
   * @inheritdoc
   *  
   */
  public function applies(RouteMatchInterface $route_match) {
    // This breadcrumb will apply for all nodes.
    $parameters = $route_match->getParameters()->all();

    //Checking if node then only calling our builder otherwise loading default loader
    if (isset($parameters['node'])) {
     return TRUE;
    }

    return FALSE;
  }

  /**
   * @inheritdoc
   * Add your logic in below method
   */
  public function build(RouteMatchInterface $route_match) {

    $parameters = $route_match->getParameters()->all();

    $node = $parameters['node'];

    //Getting latest node revision
    $vid = \Drupal::entityTypeManager()->getStorage('node')->getLatestRevisionId($node->id());
    $node_new = \Drupal::entityTypeManager()->getStorage('node')->loadRevision($vid);
    $node_array = $node_new->toArray();

    //Creating new Breadcrumb
    $breadcrumb = new \Drupal\Core\Breadcrumb\Breadcrumb();

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

    $breadcrumb->addLink(Link::createFromRoute($node_array["title"][0]["value"], 'entity.node.canonical', ['node' => $node->id()]));

    //Adding cache control,otherwise 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"]);
    $breadcrumb->addCacheTags(["node:{$node->id()}"]);

    return $breadcrumb;
  }
}

Hope this helps. Thanks!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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