web-dev-qa-db-fra.com

Ajoutez la classe 'has_children' au parent parent lors de la modification de Walker_Nav_Menu

J'écris une classe de marcheur personnalisée pour wp_nav_menu et je veux pouvoir spécifier si un li contient un sous-menu. Donc, je veux que mon balisage soit:

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

Je sais comment ajouter et supprimer les classes très bien. Je ne trouve rien qui puisse me dire si l'élément en cours contient des éléments enfants.

Des idées?

Merci d'avance.

22
patnz

start_el() devrait obtenir cette information dans son paramètre $args, mais il apparaît/ WordPress ne le remplit que si $args est un tableau , alors que pour les menus de navigation personnalisés, il s'agit d'un objet. Ceci est rapporté dans un ticket Trac . Mais pas de problème, vous pouvez le remplir vous-même si vous redéfinissez également la méthode display_element() dans votre lecteur personnalisé (car il s'agit de l'endroit le plus facile pour accéder au tableau d'éléments enfants):

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 ) {
            // ...
        }
    }
23
Jan Fabry

Mise à jour: À partir de WordPress 3.7 (octobre 2013), des classes CSS ont été ajoutées pour indiquer les éléments de menu enfants et les pages des menus de thèmes. Inutile d'utiliser un marcheur personnalisé car pris en charge par l'utilisateur. Noyau WordPress.

Les classes CSS sont nommées menu-item-has-children et page_item_has_children.


Pour une solution complète pour les personnes pressées (crédit de la réponse précédente de Jan Fabry), voir la mise en œuvre complète ci-dessous.

Exportez la navigation dans le modèle de votre thème:

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

Ensuite, incluez les éléments suivants dans le functions.php de votre thème:

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

La sortie HTML résultante ressemblera à ceci:

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

Pour plus d'informations sur l'utilisation de la classe de promeneur WordPress, voir Comprendre la classe Walker .

Prendre plaisir!

7
rjb

Cette fonction est exactement ce que vous voulez avoir. Il vous montre également un moyen très efficace de modifier les éléments du menu de navigation. De plus, vous pouvez l'ouvrir pour des fonctions plus avancées (par exemple, un thème enfant) via le filtre d'éléments:

/**
 * 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 );

Et oui, dans presque tous les cas, il n'est pas nécessaire d'utiliser un déambulateur personnalisé.

2
kaiser

si vous voulez faire du menu déroulant, vous pouvez le faire avec css uniquement. créer une navigation personnalisée dans WP avec des enfants, WordPress assigne automatiquement la classe .sub-menu à l'enfant ul. Essayez ce CSS

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

Vous voudrez peut-être ajouter un peu de jQuery pour le pimenter un peu, mais cela devrait vous donner un menu déroulant fonctionnel.

1
alexndm