Фильтр wp_nav_menu ()

9

Я пытаюсь разделить навигацию на 3 отдельные панели навигации (уровень 1, уровень 2 и уровень 3+). Три, потому что они разделены по сайту, и они должны появляться только в зависимости от текущей страницы.

-0-------1--------2-------3+- level/depth
Home
 |
 |\___ Lobby
 |
 |\___ Projects
 |       |\___ Project A
 |       |       |\___ Review
 |       |       |\___ Comments
 |       |       \____ Download
 |       \____ Project B
 |               |\___ Review
 |               |\___ Comments
 |               \____ Download
 |\___ Blog
 |
 \____ About
         |\___ Legal
         \____ Contact

Первая навигационная панель, содержащая уровень 1, всегда видна. Вторая навигационная панель (уровень 2) только тогда, когда я нахожусь на соответствующей родительской странице. То же самое относится и к третьей панели навигации (уровень 3+, плюс, потому что эта панель навигации также будет содержать вложенные страницы и подчиненные страницы ... уровня 3).

Вкратце: я хочу отобразить все родительские меню на их панелях навигации и только прямые дочерние элементы текущей страницы.

Что я пробовал:

function my_nav_menu( $args = array() )
{
    $echo = isset( $args['echo'] ) ? (bool)( $args['echo'] ) : true;
    $args['echo'] = false;

    add_filter( 'wp_get_nav_menu_items' , 'my_nav_menu_filter' , 666 , 3 );

    $menu = wp_nav_menu( $args );

    remove_filter( 'wp_nav_menu_objects' , 'my_nav_menu_filter' , 666 );

    if( $echo )
        echo $menu;
    else
        return $menu;
}

function my_nav_menu_filter( $items , $menu , $args )
{
    //var_dump( $args );

    $navLevel = isset( $args['navlevel'] ) ? (int)( $args['navlevel'] ) : 0;

    //echo 'navlevel = ' . $args['navlevel'] . ' | ' . $navLevel;

    if( $navLevel == 1 )
    {
        foreach( $items as $key => $item )
        {
            if( $item->menu_item_parent != 0 )
                unset( $items[$key] );
        }
    }
    else if( $navLevel == 2 )
    {
        foreach( $items as $key => $item )
        {
            if( $item->menu_item_parent != 0 )
            {
                $page = get_page( $item->menu_item_parent );

                if( $page->menu_item_parent == 0 )
                    continue;
            }

            unset( $items[$key] );
        }
    }
    else if( $navLevel == 3 )
    {
        foreach( $items as $key => $item )
        {
            if( $item->menu_item_parent != 0 )
            {
                $page = get_page( $item->menu_item_parent );

                if( $page->menu_item_parent != 0 )
                    continue;
            }

            unset( $items[$key] );
        }
    }
    else
    {
        //var_dump( $items );
    }

    return $items;
}

Вызов это в моем header.php: <?php my_nav_menu( array( 'echo' => false , 'navlevel' => 1 ) ); ?>

Однако $argsустановлено значение по умолчанию, и моя пользовательская запись navlevelне отображается в фильтре.

Как я могу разделить свою навигационную панель, как описано? Как мне установить мой пользовательский $argsввод?

nonsensation
источник
2
Добрый день и добро пожаловать в WPSE. Я должен поздравить вас с эпическим построенным вопросом для первого таймера. Хорошо продуманные и понятные вопросы всегда привлекают много внимания хорошими ответами. +1
Питер Гусен
3
Ответ на этот вопрос включает в себя пользовательский класс Уокера, возможно, это поможет любым потенциальным ответчикам
Том Дж. Новелл
Спасибо. Я копался в php / wp только в эти выходные, так что я не такой знакомый. Я попробовал пользовательский Walker, однако Walker обрабатывает только один элемент за раз, поэтому я не могу сравнить его с текущим элементом. И фильтр не принимает мой пользовательский аргумент. Хммм ...
сенсации

Ответы:

3

Я думаю, что я получил ответ:

function my_nav_menu( $args = array() )
{
    $echo = isset( $args['echo'] ) ? (bool)( $args['echo'] ) : true;

    $args['echo'] = false;

    add_filter( 'wp_nav_menu_objects' , 'my_filter_nav_menu' , 100 , 2 );

    $menu = wp_nav_menu( $args );

    remove_filter( 'wp_nav_menu_objects' , 'my_filter_nav_menu' , 100, 2 );

    if( $echo )
        echo $menu;
    else
        return $menu;
}

Это делает свое дело: позволяет мне изменять пункты меню, и пользовательские аргументы все еще доступны. Я случайно подключил фильтр wp_get_nav_menu_itemsвместо wp_nav_menu_objects. У меня все еще есть проблемы с фильтрацией, однако это, вероятно, некоторые логические ошибки ..

РЕДАКТИРОВАТЬ: я решил свою проблему, объединив уровень 2 Navbar и уровень 3+ Navbar в один и разделив их с помощью CSS

Вот текущая часть PHP:

function serthy_filter_nav_menu( $items , $args )
{
    $argArray = (array)( $args );

    if( isset( $argArray['toplevel'] ) )
    {
        foreach( $items as $key => $item )
        {
            if( $item->menu_item_parent != 0 )
                unset( $items[$key] );
        }

        return $items;
    }

    global $post;

    $arr = array();

    foreach( $items as $key => $item )
    {
        $parentIDs = get_post_ancestors( $item->ID );

        foreach( $parentIDs as $i => $parentID )
        {
            if( $parentID == $post->ID )
            {
                array_push( $arr , $item );

                break;
            }
        }
    }

    return $arr;
}
nonsensation
источник
Выглядит хорошо для меня на первый взгляд. У вас есть проблемы с этим кодом? Sidenote: Вы можете сократить свое первое утверждение:$echo = ! isset( $args['echo'] ) ?: $args['echo'];
kaiser
1

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

На этой странице Кодекса вы можете увидеть классы меню (и на самой странице). Таким образом, для «второго уровня», который вы описали, предполагается, что меню первого уровня - это уровень 1, а не 0.

ul > li > ul.sub-menu { display: none; }  /* Hide by default */
ul > li.current-menu-parent > ul.sub-menu { display: block; } /* Show menu */

А потом что-то похожее для следующего уровня вниз:

ul > li > ul.sub-menu > li > ul.sub-menu{ display: none; }  /* Hide by default */
ul > li > ul.sub-menu > li.current-menu-parent > ul.sub-menu { display: block; }

Очевидно, замените «block» на «inline-block» или на то, на что обычно настроено ваше меню.

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

Аманда Джайлс
источник
Спасибо, я использовал некоторые классы в css для своих навигационных панелей! :)
безрассудство
Если вы в конечном итоге использовали это решение, не могли бы вы пометить мой ответ как принятый? Спасибо.
Аманда Джайлс