wp_get_nav_menu_items() не работает с ярлыком (slug) в WordPress

25 авг. 2016 г., 01:53:32
Просмотры: 17.3K
Голосов: 11

Согласно документации, первый параметр функции wp_get_nav_menu_items() принимает:

(string) (Обязательный) Название меню, ID или ярлык (slug).

Вот как я регистрирую свои меню:

register_nav_menus(
    array(
        'primary' => 'Navigation primaire',
        'secondary' => 'Navigation secondaire',
    )
);

Вот как я пытаюсь загрузить меню:

var_dump( wp_get_nav_menu_items('primary') );             // bool(false)
var_dump( wp_get_nav_menu_items('navigation-primaire') ); // bool(false)
var_dump( wp_get_nav_menu_items('Navigation primaire') ); // bool(false)

var_dump( wp_get_nav_menu_items(51) );                      // array([...]) (корректно)

Функция возвращает меню только когда я использую ID. Я бы предпочел использовать ярлык (slug), так как мой сайт многоязычный и я не хочу использовать разные ID для разных языков.

Я делаю что-то не так или это баг в ядре WordPress? Я пробовал это в теме TwentySixteen с отключенным мультиязычным плагином (Polylang).

0
Все ответы на вопрос 4
2
26

Поскольку никто толком не объяснил, почему функция не работает так, как вы ожидали, я попробую подробно разобрать этот момент, так как сам недавно попал в ту же ловушку.

Проблема в том, что документация не совсем четко объясняет, к чему относится параметр slug. Большинство предполагает, что это slug зарегистрированного меню, но это неверно. На самом деле, это slug термина для таксономии nav_menu.

Давайте углубимся в исходный код, чтобы увидеть, как WordPress ядро интерпретирует slug меню.

function wp_get_nav_menu_items( $menu, $args = array() ) {
    $menu = wp_get_nav_menu_object( $menu );
....

Первая строка показывает, что используется функция wp_get_nav_menu_object() для получения меню. В нее передается параметр $menu, который мы используем в качестве slug. Поэтому нам нужно изучить исходный код функции wp_get_nav_menu_object().

function wp_get_nav_menu_object( $menu ) {
    $menu_obj = false;

    if ( is_object( $menu ) ) {
            $menu_obj = $menu;
    }

    if ( $menu && ! $menu_obj ) {
            $menu_obj = get_term( $menu, 'nav_menu' );

            if ( ! $menu_obj ) {
                    $menu_obj = get_term_by( 'slug', $menu, 'nav_menu' );
            }

            if ( ! $menu_obj ) {
                    $menu_obj = get_term_by( 'name', $menu, 'nav_menu' );
            }
    }
....

Мы видим, что эта функция использует get_term_by для получения объекта $menu_obj. Именно здесь определяется наше меню.

Когда вы создаете меню в админке WordPress, система создает новый термин. Термины имеют slug на основе их названия. Например, если меню называется "Мое Крутое Меню", WordPress сгенерирует slug "мое-крутое-меню". Вы могли зарегистрировать меню как "primary", но это не тот slug, к которому обращаются эти функции. Речь идет именно о slug термина меню.

Чтобы было понятнее, допустим, вы зарегистрировали меню так:

register_nav_menu('primary', 'Мое основное меню');

В этом случае primary — это не slug. мое-основное-меню — тоже не slug.

Если мы создали меню с названием "Мое Крутое Меню" (для примера), то его slug будет 'мое-крутое-меню', и получить его можно так:

$awesome_menu = wp_get_nav_menu_items( 'мое-крутое-меню' );

Вы можете проверить slug, посмотрев в таблицу wp_terms (или с вашим префиксом) и найдя там название вашего меню.

Если у вас мультиязычный сайт или мультисайт, этот метод не будет оптимальным, так как название и slug могут отличаться.

Поэтому лучший способ — получить все расположения меню с помощью get_nav_menu_locations(), которая вернет ассоциативный массив, где ключ — это slug зарегистрированного меню, а значение — ID термина меню, выбранного для этого расположения.

С ID термина мы можем получить информацию о термине и затем вернуть правильный slug, который требует функция.

Ниже приведена функция, которая использует wp_get_nav_items(), но вы передаете в нее slug зарегистрированного меню. В вашем случае это будет 'primary'.

Решение в коде

// название функции длинное, но не суть
function get_menu_items_by_registered_slug($menu_slug) {

    $menu_items = array();

    if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_slug ] ) ) {
        $menu = get_term( $locations[ $menu_slug ] );

        $menu_items = wp_get_nav_menu_items($menu->term_id);


    }

    return $menu_items;

}
2 июн. 2017 г. 03:09:05
Комментарии

Отличное объяснение.

Bagseye Bagseye
26 нояб. 2021 г. 12:23:01

Так хорошо объяснено, в отличие от документации (попробую добавить это в комментарии). Потерял часы, думая, что это было связано с временем вызова хука.. СПАСИБО.

cdsaenz cdsaenz
24 нояб. 2023 г. 01:34:16
0

Небольшая модификация принятого ответа

После удаления меню из расположения, $locations[ $menu_slug ] возвращает 0, поэтому хорошо добавить эту проверку:

function get_menu_items_by_registered_slug($menu_slug) {
  $menu_items = array();

  if ( ($locations = get_nav_menu_locations()) && isset($locations[$menu_slug]) && $locations[$menu_slug] != 0 ) {
    $menu = get_term( $locations[ $menu_slug ] );
    $menu_items = wp_get_nav_menu_items($menu->term_id);
  }

  return $menu_items;
}
27 апр. 2018 г. 13:38:11
3

Попробуйте так:

    $menu_name = 'primary'; // Имя меню

    if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_name ] ) ) {
        $menu = wp_get_nav_menu_object( $locations[ $menu_name ] ); // Получаем объект меню

        $menu_items = wp_get_nav_menu_items($menu->term_id); // Получаем элементы меню
        // Ваш код для вывода
    }
25 авг. 2016 г. 13:06:21
Комментарии

Не могли бы вы немного объяснить, почему ваш ответ должен сработать?

cjbj cjbj
25 авг. 2016 г. 13:36:42

У меня не срабатывает. get_nav_menu_locations() возвращает массив с одним элементом ('primary' => 51), но wp_get_nav_menu_items() возвращает false при использовании слага.

somebodysomewhere somebodysomewhere
25 авг. 2016 г. 17:54:07

Только что понял, что могу использовать массив из get_nav_menu_locations() для загрузки правильного меню для каждого языка без необходимости определять константы. Спасибо, что обратили мое внимание на эту функцию.

somebodysomewhere somebodysomewhere
25 авг. 2016 г. 18:09:51
0
custom_menu('primary');

function custom_menu( $theme_location ) {
if ( ($theme_location) && ($locations = get_nav_menu_locations()) && isset($locations[$theme_location]) ) {
    $menu = get_term( $locations[$theme_location], 'nav_menu' );
    $menu_items = wp_get_nav_menu_items($menu->term_id);
    //ваш код меню.
}
19 мая 2017 г. 09:51:59