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

22

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. Je veux donc 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 bien, je ne trouve rien pour me dire si l'élément actuel a des éléments enfants.

Des idées?

Merci d'avance.

patnz
la source

Réponses:

23

start_el()devrait obtenir ces informations dans son $argsparamètre, mais il semble que WordPress ne le remplisse que s'il $argss'agit d'un tableau , tandis que pour les menus de navigation personnalisés, il s'agit d'un objet. Cela est rapporté dans un ticket Trac . Mais pas de problème, vous pouvez le remplir vous-même, si vous remplacez également la display_element()méthode dans votre marchette personnalisée (car c'est l'endroit le plus simple pour accéder au tableau des é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 ) {
            // ...
        }
    }
Jan Fabry
la source
Bonjour Jan, pouvez-vous m'aider avec cette question ? J'ai essayé votre code mais je n'ai pas pu le faire fonctionner. Pouvez-vous me donner d'autres exemples de code?
Giri
Reportez-vous à l' exemple d'implémentation complet plus bas sur cette page.
rjb
Merci beaucoup @Jan fabry .. J'ai été retardé avec mon déambulateur personnalisé .. Enfin, votre extrait m'a aidé.
Harish Chinju
7

Mise à jour: Depuis WordPress 3.7 (octobre 2013), des classes CSS ont été ajoutées pour indiquer les éléments de menu enfant et les pages dans les menus de thème - pas besoin d'utiliser un marcheur personnalisé car il est pris en charge dans WordPress core.

Les classes CSS sont nommés menu-item-has-childrenet page_item_has_children.


Pour une solution complète pour toute personne pressée (crédit à la réponse précédente de Jan Fabry), voir l'implémentation complète ci-dessous.

Générez 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 votre thème functions.php:

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 à ce qui suit:

<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 Walker de WordPress, voir Comprendre la classe Walker .

Prendre plaisir!

rjb
la source
Erreur fatale: la référence de passage par appel a été supprimée dans D: \ www \ wordpress \ wp-content \ themes \ wpt_theme \ functions.php sur la ligne 44
Tahir Yasin
La ligne # 44 est parent :: start_el (& $ output, $ item, $ depth, $ args);
Tahir Yasin
2

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

/**
 * 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, il n'y a - dans presque tous les cas - pas besoin d'un déambulateur personnalisé.

kaiser
la source
Merci, j'ai besoin du déambulateur pour l'instant mais j'y reviendrai pour la prochaine fois!
patnz
1

si vous voulez faire dérouler, vous pouvez le faire uniquement avec css. faire une navigation personnalisée dans WP avec des enfants, WordPress attribue 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.

alexndm
la source
Merci, c'est pour un menu arborescent pliable à plusieurs niveaux dans lequel j'insère également des éléments de contrôle, mais certainement bon de faire autant avec css que possible!
patnz
-1
if ( $this->has_children ) {
    $item_output .= 'has_children';
}
yaroslav
la source
3
Veuillez expliquer ce que fait ce code et comment il répond à la question.
cybmeta
Et veuillez poster le code dans plus de contexte. En l'état, la plupart des gens qui visitent n'auront aucune idée où essayer de coller cela et se tromperont.
s_ha_dum