Les Walkers WordPress

Comme je l’ai brièvement évoqué dans la chaîne WordPress, redéfinir le comportement naturel d’un menu n’est pas une tâche particulièrement aisée.

Si vous souhaitez par exemple changer la nature d’un élément du menu, y faire paraître une description ou bien y ajouter un sous menu qui se complète dynamiquement, WordPress vous en donne la possibilité via un objet appelé «Walker», mais la fonctionnalité est relativement peu (pas) documentée dans le codex.

Bref, une petite explication s’impose…

Walker WordPress Ranger...
Walker WordPress Ranger…

Les menus de WordPress

La version 3 de WordPress a fait naître la fonction wp_nav_menu(). Elle est relativement utile car elle permet de constituer ses propres menus, de façon très flexible, en les remplissant avec des liens vers des pages, des taxonomies, des articles, des liens externes, des pages d’archives…

Après avoir activé la fonctionnalité via register_nav_menus() dans le fichier functions.php, une nouvelle sous-rubrique «menus» apparait dans la partie «apparence» de l’administration. C’est ici que l’on va pouvoir administrer ses différents menus.

Ceux-ci vont pouvoir maintenant être utilisés dans le thème, de la façon suivante :

wp_nav_menu(
array(
'theme_location' => 'menu_primaire', // identifiant du menu, défini dans functions.php
'container' => 'nav', // élément conteneur
'container_class' => 'class_menu_primaire', // classe de cet élément
'container_id' => 'ID_menu_primaire', // ID de cet élément
'menu_class' => 'class_du_menu', // class du menu
'menu_id' => 'ID_du_menu', // ID du menu
'echo' => true, //true si on veut écrire le menu, false pour un simple return
'fallback_cb' => 'wp_page_menu', //fonction de substitution à utiliser si le menu n'existe pas
'before' => '', // texte à mettre devant le lien
'after' => '', // texte à mettre après le lien
'link_before' => '', // texte par lequel commence le lien
'link_after' => '', // texte par lequel termine le lien
'items_wrap' => '<ul id="\"%1$s\"" class="\"%2$s\"">%3$s</ul>', //défini la forme du menu (ul, ol, rien...)
'depth' => 0, // profondeur de menu admise (0 pour no-limit)
'walker' => new My_Walker() // C'EST CET ELEMENT QUI NOUS INTÉRESSE !!
)
);

Aucun des arguments n’est spécialement requis, mais renseignez tout de même theme_location, sans lequel la fonction n’a aucune d’utilité 😛

Qu’est-ce qu’un Walker ?

Un walker est un objet qui peut, comme vous venez de le voir, être passé en argument des quelques fonctions de menus et de listes de WordPress. Son rôle est de redéfinir leur comportement, la façon dont elles vont créer ces listes.

Les fonctions qui peuvent actuellement accepter un Walker en paramètre sont :

  • wp_nav_menu()
  • wp_list_pages()
  • wp list categories()
  • wp_list_pages()
  • wp_list_comments()

J’en ai certainement oublié d’autres, mais ce qu’il est important de savoir, c’est qu’un Walker hérite toujours d’une de ces fonctions (ou plutôt de ces classes…)

Dans notre cas, je vais m’intéresser plus particulièrement au Walker de wp_nav_menu().

Les 4 éléments du walker

Un Walker est donc une classe php qui va être ajoutée au fichier fonctions.php, de manière à pouvoir être appelée dans le thème par la suite.

Il est possible d’intervenir séparément à 4 instants de la construction d’un menu :

  • lorsqu’un niveau commence (<ul>+content)
  • lorsqu’un élément est initialisé (<li>+content)
  • lorsqu’un élément se termine (</li>)
  • lorsqu’un niveau se termine (</ul>)

On utilise les fonctions respectives :

class My_Walker extends Walker_Nav_Menu {
function start_lvl( &$output, $depth, $args ) {
// $output correspond à la variable retournée en fin de walker
// $depth correspond à la profondeur du niveau
// $arg aux variable supplémentaires
}
function start_el( &$output, $item, $depth, $args ) {
// $output correspond à la variable retournée en fin de walker
// $item correspond aux information sur l'item en cours
// $depth correspond à la profondeur du niveau
// $arg aux variable supplémentaires
}
function end_el( &$output, $item, $depth, $args ) {
// $output correspond à la variable retournée en fin de walker
// $item correspond aux information sur l'item en cours
// $depth correspond à la profondeur du niveau
// $arg aux variable supplémentaires
}
function end_lvl( &$output, $depth, $args ) {
// $output correspond à la variable retournée en fin de walker
// $depth correspond à la profondeur du niveau
// $arg aux variable supplémentaires
}
}

Néanmoins je vous déconseille vivement de partir de zéro. Il sera plus facile de copier la fonction souhaitée de la classe Walker_Nav_Menu et de la modifier.

Voyons maintenant quelques exemples de Walkers personnalisés…

Un Walker pour transformer les liens vides en une autre balise

Pour ajouter à votre menu un élément non-cliquable, la solution est d’utiliser le champ «Liens personnalisés» et de renseigner une ancre vide dans le champ «Adresse web»

Ajouter d’éléments non cliquables

Cependant ce n’est pas très propre. Lorsque le menu va être construit, cet élément sera toujours un lien, qui pointera vers une ancre nulle…

Pour faire propre il faudrait que ce ne soit plus un lien, mais un élément tel un ou autre, et qu’il n’ai plus d’attribut href, évidemment.

On va donc créer un Walker et l’associer à notre fonction d’appel du menu. Son rôle sera de trouver les éléments vides, et de leur substituer une forme plus correcte.

Voici le Walker correspondant :

function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$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 ) . '"' : '';

$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 .'>';

// MODIF 1
// si le lien est vide...
// ou s'il comment par '#' (ancre)...
// alors la balise sera un 'span' ou lieu d'un 'a'
$balise = ( ! empty( $item->url ) && substr( $item->url, 0, 1 ) != '#') ? 'a' : 'span';

$atts = array();
$atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : '';
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';

// MODIF 2 : on n'ajout l'URL seulent si c'est un lien
if( 'a' == $balise )
$atts['href'] = ! empty( $item->url ) ? $item->url : '';

$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );

$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}

// MODIF 3 : on remplace 'a' par $balise
$item_output = $args->before;
$item_output .= '<' . $balise . ''. $attributes .'>';
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= '</' . $balise . '>';
$item_output .= $args->after;

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

La modification s’opère en trois étapes :

  1. création d’une variable représentant la balise : elle correspond à un si le lien existe ; à un le cas échéant.
  2. création d’une variable attribut : elle prend pour valeur href= »… si un lien existe
  3. on place ces variables dans le code qui va généré l’élément à sortir

Ôter le lien de l’élément courant

Si vous le souhaitez, il est aussi possible de dégager le lien de l’élément courant du menu. Cela permettra à la page de ne pas faire un lien vers elle-même.

Pour cela, reprenez le Walker ci-dessus et remplacez la modification n°1 par :

// MODIF 1
// $balise = a seulement si il y a un lien et que ce n'est pas une ancre
// $balise = a si current-menu-item n'est pas dans les classes
$balise = ( ! empty( $item->url ) && substr( $item->url, 0, 1 ) != '#' && ! in_array( 'current-menu-item', $classes ) ) ? 'a' : 'span';

Nous venez simplement de préciser que si l’élément en cours de construction correspond à la page actuelle, la balise devait se transformer en et ne plus comporter d’attribut href.

Un walker pour un sous-menu automatique

Pour de nombreux sites j’ai besoin d’un Walker uniquement pour créer automatiquement des sous menus. Par exemple pour afficher dynamiquement les 5 derniers articles d’une catégorie ou bien pour lister les termes d’une taxonomie.

Dans ce cas il faut procéder en deux temps. D’abord aller dans l’administration signaler que tel élément de menu va accueillir un sous-menu dynamique. J’utilise les attributs rel (XFN) et classes que mon Walker va intercepter, pour savoir quel type de sous-menu il doit créer.

J’utilise les champs rel et classes pour passer les informations à mon Walker

Ici j’ai ajouté une classe menu-taxonomylist qui va demander à mon Walker de créer une liste de termes issue d’une taxonomie, ainsi qu’un rel portfolio précisant que ce sont les termes de la taxonomie portfolio que je veux lister ici.

Je n’ai plus qu’à concevoir mon Walker de la sorte :

function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$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 ) . '"' : '';

$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 .'>';

// MODIF 1
// $balise = a seulement si il y a un lien et que ce n'est pas une ancre
// $balise = a si current-menu-item n'est pas dans les classes
$balise = ( ! empty( $item->url ) && substr( $item->url, 0, 1 ) != '#' && ! in_array( 'current-menu-item', $classes ) ) ? 'a' : 'span';

$atts = array();
$atts['title'] = ! empty( $item->attr_title ) ? $item->attr_title : '';
$atts['target'] = ! empty( $item->target ) ? $item->target : '';
$atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';

// MODIF 2 : on n'ajout l'URL seulent si c'est un lien
if( 'a' == $balise )
$atts['href'] = ! empty( $item->url ) ? $item->url : '';

$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );

$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}

// MODIF 3 : on remplace 'a' par $balise
$item_output = $args->before;
$item_output .= '<' . $balise . ''. $attributes .'>';
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= '</' . $balise . '>';
$item_output .= $args->after;

// MODIF 4
// si cet élément a une classe menu-taxonomylist...
// on récupère le XFN (correspondant à la taxonomie souhaité)...
// on conçoit alors une liste des terms disponibles :-)
if( in_array( 'menu-taxonomylist', $classes ) ) {
$item_output .= '<ul>';
$taxo = ! empty( $item->xfn ) ? $item->xfn : 'category';
$item_output .= wp_list_categories(
array(
'taxonomy' => $taxo,
'echo' => 0,
'title_li' => '',
'hierarchical' => 1
)
);
$item_output .= '</ul>';
}

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

Après avoir rendu chaque élément, je fais un test pour savoir s’il contient la classe menu-taxonomylist. Si c’est le cas je récupère le XFN pour savoir quelle taxonomie cibler. Ensuite j’exécute un simple wp_list_categories().

Ce n’est pas si dur que ça tout compte fait… n’est-ce pas ?

Walkers imbriqués

Une dernière précision : on vient juste de voir que j’ai utilisé la fonction wp_list_categories() à l’intérieur de mon Walker, mais j’aurais très bien pu appliquer un Walker customisé à cette fonction, de manière à personnaliser encore davantage la chose.

imbriquer des walkers
walker into another walker : INCEPTION

Si ma taxonomie portoflio était hiérarchique, et que seuls les éléments terminaux comportait des articles, je pourrai créer un sous-sous-menu sur chaque élément terminal pour lister les posts qui lui sont relatifs.

Créons donc un walker supplémentaire dans le functions.php de notre thème WordPress (celui-ci héritera cette fois ci de la classe Walker_Category) :

class Walker_into_walker extends Walker_Category {
function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
extract($args);

$cat_name = esc_attr( $category->name );
$cat_name = apply_filters( 'list_cats', $cat_name, $category );

// MODIF 1
// le 'a' devient un 'span' car je ne veux pas de liens sur le nom des termes
$link = '<span ';
if ( $use_desc_for_title == 0 || empty($category->description) )
$link .= 'title="' . esc_attr( sprintf(__( 'View all posts filed under %s' ), $cat_name) ) . '"';
else
$link .= 'title="' . esc_attr( strip_tags( apply_filters( 'category_description', $category->description, $category ) ) ) . '"';
$link .= '>';

// pareil pour la balise fermante
$link .= $cat_name . '</span>';

// MODIF 2
// si la catégorie est une catégory finale...
// alors on liste les hébergements de cette catégorie
$z = get_term_children( $category->term_id, $category->taxonomy );
if( empty( $z ) ) {
$link .= '<ul>';
$items = get_posts( 'post_type=any&' . $category->taxonomy . '=' . $category->slug );
foreach( $items as $item ) {
$current_menu = ( get_queried_object_id() == $item->ID ) ? ' class="current-menu-item"' : '' ;
$link .= '<li' . $current_menu . '><a href="' . get_permalink( $item->ID ) . '">' . $item->post_title . '</a></li>';
}
$link .= '</ul>';
}

if ( !empty($feed_image) || !empty($feed) ) {
$link .= ' ';

if ( empty($feed_image) )
$link .= '(';

$link .= '<a href="' . esc_url( get_term_feed_link( $category->term_id, $category->taxonomy, $feed_type ) ) . '"';

if ( empty($feed) ) {
$alt = ' alt="' . sprintf(__( 'Feed for all posts filed under %s' ), $cat_name ) . '"';
} else {
$title = ' title="' . $feed . '"';
$alt = ' alt="' . $feed . '"';
$name = $feed;
$link .= $title;
}

$link .= '>';

if ( empty($feed_image) )
$link .= $name;
else
$link .= "<img src='$feed_image'$alt$title" . ' />';

$link .= '</a>';

if ( empty($feed_image) )
$link .= ')';
}

if ( !empty($show_count) )
$link .= ' (' . intval($category->count) . ')';

if ( 'list' == $args['style'] ) {
$output .= "\t<li";
$class = 'cat-item cat-item-' . $category->term_id;
if ( !empty($current_category) ) {
$_current_category = get_term( $current_category, $category->taxonomy );
if ( $category->term_id == $current_category )
$class .= ' current-cat';
elseif ( $category->term_id == $_current_category->parent )
$class .= ' current-cat-parent';
}
$output .= ' class="' . $class . '"';
$output .= ">$link\n";
} else {
$output .= "\t$link<br />\n";
}
}
}

Dans un premier temps, je transforme tous les liens des termes de taxonomy en (car je ne veux pas de liens vers ceux-ci).

Dans un second temps, je test si l’élément courant contient un enfant. Si oui, je ne fais rien, sinon j’exécute la suite…

Pour finir, si on est dans un élément sans enfant, je récupère tous les articles liés à cet item, et je les affiche sous la forme d’une liste.

Il n’y a maintenant plus qu’à lier ce Walker avec la fonction wp_list_categories() de mon précédent Walker et le tour est joué :

$item_output .= wp_list_categories(
array(
'taxonomy' => $taxo,
'echo' => 0,
'title_li' => '',
'hierarchical' => 1,
'walker' => new Walker_into_walker()
)
);

Alors, qu’en pensez-vous de cette histoire de Walker dans WordPress ? Puissant n’est-ce pas ?

47 commentaires
Daniel Roch, il y a 12 ans
C’est tout simplement l’article qu’il manquait pour la communauté Fr pour mieux comprendre les walkers des menus. A ma connaissance, je crois qu’il n’y avait que des tutos anglais.

Bravo donc pour le tuto, et pour le magnifique visuel du début ^^

Rémy, il y a 12 ans
Je découvre complètement cette histoire de walker avec ton article, c’est très puissant et incroyablement pratique (même si je reste convaincu que ce sont des choses que l’on devrait pouvoir faire depuis l’administration).

Merci beaucoup je garde ce tuto en favori ! (walker et rage face en bonus, j’aime)

Julio Potier, il y a 12 ans
Ha ouè … quand même, c’est tttttrrrrreeeeeeeès bon çaaaaaaaa !
La technique est excellente, bravo !
Pourvoir insérer les X derniers articles dans le menu est vraiment top, je RT et je fav.
Screenfeed, il y a 12 ans
Très bon article (même si j’ai pas encore tout regardé ^^). Perso je me suis fait un walker pour avoir un menu horizontal plus flexible au niveau CSS. En gros je remplace les li par des span, c’est beaucoup plus facile à manipuler et ça casse pas avec IE :]

Merci :]

Geoffrey, il y a 12 ans
Très bon Article Willy !
Je garde également cela en favori.

Juste un point concernant l’utilisation de l’attribut rel : il y a des règles à respecter du côté des valeurs, attention à ne pas renseigner n’importe quoi.
http://www.alsacreations.com/article/lire/1400-attribut-rel-relations.html

: tu lances un troll là ? Tu remplaces vraiment « une liste de liens » par des span ? Ça marche bien les li sur IE ! :p

Screenfeed, il y a 12 ans
: ha oui? Tente li { display: inline; } pour voir 😉
Screenfeed, il y a 12 ans
rectif : inline-block plutôt (d’ailleurs tu as fait un article qui en parle sur alsa récemment ^^)
Willy Bahuaud, il y a 12 ans
Merci pour vos compliments, ils me vont droit au cœur 😉

Les Walkers permettent de pousser la fonctionnalité menu de WordPress assez loin. Mais comme le dit je pense qu’une partie aurait peut être sa place de le core de WP, et je ne suis pas sûr que ça chargerai tant que ça le mulet…

je m’étais déjà posé la question pour les attributs rel, mais je n’avais pas vu ton article. C’est sûr, il serait plus logique de passer par des attributs data, il faudrait alors ajouter un ou deux champs dans les attributs de lien de la gestion des menus… il doit bien y avoir un hook pour ça non ?

Julio Potier, il y a 12 ans
@geoffrey : Je viens de regarder pour le hook et je n’en ai pas vu, il ne semble pas possible d’ajouter des champs ici :/ Dommage.
Screenfeed, il y a 12 ans
oui inline marche mais parfois n’est pas suffisant (la plupart du temps dans mon cas), et ajouter un zoom: 1 pour inline-block ne me plait guerre :/
Sémantique de ul et li? On m’aurait menti? Je pensais que ces balises étaient neutres.

Mais bon, on est hors sujet ^^

Lionel Pointet, il y a 12 ans
Les visuels et le contenu de cet article sont vraiment bons ! Bravo !

J’ai juste des petites remarques sur les exemples où il me semble que certaines conditions sont inversées :


$balise = (! empty( $item->url )   && $item->url != '#') ? 'span' : "a";
//devrait être :
$balise = (! empty( $item->url )   && $item->url != '#') ? 'a' : "span";

Pareil :


$balise = ((! empty( $item->url )   && $item->url != '#')||(in_array('current-menu-item',$classes))) ? 'span' : "a";
//devrait être :
$balise = ((! empty( $item->url )   && $item->url != '#')||(!in_array('current-menu-item',$classes))) ? 'a' : "span";

Et enfin :


$attributes .= ((! empty( $item->url )   && $item->url != '#')||(in_array('current-menu-item',$classes)))    ? ' href="'   . esc_attr( $item->url        ) .'"' : '';
//devrait être :
$attributes .= ((! empty( $item->url )   && $item->url != '#')||(!in_array('current-menu-item',$classes)))    ? ' href="'   . esc_attr( $item->url        ) .'"' : '';
Willy Bahuaud, il y a 12 ans
Nom de Zeus !!

Tu as raison !! je rectifie ça ce soir !

EDIT : c’est good… merci encore (ça m’apprendra à ne pas tester mon code 😉 )

Thomas, il y a 12 ans
Salut,
j’intègre mon menu via un widget, comment je peux faire pour lui passer en paramètre mon walker ?
Robin, il y a 12 ans
Salut!
Merci pour ce très bon tuto!

Il reste tout de même une petite erreur…
Il faut remplacer:


 $attributes .= (! empty( $item->;url )   && $item->url != '#')    ? '' : ' href="'   . esc_attr( $item->url        ) .'"' ;

par


 $attributes .= (! empty( $item->url )   && $item->url != '#')    ?  ' href="'   . esc_attr( $item->url        ) .'"' :'' ;

La condition était inversée et on se retrouvait donc avec un href dans le span!

Olivier, il y a 12 ans
salut Willy
l’ article qu’il me fallait. Je suis en train de passer de codeigniter à wordpress ( surtout pour de raisons de BackOffice ), je suis en train de créer un menu dans lequel le premier niveau est constitué d’un custom_post_type Concerts.
J’aimerai créer un sous menu qui puisse contenir tous les custom_type concerts. En clair j’aimerai obtenir:
Concerts
artiste 1
artiste 2.
j’essaye d’adapter ton explication sur


$item_output .= wp_list_categories(array('taxonomy'=>$taxo,'echo'=>0,'title_li'=>'','hierarchical' => 1));

Mais je n’arrive pas à obtenir la list des post_type concerts.
Si toi ou quelqu’un a une piste je suis preneur
A bientôt et encore merci pour ton travail
Olivier

Et voilà, j’en ai eu besoin et ça marche du tonnerre ! Merci encore, je RT pour la peine 🙂
soykje, il y a 12 ans
Bonjour,

Je viens de tomber sur cet article, qui semble correspondre à ma volonté de faire un menu déroulant avec catégorie et liste d’article correspondants.
Malheureusement, n’étant pas « expert », les explications données ne me permettent pas d’obtenir un résultat concluant… Serait-il possible, d’avoir une explication plus détaillée de l’utilisation d’un walker (pour créer un sous-menu automatique) ?

Merci d’avance !

darknote, il y a 12 ans
merci pour l’article, comment faire pour que les sous-menu est une puce avant le nom ?
Merci
Greg, il y a 12 ans

Pas besoin de walker pour ça, CSS est suffisant. Trois possibilités :
– utiliser les puces des <li> (puces simples),
– utiliser le pseudo-élément :before (marche pas pour IE7 et inférieur),
– utiliser le paramètre ‘link_before’ de wp_nav_menu() pour ajouter une <span> devant chaque lien, puis masquer celles au premier niveau.
darknote, il y a 12 ans
Merci de m’avoir répondu, c’est ce que je pensais juste un code à rajouter dans wp_navi_menu mais étant une bille en code , je ne vois pas comment, j’ai testé ceci ‘items_wrap’ => ‘%3$s’ mais rien.
Je crois que li c’était pour numéroter 1,2,3,etc..
Merci
darknote, il y a 12 ans
‘items_wrap’ => ul id %3$s ul
les ul ont disparu
Arnaud, il y a 11 ans
Merci pour cet article car il y a vraiment très peu d’informations claires sur les Walker en français
revalice, il y a 11 ans
Merci pour ces infos sur –walker– j’ai utilisé les walkers tels que tu les as décrits et ça marche nickel j’ai juste une question sur les Walkers imbriqués comment puis-je intervenir sur le « li » parent afin d’y appliquer une class
Julio Potier, il y a 11 ans
Hey encore moi,
Sous WordPress 3.6 ce code n’est plus correct car le walker de base a changé et comme tu reprends ce walker pour ajouter tes modifs, ça foire ;p
Donc il suffit juste de reprendre le Walker de la 3.6 et remettre tes modifs et ça repart, je viens de le faire 😀
Willy Bahuaud, il y a 11 ans
Je viens de mettre à jour cet article qui, effectivement, commençait à dater. Du coup je l’ai aussi relu et corrigé.

Par contre le temps que mon nouveau système de coloration syntaxique soit mis en place, il se peut que la lecture de l’article ou des commentaires bug un peu 😉

Roland, il y a 11 ans
bjour,
je cherche comment ajouter dans le menu twenty12 à la suite des items du menu un nouveau item mais qui n’est pas defini par le menu dans l’admin mais plutot par une fonction qui ajouterai cet item à la suite des autres. je sais pas si je suis clair !
Lionel Pointet, il y a 11 ans
Tu peux te servir du filtre ‘wp_nav_menu_items’ comme ceci :

add_filter( 'wp_nav_menu_items', 'ma_fonction', 10, 2 );

function ma_fonction( $items, $args ) {
    // Avec $args, tu peux vérifier quel menu tu affiches
    // $items contient le code HTML généré ( une suite de '<li></li>'...)

    return $items;
}

Gaël, il y a 11 ans
Merci pour cet article, ça m’a bien été utile ! Indice : un walker pour ajouter les roles ARIA aux éléments de navigation 😉

J’adore ce blog, d’excellentes ressources !

darknote, il y a 10 ans
bonjour,
on peut avoir des infobulles ou tooltip avec une image dedans ??
Merci
Clémentine, il y a 10 ans
Merci beaucoup pour cet article très instructif.

Je cherchai justement comment insérer des textes sans liens dans mon menu, j’ai donc pris ton premier walker et copié-collé tel quel dans mon fichier functions.php et j’ai rajouté au menu concerné l’attribut ‘walker’ => new My_Walker() .

Pourtant ça ne fonctionne pas, j’ai du mal comprendre une étape, étant pas très douée en php 🙂

Clémentine, il y a 10 ans
Bonjour,

Merci pour cet article très intéressant, je cherchai justement comment insérer un texte sans lien dans mon menu j’ai donc tenté de prendre ton premier walker.

J’ai collé la fonction dans mon function.php et j’ai rajouté l’attribut walker au menu concerné mais j’ai un jolie erreur php Fatal error: Class ‘My_Walker’ not found. J’ai mal comprendre une étape de ton explication, comme je ne suis pas très douée en php 🙂

Willy Bahuaud, il y a 10 ans
Alors, cela signifie que le problème est la façon, ou l’endroit où tu as déposé le walker.

Il est bien dans le fichier functions.php du thème, et la classe se nomme bien My_Walker ?

Clémentine, il y a 10 ans
Il est bien dans functions.php mais il n’est pas une classe, il faut que je rajoute class My_Walker { } autour de la fonction c’est ça ?
Clémentine, il y a 10 ans
J’ai rajouté la classe class My_Walker extends Walker_Nav_Menu { } autour de la fonction et maintenant l’erreur est : Call to undefined function subrstr()
Willy Bahuaud, il y a 10 ans
Alors là c’est ma faute, une faute de frappe…
La fonction subrstr n’existe pas, il faut la remplacer par substr.

J’ai donc mis l’article à jour 🙂

parm, il y a 10 ans
y’a un truc que je n’arrive pas à faire.
J’aimerais pour chaque item être capable de savoir si c’est le 1er, 2eme etc… de la liste <ul> dont il fait partie
OU
être capable de récupérer le menu_order de son parent…

Tu as une idée ? Merci par avance !

Willy Bahuaud, il y a 10 ans
Oui, c’est possible, je l’ai déjà fait pour un projet. Il suffit de déclarer une variable globale dans la fonction start_lvl() (et de lui assigner la valeur 0), puis de l’itérer (+1) dans la fonction start_el() 😉

Ainsi pour connaitre la position du menu, il suffit de questionner la variable (toujours l’appeler avec « global » avant).

Attention, sur les menus à plusieurs niveaux, il faudra parfois déclarer autant de globale que de niveau, et les itérer uniquement au besoin (si le menu n’a pas d’ancêtre par exemple, on sait qu’il s’agit d’un menu de niveau 1)

parm, il y a 10 ans
yes ! parfait 🙂 merci willy
Raym, il y a 10 ans
Bonjour !
merci pour cet article 🙂

est-ce qu’il y a moyen d’afficher le nombre d’articles (posts) dans une catégorie (+ses enfants) dans un élément du menu avec cette méthode ?

Merci ! 🙂

Willy Bahuaud, il y a 10 ans
Oui, c’est tout à fait possible.
Il suffit, dans le start_el, s’il s’agit d’une catégorie, de récupérer l’objet catégorie (ou term, ou taxonomie) et d’afficher sa propriété count.
Rayl, il y a 10 ans

Mais c’est génial ! Je suppose qu’après il ya moyen de le mettre dans une balise pour le placer comme on veut ?

Autre petit question pour être sûr d’avoir compris, quand on utilise les walkers, ça modifie le menu qui existe déjà, genre il faut le reconstruire en intégralité, ou est-ce que ça ajoute des petites fonctionnalités au menu par défaut ?

Je sens que ce sujet dépasse un peu mes compétences actuelles mais je dois avouer que cela m’intrigue fortement !

Merci encore pour les réponses ! 🙂

Willy Bahuaud, il y a 10 ans
Oui tout à fait, tu peux en faire ce que tu veux.
Lorsque l’on utilise les walkers, on modifie des sections de menus complètes (début d’élément, fin d’élément, début de niveau et fin de niveau). C’est pour cela qu’on ne peut appliquer qu’un seul walker à un menu.

Si un plugin altère déjà un menu, il est possible qu’il faille réappliquer les modifications du menu dans ton walker (attention, en général les plugins qui altèrent les menus préfèrent se greffer sur les filtres de fin de fonction, comme walker_nav_menu_start_el ).

Medo, il y a 9 ans
on peut utiliser ce walker pour generer automatiquement des custom menu avec hashtag pour un one page theme ??
Willy Bahuaud, il y a 9 ans
Oui tout à fait. Mais si tu veux transformer tes liens de pages, ou plutôt de «section de page» en ancre de l’accueil, je te conseille plutôt de regarder du côté des filtres post_link, page_link et post_type_link 🙂
Augustin, il y a 7 ans
Bonjour,

Merci pour ton article, très intéressant !
Par contre concernant la partie « Un walker pour un sous-menu automatique » je ne parviens pas à créer de rubrique /élément comme la tienne dans mon menu (je ne peux pas mettre de classe css et un référencer un nom de taxonomy… ici c’est une taxonomy de type post je suppose ?). Serait-il possible d’avoir des précisions sur comment tu as crée cette partie du menu ? (est-ce une rubrique custom ? Sinon, sais-tu où je peux trouver des détailles sur l’usages des différentes « object_type » de taxonomies ? (mes recherches google n’ont pas été très fructeuses…). Merci !

Willy Bahuaud, il y a 7 ans
Bonjour !

Pour ajouter des classes, il faut cliquer sur le bouton « options de l’écran » et cocher la fenêtre « classes CSS » ?
Sinon, j’ai développé l’extension Auto Generate Submenus qui répondra probablement à tes attentes, n’hésites pas à me dire ce que tu en penses…

Augustin, il y a 7 ans
[Résolu] Merci beaucoup ! Je ne connais pas assez wordpress pour avoir eu besoin de ça encore… Quel tristesse de perdre autant de temps sur quelque chose d’aussi simple… Résolu !
Tu as des informations sur l’utilisation des différents  » objects_type  » de la fonction register_taxonomy ? (post, page, attachement , revision, nav_menu_item, custom_css, customize_changeset) ?

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Publié le 06 mars 2012
par Willy Bahuaud
Catégorie Développement WordPress