Drupal - Les « menu deriver » pour générer des éléments de menu dynamiquement

Dans Drupal, les éléments de menu sont gérés soit via l'interface d'administration soit dans les fichiers mon_module.links.menu.yml, de la manière suivante : 

Un lien vers un noeud : 

enfarandole.main.help:
  title: 'Nous aider'
  weight: 2
  route_name: entity.node.canonical
  route_parameters:
    node: 5
  menu_name: main

Un lien vers une vue :

amicale.main.events:
  title: 'Évènements'
  weight: 1
  route_name: view.evenements.listing
  menu_name: main

Mais il est aussi possible d'utiliser un deriver, pour créer des éléments de menu de manière dynamique, dans l'exemple suivant je vais lister dans un sous menu tous les contenus d'un certains type, je commence par la déclaration de mon menu parent et de mon deriver, toujours dans le fichier mon_module.links.menu.yml :

# Mon élément parent, sans lien, qui sera dans le menu principal
amicale.main.sections:
  title: 'Sections'
  weight: 1
  route_name: '<nolink>'
  menu_name: main

# La définition de mon dériver pointant vers une classe
amicale.main.sections.section: 
  deriver: '\Drupal\mon_module\Plugin\Derivative\SectionMenuLinkDeriver'
  class: '\Drupal\Core\Menu\MenuLinkDefault'

La classe de mon dériver (web/modules/mon_module/src/Plugin/Derivative/SectionMenuLinkDeriver.php)

<?php

namespace Drupal\mon_module\Plugin\Derivative;

use Drupal\Component\Plugin\Derivative\DeriverBase;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
use Drupal\Core\Url;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Menu deriver for content type « page_de_section ».
 */
final class SectionMenuLinkDeriver extends DeriverBase implements ContainerDeriverInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManager
   */
  protected EntityTypeManager $entityTypeManager;

  /**
   * CategoryMenuLinkDeriver constructor.
   *
   * @param \Drupal\Core\Entity\EntityTypeManager $entityTypeManager
   *   The entity type manager.
   */
  public function __construct(EntityTypeManager $entityTypeManager) {
    $this->entityTypeManager = $entityTypeManager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, $base_plugin_id) {
    return new static($container->get('entity_type.manager'));
  }

  /**
   * {@inheritdoc}
   */
  public function getDerivativeDefinitions($base_plugin_definition) {
    $links = [];

    $storage = $this->entityTypeManager->getStorage('node');

    $query = $storage->getQuery();
    // Je charge tous les noeud du type « page_de_section »
    $query->accessCheck(TRUE);
    $query->condition('type', 'page_de_section');
    $query->sort('title');
    $sections = $query->execute();

    // Et pour chaque, je vais créer un élément de menu
    foreach ($sections as $section) {
      if (!$section = $storage->load($section)) {
        continue;
      }

      // Create menu ID.
      $menuId = 'amicale.main.sections.section:' . $section->id();

      $link = [
        'id' => $menuId,
        'route_name' => entity.node.canonical,
        'route_parameters' => ['node' => $section->id()],
        'title' => $section->label(), // Le titre de mon élément de menu (ici le titre du noeud)
        'parent' => 'amicale.main.sections', // je définis ici le menu item parent, si omis, ça sera un élément de menu de niveau 1
      ] + $base_plugin_definition;
      
      $links[$menuId] = $link;
    }

    return $links;
  }

}

On vide son cache, et voila !

Évidement tout est possible au niveau de ce que l'on veut ajouter comme élément de menu, catégories basée sur un vocabulaire, liste de membres...

 

 

Contenus en rapport

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

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).

Ajouter un commentaire

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