Aggiungere la classe 'has_children' all'elemento li genitore quando si modifica Walker_Nav_Menu

10 mag 2011, 10:46:04
Visualizzazioni: 38.8K
Voti: 24

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.

0
Tutte le risposte alla domanda 4
3
27

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 ) {
            // ...
        }
    }
10 mag 2011 11:45:58
Commenti

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?

PrivateUser PrivateUser
4 feb 2012 00:18:13

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

rjb rjb
6 mar 2013 22:41:15

Grazie mille @Jan fabry.. Ero bloccato con il mio custom walker.. Alla fine il tuo snippet mi ha aiutato.

Harish Kanakarajan Harish Kanakarajan
5 mag 2014 13:12:39
2

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!

6 mar 2013 21:30:09
Commenti

Errore fatale: Il passaggio per riferimento al momento della chiamata è stato rimosso in D:\www\wordpress\wp-content\themes\wpt_theme\functions.php alla riga 44

Tahir Yasin Tahir Yasin
14 lug 2014 22:43:55

La riga#44 è parent::start_el(&$output, $item, $depth, $args);

Tahir Yasin Tahir Yasin
14 lug 2014 22:44:23
1

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.

10 mag 2011 22:36:49
Commenti

Grazie, per ora mi serve il walker ma darò un'occhiata a questo per la prossima volta!

patnz patnz
11 mag 2011 02:50:17
1

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.

10 mag 2011 11:07:48
Commenti

Grazie, è per un menu ad albero a più livelli espandibile in cui sto inserendo anche elementi di controllo, ma è sicuramente meglio fare il più possibile con il CSS!

patnz patnz
11 mag 2011 02:49:02