Descrizione delle voci di menu? Custom Walker per wp_nav_menu()
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)

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:
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.
Ulteriori letture:
- Bug associati
- Esempio simile con markup e formattazione diversi
- Abilita la casella di descrizione nella schermata di gestione del menu programmaticamente
- Raccogli la descrizione dell'elemento per un uso successivo
E questo è tutto.

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

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!

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

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.

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

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.
