Cómo generar enlaces secundarios basados ​​en la página actual


10

Al aterrizar en una página que tiene un elemento de menú que es un elemento primario de los elementos de menú de otras páginas, me gustaría poder mostrar una lista de esos elementos de menú secundarios. Estoy usando el siguiente código.

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

Sin embargo, la matriz devuelta se ve así (con una gran cantidad de innecesarios eliminados).

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)

Observe cómo 314, 315 y 316 están 'por debajo' de 312? Son hermanos en la estructura de mi menú, y eso parece ser verificado por cada uno que tiene el mismo valor para plid(311). Obviamente, puedo solucionar esto pasando la matriz a través de otra función, pero no puedo evitar pensar que solo me falta algo.


En aras del tiempo, estoy solucionando el problema con CSS, aunque no estoy contento con él. $tree = menu_build_tree('main-menu', array( 'expanded' => array($trail[1]['mlid']) )); drupal_render(menu_tree_output($tree))Luego, usando CSS, puedo diseñar los enlaces para eliminar el ulrelleno, haciendo que parezca que están todos en el mismo nivel. No es ideal, pero efectivo. EDITAR: lo siento, no puedo entender cómo hacer que los saltos de línea funcionen.
Chris Rockwell

¿no podrías publicar una captura de pantalla de muestra de lo que te gustaría lograr? Para ser sincero, la pregunta me pareció un poco desordenada (me atrevo a decir eso porque todavía no se han escrito respuestas). ¿Dónde le gustaría poder mostrar los elementos secundarios? ¿Por qué los módulos relacionados con el menú no son satisfactorios? Por favor aclare la pregunta un poco más, y tal vez podamos encontrar una buena solución.
Sk8erPeter

@ Sk8erPeter, me disculpo si es desordenado. La solución que utilicé (mencionada en mi comentario) se está utilizando aquí: enlace . La pregunta principal es: ¿por qué menu_build_tree () devuelve una matriz anidada que tiene niveles inesperados (todos los enlaces deben estar en el mismo)? Para ver dónde estoy mostrando los elementos secundarios, use el enlace que incluí y haga clic en cualquier enlace en la barra de navegación principal (css se usa para dar la ilusión de que no se puede hacer clic).
Chris Rockwell

Con respecto a los módulos, una mirada superficial no arrojó nada que fuera suficiente. Eso podría deberse a que no estaba muy interesado en instalar otro módulo para una solución que debería lograrse en 4 o 5 líneas de código. Ya tengo un módulo personalizado 'incluye' que uso para cosas como esta. Ahora, desde cualquier lugar, llamo get_sub_menu_based_on_active_page()y estoy listo. Tuve que pasar de tratar de resolver el problema de anidación ya que css hace que el usuario no sea más sabio.
Chris Rockwell

1
Me envió una respuesta con otro enfoque, creo que es una de las soluciones más fáciles. Y funciona correctamente. El módulo sugerido es realmente popular entre los usuarios de Drupal.
Sk8erPeter

Respuestas:


8

Solo quería hacer un seguimiento. Volví a esta pregunta y encontré lo siguiente: /programming/2716787/how-to-get-all-the-menu-items-below-a-certain-parent-in-drupal que es exactamente lo que necesitaba

El código, copiado del enlace mencionado anteriormente y modificado para ajustarse a mis necesidades (principalmente para usar la ruta actual para construir el árbol de menús, en lugar de usar un valor codificado:

$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>';

1
Esto funciona bien, pero debe usarlo en current_path()lugar de $_GET['q']. $_GET['q']devolverá el alias de ruta, donde current_path()obtendrá nodo / id.
mediaashley

6

Se puede hacer fácilmente usando el módulo de bloque de menú (se tarda unos 5 minutos en configurarlo).

Captura de pantalla de bloque de menú

Todo lo que tienes que hacer es

  1. Habilitando el módulo
  2. Caminante a admin/structure/block
  3. Al hacer clic en "Agregar bloque de menú"
  4. Establezca "Nivel inicial" en "2do nivel (Secundario)" y configure la región donde debe mostrarse en "Especifique en qué temas y regiones se muestra este bloque".

  5. Capturas de pantalla

    • Así es como se ve la página de configuración

      captura de pantalla

    • admin / estructura / página de bloque con el módulo de bloque de menú activado

      captura de pantalla

    • Generé algunos contenidos de "Página básica" con el módulo Devel, les proporcioné algunos enlaces de menú y creé una jerarquía de menú anidada

      • Esta es la portada predeterminada sin submenús (el bloque "Menú principal - 2do nivel" NO se puede ver en la barra lateral izquierda, ya que no tiene elementos secundarios de segundo nivel)

      captura de pantalla

      • Este es el segundo menú, con algunos elementos secundarios, ya puede ver el "Menú principal - 2do nivel" en la barra lateral izquierda, pero solo se pueden ver los elementos secundarios del 2do nivel

        captura de pantalla

        artículos de segundo nivel

      • Ahora yendo más profundo:

        También se pueden ver elementos secundarios de tercer nivel.

Creo que usar el módulo de bloque de menú para esta tarea es una de las soluciones más fáciles y rápidas.


Sería realmente curioso por qué recibí un voto negativo para esta publicación. El módulo recomendado hace el trabajo, y escribí un tutorial paso a paso. ¿Por qué el votante no publica un comentario de los motivos? (Tal vez sería útil (tal vez no), al menos podría reaccionar.)
Sk8erPeter

0

Como se señaló en los comentarios, terminé usando la función API y luego peinando con 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%;
}

0

Esto funciona correctamente para obtener el submenú de la página actual:

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;
}

¡Espero que esto ayude!


¡Su función llama a una función indefinida (override_left_l)!
DrCord

0

@ Chris Rockwell y @ Mario Awad

Soy novato en Drupal, así que es difícil de entender para mí dónde agregar esta función. Pido disculpas por eso. Pero, ¿pueden mencionarlo en qué archivo, debemos agregar esta función?

Estoy tratando de crear una barra de navegación lateral que muestre solo elementos secundarios en cada página. ¿Cómo crear un menú de navegación en la barra lateral con diferentes enlaces de navegación que se muestran en diferentes páginas?

¡Yo aprecio!

¡Gracias!


0

Acabo de terminar de publicar una función que obtiene elementos del menú secundario dada la ruta de un nodo. Puede verificarlo aquí: http://softkube.com/blog/getting-child-menu-items-drupal-menu-tree

Incluyo el enlace a prueba futura de la respuesta en caso de que la publicación se actualice y también copiaré / pegaré el código completo al final.

En su caso, simplemente puede ejecutar algo como esto en su tema para enumerar todos los elementos del menú secundario. Modifique la echodeclaración y el tema a su gusto.

$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 />';
}

Y aquí está el código completo de la función. Consulte el enlace para posibles actualizaciones futuras.

Buena suerte.

/**
 * 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;
}

Gracias mario ¿Puede comentar sobre por qué eligió este sobre el uso $parametersde menu_build_tree?
Chris Rockwell

Gracias por la respuesta. No pude obtener la información necesaria sin importar lo $parametersque usé, y créeme, me veía mucho. Todo lo que quería es, dado un camino, obtener todos los elementos del menú secundario en todos los niveles, y simplemente no pude encontrar una manera. Si hay alguno, infórmeme, estaré encantado de aprender y actualizar mi respuesta y publicación de blog. Salud.
Mario Awad
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.