Comment générer des liens enfants en fonction de la page actuelle

10

Lors de l'atterrissage sur une page qui a un élément de menu parent aux autres éléments de menu des pages, je voudrais pouvoir afficher une liste de ces éléments de menu enfant. J'utilise le code suivant.

$trail = menu_get_active_trail();
menu_build_tree('main-menu', array(
  'expanded' => array($trail[1]['mlid'])
));

Cependant, le tableau renvoyé ressemble à ceci (avec beaucoup de suppression inutile).

array
'49950 PKY Truck Beauty 312' => 
array
  'link' => &
    array
      'menu_name' => string 'main-menu' (length=9)
      'mlid' => string '312' (length=3)
      'plid' => string '311' (length=3)
  'below' => 
    array
      '49952 Seminars 314' => 
        array
          'link' => &
            array
              'menu_name' => string 'main-menu' (length=9)
              'mlid' => string '314' (length=3)
              'plid' => string '311' (length=3)
      '50000 HDMA Breakfast 316' => 
        array
          'link' => &
            array
              'menu_name' => string 'main-menu' (length=9)
              'mlid' => string '316' (length=3)
              'plid' => string '311' (length=3)
      '50000 MATS Concert 315' => 
        array
          'link' => &
            array
              'menu_name' => string 'main-menu' (length=9)
              'mlid' => string '315' (length=3)
              'plid' => string '311' (length=3)

Remarquez comment 314, 315 et 316 sont «inférieurs» à 312? Ce sont des frères et sœurs dans ma structure de menu, et cela semble être vérifié par chacun ayant la même valeur pour plid(311). Évidemment, je peux résoudre ce problème en passant le tableau via une autre fonction, mais je ne peux pas m'empêcher de penser que je manque juste quelque chose.

Chris Rockwell
la source
Dans l'intérêt du temps, je corrige le problème avec CSS, même si je ne suis pas satisfait. $tree = menu_build_tree('main-menu', array( 'expanded' => array($trail[1]['mlid']) )); drupal_render(menu_tree_output($tree))Ensuite, en utilisant CSS, je peux styliser les liens pour supprimer le ulrembourrage, les faisant apparaître qu'ils sont tous au même niveau. Pas idéal, mais efficace. EDIT: désolé, je ne peux pas comprendre comment faire fonctionner les sauts de ligne.
Chris Rockwell
ne pourriez-vous pas publier un exemple de capture d'écran de ce que vous aimeriez réaliser? Pour être honnête, j'ai trouvé la question un peu brouillonne (j'ose le dire car aucune réponse n'a encore été écrite). Où aimeriez-vous pouvoir montrer les articles enfants? Pourquoi les modules liés au menu ne sont-ils pas satisfaisants? Veuillez clarifier un peu plus la question et nous pourrions peut-être trouver une bonne solution.
Sk8erPeter
@ Sk8erPeter, je m'excuse si c'est désordonné. La solution que j'ai choisie (référencée dans mon commentaire) est utilisée ici: lien . La question principale est: pourquoi menu_build_tree () retourne un tableau imbriqué qui a des niveaux inattendus (tous les liens devraient être sur le même)? Pour voir où je montre les éléments enfants, utilisez le lien que j'ai inclus et cliquez sur n'importe quel lien dans la barre de navigation principale (css est utilisé pour donner l'illusion qu'ils ne sont pas cliquables).
Chris Rockwell
En ce qui concerne les modules, un coup d'œil rapide n'a pas révélé quoi que ce soit qui suffirait. Cela pourrait être dû au fait que je n'étais pas très intéressé par l'installation d'un autre module pour une solution qui devrait être réalisée en 4 ou 5 lignes de code. J'ai déjà un module «comprend» personnalisé que j'utilise pour des choses comme ça. Maintenant, de n'importe où, j'appelle get_sub_menu_based_on_active_page()et je suis prêt. J'ai dû cesser d'essayer de comprendre le problème d'imbrication car CSS rend l'utilisateur plus sage.
Chris Rockwell
1
J'ai posté une réponse avec une autre approche, je pense que c'est l'une des solutions les plus simples. Et cela fonctionne correctement. Le module suggéré est vraiment populaire parmi les utilisateurs de Drupal.
Sk8erPeter

Réponses:

8

Je voulais juste faire un suivi. Je suis revenu à cette question et j'ai trouvé ce qui suit: /programming/2716787/how-to-get-all-the-menu-items-below-a-certain-parent-in-drupal qui est exactement ce dont j'avais besoin.

Le code, copié à partir du lien mentionné ci-dessus et modifié pour répondre à mes besoins (principalement pour utiliser le chemin actuel pour construire l'arborescence de menus, plutôt que d'utiliser une valeur codée en dur:

$parent = menu_link_get_preferred($_GET['q']);
$parameters = array(
  'active_trail' => array($parent['plid']),
  'only_active_trail' => FALSE,
  'min_depth' => $parent['depth']+1,
  'max_depth' => $parent['depth']+1,
  'conditions' => array('plid' => $parent['mlid']),
);

$children = menu_build_tree($parent['menu_name'], $parameters);

return '<div class="content-sub-menu content-padder">' . drupal_render(menu_tree_output($children)) . '</div>';
Chris Rockwell
la source
1
Cela fonctionne bien, mais vous devez utiliser à la current_path()place de $_GET['q']. $_GET['q']renverra l'alias du chemin, où current_path()obtiendra le noeud / id.
mediaashley
6

Cela peut facilement être fait en utilisant le module de bloc de menu (il faut environ 5 minutes pour le configurer).

Capture d'écran du bloc de menu

Tout ce que tu dois faire est

  1. Activation du module
  2. Aller à admin/structure/block
  3. Cliquer sur "Ajouter un bloc de menu"
  4. Réglez «Niveau de départ» sur «2e niveau (secondaire)» et définissez la région où il doit être affiché sous «Spécifiez dans quels thèmes et régions ce bloc est affiché».

  5. Captures d'écran:

    • Voici à quoi ressemble la page de configuration

      capture d'écran

    • page admin / structure / bloc avec les blocs de module de bloc de menu activés

      capture d'écran

    • J'ai généré du contenu "Page de base" avec le module Devel, et y ai fourni des liens de menu, et j'ai créé une hiérarchie de menu imbriquée

      • Il s'agit de la page d'accueil par défaut sans sous-menus (le bloc "Menu principal - 2e niveau" ne peut PAS être vu dans la barre latérale gauche, car il ne contient aucun élément enfant de deuxième niveau)

      capture d'écran

      • Ceci est le deuxième menu, avec quelques éléments enfants, vous pouvez déjà voir le "Menu principal - 2ème niveau" dans la barre latérale gauche, mais seuls les éléments enfants de 2ème niveau sont visibles

        capture d'écran

        articles de deuxième niveau

      • Approfondissons maintenant:

        Des éléments enfants de troisième niveau peuvent également être vus

Je pense que l'utilisation du module de bloc de menu pour cette tâche est l'une des solutions les plus simples et les plus rapides.

Sk8erPeter
la source
Je serais vraiment curieux de savoir pourquoi j'ai reçu un downvote pour ce poste. Le module recommandé fait le travail, et j'ai écrit un tutoriel étape par étape. Pourquoi le downvoter ne poste-t-il pas un commentaire des raisons? (Peut-être que ce serait utile (peut-être pas), je pourrais au moins réagir.)
Sk8erPeter
0

Comme indiqué dans les commentaires, j'ai fini par utiliser la fonction API, puis styliser avec CSS:

/* --------------- *\
    Sub-menus
    used on main pages
\* --------------- */
.content-sub-menu ul.menu {
  list-style: none;
  padding: 0;
  margin: 0;
}
.content-sub-menu > ul.menu {
  margin-bottom: 25px;
}
.content-sub-menu ul.menu a {
  font-size: 1.5em;
  padding: 10px;
  margin-top: 5px;
  display: inline-block;
  min-width: 33%;
}
Chris Rockwell
la source
0

Cette fonction fonctionne correctement pour obtenir le sous-menu de la page actuelle:

function build_left_menu()
{
    global $language_url;
    static $use_theme = NULL;
// Get the entire main menu tree
    $left_menu_tree = menu_tree_all_data('main-menu'); // Your main menu
$left_menu_tree_values = array_values($left_menu_tree); //get value only
    $html = "<div id=\"sidemenu\"><ul id=\"side-nav\" class=\"side-nav-content\"><h3>In this section:</h3>";
foreach ($left_menu_tree_values as $index => $item) {
        $link = $item["link"];
        if ($index === 0) {
            $item_class = "first-item panel side-menu ";
        } else {
            $item_class = "panel side-menu ";
        }
        $options_anchor = array();
        if ($item["below"]) {
            $options_anchor = array("attributes" => array('class' => array('dropdown-toggle'),
                'data-toggle' => 'dropdown',
                'data-delay' => 1000,
                'data-close-others' => "false",
                'data-hover' => "dropdown",
            )
            );
        }
        // Merge in defaults.
        $options_anchor += array(
            'attributes' => array(),
            'html' => FALSE,
        );

        //Default needed class
        $options['attributes']['class'][] = 'subpage-link collapsed';
        // Append active class.
        if (($link['link_path'] == $_GET['q'] || ($link['link_path'] == '<front>' && drupal_is_front_page())) &&
            (empty($options_anchor['language']) || $options_anchor['language']->language == $language_url->language)) {
            if ($item["below"]) {
                foreach ($item["below"] as $item_below) {
                    $link_below = $item_below["link"];
                    $options_anchor = array();
                    $html .= "<li class='" . $item_class . "'>";
                    $html .= override_left_l($link_below['link_title'], $link_below['link_path'], $options_anchor).'</li>';
                }
            }
        }
    }
    $html .= "</ul></div>";
    return $html;
}

J'espère que cette aide!

Xman Classique
la source
Votre fonction appelle une fonction non définie (override_left_l)!
DrCord
0

@Chris Rockwell et @ Mario Awad

Je suis débutant à Drupal, donc c'est difficile de comprendre pour moi où ajouter cette fonction .. Je m'en excuse. Mais, pouvez-vous s'il vous plaît mentionner que dans quel fichier, devrions-nous ajouter cette fonction?

J'essaie de créer une navigation dans la barre latérale qui n'affichera que les éléments enfants sur chaque page. Comment créer un menu de navigation sur la barre latérale avec différents liens de navigation affichés sur différentes pages?

J'apprécie!

Merci!

Vidushi
la source
0

Je viens de terminer la publication d'une fonction qui obtient les éléments du menu enfant en fonction du chemin d'accès d'un nœud. Vous pouvez le vérifier ici: http://softkube.com/blog/getting-child-menu-items-drupal-menu-tree

J'inclus le lien vers la preuve future de la réponse au cas où le message serait mis à jour et je copierai / collerai également le code complet à la fin.

Dans votre cas, vous pouvez simplement exécuter quelque chose comme ça dans votre thème pour répertorier tous les éléments du menu enfant. Modifiez la echodéclaration et le thème à votre convenance.

$path = current_path();
$nids = skl_get_all_menu_node_children_ids($path);
$children = node_load_multiple($nids);
foreach($children as $c) {
    echo $c->title . ': ' . url('node/' $c->nid) . '<br />';
}

Et voici le code complet de la fonction. Vérifiez le lien pour d'éventuelles mises à jour futures.

Bonne chance.

/**
 * Returns node ids of all the child items, including children of children
 * on all depth levels, of the given node path. Returns an empty array
 * if any error occurs.
 * 
 * @param string $node_path
 * @return array
 */
function skl_get_all_menu_node_children_ids($node_path) {
    //Stop and return an empty array if node path is empty
    if(empty($node_path)) {
        return array();
    }

    //Init empty array to hold the results
    $nids = array();

    //Init parent keys. Check 'foreach' loop on parent keys for more info.
    $parent_keys = array('plid', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9');

    //Collect menu item corresponding to this path to begin updates.
    //Reference: http://stackoverflow.com/a/11615338/136696
    //Note: we couldn't find a way to get the sub-tree starting from this item
    //only and hence we had to get the whole menu tree built and then loop on
    //the current item part only. Not so bad considering that Drupal will
    //most probably have the whole menu cached anyway.
    $parent_menu_item = menu_link_get_preferred($node_path);

    //Stop and return empty array if a proper current menu item couldn't be found
    if(empty($parent_menu_item['menu_name']) || empty($parent_menu_item['mlid'])) {
        return array();
    }

    //Init parent item mlid for easier usage since now we know it's not empty
    $parent_menu_item_mlid = $parent_menu_item['mlid'];

    //Build whole menu based on the preferred menu_name gotten from this item
    $menu = menu_build_tree($parent_menu_item['menu_name']);

    //Reset menu cache since 'menu_build_tree' will cause trouble later on after 
    //you call pathauto to update paths as it can only be called once. 
    //Check: https://www.drupal.org/node/1697570
    menu_reset_static_cache();

    //Init processing array. This will hold menu items as we process them.
    $menu_items_to_process = array();

    //First run to fill up the processing array with the top level items
    foreach($menu as $top_level_menu_item) {
        $menu_items_to_process[] = $top_level_menu_item;
    }

    //While the processing array is not empty, keep looping into lower
    //menu items levels until all are processed.
    while(count($menu_items_to_process) > 0) {
        //Pop the top item from the processing array
        $mi = array_pop($menu_items_to_process);

        //Get its node id and add it to $nids if it's a current item child
        //Note that $parent_keys contains all keys that drupal uses to
        //set a menu item inside a tree up to 9 levels.
        foreach($parent_keys as $parent_key) {
            //First, ensure the current parent key is set and also mlid is set
            if(!empty($mi['link']['mlid']) && !empty($mi['link'][$parent_key])) {
                //If the link we're at is the parent one, don't add it to $nids
                //We need this check cause Drupal sets p1 to p9 in a way you
                //can easily use to generate breadcrumbs which means we will
                //also match the current parent, but here we only want children
                if($mi['link']['mlid'] != $parent_menu_item_mlid) {
                    //Try to match the link to the parent menu item
                    if($mi['link'][$parent_key] == $parent_menu_item_mlid) {
                        //It's a child, add it to $nids and stop foreach loop.
                        //Link_path has the path to the node. Example: node/63.
                        if(!empty($mi['link']['link_path'])) {
                            $nids[] = str_replace('node/', '', 
                                      $mi['link']['link_path']);
                            break;
                        }
                    }
                }
            }
        }

        //Add its child items, if any, to the processing array
        if(!empty($mi['below']) && is_array($mi['below'])) {
            foreach($mi['below'] as $child_menu_item) {
                //Add child item at the beginning of the array so that when
                //we get the list of node ids it's sorted by level with
                //the top level elements first; which is easy to attain
                //and also useful for some applications; why not do it.
                array_unshift($menu_items_to_process, $child_menu_item);
            }
        }
    }

    //Return
    return $nids;
}
Mario Awad
la source
Merci Mario. Pouvez-vous expliquer pourquoi vous avez choisi cette option plutôt que d'utiliser $parametersdans menu_build_tree?
Chris Rockwell
Merci pour les commentaires. Je ne pouvais pas obtenir les informations nécessaires, peu importe ce que $parametersj'utilisais, et croyez-moi, je regardais beaucoup. Tout ce que je voulais, c'était, étant donné un chemin, obtenir tous les éléments du menu enfant à tous les niveaux, et je ne pouvais tout simplement pas trouver un moyen. S'il y en a un, informez-moi, je serai heureux d'apprendre et de mettre à jour ma réponse et mon billet de blog. À votre santé.
Mario Awad