Drupal 8 - Définir l'item de menu actif en fonction du type de noeud

Posté le Mercredi 20 septembre 2017 - 17:48
Dernière mise à jour le Vendredi 26 janvier 2018 - 18:35

Sur ce site, j'ai trois types de contenu :

  • Article
  • Snippet
  • Réalisation

Pour chacun de ces trois types de contenu, j'ai une vue (View) de listing qui correspond (cf le menu ci-dessus).

Par défaut quand on est sur la vue de listing des snippets par exemple, on a bien l'élément de menu "Snippets" qui est marqué comme actif, par contre quand on va sur le détail d'un snippet, on perd cette information. Nous allons voir comment sélectionner le menu item qui doit être actif en fonction du type de contenu sur lequel on se trouve.

1ère étape : surcharger le service MenuActiveTrail

dans mon module « kgaut » je créé le fichier KgautMenuActiveTrail.php dans le dossier src/Menu avec le contenu suivant :

<?php

namespace Drupal\kgaut\Menu;

use Drupal\Core\Menu\MenuActiveTrail;
use Drupal\node\NodeInterface;

/**
 * Extend the MenuActiveTrail class.
 */
class KgautMenuActiveTrail extends MenuActiveTrail {

  /**
   * {@inheritdoc}
   */
  public function getActiveLink($menu_name = NULL) {
    // Call the parent method to implement the default behavior.
    $found = parent::getActiveLink($menu_name);

    // If a node is displayed, load the default parent menu item
    // from the node type's menu settings and return it instead
    // of the default one.
    $node = $this->routeMatch->getParameter('node');

    if ($node instanceof NodeInterface) {
      $bundle = $node->bundle();
      switch ($bundle) {
        case 'article':
          //Ici je demande à recherche le menu item qui utilise la route correspondant à mon type de contenu
          $links = $this->menuLinkManager->loadLinksByRoute('view.front_articles.page', [], $menu_name);
          break;

        case 'snippet':
          $links = $this->menuLinkManager->loadLinksByRoute('view.front_snippets.page', [], $menu_name);
          break;

        case 'realisation':
          $links = $this->menuLinkManager->loadLinksByRoute('view.front_realisations.page', [], $menu_name);
          break;
      }

      if (isset($links) && $links) {
        $found = reset($links);
      }
    }
    return $found;
  }
}

C'est bien beau, mais maintenant il faut signaler à Drupal que l'on a surchargé un de ses services. Pour cela il faut créer le fichier src/MonModuleServiceProvider.php (attention c'est normé !) Dans mon cas j'ai donc créé le fichier KgautServiceProvider.php dans le dossier src de mon module kgaut (oui je suis très égocentrique).
En voici le contenu :

<?php
/**
 * @file
 * Contains Drupal\kgaut\KgautServiceProvider.
 */

namespace Drupal\kgaut;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;

class KgautServiceProvider extends ServiceProviderBase {

  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container) {
    $container->getDefinition('menu.active_trail')->setClass('Drupal\kgaut\Menu\KgautMenuActiveTrail');
  }

}

Un petit vidage de cache plus tard, et on est bon !

Aller plus loin ?

 

Commentaires

Bonjour Kgaut,

Il existe également un module qui permet de faire cela menu_trail_by_path

Un grand merci pour ton article, clair et précis.
J'ai pu implanter le même genre de service mais sur des termes de taxonomy.
Et ça fonctionne parfaitement bien.

Ajouter un commentaire

Ne sera pas publié

CAPTCHA Désolé, pour ça, mais c'est le seul moyen pour éviter le spam...