Как вывести дочерние ссылки на основе текущей страницы

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отступы, чтобы они выглядели на одном уровне. Не идеально, но эффективно. РЕДАКТИРОВАТЬ: извините, я не могу понять, как заставить работать разрывы строк.
Крис Роквелл
Не могли бы вы опубликовать пример скриншота того, что вы хотели бы достичь? Честно говоря, я нашел вопрос немного беспорядочным (смею сказать, потому что ответы еще не написаны). Где бы вы хотели, чтобы дети могли показывать предметы? Почему модули, связанные с меню, не удовлетворяют? Пожалуйста, уточните вопрос немного больше, и, возможно, мы могли бы найти хорошее решение.
Sk8erPeter
@ Sk8erPeter, прошу прощения, если это грязно. Решение, которое я использовал (упомянуто в моем комментарии), используется здесь: ссылка . Основной вопрос: почему menu_build_tree () возвращает вложенный массив с неожиданными уровнями (все ссылки должны быть одинаковыми)? Чтобы увидеть, где я показываю дочерние элементы, используйте ссылку, которую я включил, и нажмите любую ссылку на главной навигационной панели (css используется, чтобы создать иллюзию, что на них нельзя нажимать).
Крис Роквелл
Что касается модулей, беглый взгляд не нашел ничего, что было бы достаточно. Это может быть потому, что я не очень заинтересован в установке другого модуля для решения, которое должно быть выполнено в 4 или 5 строках кода. У меня уже есть собственный модуль «include», который я использую для подобных вещей. Теперь откуда угодно звоню get_sub_menu_based_on_active_page()и у меня все готово. Мне пришлось отказаться от попыток выяснить проблему с вложенностью, так как css делает пользователя не мудрее.
Крис Роквелл
1
Я разместил ответ с другим подходом, я думаю, что это одно из самых простых решений. И это работает правильно. Предлагаемый модуль действительно популярен среди пользователей Drupal.
Sk8erPeter

Ответы:

8

Просто хотел продолжить. Я вернулся к этому вопросу и обнаружил следующее: /programming/2716787/how-to-get-all-the-menu-items-below-a-sure-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()получит узел / идентификатор.
медиаашлей
6

Это легко сделать с помощью модуля «Блок меню» (его настройка занимает около 5 минут).

Скриншот блока меню

Все, что вам нужно сделать, это

  1. Включение модуля
  2. Собираюсь admin/structure/block
  3. Нажав «Добавить блок меню»
  4. Установите «Начальный уровень» на «2-й уровень (Вторичный)» и укажите регион, в котором он должен отображаться, в разделе «Укажите, в каких темах и регионах отображается этот блок».

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

    • Так выглядит страница конфигурации

      Скриншот

    • Страница администратора / структуры / блока с включенными блоками модуля меню блока

      Скриншот

    • Я сгенерировал некоторое содержимое «Базовой страницы» с помощью модуля Devel, предоставил несколько ссылок на меню и создал иерархию вложенных меню.

      • Это титульная страница по умолчанию без подменю (блок «Главное меню - 2-й уровень» НЕ виден на левой боковой панели, поскольку у него нет дочерних элементов второго уровня)

      Скриншот

      • Это второе меню, с некоторыми дочерними элементами, вы уже можете видеть «Главное меню - 2-й уровень» на левой боковой панели, но видны только дочерние элементы 2-го уровня

        Скриншот

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

      • Теперь углубляясь:

        Также можно увидеть дочерние элементы третьего уровня

Я думаю, что использование модуля « Меню » для этой задачи - одно из самых простых и быстрых решений.

Sk8erPeter
источник
Мне было бы очень любопытно, почему я получил понижение на этот пост. Рекомендуемый модуль выполняет свою работу, и я написал пошаговое руководство. Почему downvoter не публикует комментарий о причинах? (Может быть, это будет полезно (может быть, нет), я мог бы по крайней мере реагировать.)
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;
}

Надеюсь, это поможет!

Xman Классика
источник
Ваша функция вызывает неопределенную функцию (override_left_l)!
DrCord
0

@ Крис Роквелл и @ Марио Авад

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

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

Я ценю!

Спасибо!

Vidushi
источник
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я использовал, и поверьте мне, я выглядел много. Все, что я хотел, это дать путь, получить все дочерние элементы меню на всех уровнях, и я просто не мог найти путь. Если есть, сообщите мне, я буду рад узнать и обновить мой ответ и сообщение в блоге. Приветствия.
Марио Авад