Jak wyprowadzać łącza potomne na podstawie bieżącej strony

10

Gdy ląduję na stronie, która ma element menu będący rodzicem elementów menu innych stron, chciałbym móc wyświetlić listę tych elementów menu potomnego. Korzystam z następującego kodu.

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

Jednak zwrócona tablica wygląda tak (z dużą ilością niepotrzebnych usuniętych).

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)

Zauważ, że 314, 315 i 316 są „poniżej” 312? Są rodzeństwem w mojej strukturze menu i wydaje się, że jest to weryfikowane przez każdego o tej samej wartości plid(311). Oczywiście mogę to naprawić, przekazując tablicę przez inną funkcję, ale nie mogę nie myśleć, że po prostu czegoś brakuje.

Chris Rockwell
źródło
W trosce o czas naprawiam problem z CSS, chociaż nie jestem z tego zadowolony. $tree = menu_build_tree('main-menu', array( 'expanded' => array($trail[1]['mlid']) )); drupal_render(menu_tree_output($tree))Następnie za pomocą CSS mogę stylizować linki, aby usunąć uldopełnienie, dzięki czemu wyglądają na wszystkie na tym samym poziomie. Nie idealny, ale skuteczny. EDYCJA: przepraszam, nie mogę wymyślić, jak uzyskać podział linii do pracy.
Chris Rockwell
nie możesz opublikować przykładowego zrzutu ekranu z tego, co chcesz osiągnąć? Szczerze mówiąc, uznałem to pytanie za nieco niechlujne (ośmielę się to powiedzieć, ponieważ nie ma jeszcze odpowiedzi). Gdzie chciałbyś móc pokazać przedmioty potomne? Dlaczego moduły związane z menu nie są satysfakcjonujące? Proszę wyjaśnić to pytanie nieco więcej, a być może moglibyśmy znaleźć dobre rozwiązanie.
Sk8erPeter
@ Sk8erPeter, przepraszam, jeśli jest bałagan. Rozwiązanie, z którym poszedłem (o którym mowa w moim komentarzu) jest tutaj użyte: link . Główne pytanie brzmi: dlaczego menu_build_tree () zwraca zagnieżdżoną tablicę o nieoczekiwanych poziomach (wszystkie łącza powinny być takie same)? Aby zobaczyć, gdzie pokazuję elementy potomne, użyj dołączonego linku i kliknij dowolny link na głównym pasku nawigacyjnym (css służy do złudzenia, że ​​nie można ich kliknąć).
Chris Rockwell,
Jeśli chodzi o moduły, pobieżne spojrzenie nie wykazało niczego, co wystarczyłoby. Może to być spowodowane tym, że nie byłem bardzo zainteresowany instalowaniem kolejnego modułu dla rozwiązania, które powinno zostać zrealizowane w 4 lub 5 liniach kodu. Mam już niestandardowy moduł „obejmuje”, którego używam do takich rzeczy. Teraz dzwonię z dowolnego miejsca get_sub_menu_based_on_active_page()i wszystko gotowe. Musiałem przejść od próby znalezienia problemu z zagnieżdżaniem, ponieważ css sprawia, że ​​użytkownik nie jest mądrzejszy.
Chris Rockwell,
1
I pisał odpowiedź z innym podejściem, myślę, że to jedna z najprostszych rozwiązań. I działa poprawnie. Sugerowany moduł jest bardzo popularny wśród użytkowników Drupala.
Sk8erPeter,

Odpowiedzi:

8

Chciałem tylko kontynuować. Wróciłem do tego pytania i znalazłem: /programming/2716787/how-to-get-all-the-menu-items-below-a-certain-parent-in-drupal, który jest dokładnie to, czego potrzebowałem.

Kod skopiowany z wyżej wspomnianego linku i zmodyfikowany w celu dostosowania do moich potrzeb (głównie w celu użycia bieżącej ścieżki do zbudowania drzewa menu, zamiast używania zakodowanej wartości:

$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
źródło
1
Działa to dobrze, ale powinieneś użyć current_path()zamiast $_GET['q']. $_GET['q']zwróci alias ścieżki, gdzie current_path()otrzyma węzeł / id.
mediaashley
6

Można to łatwo zrobić za pomocą modułu bloku menu (konfiguracja zajmuje około 5 minut).

Zrzut ekranu bloku menu

Wszystko co musisz zrobić to

  1. Włączanie modułu
  2. Zamierzam admin/structure/block
  3. Kliknięcie „Dodaj blok menu”
  4. Ustaw „Poziom początkowy” na „2 poziom (wtórny)” i ustaw region, w którym powinien być wyświetlany w „Określ, w których tematach i regionach ma być wyświetlany ten blok”.

  5. Zrzuty ekranu:

    • Tak wygląda strona konfiguracji

      zrzut ekranu

    • strona admin / structure / block z włączonymi blokami modułów bloku menu

      zrzut ekranu

    • Wygenerowałem część „Podstawowej strony” za pomocą modułu Devel i podałem kilka linków do nich oraz stworzyłem zagnieżdżoną hierarchię menu

      • Jest to domyślna strona główna bez podmenu (blok „Menu główne - 2. poziom” NIE jest widoczny na lewym pasku bocznym, ponieważ nie zawiera żadnych elementów potomnych drugiego poziomu)

      zrzut ekranu

      • To jest drugie menu, z niektórymi elementami potomnymi, możesz już zobaczyć „Menu główne - 2. poziom” na lewym pasku bocznym, ale widoczne są tylko elementy potomne 2. poziomu

        zrzut ekranu

        przedmioty drugiego poziomu

      • Teraz idzie głębiej:

        Można również zobaczyć elementy potomne trzeciego poziomu

Myślę, że użycie modułu Blok menu do tego zadania jest jednym z najłatwiejszych i najszybszych rozwiązań.

Sk8erPeter
źródło
Byłbym naprawdę ciekawy, dlaczego dostałem głos negatywny na ten post. Zalecany moduł wykonuje zadanie, a ja napisałem samouczek krok po kroku. Dlaczego downvoter nie komentuje powodów? (Może to byłoby przydatne (może nie), mógłbym przynajmniej zareagować.)
Sk8erPeter
0

Jak zauważono w komentarzach, skończyło się na użyciu funkcji API, a następnie stylizacji za pomocą 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
źródło
0

Ta funkcja działa poprawnie, aby uzyskać podmenu bieżącej strony:

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

Mam nadzieję, że to pomoże!

Xman Classical
źródło
Twoja funkcja wywołuje niezdefiniowaną funkcję (override_left_l)!
DrCord,
0

Właśnie skończyłem publikować funkcję, która pobiera elementy menu potomnego na podstawie ścieżki węzła. Możesz to sprawdzić tutaj: http://softkube.com/blog/getting-child-menu-items-drupal-menu-tree

Podaję link do przyszłego potwierdzenia odpowiedzi na wypadek, gdyby post został zaktualizowany, a także skopiuję / wkleję pełny kod na końcu.

W twoim przypadku możesz po prostu uruchomić coś takiego w swoim motywie, aby wyświetlić listę wszystkich elementów menu podrzędnego. Zmodyfikuj echozestawienie i motyw według własnych upodobań.

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

A oto pełny kod funkcji. Sprawdź link pod kątem możliwych przyszłych aktualizacji.

Powodzenia.

/**
 * 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
źródło
Dzięki Mario. Można komentować, dlaczego wybrał ten nad użyciem $parametersw menu_build_tree?
Chris Rockwell
Dzięki za opinie. Nie mogłem uzyskać potrzebnych informacji bez względu na to, z $parametersczego korzystałem, i wierz mi, że wyglądałem dużo. Chciałem tylko, podając ścieżkę, uzyskać wszystkie elementy menu podrzędnego na wszystkich poziomach i po prostu nie mogłem znaleźć drogi. Jeśli jest taka, proszę o informację, chętnie poznam i zaktualizuję swoją odpowiedź i post na blogu. Twoje zdrowie.
Mario Awad