0

Unrelated to this question, which is about how to properly inject breadcrumbs as a renderable item into a node template.. I have a custom breadcrumb builder for certain node types with the same sort of cache clearing issue.

After I deploy code to production, and clear the Drupal cache, about 50% of the time anonymous users stop seeing breadcrumbs on these 3 node types. I find that I have to clear cache again, then clear the Varnish cache on the server, and then they appear again for anonymous users. Am I missing something in the build method?

<?php

declare(strict_types = 1);

namespace Drupal\harlib_breadcrumbs;

use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Link;
use Drupal\Core\Routing\AdminContext;
use Drupal\node\NodeInterface;
use Drupal\Core\Path\AliasManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Url;

/**
 * Class ContentTypeBasedBreadcrumbBuilder.
 *
 * @package Drupal\harlib_breadcrumbs
 */
class ContentTypeBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface {

  use StringTranslationTrait;

  /**
   * The AdminContext service.
   *
   * @var \Drupal\Core\Routing\AdminContext
   */
  protected $adminContext;

  /**
   * The AliasManager service.
   *
   * @var \Drupal\Core\Path\AliasManagerInterface
   */
  protected $aliasManager;

  /**
   * The EntityTypeManager service.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * {@inheritdoc}
   */
  public function __construct(
    AdminContext $admin_context,
    AliasManagerInterface $alias_manager,
    EntityTypeManagerInterface $entity_type_manager
  ) {
    $this->adminContext = $admin_context;
    $this->aliasManager = $alias_manager;
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public function applies(RouteMatchInterface $route_match) : bool {
    if (!$this->adminContext->isAdminRoute()) {
      $parameters = $route_match->getParameters()->all();

      if (isset($parameters['node']) && $parameters['node'] instanceof NodeInterface) {
        $types = ['story', 'press_release', 'news_mention'];
        $type = $parameters['node']->getType();
        return in_array($type, $types);
      }
    }

    return FALSE;
  }

  /**
   * {@inheritdoc}
   */
  public function build(RouteMatchInterface $route_match) : Breadcrumb {
    $node = $route_match->getParameter('node');
    $breadcrumb = new Breadcrumb();
    $breadcrumb->addLink(Link::createFromRoute($this->t('Home'), '<front>'));

    if ($url = $this->getNodeUrlByAlias('/about')) {
      $breadcrumb->addLink(Link::fromTextAndUrl($this->t('About'), $url));
    }

    if ($url = $this->getNodeUrlByAlias('/about/news')) {
      $breadcrumb->addLink(Link::fromTextAndUrl($this->t('News'), $url));
    }

    $breadcrumb->addCacheContexts(['url.path']);
    $breadcrumb->addCacheTags(["node:{$node->nid->value}"]);  
    return $breadcrumb;
  }

  /**
   * Create a Url object if the alias matches a node object path.
   *
   * @param string $alias
   *   The node alias.
   *
   * @return bool|\Drupal\Core\Url
   *   A Url object, or FALSE if no result found.
   */
  protected function getNodeUrlByAlias(string $alias) {
    $path = $this->aliasManager->getPathByAlias($alias);

    if (preg_match('/node\/(\d+)/', $path, $matches)) {
      $id = $matches[1];
      return Url::fromRoute('entity.node.canonical', ['node' => $id]);
    }

    return FALSE;
  }

}

1 Answer 1

0

Pretty sure I found the root cause. I found some errant code here in the else condition.

/**
 * Implements hook_preprocess_block().
 */
function mytheme_preprocess_block(&$variables) {
  if ($variables['plugin_id'] == 'system_breadcrumb_block') {
    if (...) {
      $variables['attributes']['class'][] = 'hl__breadcrumb--light';
    }
    else {
      if (!empty($variables['content']['#links'])) {
        if (count($variables['content']['#links']) == 1) {
          $variables['content'] = [];
          $variables['elements']['content'] = $variables['content'];
        }
      }
    }
  }
}

Deleting the entire else block seems to have corrected the issue, unable to replicate it now.

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.