Destacando wp_nav_menu () Clase de antepasado sin hijos en la estructura de navegación?

30

( Nota de los moderadores: originalmente se titulaba "clase de antepasado wp_nav_menu sin hijos en la estructura de navegación")

Tengo un wp_nav_menuencabezado en mi que tenía tres páginas. Cuando estoy en una de esas páginas, el licontenido de esa página en el menú obtiene la clase .current_page_item. Estas tres páginas tienen plantillas, y estas plantillas contienen consultas personalizadas para obtener todas las publicaciones de un determinado tipo de contenido. En efecto, los "hijos" percibidos de esta página de nivel superior no son en realidad hijos, son solo del tipo de contenido que he asociado con esa página de nivel superior mediante una plantilla.

Me gustaría que los elementos del menú de nivel superior obtengan una 'current-ancestor'clase cuando el usuario esté explorando una sola página de un tipo de publicación específico, nuevamente, asociado con esa página solo en una consulta personalizada en el archivo de plantilla.

Espero que tenga sentido; si no, ¡avísame dónde te perdí! Agradezco mucho cualquier ayuda.

--Editado para detalles: por ejemplo, tengo una página estática llamada Talleres que está usando una plantilla. Su babosa es talleres . La plantilla tiene una función personalizada get_posts y un bucle dentro de ella, que extrae y muestra todas las publicaciones de un tipo de contenido personalizado llamado talleres . Si hago clic en el título de uno de estos talleres, me lleva al contenido completo de ese contenido. La estructura de enlace permanente del tipo de publicación personalizada se establece en talleres / nombre de la publicación, tal como lo ve el usuario, estas piezas de contenido son elementos secundarios de la página de Talleres, cuando en realidad son todos de un tipo de contenido pero no están relacionados con la página. Es esa brecha la que necesito cerrar efectivamente en el menú, destacando el elemento de menú 'Talleres' cuando busco contenido del tipo 'taller'.

De nuevo, espero que tenga sentido, ¡creo que dije 'taller' más de 20 veces en un párrafo!

Gavin
fuente
@Gavin - ¿Puede incluir algunos detalles más de lo que está tratando de lograr? Es más fácil escribir una respuesta en términos concretos que si tratamos de hacerlo en abstracto. Además, si pudiera explicar su estructura de URL relacionada con estos, sería útil.
MikeSchinkel
1
@Gavin - Eso ayuda. Entonces, su opción de menú de nivel superior es una lista de talleres en "Talleres" con una ruta de acceso /workshops/y cuando un usuario está en la página de un taller (es decir /workshops/example-workshop/, desea que el elemento del menú "Talleres" tenga current_page_itemasignada la clase , ¿correcto?
MikeSchinkel
wp_nav_menu () expone la clase actual-menu-ancestor
Daniel Sachs

Respuestas:

29

Hay una solución más simple. Olvídate de crear páginas para cada tipo de publicación para que puedas tener elementos de navegación, porque como has aprendido, WP no tiene forma de reconocer que los tipos personalizados que estás navegando están relacionados con esa página.

En su lugar, cree un enlace personalizado en Apariencia-> Menús. Simplemente coloque la URL que le devolverá su tipo personalizado y asígnele una etiqueta, luego presione "Agregar al menú".

http://example.com/workshops/

o enlaces no bonitos:

http://example.com/?post_type=workshops

esto solo creará un botón de navegación que muestra todas las publicaciones con ese tipo de publicación personalizado, y también agregará la clase de elemento de menú actual cuando haya hecho clic en ese elemento de navegación, pero aún no agregará la clase de navegación en ninguna URL diferente a esta

Luego, una vez creado, ingrese a la configuración para ese nuevo elemento e ingrese la ficha del tipo de publicación personalizada en el campo "Atributo de título" (también puede usar el campo de descripción, pero ese está oculto en las opciones de la pantalla de administración por defecto).

Ahora, debe conectar el nav_menu_css_classfiltro (que se activa para cada elemento de navegación) y verificar si el contenido que se está viendo es del tipo de publicación indicado en su elemento de navegación personalizado:

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {
    $post_type = get_query_var('post_type');
    if ($item->attr_title != '' && $item->attr_title == $post_type) {
        array_push($classes, 'current-menu-item');
    };
    return $classes;
}

En este caso, vamos a verificar que el contenido del campo de atributo de título no esté vacío y si coincide con el post_type actual que se está consultando. Si es así, agregamos la clase de elemento de menú actual a su matriz de clase, luego devolvemos la matriz modificada.

Puede modificar esto para que simplemente coincida con el título del elemento de navegación, pero si por alguna razón desea titular el elemento de navegación de manera diferente a la ficha simple del tipo de publicación, el uso del campo Atributo de título o Descripción le brinda esa flexibilidad.

Ahora, cada vez que esté viendo un solo elemento (o probablemente incluso listas de archivos) de un tipo de publicación que coincida con un elemento del menú de navegación, ese elemento recibirá la clase CSS elemento-menú-actual para que su resaltado funcione.

No se necesitan páginas ni plantillas de página ;-) La consulta de URL se encarga de buscar las publicaciones correctas. Su plantilla de bucle se encarga de mostrar la salida de la consulta. Esta función se encarga de reconocer lo que se muestra y agregar la clase CSS.

PRIMA

Incluso puede automatizar el proceso mediante el uso wp_update_nav_menu_itemde elementos de menú generados automáticamente para todos sus tipos de publicación. Para este ejemplo, primero debería haber recuperado el $menu_idmenú de navegación al que desea agregar estos elementos.

$types = get_post_types( array( 'exclude_from_search' => false, '_builtin' => false  ), 'objects' );
foreach ($types as $type) {
    wp_update_nav_menu_item( $menu_id, 0, array(
        'menu-item-type' => 'custom',
        'menu-item-title' => $type->labels->name,
        'menu-item-url' => get_bloginfo('url') . '/?post_type=' . $type->rewrite['slug'],
        'menu-item-attr-title' => $type->rewrite['slug'],
        'menu-item-status' => 'publish'
        )
    );
}
somático
fuente
¡Esa es la cosa! Estoy usando plantillas de página solo porque los diseños son bastante complejos para esas páginas y no solo enumeran las páginas, sino que también puedo utilizar el filtro que proporcionó para verificar la ID de la página. La naturaleza de este tema es que las opciones del tema hacen que coincidan las páginas ('inicio' es esta página, 'acerca de' es esta página, etc.), por lo que debería funcionar perfectamente. ¡Gracias por la asistencia (increíblemente detallada)!
Gavin
Tuve que eliminar el current_page_parentelemento de navegación que era mi blog, pero por lo demás funcionó. thx
pkyeck
esto no estaba funcionando para mí, ya que $item->attr_titlesaqué el TÍTULO, y escribí el título en mayúsculas. así que cambié el atributo a $item->post_namey ahora funciona bien para mí.
honk31
Intenté hacer que el código funcionara para mi tema, pero no puedo hacerlo funcionar. No se aplicará ninguna clase a mi elemento principal en el menú, cuando esté en el tipo de publicación personalizada portfolio. He usado el código anterior. ¿Cual puede ser el problema?
Casper
4

En lugar de usar

$ post_type = get_query_var ('post_type');

Es posible que desee probar:

$ post_type = get_post_type ();

Como a veces el tipo de publicación no se establece en la consulta var. Este es el caso del post_type predeterminado de "post", por lo que si desea resaltar una publicación que figura en la lista de una página de listado, deberá usarla. get_very_var () solo devuelve una cadena vacía para los tipos de publicación que no son personalizados.

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {
    $post_type = get_post_type();
    if ($item->attr_title != '' && $item->attr_title == $post_type) {
        array_push($classes, 'current-menu-item');
    };
    return $classes;
}
Eric
fuente
2

@Somatic: ¡eso es fantástico! Modifiqué un poco su código para que también funcione para una Taxonomía específica (que estoy usando solo para el post_type relacionado). La idea es utilizar el atributo Título del elemento de menú para almacenar tanto el nombre de post_type como el nombre de la taxonomía, separados por punto y coma, y ​​luego explotados por la función.

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {

    # get Query Vars
    $post_type = get_query_var('post_type');  
    $taxonomy = get_query_var('taxonomy');

    # get and parse Title attribute of Menu item
    $title = $item->attr_title; // menu item Title attribute, as post_type;taxonomy
    $title_array = explode(";", $title);
    $title_posttype = $title_array[0];
    $title_taxonomy = $title_array[1];

    # add class if needed
    if ($title != '' && ($title_posttype == $post_type || $title_taxonomy == $taxonomy)) {
        array_push($classes, 'current-menu-item');
    };
    return $classes;
}
tzeldin88
fuente
2

Aquí mi solución si quieres trabajar con wp_list_pages.

agregue esto en sus functions.php

add_filter('page_css_class', 'my_page_css_class', 10, 2);
function my_page_css_class($css_class, $page){
    $post_type = get_post_type();
    if($post_type != "page"){
        $parent_page = get_option('page_for_custom_post_type-'.$post_type);
        if($page->ID == $parent_page)
            $css_class[] = 'current_page_parent';
    }
    return $css_class;
}

Ahora solo agregue en la tabla wp_options una nueva fila con un nombre_opción de page_for_custom_post_type-xxxx y un valor_opción con el ID de página que desea conectar.

Quizás haya reconocido que ya existe una opción llamada page_for_posts . Si solo tiene 1 tipo de publicación personalizada, puede configurar su página en /wp-admin/options-reading.php en el menú desplegable y la navegación configurará la página actual correctamente.

Creo que Wordpress Core debería ampliar esta sección con un menú desplegable para cada tipo de publicación registrada.

Temo
fuente
2

Decidí seguir con las páginas y usar el nombre de la plantilla de página como una clase en el elemento de navegación. Esto me permite evitar saturar el atributo de título que no me gustó de algunas de las otras soluciones.

add_filter('nav_menu_css_class', 'mbudm_add_page_type_to_menu', 10, 2 );
//If a menu item is a page then add the template name to it as a css class 
function mbudm_add_page_type_to_menu($classes, $item) {
    if($item->object == 'page'){
        $template_name = get_post_meta( $item->object_id, '_wp_page_template', true );
        $new_class =str_replace(".php","",$template_name);
        array_push($classes, $new_class);
        return $classes;
    }   
}

También tengo clases de cuerpo agregadas a header.php

<body <?php body_class(); ?>>

Finalmente, esta solución requiere un poco de CSS adicional para aplicar el estado seleccionado / activo a los elementos del menú de navegación. Lo uso para mostrar archivos de taxonomía y tipos de publicaciones personalizadas relacionadas con la página como elementos secundarios de esta página:

/* selected states - include sub pages for anything related to products */
#nav-main li.current-menu-item a,
body.single-mbudm_product #nav-main li.lp_products a,
body.tax-mbudm_product_category #nav-main li.lp_products a,
#nav-main li.current_page_parent a{color:#c00;}
Steve
fuente
Esto me dio el siguiente error: ¿ Warning: join() [function.join]: Invalid arguments passed in /home/path/to/wp-includes/nav-menu-template.php on line 76 Alguna idea de lo que sucedió aquí?
Jeff K.
Oh, creo que veo lo que está pasando. Es porque está devolviendo $ clases dentro de la instrucción if. Simplemente moverse return $classesafuera y después de eso ifparece resolver el error anterior.
Jeff K.
1

@Somatic - ¡Gran código! Hice uno cambiar yo mismo. Quería mantener el Atributo de título para su propósito previsto, por lo que coloqué la ficha Tipo de publicación personalizada en las propiedades del menú avanzado Relación de enlace (XFN) que puede habilitar en Opciones de pantalla. Yo modifiqué

if ($item->attr_title != '' && $item->attr_title == $post_type) {

y lo cambié a

if ($item->xfn != '' && $item->xfn == $post_type) {
usuario8899
fuente
0

Buen trabajo somático.

Desafortunadamente, no entiendo cómo puede enumerar sus tipos de publicaciones personalizadas en una página de la manera que explica. Si no uso un page-portfolio.php y lo agrego a una página, todo lo que obtengo es 404 page.

Si hago lo que hace Gavin, he modificado un poco tu función para eliminar también el "current_page_parent" de la página del blog de esta manera.

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2);
function current_type_nav_class($css_class, $item) {
$post_type = get_query_var('post_type');

if (get_post_type()=='portfolio') {
    $current_value = "current_page_parent"; 
    $css_class = array_filter($css_class, function ($element) use ($current_value) { return ($element != $current_value); } );
}

if ($item->attr_title != '' && $item->attr_title == $post_type) {       
    array_push($css_class, 'current_page_parent');
};
return $css_class;

}

Vayu
fuente