Filtrar wp_nav_menu ()


9

Intento dividir mi navegación en 3 barras de navegación individuales (nivel 1, nivel 2 y nivel 3+). Tres porque están separados en el sitio y solo deberían aparecer dependiendo de la página actual.

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

La primera barra de navegación que contiene el nivel 1 siempre está visible. La segunda barra de navegación (nivel 2) solo cuando estoy actualmente en la página principal correspondiente. Lo mismo ocurre con la tercera barra de navegación (nivel 3+, más porque esta barra de navegación también contendrá subpáginas y subpáginas ... del nivel 3).

En resumen: quiero mostrar todos los menús principales en sus barras de navegación y solo los elementos secundarios directos de la página actual.

Lo que probé:

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

Llamando a esto en mi header.php: <?php my_nav_menu( array( 'echo' => false , 'navlevel' => 1 ) ); ?>

Sin embargo, $argsse establece en los valores predeterminados y mi entrada personalizada navlevelno se muestra en el filtro.

¿Cómo puedo dividir mi barra de navegación como se describe? ¿Cómo configuro mi $argsentrada personalizada ?


2
Buen día y bienvenido a WPSE. Debo felicitarte por una pregunta épica construida para un primer contador de tiempo. Las preguntas bien construidas que son claras siempre reciben mucha atención con buenas respuestas. +1
Pieter Goosen el

3
La respuesta a esto implica una clase Walker personalizada, tal vez esto ayude a cualquier posible respondedor
Tom J Nowell

Gracias. Excavé en php / wp solo este fin de semana, así que no estoy tan familiarizado. Probé un Walker personalizado, sin embargo, el Walker solo maneja un solo artículo a la vez, por lo que no puedo compararlo con el artículo actual. Y un filtro no acepta mi argumento personalizado. Hmmm ...
sentido

Respuestas:


3

Creo que obtuve la respuesta:

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

Esto hace el truco: me permite alterar los elementos del menú y los argumentos personalizados aún están disponibles. Accidentalmente enganché el filtro en wp_get_nav_menu_itemslugar de wp_nav_menu_objects. Todavía tengo problemas con el filtrado, sin embargo, estos son probablemente algunos errores lógicos.

EDITAR: resolveré mi problema combinando el nivel 2 de la barra de navegación y el nivel 3 + de la barra de navegación en uno y separándolos con css

Aquí está la parte php actual:

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

Me parece bien a primera vista. ¿Tienes problemas con ese código? Nota al margen: puede acortar su primera declaración:$echo = ! isset( $args['echo'] ) ?: $args['echo'];
kaiser

1

Me parece que podría manejar esto a través de CSS, ya que podría ocultar las opciones de menú de nivel inferior de forma predeterminada y luego elegir mostrarlas si tienen ciertas clases por encima de ellas.

En esta página del Codex , puede ver las clases de menú (y en su propia página). Entonces, para el "segundo nivel" que describió, suponiendo que el menú del primer nivel es el nivel 1, no el 0.

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

Y luego algo similar para el siguiente nivel:

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

Obviamente reemplace "bloque" con "bloque en línea" o lo que sea que sus menús estén configurados normalmente.

Puede que tenga que jugar para encontrar la combinación correcta de clases, pero he tenido buena suerte con este método antes. WP deja caer un montón de clases allí, también podría usarlas.


¡Gracias, usaré algunas clases en CSS para mis barras de navegación! :)
sentido

Si terminó usando esta solución, ¿podría marcar mi respuesta como aceptada? Gracias.
Amanda Giles
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.