Aggiungere la classe 'has_children' all'elemento li genitore quando si modifica Walker_Nav_Menu
Sto scrivendo una classe walker personalizzata per wp_nav_menu e voglio poter specificare se un elemento li contiene un sottomenu. Quindi voglio che il mio markup sia:
<li class="has_children [altre-classi-wordpress]">
<a class="parent-link">Elemento menu</a>
<ul class="sub-menu">
So come aggiungere e rimuovere le classi correttamente, ma non riesco a trovare nulla che mi dica se l'elemento corrente ha elementi figli.
Qualche idea?
Grazie in anticipo.

start_el()
dovrebbe ricevere queste informazioni nel suo parametro $args
, ma sembra che WordPress lo compili solo se $args
è un array, mentre per i menu di navigazione personalizzati è un oggetto. Questo è segnalato in un ticket Trac. Ma nessun problema, puoi compilarlo tu stesso, se sovrascrivi anche il metodo display_element()
nel tuo walker personalizzato (perché questo è il posto più semplice per accedere all'array degli elementi figli):
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 ) {
// ...
}
}

Ciao Jan, puoi aiutarmi con questa domanda? Ho provato il tuo codice ma non sono riuscito a farlo funzionare. Potresti fornirmi qualche altro esempio di codice?

Fai riferimento all'esempio di implementazione completo più avanti in questa pagina.

Aggiornamento: A partire da WordPress 3.7 (ottobre 2013), sono state aggiunte classi CSS per indicare gli elementi e le pagine figlie nei menu del tema — non è più necessario utilizzare un walker personalizzato poiché è gestito direttamente nel core di WordPress.
Le classi CSS sono denominate menu-item-has-children
e page_item_has_children
.
Per una soluzione completa per chi ha fretta (crediti alla risposta precedente di Jan Fabry), vedi l'implementazione completa qui sotto.
Mostra la navigazione nel template del tuo tema:
wp_nav_menu( array(
'theme_location' => 'navigation-primary',
'container' => false,
'container_class' => '',
'container_id' => '',
'menu_class' => '',
'menu_id' => '',
'walker' => new Selective_Walker(),
'depth' => 2
)
);
Poi, includi il seguente codice nel file functions.php
del tuo tema:
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);
}
}
L'output HTML risultante sarà simile al seguente:
<ul>
<li><a href="#">Home</a></li>
<li class="has_children"><a href="#">Chi Siamo</a>
<ul class="sub-menu">
<li><a href="#">La Nostra Missione</a></li>
</ul>
</li>
<li><a href="#">Servizi</a></li>
<li class="has_children"><a href="#">Prodotti</a>
<ul class="sub-menu">
<li><a href="#">Lorem Ipsum</a></li>
<li><a href="#">Lorem Ipsum</a></li>
</ul>
</li>
<li><a href="#">Contattaci</a></li>
</ul>
Per maggiori informazioni sull'utilizzo della classe walker di WordPress, consulta Understanding the Walker Class.
Buon lavoro!

Questa funzione è esattamente quello che stai cercando. Ti mostra anche un modo molto efficace per modificare gli elementi del menu di navigazione. Inoltre, puoi aprirla per funzioni più avanzate (ad es. child theme) tramite il filtro degli elementi:
/**
* Classi per una navigazione chiamata "Topnav" nella posizione del menu "top".
* Mostra esempi su come modificare l'elemento corrente del menu di navigazione
*
* @param (object) $items
* @param (object) $menu
* @param (object) $args
*/
function wpse16818_nav_menu_items( $items, $menu, $args )
{
# >>>> inizia modifica
// esempi di possibili target
$target['name'] = 'Topnav';
// Gli elementi del menu target
$target['items'] = array( (int) 6 );
# <<<< fine modifica
// filtro per child theme: "config_nav_menu_topnav"
$target = apply_filters( 'config_nav_menu_'.strtolower( $target['name'] ), $target );
// Interrompi se non siamo nel menu specificato
if ( $menu->name !== $target['name'] )
return;
foreach ( $items as $item )
{
// Controlla cosa contiene $item
echo '<pre>'; print_r($item); echo '</pre>';
// Primo esempio reale:
$item->classes = 'span-4';
// Secondo esempio reale:
// Aggiungi questa classe se siamo in uno degli elementi target
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 );
E sì, in quasi tutti i casi non c'è bisogno di un custom walker.

se vuoi creare un menu a tendina, puoi farlo utilizzando solo CSS. crea un menu personalizzato in WordPress con elementi figli, WordPress assegna automaticamente la classe .sub-menu agli ul figli. Prova questo CSS
nav li {position:relative;}
.sub-menu {display:none; position:absolute; width:300px;}
nav ul li:hover ul {display:block;}
Potresti voler aggiungere un po' di jQuery per renderlo più interessante, ma questo dovrebbe darti un menu a tendina funzionante.
