Mostrare una porzione/ramo dell'albero del menu utilizzando wp_nav_menu()
Ho un menu definito in WP Admin che si presenta così:
Vorrei poter visualizzare tutti i link secondari nella sidebar quando mi trovo in una pagina principale. Per esempio, se l'utente si trova nella pagina "Chi Siamo", vorrei che apparisse nella sidebar una lista dei 4 link evidenziati in verde.
Ho esaminato la documentazione di wp_nav_menu() e non sembra avere alcun modo predefinito per specificare un particolare nodo di un determinato menu da utilizzare come punto di partenza quando si generano i link.
Ho creato una soluzione per una situazione simile che si basava sulle relazioni create dalla pagina padre, ma sto cercando una soluzione che utilizzi specificamente il sistema dei menu. Qualsiasi aiuto sarebbe apprezzato.
Questo mi rimaneva ancora in mente, quindi ci sono tornato sopra e ho messo insieme questa soluzione, che non dipende così tanto dal contesto:
add_filter( 'wp_nav_menu_objects', 'submenu_limit', 10, 2 );
function submenu_limit( $items, $args ) {
if ( empty( $args->submenu ) ) {
return $items;
}
$ids = wp_filter_object_list( $items, array( 'title' => $args->submenu ), 'and', 'ID' );
$parent_id = array_pop( $ids );
$children = submenu_get_children_ids( $parent_id, $items );
foreach ( $items as $key => $item ) {
if ( ! in_array( $item->ID, $children ) ) {
unset( $items[$key] );
}
}
return $items;
}
function submenu_get_children_ids( $id, $items ) {
$ids = wp_filter_object_list( $items, array( 'menu_item_parent' => $id ), 'and', 'ID' );
foreach ( $ids as $id ) {
$ids = array_merge( $ids, submenu_get_children_ids( $id, $items ) );
}
return $ids;
}
Utilizzo
$args = array(
'theme_location' => 'slug-del-menu', // quello usato in register_nav_menus
'submenu' => 'Chi Siamo', // potrebbe essere usato __() per le traduzioni
);
wp_nav_menu( $args );

Tecnica fantastica! Posso chiederti qualcosa che potrebbe riguardare questa: Come visualizzeresti il contenuto di quelle pagine del sottomenu elencate nel template?

@daniel.tosaba dovrai creare una sottoclasse o utilizzare i filtri nella classe Walker_Nav_Menu
. Come tutto ciò che riguarda i menu, è troppo per un commento - fai una nuova domanda a riguardo?

http://wordpress.stackexchange.com/questions/62758/display-content-of-child-links

Che risposta fantastica. Grazie mille. Dovrebbe davvero essere un'opzione predefinita in WordPress.

Hmm, in realtà ho un problema strano. Ho una pagina chiamata "Children's". E sembra che l'apostrofo nella parola impedisca di trovare la pagina. Qualche idea?

@dotty Non ricordo esattamente cosa sia memorizzato nel campo su cui il codice filtra. Potrebbe essere una versione sanificata o con escape degli slash del titolo.

@dotty potrebbe essere memorizzato come Children\'s
o qualcosa del genere, al momento non ho questo codice configurato per testare...

Sembra che questo non funzioni più in WP 4. Ricevo questo errore: Strict Standards: Solo le variabili dovrebbero essere passate per riferimento in -> alla riga -> $parent_id = array_pop( wp_filter_object_list( $items, array( 'title' => $args->submenu ), 'and', 'ID' ) );

@gdaniel testato - funziona e non ha nulla a che fare con l'aggiornamento di WP, serviva solo una piccola modifica per essere un codice PHP più corretto :)

Strano. Tutti i miei sottomenu che utilizzavano quella funzione sono scomparsi subito dopo l'aggiornamento a wp 4. Grazie comunque per aver dato un'occhiata. Controllerò per vedere cos'altro potrebbe essere successo.

Ho capito qual era il mio problema. Stavo usando l'argomento menu => "nome-menu" in wp_nav_menu... Ho rimosso 'menu' e aggiunto theme_location, e tutto è tornato alla normalità.

Ehi @Rarst, stai ancora emergendo in molti punti di questa risposta. La versione accettata dovrebbe essere riscritta per tenere conto dei navigatori personalizzati, dato che si potrebbe semplicemente filtrare per "current-menu-item", "current-menu-parent" e "current-menu-ancestor" per poi visualizzare il sottomenu. Niente filtri, niente hack.

@ImperativeIdeas La mia risposta mostra un ramo arbitrario per nome, non solo quello corrente.

@goldenapples: La tua Walker Class non funziona. Ma l'idea è davvero buona. Ho creato un walker basato sulla tua idea:
class Selective_Walker extends Walker_Nav_Menu
{
function walk( $elements, $max_depth) {
$args = array_slice(func_get_args(), 2);
$output = '';
if ($max_depth < -1) //parametro non valido
return $output;
if (empty($elements)) //niente da esaminare
return $output;
$id_field = $this->db_fields['id'];
$parent_field = $this->db_fields['parent'];
// visualizzazione piatta
if ( -1 == $max_depth ) {
$empty_array = array();
foreach ( $elements as $e )
$this->display_element( $e, $empty_array, 1, 0, $args, $output );
return $output;
}
/*
* necessità di visualizzare in ordine gerarchico
* separa gli elementi in due gruppi: elementi di primo livello e figli
* children_elements è un array bidimensionale, es.
* children_elements[10][] contiene tutti i sotto-elementi il cui genitore è 10.
*/
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( 0 == $e->$parent_field )
$top_level_elements[] = $e;
else
$children_elements[ $e->$parent_field ][] = $e;
}
/*
* quando nessuno degli elementi è di primo livello
* assume che il primo debba essere la radice dei sotto-elementi
*/
if ( empty($top_level_elements) ) {
$first = array_slice( $elements, 0, 1 );
$root = $first[0];
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( $root->$parent_field == $e->$parent_field )
$top_level_elements[] = $e;
else
$children_elements[ $e->$parent_field ][] = $e;
}
}
$current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' ); //aggiunto da continent7
foreach ( $top_level_elements as $e ){ //modificato da continent7
// scende solo nell'albero corrente
$descend_test = array_intersect( $current_element_markers, $e->classes );
if ( !empty( $descend_test ) )
$this->display_element( $e, $children_elements, 2, 0, $args, $output );
}
/*
* se stiamo visualizzando tutti i livelli e children_elements non è vuoto,
* allora abbiamo orfani che dovrebbero essere visualizzati comunque
*/
/* rimosso da continent7
if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
$empty_array = array();
foreach ( $children_elements as $orphans )
foreach( $orphans as $op )
$this->display_element( $op, $empty_array, 1, 0, $args, $output );
}
*/
return $output;
}
}
Ora puoi usare:
<?php wp_nav_menu(
array(
'theme_location'=>'test',
'walker'=>new Selective_Walker() )
); ?>
L'output è una lista che contiene l'elemento radice corrente e i suoi figli (non i figli dei figli). Def: Elemento radice := L'elemento di menu di primo livello che corrisponde alla pagina corrente o è genitore di una pagina corrente o genitore di un genitore ...
Questo non risponde esattamente alla domanda originale ma ci si avvicina, poiché c'è ancora l'elemento di primo livello. Per me va bene, perché voglio l'elemento di primo livello come titolo della sidebar. Se vuoi eliminarlo, potresti dover sovrascrivere display_element o usare un HTML-Parser.

Ciao @jessegavin:
I menu di navigazione sono memorizzati in una combinazione di custom post type e tassonomie personalizzate. Ogni menu è archiviato come Termine (es. "Menu Chi Siamo", presente in wp_terms
) di una Tassonomia Personalizzata (es. nav_menu
, presente in wp_term_taxonomy
).
Ogni voce del menu di navigazione è memorizzata come un post con post_type=='nav_menu_item'
(es. "Lo Studio", presente in wp_posts
) con i suoi attributi archiviati come post meta (in wp_postmeta
) utilizzando un prefisso meta_key
di _menu_item_*
dove _menu_item_menu_item_parent
è l'ID del post della voce del menu genitore.
La relazione tra menu e voci di menu è memorizzata in wp_term_relationships
dove object_id
si riferisce all'$post->ID
della voce del menu di navigazione e $term_relationships->term_taxonomy_id
si riferisce al menu definito collettivamente in wp_term_taxonomy
e wp_terms
.
Sono abbastanza sicuro che sarebbe possibile agganciare sia 'wp_update_nav_menu'
che 'wp_update_nav_menu_item'
per creare menu effettivi in wp_terms
e un set parallelo di relazioni in wp_term_taxonomy
e wp_term_relationships
dove ogni voce del menu di navigazione che ha sotto-voci diventa a sua volta un menu autonomo.
Vorresti anche agganciare 'wp_get_nav_menus'
(che ho suggerito di aggiungere a WP 3.0 basandomi su un lavoro simile che stavo facendo qualche mese fa) per assicurarti che i menu generati non vengano visualizzati per la modifica da parte dell'utente nell'amministrazione, altrimenti andrebbero fuori sincronizzazione molto rapidamente e avresti un incubo di dati tra le mani.
Sembra un progetto divertente e utile, ma richiede un po' più di codice e testing di quanto io possa permettermi di affrontare ora, in parte perché tutto ciò che sincronizza dati tende a essere una rottura quando si tratta di eliminare tutti i bug (e perché i clienti che pagano mi pressano per finire il lavoro. :) Ma con le informazioni sopra sono sicuro che uno sviluppatore motivato di plugin WordPress potrebbe codificarlo se lo desiderasse.
Ovviamente ora se lo codifichi sei obbligato a condividerlo qui così possiamo tutti beneficiare della tua generosità! :-)

Non sono sicuro di aver capito quello che stai dicendo. Sto cercando una soluzione in sola lettura per visualizzare "sottomenu" relativi alla pagina corrente in cui si trova l'utente. Stiamo parlando della stessa cosa? - Apprezzo comunque la tua spiegazione più approfondita sullo schema del database.

@jessegavin - Sì, se vuoi usare wp_nav_menu()
dovrai clonare i menu perché wp_nav_menu()
è strettamente legato alla struttura del menu. L'altra opzione è copiare il codice di wp_nav_menu()
e apportare le modifiche necessarie per visualizzarlo come sottomenu.

Questa è un'estensione di Walker che dovrebbe fare ciò che stai cercando:
class Selective_Walker extends Walker_Nav_Menu
{
function walk( $elements, $max_depth) {
$args = array_slice(func_get_args(), 2);
$output = '';
if ($max_depth < -1) //parametro non valido
return $output;
if (empty($elements)) //niente da scorrere
return $output;
$id_field = $this->db_fields['id'];
$parent_field = $this->db_fields['parent'];
// visualizzazione piatta
if ( -1 == $max_depth ) {
$empty_array = array();
foreach ( $elements as $e )
$this->display_element( $e, $empty_array, 1, 0, $args, $output );
return $output;
}
/*
* bisogno di visualizzare in ordine gerarchico
* separa gli elementi in due gruppi: elementi di primo livello e figli
* children_elements è un array bidimensionale, es.
* children_elements[10][] contiene tutti i sotto-elementi il cui genitore è 10.
*/
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( 0 == $e->$parent_field )
$top_level_elements[] = $e;
else
$children_elements[ $e->$parent_field ][] = $e;
}
/*
* quando nessuno degli elementi è di primo livello
* assumi che il primo debba essere la radice dei sotto-elementi
*/
if ( empty($top_level_elements) ) {
$first = array_slice( $elements, 0, 1 );
$root = $first[0];
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( $root->$parent_field == $e->$parent_field )
$top_level_elements[] = $e;
else
$children_elements[ $e->$parent_field ][] = $e;
}
}
$current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' );
foreach ( $top_level_elements as $e ) {
// discendi solo sull'albero corrente
$descend_test = array_intersect( $current_element_markers, $e->classes );
if ( empty( $descend_test ) ) unset ( $children_elements );
$this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
}
/*
* se stiamo visualizzando tutti i livelli e children_elements non è vuoto,
* allora abbiamo orfani che dovrebbero essere visualizzati comunque
*/
if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
$empty_array = array();
foreach ( $children_elements as $orphans )
foreach( $orphans as $op )
$this->display_element( $op, $empty_array, 1, 0, $args, $output );
}
return $output;
}
}
Basato liberamente sul codice di mfields che ho referenziato nel mio commento precedente. Tutto ciò che fa è verificare durante la navigazione del menu se l'elemento corrente è (1) l'elemento corrente del menu, oppure (2) un antenato dell'elemento corrente del menu, e espande il sottoalbero sotto di esso solo se una di queste condizioni è vera. Spero che funzioni per te.
Per usarlo, basta aggiungere un argomento "walker" quando chiami il menu, es:
<?php wp_nav_menu(
array(
'theme_location'=>'test',
'walker'=>new Selective_Walker() )
); ?>

Oh... Ho riletto la tua domanda e mi sono reso conto di averla fraintesa inizialmente. Questo walker mostrerà tutti gli altri elementi di menu di primo livello, semplicemente senza espanderli. Non era esattamente quello che volevi fare. Tuttavia, questo codice può essere modificato in qualsiasi modo tu voglia. Basta guardare il ciclo attraverso $top_level_elements
e aggiungere il tuo test prima della chiamata a $this->display_element
.

È possibile fare in modo che questa classe mostri la profondità della sottopagina corrente? Cioè... Se ho una profondità di tre o più livelli, che il terzo e i livelli successivi vengano mostrati per la (sotto)pagina corrente? Al momento, mostra solo A > B, e non > C (dove C è il terzo livello)

@Zolomon - Non sono sicuro di capire la tua domanda. Questo dovrebbe espandere l'intera struttura sotto qualsiasi elemento del menu con le classi 'current-menu-item', 'current-menu-parent' o 'current-menu-ancestor'. Quando lo testo, mostra tutti i livelli di sottopagine nel menu. Cosa stai cercando di fare?

Aggiornamento: Ho trasformato questo in un plugin. Scarica qui.
Ho avuto bisogno di risolvere questo problema personalmente e alla fine ho scritto un filtro sui risultati della ricerca del menu. Ti permette di usare wp_nav_menu
normalmente, ma selezionare una sotto-sezione del menu basandoti sul titolo dell'elemento genitore. Aggiungi un parametro submenu
al menu in questo modo:
wp_nav_menu(array(
'menu' => 'header',
'submenu' => 'Chi Siamo',
));
Puoi anche andare diversi livelli in profondità inserendo slash:
wp_nav_menu(array(
'menu' => 'header',
'submenu' => 'Chi Siamo/Consiglio di Amministrazione'
));
Oppure, se preferisci, con un array:
wp_nav_menu(array(
'menu' => 'header',
'submenu' => array('Chi Siamo', 'Consiglio di Amministrazione')
));
Utilizza una versione slug del titolo, il che dovrebbe renderlo più tollerante a cose come maiuscole e punteggiatura.

È possibile raggiungere un sottomenu tramite id? Intendo l'id della pagina o del post.

split() è deprecato, sostituisci $loc = split( "/", $loc );
nel plugin con $loc = preg_split( "~/~", $loc );

Ho creato la seguente classe per uso personale. Troverà il genitore principale del menu di navigazione per la pagina corrente, oppure puoi specificare un ID di un elemento principale nel costruttore del walker.
class Walker_SubNav_Menu extends Walker_Nav_Menu {
var $target_id = false;
function __construct($target_id = false) {
$this->target_id = $target_id;
}
function walk($items, $depth) {
$args = array_slice(func_get_args(), 2);
$args = $args[0];
$parent_field = $this->db_fields['parent'];
$target_id = $this->target_id;
$filtered_items = array();
// se il genitore non è impostato, lo imposta in base al post
if (!$target_id) {
global $post;
foreach ($items as $item) {
if ($item->object_id == $post->ID) {
$target_id = $item->ID;
}
}
}
// se non c'è un genitore, mostra un menu regolare
if (!$target_id) return parent::walk($items, $depth, $args);
// ottieni l'elemento principale
$target_id = $this->top_level_id($items, $target_id);
// includi solo gli elementi sotto il genitore
foreach ($items as $item) {
if (!$item->$parent_field) continue;
$item_id = $this->top_level_id($items, $item->ID);
if ($item_id == $target_id) {
$filtered_items[] = $item;
}
}
return parent::walk($filtered_items, $depth, $args);
}
// ottieni l'ID del livello superiore per un ID di elemento
function top_level_id($items, $item_id) {
$parent_field = $this->db_fields['parent'];
$parents = array();
foreach ($items as $item) {
if ($item->$parent_field) {
$parents[$item->ID] = $item->$parent_field;
}
}
// trova l'elemento di livello superiore
while (array_key_exists($item_id, $parents)) {
$item_id = $parents[$item_id];
}
return $item_id;
}
}
Chiamata del menu:
wp_nav_menu(array(
'theme_location' => 'main_menu',
'walker' => new Walker_SubNav_Menu(22), // con ID
));

@davidn @hakre Ciao, ho una soluzione poco elegante senza un HTML-Parser o sovrascrivere display_element.
class Selective_Walker extends Walker_Nav_Menu
{
function walk( $elements, $max_depth) {
$args = array_slice(func_get_args(), 2);
$output = '';
if ($max_depth < -1) //parametro non valido
return $output;
if (empty($elements)) //niente da elaborare
return $output;
$id_field = $this->db_fields['id'];
$parent_field = $this->db_fields['parent'];
// visualizzazione piatta
if ( -1 == $max_depth ) {
$empty_array = array();
foreach ( $elements as $e )
$this->display_element( $e, $empty_array, 1, 0, $args, $output );
return $output;
}
/*
* necessità di visualizzare in ordine gerarchico
* separa gli elementi in due gruppi: elementi di primo livello e figli
* children_elements è un array bidimensionale, es.
* children_elements[10][] contiene tutti i sotto-elementi il cui genitore è 10.
*/
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( 0 == $e->$parent_field )
$top_level_elements[] = $e;
else
$children_elements[ $e->$parent_field ][] = $e;
}
/*
* quando nessuno degli elementi è di primo livello
* assume che il primo debba essere la radice dei sotto-elementi
*/
if ( empty($top_level_elements) ) {
$first = array_slice( $elements, 0, 1 );
$root = $first[0];
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( $root->$parent_field == $e->$parent_field )
$top_level_elements[] = $e;
else
$children_elements[ $e->$parent_field ][] = $e;
}
}
$current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' ); //aggiunto da continent7
foreach ( $top_level_elements as $e ){ //modificato da continent7
// scendi solo sull'albero corrente
$descend_test = array_intersect( $current_element_markers, $e->classes );
if ( !empty( $descend_test ) )
$this->display_element( $e, $children_elements, 2, 0, $args, $output );
}
/*
* se stiamo visualizzando tutti i livelli e children_elements rimanente non è vuoto,
* allora abbiamo orfani che dovrebbero essere visualizzati comunque
*/
/* rimosso da continent7
if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
$empty_array = array();
foreach ( $children_elements as $orphans )
foreach( $orphans as $op )
$this->display_element( $op, $empty_array, 1, 0, $args, $output );
}
*/
/*aggiunto da alpguneysel */
$pos = strpos($output, '<a');
$pos2 = strpos($output, 'a>');
$topper= substr($output, 0, $pos).substr($output, $pos2+2);
$pos3 = strpos($topper, '>');
$lasst=substr($topper, $pos3+1);
$submenu= substr($lasst, 0, -6);
return $submenu;
}
}

Dopo aver provato tutte le soluzioni, quella di Alp è stata l'unica che ha funzionato per me. Tuttavia c'è un problema. Mostra solo i figli di primo livello, ma non mostra i figli di terzo o quarto livello. Ho provato per giorni a farlo funzionare in questo modo. Qualcuno sa come modificare la sua soluzione per ottenere questo? PS. Non mi permette di aggiungere commenti quindi devo farlo come risposta.

L'output del menu di navigazione include molte classi per l'elemento corrente, l'antenato dell'elemento corrente, ecc. In alcune situazioni, sono riuscito a fare ciò che vuoi fare lasciando che venga generato l'intero albero di navigazione e poi usando il CSS per ridurlo solo ai figli della pagina corrente, ecc.

Ho creato un walker modificato che dovrebbe aiutare! Non è perfetto - lascia alcuni elementi vuoti, ma fa il suo lavoro. La modifica consiste fondamentalmente in quei pezzi con $current_branch. Spero possa essere utile a qualcuno!
class Kanec_Walker_Nav_Menu extends Walker {
/**
* @see Walker::$tree_type
* @since 3.0.0
* @var string
*/
var $tree_type = array( 'post_type', 'taxonomy', 'custom' );
/**
* @see Walker::$db_fields
* @since 3.0.0
* @todo Decouple this.
* @var array
*/
var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );
/**
* @see Walker::start_lvl()
* @since 3.0.0
*
* @param string $output Passato per riferimento. Usato per aggiungere contenuto aggiuntivo.
* @param int $depth Profondità della pagina. Usato per il padding.
*/
function start_lvl(&$output, $depth) {
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul class=\"sub-menu\">\n";
}
/**
* @see Walker::end_lvl()
* @since 3.0.0
*
* @param string $output Passato per riferimento. Usato per aggiungere contenuto aggiuntivo.
* @param int $depth Profondità della pagina. Usato per il padding.
*/
function end_lvl(&$output, $depth) {
global $current_branch;
if ($depth == 0) $current_branch = false;
$indent = str_repeat("\t", $depth);
$output .= "$indent</ul>\n";
}
/**
* @see Walker::start_el()
* @since 3.0.0
*
* @param string $output Passato per riferimento. Usato per aggiungere contenuto aggiuntivo.
* @param object $item Oggetto dati del menu item.
* @param int $depth Profondità del menu item. Usato per il padding.
* @param int $current_page ID del menu item.
* @param object $args
*/
function start_el(&$output, $item, $depth, $args) {
global $wp_query;
global $current_branch;
// Questo menu item è nel ramo corrente?
if(in_array('current-menu-ancestor',$item->classes) ||
in_array('current-menu-parent',$item->classes) ||
in_array('current-menu-item',$item->classes)) {
$current_branch = true;
}
if($current_branch && $depth > 0) {
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
$class_names = ' class="' . esc_attr( $class_names ) . '"';
$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
$id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';
$output .= $indent . '<li' . $id . $value . $class_names .'>';
$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
/**
* @see Walker::end_el()
* @since 3.0.0
*
* @param string $output Passato per riferimento. Usato per aggiungere contenuto aggiuntivo.
* @param object $item Oggetto dati della pagina. Non usato.
* @param int $depth Profondità della pagina. Non usato.
*/
function end_el(&$output, $item, $depth) {
global $current_branch;
if($current_branch && $depth > 0) $output .= "</li>\n";
if($depth == 0) $current_branch = 0;
}
}

Dai un'occhiata al codice nel mio plugin o usalo per il tuo scopo ;)
Questo plugin aggiunge un widget avanzato per il "Menu di Navigazione". Offre molte opzioni che possono essere impostate per personalizzare l'output del menu personalizzato tramite il widget.
Le caratteristiche includono:
- Gerarchia personalizzata - "Solo sotto-elementi correlati" o "Solo sotto-elementi strettamente correlati".
- Profondità iniziale e livello massimo da visualizzare + visualizzazione piatta.
- Visualizza tutti gli elementi del menu a partire da quello selezionato.
- Visualizza solo il percorso diretto all'elemento corrente o solo i figli dell'elemento selezionato (con l'opzione per includere l'elemento genitore).
- Classe personalizzata per il blocco del widget.
- E quasi tutti i parametri per la funzione wp_nav_menu.

La risposta accettata riconosce che richiede un input e non si basa sul contesto. Ecco una versione che supporta l'essere fornita di un contesto, oppure può utilizzare le classi integrate di WordPress current-x
per determinare il contesto:
add_filter( 'wp_nav_menu_objects', 'limit_tree', 10, 2 );
function limit_tree( $items, $args ) {
if ( empty( $args->context ) ) {
return $items;
}
if('current' == $args->context) {
$current_pages = array_filter($items, function($item) {
return !empty(array_intersect(['current-menu-parent', 'current-menu-ancestor', 'current-menu-item'], $item->classes));
});
$parent_id = array_pop($current_pages)->ID;
} else {
$ids = wp_filter_object_list( $items, array( 'object_id' => $args->context ), 'and', 'ID' );
$parent_id = array_pop( $ids );
}
$children = submenu_get_children_ids( $parent_id, $items );
foreach ( $items as $key => $item ) {
// Questo può essere modificato se non si desidera includere il genitore
if ( $item->ID != $parent_id && ! in_array( $item->ID, $children ) ) {
unset( $items[$key] );
}
}
return $items;
}
function submenu_get_children_ids( $id, $items ) {
$ids = wp_filter_object_list( $items, array( 'menu_item_parent' => $id ), 'and', 'ID' );
foreach ( $ids as $id ) {
$ids = array_merge( $ids, submenu_get_children_ids( $id, $items ) );
}
return $ids;
}
E l'utilizzo:
wp_nav_menu([
'theme_location' => 'foo-bar',
'context' => 'current',
]);
Oppure...
wp_nav_menu([
'theme_location' => 'foo-bar',
'context' => get_queried_object_id(), // o un ID post arbitrario
]);
