Como gerar links filhos com base na página atual

10

Ao aterrar em uma página que possui um item de menu pai de outros itens de menu, gostaria de poder mostrar uma lista desses itens de menu filho. Estou usando o seguinte código.

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

No entanto, a matriz retornada se parece com isso (com muitas desnecessárias removidas).

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 como 314, 315 e 316 estão 'abaixo' 312? Eles são irmãos na minha estrutura de menus, e isso parece ser verificado por cada um com o mesmo valor para plid(311). Obviamente, eu posso consertar isso passando a matriz por outra função, mas não posso deixar de pensar que estou perdendo alguma coisa.

Chris Rockwell
fonte
No interesse do tempo, estou corrigindo o problema com CSS, embora não esteja satisfeito com isso. $tree = menu_build_tree('main-menu', array( 'expanded' => array($trail[1]['mlid']) )); drupal_render(menu_tree_output($tree))Depois, usando CSS, posso estilizar os links para remover o ulpreenchimento, fazendo com que pareçam que estão todos no mesmo nível. Não é o ideal, mas é eficaz. EDIT: desculpe, não consigo descobrir como fazer com quebras de linha funcionem.
22612 Chris Rockwell
você não conseguiu publicar uma captura de tela de amostra do que gostaria de alcançar? Para ser sincero, achei a pergunta um pouco confusa (ouso dizer isso porque ainda não foram escritas respostas). Onde você gostaria de mostrar os itens filhos? Por que os módulos relacionados ao menu não são satisfatórios? Esclareça a questão um pouco mais e talvez possamos encontrar uma boa solução.
precisa saber é o seguinte
@ Sk8erPeter, peço desculpas se estiver bagunçado. A solução que eu usei (mencionada no meu comentário) está sendo usada aqui: link . A principal questão é: por que o menu_build_tree () está retornando uma matriz aninhada que possui níveis inesperados (todos os links devem estar no mesmo)? Para ver onde estou mostrando os itens filhos, use o link que incluí e clique em qualquer link na barra de navegação principal (o css é usado para dar a ilusão de que eles não são clicáveis).
22630 Chris Rockwell
Em relação aos módulos, um olhar superficial não encontrou nada que fosse suficiente. Isso pode ser porque eu não estava muito interessado em instalar outro módulo para uma solução que deveria ser realizada em 4 ou 5 linhas de código. Eu já tenho um módulo 'incluso' personalizado que uso para coisas como esta. Agora, de qualquer lugar, eu ligo get_sub_menu_based_on_active_page()e estou pronto. Eu tive que deixar de tentar descobrir o problema de aninhamento, pois o css torna o usuário nem o mais sábio.
22630 Chris Rockwell
1
Eu postei uma resposta com outra abordagem, acho que é uma das soluções mais fáceis. E funciona corretamente. O módulo sugerido é realmente popular entre os usuários do Drupal.
precisa saber é o seguinte

Respostas:

8

Só queria acompanhar. Voltei a esta pergunta e encontrou o seguinte: /programming/2716787/how-to-get-all-the-menu-items-below-a-certain-parent-in-drupal que é exatamente o que eu precisava.

O código, copiado do link acima mencionado e modificado para atender às minhas necessidades (principalmente para usar o caminho atual para construir a árvore de menus, em vez de usar um 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>';
Chris Rockwell
fonte
1
Isso funciona bem, mas você deve usar em current_path()vez de $_GET['q']. $_GET['q']retornará o alias do caminho, onde current_path()obterá o nó / id.
mediaashley
6

Isso pode ser feito facilmente com o uso do módulo de bloco de menus (leva cerca de 5 minutos para configurá-lo).

Captura de tela do bloco de menus

Tudo o que tem a fazer é

  1. Ativando o módulo
  2. Indo a admin/structure/block
  3. Clicando em "Adicionar bloco de menu"
  4. Defina "Nível inicial" como "2º nível (secundário)" e defina a região onde deve ser exibida em "Especifique em quais temas e regiões esse bloco será exibido".

  5. Imagens:

    • É assim que a página de configuração se parece

      captura de tela

    • página admin / estrutura / bloco com o módulo de bloco de menu ativado

      captura de tela

    • Eu gerei alguns conteúdos da "Página básica" com o módulo Devel, forneci alguns links de menu para eles e criei uma hierarquia de menus aninhada

      • Esta é a primeira página padrão sem submenus (o bloco "Menu principal - 2º nível" NÃO pode ser visto na barra lateral esquerda, pois não possui itens filhos do segundo nível)

      captura de tela

      • Este é o segundo menu, com alguns elementos filho, você já pode ver o "Menu principal - 2º nível" na barra lateral esquerda, mas apenas os elementos filho de 2º nível podem ser vistos

        captura de tela

        itens de segundo nível

      • Agora, indo mais fundo:

        Elementos filho do terceiro nível também podem ser vistos

Penso que a utilização do módulo de bloco de menus para esta tarefa é uma das soluções mais fáceis e rápidas.

Sk8erPeter
fonte
Eu ficaria muito curioso por que recebi um voto negativo para este post. O módulo recomendado faz o trabalho e eu escrevi um tutorial passo a passo. Por que o downvoter não publica um comentário dos motivos? (Talvez seria útil (talvez não), eu poderia, pelo menos, reagir.)
Sk8erPeter
0

Conforme observado nos comentários, acabei usando a função API e depois estilizando com 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
fonte
0

Isso funciona corretamente para obter o submenu da página atual:

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 esta ajuda!

Xman Classical
fonte
Sua função chama uma função indefinida (override_left_l)!
DrCord 23/09
0

Acabei de publicar uma função que obtém itens de menu filho, conforme o caminho de um nó. Você pode vê-lo aqui: http://softkube.com/blog/getting-child-menu-items-drupal-menu-tree

Estou incluindo o link para a prova futura da resposta, caso a postagem seja atualizada e também copie / cole o código completo no final.

No seu caso, você pode simplesmente executar algo assim no seu tema para listar todos os itens do menu filho. Modifique a echodeclaração e o tema ao seu gosto.

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

E aqui está o código completo da função. Verifique o link para possíveis atualizações futuras.

Boa sorte.

/**
 * 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
fonte
Obrigado Mario. Você pode comentar por que escolheu isso ao usar o $parametersin menu_build_tree?
Chris Rockwell
Obrigado pelo feedback. Não consegui obter as informações necessárias, independentemente do que $parameterseu usasse, e acredite em mim. Tudo o que eu queria era, dado um caminho, obter todos os itens do menu filho em todos os níveis, e simplesmente não conseguia encontrar um caminho. Se houver um, informe-me. Ficarei feliz em aprender e atualizar minha resposta e postagem no blog. Felicidades.
Mario Awad 31/10