Creando un submenú: muestra la categoría de los padres / los hijos de la página cuando ve a los niños

2

Me gustaría un submenú en el que el usuario visita una página, publicación o categoría (en este ejemplo, "información") y luego muestra una lista de categorías / páginas de niños. No es un menú desplegable, sino un menú que aparece solo cuando el usuario ya está en la categoría principal.

Necesito un código que continúe mostrando los hijos de parent incluso en esa página, publicación o categoría secundaria. Tal vez hay una manera de hacer esto con los menús de WP que no conozco?

El código debe estar separado del menú principal y asignarse a las clases CSS tradicionales que indican si el usuario está en la página actual. El código también debe reconocer automáticamente a los hijos del padre, en lugar de asignar a los hijos y llamar a varios menús en todo el sitio. Estoy seguro de que esto es posible porque solía utilizar dicho código. Sin embargo, no puedo recordar cuál era ese código!

A continuación se muestra un ejemplo ilustrado de cómo podría ser un menú de este tipo:

    
pregunta AndrettiMilas 25.04.2013 - 18:12

2 respuestas

4

Curioso, acabo de encontrarme con este mismo enigma hace unos meses ...

Fondo

Me pareció bastante extraño que Wordpress aplique toda clase de clases CSS a los elementos del menú para distinguir el elemento actual y sus antepasados, pero luego ignora por completo los submenús y su relación con el elemento actual. Quería una clase .current-sub CSS para poder ocultar todos .sub-menu s excepto .current-sub s.

Teoría

Después de mucha investigación y vadeando la fuente, la solución que terminé abrazando fue extender the Walker_Nav_Menu class y modifica su comportamiento en dos puntos distintos para obtener mi clase .current-sub CSS imaginado:

  1. Al procesar un elemento de menú (consulte Walker_Nav_Menu->start_el() ), examine las clases que Wordpress asignó al elemento del menú para determinar si corresponde a la página actual o si es un antepasado del menú de la página actual.
  2. Al procesar un nuevo menu-lvl (también conocido como "submenú"; consulte Walker_Nav_Menu->start_lvl() ), si el elemento del menú anterior procesado fue el elemento del menú actual o un antepasado del mismo, aplique una nueva clase al elemento del submenú en Para distinguirlo como un submenú actual.
  

Aside

     

Tenga en cuenta que he reforzado el ancestro del menú arriba. En mi situación, resultó que en realidad no me importaba la jerarquía de las publicaciones, páginas o categorías o las relaciones entre sí (es decir, no importaba si la página B era o no un elemento secundario de la página A). Lo único de lo que tenía que preocuparme era la jerarquía de sus correspondientes menu-item s .

Después de que se implementó el Walker, todo lo que necesitaba era una nueva llamada en un archivo de plantilla a wp_nav_menu() con un ejemplo de mi nuevo menú Walker como argumento.

Implementación

Por conveniencia y brevedad, proporcioné mi implementación en un complemento de estilo de procedimiento. En su mayor parte, el código es idéntico al nativo Walker_Nav_Menu : mis comentarios denotan mis adiciones.

//Register a new theme location for a custom menu
function after_setup_theme_97226() {
    register_nav_menu( 'menu-97226', 'Primary Navigation (uses Menu_Walker_97226)' );
}
add_action( 'after_setup_theme', 'after_setup_theme_97226' );

//Queue up CSS modifications
function enqueue_styles_97226() {
    wp_enqueue_style( 'style-97226', plugins_url('style.css', __FILE__) );
}
add_action( 'wp_enqueue_scripts', 'enqueue_styles_97226' );

//Now walk it out.
class Menu_Walker_97226 extends Walker_Nav_Menu {
    const CURRENT_SUBMENU_CLASS = 'current-sub';    //The CSS class to apply to the active submenu
    var $is_current_submenu     = FALSE;            //Whether or not the next sub-menu to be processed is related to the current-menu-item.

    function start_lvl( &$output, $depth = 0, $args = array() ) {
        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

        //If we've begun processing an "active" submenu, add a class to indicate as much.
        $current_sub_class = ( $this->is_current_submenu ) ? Menu_Walker_97226::CURRENT_SUBMENU_CLASS : '';

        //Add the new sub-menu ul element to the markup. Always give sub-menus the standard Wordpress "sub-menu" class.
        $output .= "\n$indent<ul class=\"sub-menu $current_sub_class\">\n";

        //We've now processed the sub-menu; reset the flag
        $this->is_current_submenu = FALSE;
    }

    function start_el( &$output, $item, $depth = 0, $args = array() ) {
        //Reset the flag such that "active" menu-items without sub-menus don't pass their "current" status on to the sub-menus of their siblings
        $this->is_current_submenu = FALSE;

        $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_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

            //Check to see if this element is "current" or a menu ancestor of "current" so that the "current" status may be passed on to any immediate sub-menu of the item.
            //You should add or remove conditions here in order to fit your application.
            //Also see "Final Notes" section below regarding performance
        if (strpos($class_names, 'current-menu-item')
            || strpos($class_names, 'current-menu-parent')
            || strpos($class_names, 'current-menu-ancestor')
            || strpos($class_names, 'current_page_parent'))
            $this->is_current_submenu = TRUE;

        $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
        $id = $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        ) .'"' : '';

        $item_output = $args->before;
        $item_output .= '<a'. $attributes .'>';
        $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

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

El contenido completo del archivo style.css referenciado es el siguiente:

ul.sub-menu {
    display:none;
}
ul.current-sub {
    display:block;
}

Y, por último, haga una llamada a wp_nav_menu() en un archivo de plantilla donde se mostrará el menú en orden para utilizar el nuevo Walker (consulte la documentación para obtener argumentos adicionales):

wp_nav_menu( array(
    'theme_location' => 'menu-97226',
    'walker' => new Menu_Walker_97226()
) );

Notas finales

  • No he ejecutado puntos de referencia, pero es completamente posible que sea más rápido verificar las clases de un elemento del menú usando in_array() llamadas antes a la matriz $classes en lugar de usar strpos() llama después. También existe la posibilidad de usar array_flip() y posteriormente usar isset( $classes[ $class_name ] ) , aunque sospecho que la inversión derrotaría cualquier rendimiento que se obtenga al usar isset() .
  • Una parte de mi implementación se inspiró en gran medida en una publicación de blog que desde entonces he perdido de vista en los meses intermedios. Si logro localizarlo, volveré a vincularlo.
  • Si algún elemento del menú aparece varias veces en su menú, puede encontrarse con un comportamiento oscuro, ya que todas las ocurrencias de un elemento de menú "actual" mantendrán el estado "actual".
  • He usado los términos "actual" y "activo" de forma indistinta para referirse a los elementos de menú y submenús que debería mostrar ... Mi terminología es un tanto confusa y mi cabeza confuso en este momento: intentaré volver más tarde para limpiarlo;)

Puede que esta no sea la solución exacta que buscabas (y es posible que existan mejores enfoques para este problema), pero espero que sea suficiente para ponerte en el camino correcto.

    
respondido por el bosco 02.05.2013 - 03:47
1

Estoy usando el siguiente código en uno de mis sitios web:

    if ( // Maybe you want different conditionals?
        (is_page() && ! is_front_page())
        || is_category()
    ) {
        $id = get_the_ID();
        $ancestors = get_ancestors($id, 'page');
        if (! empty($ancestors)) $id = $ancestors[count($ancestors)-1];
        $subpages = wp_list_pages('title_li=&child_of='.$id.'&depth=1&echo=0');
        if ('' !== $subpages) {
            echo '<nav id="subpages" role="navigation">'.PHP_EOL
                .'<ul>'.PHP_EOL
                .$subpages
                .'</ul>'.PHP_EOL
                .'</nav><!-- #subpages -->'.PHP_EOL;
        }
    }

Por favor intente esto y verifique las características deseadas. Si no (exactamente) hace lo que quiere, avíseme e intentaré actualizar el código.

    
respondido por el tfrommen 30.04.2013 - 19:26

Lea otras preguntas en las etiquetas