Descrizione delle voci di menu? Custom Walker per wp_nav_menu()

6 apr 2011, 01:25:50
Visualizzazioni: 113K
Voti: 111

Un menu WordPress normale appare così:

Home | Blog | Chi siamo | Contatti

Ma ho visto molte pagine con descrizioni sotto questi link:

Home Page | I nostri Blog | Chi siamo | Contatti
....visitaci...| leggi di più| info base| modulo contatti

Come si può ottenere questo risultato?

(Voglio che sia una funzione core per tutti i miei temi, quindi niente plugin per favore, voglio solo sapere come si fa)

0
Tutte le risposte alla domanda 4
5
126

Hai bisogno di un custom walker per il menu di navigazione.

Sostanzialmente, aggiungi un parametro 'walker' alle opzioni di wp_nav_menu() e chiami un'istanza di una classe avanzata:

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_Walker estende Walker_Nav_Menu e modifica la funzione start_el( &$output, $item, $depth, $args ) per cercare $item->description.

Un esempio base:

/**
 * Crea una lista HTML degli elementi del menu di navigazione.
 * Sostituzione del Walker nativo, utilizzando la descrizione.
 *
 * @see    https://wordpress.stackexchange.com/q/14037/
 * @author fuxia
 */
class Description_Walker extends Walker_Nav_Menu
{
    /**
     * Inizia l'output dell'elemento.
     *
     * @param  string $output Passato per riferimento. Usato per aggiungere contenuto aggiuntivo.
     * @param  object $item   Oggetto dati dell'elemento del menu.
     * @param  int $depth     Profondità dell'elemento del menu. Può essere usato per il padding.
     * @param  array|object $args    Stringhe aggiuntive. In realtà sempre un 
                                     istanza di stdClass. Ma questo è 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        ) .'"';

        // inserisci la descrizione solo per gli elementi di primo livello
        // puoi modificare questo
        $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;

        // Poiché $output è chiamato per riferimento non abbiamo bisogno di restituire nulla.
        $output .= apply_filters(
            'walker_nav_menu_start_el'
        ,   $item_output
        ,   $item
        ,   $depth
        ,   $args
        );
    }
}

Oppure, alternativamente come ha commentato @nevvermind, potresti ereditare tutte le funzionalità della funzione start_el del parent e semplicemente aggiungere la descrizione a $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 ) 
    );
}

Output di esempio:

Visualizzazione di esempio del menu con descrizioni

Ora abilita il campo descrizione in wp-admin/nav-menus.php per ottenere la possibilità di modificare questo campo. Se non lo fai, WP semplicemente butta via tutto il contenuto del post al suo interno.

Schermata di amministrazione per abilitare le descrizioni del menu

Ulteriori letture:

E questo è tutto.

6 apr 2011 03:15:46
Commenti

Se per te ereditarietà != riscrivere l'intero metodo, mantieni semplicemente lo stesso nome, prova questo: public function start_el(&$output, $item, $depth, $args) { parent::start_el($output, $item, $depth, $args); $output .= sprintf('<i>%s</i>', esc_html($item->description)); }

nevvermind nevvermind
14 dic 2011 15:15:57

@nevvermind Dovresti almeno verificare se la descrizione ha del contenuto. ;) La posizione della descrizione nel mio codice di esempio è solo il modo più semplice per illustrare la soluzione. Se hai bisogno di inserire la descrizione nell'ancora, devi ricostruire l'intera funzione.

fuxia fuxia
16 dic 2011 12:38:44

sì, dovresti scrivere l'intero metodo, senza dubbio, ma per le persone che hanno bisogno di (diciamo...) aggiungerlo, potrebbe semplicemente risparmiargli molti mal di testa. E tutto questo è colpa di WP. Arrrgh!

nevvermind nevvermind
16 dic 2011 16:47:54

Ottimo lavoro e l'ho utilizzato in questa risposta modificandolo leggermente, forse puoi migliorarlo se ho tralasciato qualcosa, grazie.

The Alpha The Alpha
28 ago 2012 17:24:30

Ciò di cui avevo effettivamente bisogno era il wp_nav_menu, ma dovevo modificare il parametro 'container_class' per adattarlo al mio caso d'uso specifico, dove in base a una condizione sostituivo il menu principale con un altro, ma avevo bisogno che le classi fossero coerenti per il css.

D. Dan D. Dan
25 gen 2018 17:15:25
1
42

Dalla versione 3.0 di WordPress, non è più necessario utilizzare un walker personalizzato!

Esiste il filtro walker_nav_menu_start_el, vedi https://developer.wordpress.org/reference/hooks/walker_nav_menu_start_el/

Esempio:

function add_description_to_menu($item_output, $item, $depth, $args) {

   if (strlen($item->description) > 0 ) {
      // aggiunge la descrizione dopo il link
      $item_output .= sprintf('<span class="description">%s</span>', esc_html($item->description));
    
      // oppure.. inserisce la descrizione come ultimo elemento all'interno del link ($item_output termina con "</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);
23 feb 2015 17:31:03
Commenti

Bene! Stavo usando la soluzione nav walker di @toscho, ma questa è molto più pulita e facile da mantenere. Questa dovrebbe essere la risposta accettata, una pratica molto migliore.

Ronaldt Ronaldt
8 lug 2015 13:29:04
0

Questo approccio non è né migliore né peggiore rispetto ad altri suggerimenti; è semplicemente diverso. È anche breve e conciso.

Invece di utilizzare il campo descrizione come suggerisce @toscho, potresti compilare il campo "Titolo" di ogni voce di menu con il testo desiderato, e poi utilizzare questo CSS:

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

Sarebbe anche facile usare jQuery per aggiungerlo, ma dato che il testo è abbastanza ornamentale, il CSS sembra appropriato.

18 apr 2012 08:52:12
1

Puoi anche scrivere un elemento <span> dopo l'etichetta di navigazione nei menu e utilizzare la seguente regola CSS per modificare la proprietà display (di default è inline):

span {display:block}
8 set 2011 11:58:03
Commenti

È una soluzione semplice e facile, ma perché usare span se poi lo rendi comunque un blocco? XHTML/HTML4 non consente elementi di blocco all'interno dei link, mentre HTML5 sì, quindi usa semplicemente div e non avrai bisogno di alcun CSS!

James Mitch James Mitch
5 mar 2013 23:02:16