Description des éléments de menu? Walker personnalisé pour wp_nav_menu ()

105

Normal Wordpress Menu ressemble à:

Accueil | Blog | À propos de nous | Contact

Mais j'ai vu de nombreuses pages avec des descriptions sous ces liens:

Page d'accueil | Nos blogs | À propos de nous | Contact
.... nous rencontrer ... | lire plus | informations de base | formulaire de contact

Comment y parvenir?

(Je veux que ce soit la fonction principale de tous mes thèmes, donc pas de plugins s'il vous plaît, je veux juste savoir comment ça se passe)

Wordpressor
la source

Réponses:

116

Vous avez besoin d'un programme personnalisé pour le menu de navigation.

Fondamentalement, vous ajoutez un paramètre 'walker'aux wp_nav_menu()options et appelez une instance d'une classe améliorée:

wp_nav_menu(
    array (
        'menu'            => 'main-menu',
        'container'       => FALSE,
        'container_id'    => FALSE,
        'menu_class'      => '',
        'menu_id'         => FALSE,
        'depth'           => 1,
        'walker'          => new Description_Walker
    )
);

La classe Description_Walkers'étend Walker_Nav_Menuet change la fonction start_el( &$output, $item, $depth, $args )à rechercher $item->description.

Un exemple de base:

/**
 * Create HTML list of nav menu items.
 * Replacement for the native Walker, using the description.
 *
 * @see    https://wordpress.stackexchange.com/q/14037/
 * @author fuxia
 */
class Description_Walker extends Walker_Nav_Menu
{
    /**
     * Start the element output.
     *
     * @param  string $output Passed by reference. Used to append additional content.
     * @param  object $item   Menu item data object.
     * @param  int $depth     Depth of menu item. May be used for padding.
     * @param  array|object $args    Additional strings. Actually always an 
                                     instance of stdClass. But this is WordPress.
     * @return void
     */
    function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 )
    {
        $classes     = empty ( $item->classes ) ? array () : (array) $item->classes;

        $class_names = join(
            ' '
        ,   apply_filters(
                'nav_menu_css_class'
            ,   array_filter( $classes ), $item
            )
        );

        ! empty ( $class_names )
            and $class_names = ' class="'. esc_attr( $class_names ) . '"';

        $output .= "<li id='menu-item-$item->ID' $class_names>";

        $attributes  = '';

        ! empty( $item->attr_title )
            and $attributes .= ' title="'  . esc_attr( $item->attr_title ) .'"';
        ! empty( $item->target )
            and $attributes .= ' target="' . esc_attr( $item->target     ) .'"';
        ! empty( $item->xfn )
            and $attributes .= ' rel="'    . esc_attr( $item->xfn        ) .'"';
        ! empty( $item->url )
            and $attributes .= ' href="'   . esc_attr( $item->url        ) .'"';

        // insert description for top level elements only
        // you may change this
        $description = ( ! empty ( $item->description ) and 0 == $depth )
            ? '<small class="nav_desc">' . esc_attr( $item->description ) . '</small>' : '';

        $title = apply_filters( 'the_title', $item->title, $item->ID );

        $item_output = $args->before
            . "<a $attributes>"
            . $args->link_before
            . $title
            . '</a> '
            . $args->link_after
            . $description
            . $args->after;

        // Since $output is called by reference we don't need to return anything.
        $output .= apply_filters(
            'walker_nav_menu_start_el'
        ,   $item_output
        ,   $item
        ,   $depth
        ,   $args
        );
    }
}

Vous pouvez également, comme l'a souligné @nevvermind , hériter de toutes les fonctionnalités de la start_elfonction parent et simplement ajouter la description à $output:

function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) 
{
    parent::start_el( $output, $item, $depth, $args );
    $output .= sprintf( 
        '<i>%s</i>', 
        esc_html( $item->description ) 
    );
}

Exemple de sortie:

entrez la description de l'image ici

Activez maintenant le champ de description wp-admin/nav-menus.phppour pouvoir modifier ce champ. Si vous ne le faites pas, WP y jette simplement le contenu complet de votre message.

entrez la description de l'image ici

Lectures complémentaires:

Et c'est tout.

fuxia
la source
11
Si pour vous l' héritage! = Réécrivez toute la méthode, conservez simplement le même nom , essayez ceci:public function start_el(&$output, $item, $depth, $args) { parent::start_el($output, $item, $depth, $args); $output .= sprintf('<i>%s</i>', esc_html($item->description)); }
importe
2
@nevvermind Vous devriez au moins vérifier si la description a un contenu. ;) La position de la description dans mon exemple de code n’est que le moyen le plus simple d’illustrer la solution. Si vous avez besoin d'obtenir la description dans l'ancre, vous devez reconstruire toute la fonction.
fuxia
1
oui, vous auriez à écrire toute la méthode, cela ne fait aucun doute, mais pour les personnes qui ont besoin de (par exemple, l'apposer), cela leur évitera peut-être beaucoup de maux de tête. Et tout cela est de la faute de WP. Arrrgh!
Nevermind
Un joli et je l'ai utilisé dans cette réponse en modifiant un peu, peut-être que vous pouvez le rendre meilleur si je manque quelque chose, merci.
L'alpha
Ce dont j'avais réellement besoin, c'était le wp_nav_menu , mais je devais changer le paramètre 'container_class', pour fonctionner dans mon cas d'utilisation particulier, où je remplaçais le menu principal par une autre, mais j'avais besoin que les classes soient cohérentes pour css.
D. Dan
33

Depuis WordPress 3.0 , vous n'avez plus besoin d'un marcheur personnalisé!

Il y a le walker_nav_menu_start_elfiltre, voir https://developer.wordpress.org/reference/hooks/walker_nav_menu_start_el/

Exemple:

function add_description_to_menu($item_output, $item, $depth, $args) {
    if (strlen($item->description) > 0 ) {
        // append description after link
        $item_output .= sprintf('<span class="description">%s</span>', esc_html($item->description));

        // insert description as last item *in* link ($input_output ends with "</a>{$args->after}")
        //$item_output = substr($item_output, 0, -strlen("</a>{$args->after}")) . sprintf('<span class="description">%s</span >', esc_html($item->description)) . "</a>{$args->after}";
    }

    return $item_output;
}
add_filter('walker_nav_menu_start_el', 'add_description_to_menu', 10, 4);
Joost
la source
1
Agréable! J'utilisais la solution de nav walker de @toscho, mais elle est beaucoup plus propre et plus facile à maintenir. Ce devrait être la réponse acceptée, une bien meilleure pratique.
Neejoh
8

Ce n'est pas meilleur ou pire que d'autres suggestions; c'est juste différent. C'est court et gentil aussi.

Plutôt que d'utiliser le champ de description comme le suggère @toscho , vous pouvez renseigner le champ "Titre" de chaque élément de menu avec le texte souhaité, puis utiliser ce code CSS:

.menu-item a:after { content: attr(title); }

Il serait également facile d’utiliser jQuery pour l’ajouter, mais le texte est suffisamment décoratif pour que CSS semble approprié.

mrwweb
la source
2

Vous pouvez également écrire un <span>élément après le libellé de navigation dans les menus et utiliser la règle CSS suivante pour modifier ses displayparamètres ( inlinepar défaut):

span {display:block}
Markus
la source
2
C'est une solution simple et facile, mais pourquoi l'utiliser spansi vous le bloquez quand même? xhtml / html4 n'autorise pas les éléments de bloc à l'intérieur des liens, html5 cependant, alors utilisez-le div, et aucun besoin de css!
James Mitch