Excluir dinámicamente elementos de menú de wp_nav_menu

17

Intenté buscar información sobre cómo excluir / eliminar elementos del menú de navegación de los menús personalizados, y el único hilo que encontré no tenía ninguna respuesta que me fuera útil.

1. Antecedentes:

Creé un menú Dock usando los menús personalizados de WP (wp_nav_menu) y jqDock en mi sitio. Como jqDock necesita imágenes continuas o enlaces de imágenes para hacer su magia, estoy usando un andador personalizado para que la salida HTML del menú de navegación se vea algo así:

<div id="menu-first" class="nav">
<a><img src="http://path/to/image-1.png"/></a>
<a><img src="http://path/to/image-2.png"/></a>
<a><img src="http://path/to/image-3.png"/></a>
etc...
</div>

El código para mi andador personalizado es:

class custom_nav_walker extends Walker_Nav_Menu 
{
    var $tree_type = array( 'post_type', 'taxonomy', 'custom' );
    var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );

    function start_lvl(&$output, $depth) {
        $indent = str_repeat("\t", $depth);
        $output .= "\n$indent<ul class=\"sub-menu\">\n";
    }

    function end_lvl(&$output, $depth) {
        $indent = str_repeat("\t", $depth);
        $output .= "$indent</ul>\n";
    }

    function start_el(&$output, $item, $depth, $args) {
        global $wp_query;
        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

        $class_names = $value = '';

        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $classes[] = 'menu-item-' . $item->ID;

        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
        $class_names = ' class="' . esc_attr( $class_names ) . '"';

        $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
        $id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';

        //$output .= $indent . '<li' . $id . $value . $class_names .'>';

        $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
        $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
        $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
        $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';

        $description  = ! empty( $item->description ) ? esc_attr( strtolower( $item->description )) : '';
        $item_title   = ! empty( $item->attr_title )  ? esc_attr( $item->attr_title ) : '';

        if ( strpos($description, ';') !== false ) {
        $description_array = explode (';', $description);
            $image_name = $description_array[0];
            $image_alt = $description_array[1];
        } else {
            $image_name = $description;
            $image_alt = $item_title;
        }

        $item_output = $args->before;
        $item_output .= '<a'. $attributes .'>';
        $item_output .= $args->link_before .'<img src="'.get_bloginfo('template_url').'/images/skin1/'.$image_name.'" alt="'.$image_alt.'" title="'.$item_title.'" />'.$args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }

    function end_el(&$output, $item, $depth) {
        $output .= "";
    }

}

El script jqDock luego captura la ID del menú ('menu-first') y reemplaza la salida wp_nav_menu con la del menú Dock. La salida HTML del menú Dock cambia según las opciones especificadas al cargar jqDock.

2. La pregunta:

Me gustaría no mostrar (es decir, excluir) ciertos elementos del menú de acuerdo con la ubicación del usuario en el sitio. Por ejemplo, me gustaría mostrar solo el elemento de Inicio cuando el usuario no está en el Inicio, y el elemento de Publicación aleatoria solo cuando lo está.

3. Soluciones desechadas:

a. Múltiples menús: registrar y crear múltiples menús y luego llamarlos condicionalmente podría funcionar; Sin embargo, no creo que esta sea una solución ideal ni limpia en absoluto por muchas razones. Además, los menús múltiples no son fáciles de mantener o actualizar.

si. Búsqueda y reemplazo de expresiones regulares: esto podría obligarme a cambiar el parámetro de la aguja cada vez que cambie las opciones de jqDock porque se modifica la salida HTML.

C. Propiedad de 'visualización' de CSS: Ocultar los elementos a través de la propiedad de visualización de CSS funciona, pero dado que debe aplicarse a la salida del menú jqDock, afecta la representación visual del menú.

4. Soluciones perdidos:

a. Filtrar a wp_nav_menu_items : intenté atrapar la variable (cadena) '$ items' y asignarle diferentes valores a través de etiquetas condicionales con el siguiente código:

function userf_dynamic_nav_menu ($items) {
    $items_array_home = explode('<a', $items);
    $items_array_nothome = $items_array_home;

    unset($items_array_home[1]);
    unset($items_array_nothome[2]);

    $items_home = implode('<a', $items_array_home);
    $items_nothome = implode('<a', $items_array_nothome);

    if ( is_home() ) {
        $items = $items_home;
    } else {
        $items = $items_nothome;
    }
    return $items;
}
add_filter('wp_nav_menu_first_items', 'userf_dynamic_nav_menu');

Esto funciona solo parcialmente, porque los elementos del menú cambian, pero las etiquetas condicionales se ignoran. Supongo que esto tiene sentido debido al momento en que se aplica el filtro.

si. Función de menú de navegación personalizada : intenté crear mi propia función de menú de navegación personalizada para poder agregar un argumento de exclusión a la matriz $ defaults y usar este código ligeramente modificado wp_list_pagespara completar el argumento adicional:

$exclude_array = ( $args->exclude ) ? explode(',', $args->exclude) : array();
$args->exclude = implode( ',', apply_filters('wp_nav_menu_excludes', $exclude_array) );

¿Algunas ideas?

Marventus
fuente
¿Puede mostrarnos su clase personalizada de andador?
soulseekah
Hola Souleseekah, lo acabo de agregar a mi publicación original. ¡Gracias!
Marventus
Pensé en pasar un excludeargumento también, pero, a diferencia de wp_list_pagesmuchas otras funciones de WP, wp_nav_menuno incluye una. Entonces, incluso si especifico uno cuando llamo al menú o en el andador, no lo recogerán dentro wp_nav_menu, ¿verdad?
Marventus
Lo siento, no estaba pensando bien cuando escribí eso, borré de inmediato.
soulseekah
¡No te preocupes por eso!
Marventus

Respuestas:

26

Método 1

Puede agregar un constructor a su Walker personalizado para almacenar algunos argumentos de exclusión adicionales, como:

class custom_nav_walker extends Walker_Nav_Menu {
    function __construct( $exclude = null ) {
        $this->exclude = $exclude;
    }

    function skip( $item ) {
        return in_array($item->ID, (array)$this->exclude);
        // or
        return in_array($item->title, (array)$this->exclude);
        // etc.
    }

    // ...inside start_el, end_el
    if ( $this->skip( $item ) ) return;
}

O suelte el constructor y establezca su $excludepropiedad antes de pasarlo como un andador para que le wp_nav_menu()guste:

$my_custom_nav_walker = new custom_nav_walker;
$my_custom_nav_walker->exclude = array( ... );

Dependiendo de lo que esté excluyendo, proporcione el formulario correcto para la exclusión.

Método 2

Así es como lo harías enganchándote al wp_get_nav_menu_itemsfiltro.

function wpse31748_exclude_menu_items( $items, $menu, $args ) {
    // Iterate over the items to search and destroy
    foreach ( $items as $key => $item ) {
        if ( $item->object_id == 168 ) unset( $items[$key] );
    }

    return $items;
}

add_filter( 'wp_get_nav_menu_items', 'wpse31748_exclude_menu_items', null, 3 );

Nota: object_ides el objeto al que apunta el menú, mientras que IDes la ID del menú, estos son diferentes.

Déjame saber lo que piensas.

soulseekah
fuente
¡Gracias! Aquello podría funcionar. Lo intentaré y te lo haré saber.
Marventus
Intenté el enfoque del constructor y, no importa lo que intente, sigo obteniendo un error de "Tipo de datos incorrecto para el segundo argumento" para la in_arrayfunción. ¿Estoy haciendo algo mal?
Marventus
La $excludepropiedad debe ser una matriz. Así que asegúrate de pasar una matriz al constructor, o mira el código actualizado en mi respuesta. Específicamente la conversión de texto para $this->exclude, en caso de que no se pase una matriz.
soulseekah
Lo siento: tuve un error tipográfico en mi función. Acabo de probar $exclude = array ('4', '7');y usar las babosas también, pero no tiene ningún efecto en la salida del andador. Probaré el segundo enfoque y te lo haré saber.
Marventus
No, eso tampoco funcionó. Creo que estoy muerto de cerebro por tratar de resolver esto, así que eso podría estar afectando mi ... "rendimiento", :-)
Marventus
0

esto ayuda

$exclude_array = ( $args->exclude ) ? explode(',', $args->exclude) : array();
$args->exclude = implode( ',', apply_filters('wp_nav_menu_excludes', $exclude_array) );

como ejemplo

< ?php wp_nav_menu( array( 'container_class' => 'menu-header', 'theme_location' => 'primary', 'exclude' => '66' ) ); ?>
saq
fuente
Hola Saq, olvidé mencionar que una de las soluciones que no funcionó fue crear una función personalizada nav_menu y agregar ese código como argumento adicional a los valores predeterminados de la función. Lamentablemente, no funcionó. No intenté incluirlo en el andador, pero no creo que funcione tampoco por la misma razón que mencioné anteriormente, principalmente porque wp_nav_menuno tiene un argumento de "exclusión", pero podría estar equivocado.
Marventus
Actualicé mi publicación original para incluir esto para mayor claridad.
Marventus
¿Qué sucede si no utiliza un andador personalizado? En su lugar, utiliza un menú de navegación regular y extrae los elementos con wp_get_nav_menu_items () con su imagen personalizada
saq
Esa sería una buena solución en general, pero en este caso particular, wp_get_nav_menu_itemsno se recuperarán las imágenes porque las etiquetas img no se almacenan en el menú personalizado real (solo sus nombres de archivo están en el campo de descripción, por ejemplo, "image1.png" ) El andador personalizado es lo que me permite insertar las etiquetas img en la salida del menú.
Marventus