Agregue la clase 'has_children' al padre li cuando modifique Walker_Nav_Menu

22

Estoy escribiendo una clase de caminante personalizada para wp_nav_menu y quiero poder especificar si un li contiene un submenú. Así que quiero que mi marca sea:

<li class="has_children [other-wordpress-classes]">
    <a class="parent-link">Some item</a>
    <ul class="sub-menu">

Sé cómo agregar y eliminar las clases bien, simplemente no puedo encontrar nada que me diga si el elemento actual tiene elementos secundarios.

¿Alguna idea?

Gracias de antemano.

    
pregunta patnz 10.05.2011 - 09:46

5 respuestas

23

start_el() debería obtener esta información en su parámetro $args , pero aparece WordPress solo completa esto si $args es una matriz , mientras que para los menús de navegación personalizados es un objeto. Esto se informa en un boleto de Trac . Pero no hay problema, puede completar esto usted mismo, si también reemplaza el método display_element() en su andador personalizado (porque este es el lugar más fácil para acceder a la matriz de elementos secundarios):

class WPSE16818_Walker extends Walker_Nav_Menu
{
    function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output )
    {
        $id_field = $this->db_fields['id'];
        if ( is_object( $args[0] ) ) {
            $args[0]->has_children = ! empty( $children_elements[$element->$id_field] );
        }
        return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }

    function start_el( &$output, $item, $depth, $args ) {
        if ( $args->has_children ) {
            // ...
        }
    }
    
respondido por el Jan Fabry 10.05.2011 - 10:45
7

Actualización: a partir de WordPress 3.7 (octubre de 2013), las clases de CSS tienen ha sido agregado para indicar elementos y páginas del menú secundario en los menús temáticos, sin necesidad de usar un andador personalizado, ya que se cuida en el núcleo de WordPress.

Las clases CSS se denominan menu-item-has-children y page_item_has_children .

Para obtener una solución completa para cualquier persona que tenga prisa (crédito por la respuesta anterior de Jan Fabry), consulte la implementación completa a continuación.

Muestra la navegación en la plantilla de tu tema:

wp_nav_menu( array(
    'theme_location' => 'navigation-primary',
    'container' => false,
    'container_class' => '',
    'container_id' => '',
    'menu_class' => '',
    'menu_id' => '',
    'walker' => new Selective_Walker(),
    'depth' => 2
    )
);

Luego, incluye lo siguiente en el functions.php de tu tema:

class Selective_Walker extends Walker_Nav_Menu {
    function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
        $id_field = $this->db_fields['id'];

        if ( is_object( $args[0] ) ) {
            $args[0]->has_children = !empty( $children_elements[$element->$id_field] );
        }

        return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }

    function start_el( &$output, $item, $depth, $args ) {
        if ( $args->has_children ) {
            $item->classes[] = 'has_children';
        }

        parent::start_el(&$output, $item, $depth, $args);
    }
}

El resultado HTML resultante será similar al siguiente:

<ul>
    <li><a href="#">Home</a></li>
    <li class="has_children"><a href="#">About</a>
        <ul class="sub-menu">
            <li><a href="#">Our Mission</a></li>
        </ul>
    </li>
    <li><a href="#">Services</a></li>
    <li class="has_children"><a href="#">Products</a>
        <ul class="sub-menu">
            <li><a href="#">Lorem Ipsum</a></li>
            <li><a href="#">Lorem Ipsum</a></li>                
        </ul>
    </li>
    <li><a href="#">Contact Us</a></li>
</ul>

Para obtener más información sobre el uso de la clase walker de WordPress, consulte Descripción de la clase Walker .

¡Disfruta!

    
respondido por el rjb 06.03.2013 - 20:30
2

Esta función es exactamente lo que quieres tener. También te muestra una forma bastante efectiva de modificar los elementos del menú de navegación. Además, puede abrirlo para funciones más avanzadas (por ejemplo, tema infantil) a través del filtro de elementos:

/**
 * Classes for a navigation named "Topnav" in the nav location "top".
 * Shows examples on how to modify the current nav menu item
 * 
 * @param (object) $items
 * @param (object) $menu
 * @param (object) $args
 */
function wpse16818_nav_menu_items( $items, $menu, $args )
{
    # >>>> start editing

    // examples for possible targets
    $target['name'] = 'Topnav';
    // The targeted menu item/s
    $target['items'] = array( (int) 6 );

    # <<<< stop editing

    // filter for child themes: "config_nav_menu_topnav"
    $target = apply_filters( 'config_nav_menu_'.strtolower( $target['name'] ), $target );

    // Abort if we're not with the named menu
    if ( $menu->name !== $target['name'] ) 
        return;

    foreach ( $items as $item )
    {
        // Check what $item contains
        echo '<pre>'; print_r($item); echo '</pre>';

        // First real world example:
        $item->classes = 'span-4';

        // Second real world example:
        // Append this class if we are in one of the targeted items
        if ( in_array( (int) $item->menu_order, $target['items'] ) )
            $item->classes .= ' last';
    }

    return $items;
}
add_filter( 'wp_get_nav_menu_items', 'wpse16818_nav_menu_items', 10, 3 );

Y sí, en casi todos los casos no hay necesidad de un andador personalizado.

    
respondido por el kaiser 10.05.2011 - 21:36
1

si desea hacer un menú desplegable, puede hacerlo solo con css. Hacer navegación personalizada en WP con hijos, WordPress asigna automáticamente la clase .sub-menu a child ul. Prueba este CSS

    nav li {position:relative;}
   .sub-menu {display:none; position:absolute; width:300px;}
    nav ul li:hover ul {display:block;}

Es posible que desee agregar un poco de jQuery para darle un poco de sabor, pero esto debería darle un menú desplegable que funcione.

    
respondido por el alexndm 10.05.2011 - 10:07
-1
if ( $this->has_children ) {
    $item_output .= 'has_children';
}
    
respondido por el yaroslav 13.11.2015 - 19:20

Lea otras preguntas en las etiquetas