Як вивести дочірні посилання на основі поточної сторінки


10

Під час розміщення на сторінці, на якій є пункт меню, який є батьківським для інших пунктів меню, я хотів би мати можливість відобразити список цих елементів дочірнього меню. Я використовую наступний код.

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

Однак повернутий масив виглядає приблизно так (з великою кількістю зайвого видалено).

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)

Зауважте, як 314, 315 і 316 "нижче" 312? Вони є побратимами в моїй структурі меню, і це, здається, перевіряється кожним із тих же значень для plid(311). Очевидно, що я можу це виправити, передавши масив через іншу функцію, але я не можу допомогти, але думаю, що мені щось просто не вистачає.


В інтересах часу я виправляю проблему з CSS, хоча я не задоволений цим. $tree = menu_build_tree('main-menu', array( 'expanded' => array($trail[1]['mlid']) )); drupal_render(menu_tree_output($tree))Потім за допомогою CSS я можу стилювати посилання, щоб видалити ulпрокладки, роблячи їх видимими, що всі вони на одному рівні. Не ідеально, але ефективно. EDIT: Вибачте, я не можу зрозуміти, як змусити працювати розриви рядків.
Кріс Роквелл

Ви не можете опублікувати зразок скріншоту того, що ви хотіли б досягти? Якщо чесно, я знайшов це питання трохи безладним (наважуся сказати, тому що відповіді ще не написано). Де ви хотіли б показати дитині предмети? Чому модулі, пов'язані з меню, не задовольняють? Будь ласка, уточніть трохи більше питання, і, можливо, ми зможемо знайти вдале рішення.
Sk8erPeter

@ Sk8erPeter, прошу вибачення, якщо це безладно. Тут застосовується рішення, на яке я пішов (на який я посилаюся в коментарі): посилання . Головне питання: чому меню_build_tree () повертає вкладений масив, який має несподівані рівні (усі посилання мають бути на одному)? Щоб побачити, де я показую дочірні елементи, скористайтеся посиланням, яке я включив, і натисніть будь-яке посилання на головній панелі навігації (css використовується для створення ілюзії, на яку вони не можна натискати).
Кріс Роквелл

Щодо модулів, побіжний погляд не виявив нічого, що було б достатньо. Це могло бути тому, що мені було не дуже цікаво встановити інший модуль для рішення, яке повинно бути виконано в 4 або 5 рядках коду. У мене вже є спеціальний модуль "включає", який я використовую для таких речей. Зараз я звідусіль дзвоню get_sub_menu_based_on_active_page()і все налаштовано. Мені довелося перейти до спроби з'ясувати проблему вкладання, оскільки css робить користувача не мудрішим.
Кріс Роквелл

1
Я опублікував відповідь з іншим підходом, думаю, що це одне з найпростіших рішень. І це працює правильно. Пропонований модуль дуже популярний серед користувачів Drupal.
Sk8erPeter

Відповіді:


8

Просто хотіла подальших дій. Я повернувся до цього питання і виявив таке: /programming/2716787/how-to-get-all-the-menu-items-below-a-certain-parent-in-drupal котрий є саме те, що мені було потрібно.

Код, скопійований із згаданого вище посилання та модифікований відповідно до моїх потреб (головним чином, щоб використовувати поточний шлях для побудови дерева меню з, а не використовувати жорстко закодоване значення:

$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
Це добре працює, але слід використовувати current_path()замість цього $_GET['q']. $_GET['q']поверне псевдонім шляху, де current_path()отримає вузол / id.
mediaashley

6

Це легко зробити за допомогою модуля блоку меню (для його налаштування потрібно близько 5 хвилин).

Скріншот блоку меню

Все, що вам потрібно зробити - це

  1. Увімкнення модуля
  2. Збирається admin/structure/block
  3. Натиснувши "Додати блок меню"
  4. Встановіть "Початковий рівень" на "2-й рівень (вторинний)" і встановіть регіон, де він повинен відображатися в розділі "Вкажіть, в яких темах та регіонах відображається цей блок".

  5. Скріншоти:

    • Ось так виглядає сторінка конфігурації

      скріншот

    • Адміністратор / структура / блокова сторінка з увімкненими блоками модульних блоків меню

      скріншот

    • Я створив деякий вміст "Основної сторінки" за допомогою модуля Devel і надав на них деякі посилання на меню, і створив вкладену ієрархію меню

      • Це титульна сторінка за замовчуванням без підменю (блок "Головне меню - 2-й рівень" НЕ можна побачити на лівій бічній панелі, оскільки в ній немає дочірніх елементів другого рівня)

      скріншот

      • Це друге меню, з деякими дочірніми елементами ви вже можете бачити "Головне меню - 2-й рівень" на лівій бічній панелі, але видно лише дочірні елементи 2-го рівня

        скріншот

        предмети другого рівня

      • Тепер ідемо глибше:

        Дитячі елементи третього рівня також можна побачити

Я думаю, що використання модульного блоку меню для цього завдання - одне з найпростіших і швидких рішень.


Мені було б дуже цікаво, чому я отримав відгук на цю посаду. Рекомендований модуль виконує цю роботу, і я написав покроковий посібник. Чому невідомий не публікує коментар з причин? (Можливо, це буде корисно (можливо, ні). Я міг би принаймні відреагувати.)
Sk8erPeter

0

Як було зазначено в коментарях, я закінчив використовувати функцію API, а потім стилізував 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

Ця функція працює правильно, щоб отримати підменю поточної сторінки:

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

Сподіваюся, що це допоможе!


Ваша функція викликає невизначену функцію (override_left_l)!
DrCord

0

@Chris Rockwell та @ Mario Awad

Я новачок в Drupal, тому мені важко зрозуміти, куди додати цю функцію. Прошу вибачення за це. Але ви можете, будь ласка, згадайте, будь ласка, що в якому файлі ми повинні додати цю функцію?

Я намагаюся створити навігацію по бічній панелі, яка відображатиме лише дочірні елементи на кожній сторінці. Як створити навігаційне меню на бічній панелі з різними навігаційними посиланнями, що відображаються на різних сторінках?

Я ціную!

Дякую!


0

Я щойно закінчив розміщення функції, яка отримує елементи дочірнього меню, задані шлях до вузла. Перевірити це можна тут: http://softkube.com/blog/getting-child-menu-items-drupal-menu-tree

Я включаю посилання на майбутнє підтвердження відповіді на випадок, якщо публікація буде оновлена, а також в кінці копіюю та вставляю повний код.

У вашому випадку ви можете просто запустити щось подібне у вашій темі, щоб перелічити всі елементи дочірнього меню. Змініть echoзаяву та тему на свій смак.

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

І ось повний код функції. Перевірте посилання для можливих майбутніх оновлень.

Удачі.

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

Дякую Маріо. Можете чи ви прокоментувати, чому ви вибрали його , використовуючи $parametersв menu_build_tree?
Кріс Роквелл

Дякуємо за відгук. Я не міг отримати потрібну інформацію незалежно від того, чим $parametersкористувався, і повірте, я виглядав багато. Все, що я хотів - це, задавши шлях, отримати всі пункти меню дітей на всіх рівнях, і я просто не міг знайти спосіб. Якщо є, будь ласка, повідомте мене, я буду радий дізнатися та оновити свою відповідь та допис у блозі. Ура.
Маріо Авад
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.