Afișarea unei porțiuni/ramuri din arborele meniului folosind wp_nav_menu()
Am un meniu definit în WP Admin care arată astfel:
Doresc să pot afișa toate link-urile copil în sidebar ori de câte ori mă aflu pe o pagină părinte. De exemplu, dacă utilizatorul se află pe pagina "Despre noi", vreau să apară în sidebar o listă cu cele 4 link-uri evidențiate cu verde.
Am consultat documentația pentru wp_nav_menu() și se pare că nu există nicio modalitate incorporată de a specifica un anumit nod dintr-un meniu dat pentru a-l folosi ca punct de plecare în generarea link-urilor.
Am creat o soluție pentru o situație similară care se baza pe relațiile create de pagina părinte, dar caut una care să utilizeze specific sistemul de meniuri. Orice ajutor ar fi apreciat.
Încă mă gândeam la asta, așa că am revizuit-o și am creat această soluție, care nu se bazează atât de mult pe context:
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;
}
Utilizare
$args = array(
'theme_location' => 'slug-of-the-menu', // cel folosit în register_nav_menus
'submenu' => 'Despre Noi', // poate fi folosit __() pentru traduceri
);
wp_nav_menu( $args );

Tehnică minunată! Pot să întreb ceva care ar putea fi legat de asta: Cum ai afișa conținutul acelor pagini de submeniu enumerate în șablon?

@daniel.tosaba va trebui să subclasezi sau să folosești filtre în clasa Walker_Nav_Menu
. Ca și toate lucrurile legate de meniu, este prea mult pentru un comentariu - pune o nouă întrebare despre asta?

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

Un răspuns fantastic. Mulțumesc mult. Aceasta ar trebui să fie cu adevărat o opțiune implicită în WordPress.

Hmm, de fapt am o problemă ciudată. Am o pagină numită "Children's". Și se pare că apostroful din cuvânt nu reușește să găsească pagina. Aveți idei?

@dotty Nu-mi amintesc exact ce este stocat în câmpul după care filtrează codul. Ar putea fi o versiune sanitizată sau escape-uită cu backslash a titlului.

@dotty s-ar putea să fie stocat ca Children\'s
sau ceva similar, momentan nu am acest cod configurat pentru testare...

Se pare că acest lucru nu mai funcționează în WP 4. Primesc această eroare: Strict Standards: Doar variabilele ar trebui transmise prin referință în -> pe linia -> $parent_id = array_pop( wp_filter_object_list( $items, array( 'title' => $args->submenu ), 'and', 'ID' ) );

@gdaniel a testat – funcționează și nu are nicio legătură cu actualizarea WP, era nevoie doar de o mică ajustare pentru a fi un cod PHP mai corect :)

Ciudat. Toate submeniurile mele care foloseau acea funcție au dispărut imediat după ce am actualizat la wp 4. Mulțumesc oricum pentru verificare. Voi investiga să văd ce altceva ar fi putut fi cauza.

Am rezolvat problema. Foloseam argumentul menu => "nume-meniu" în wp_nav_menu... Am eliminat 'menu' și am adăugat theme_location, iar totul a revenit la normal.

Hei @Rarst, încă apareți în frunte în multe locuri în acest răspuns. Versiunea acceptată ar trebui rescrisă pentru a ține cont de navigatoarele personalizate, deoarece cineva ar putea filtra pentru "current-menu-item", "current-menu-parent" și "current-menu-ancestor", apoi să afișeze submeniul. Fără filtre, fără hack-uri.

@ImperativeIdeas Răspunsul meu afișează o ramură arbitrară după nume, nu doar cea curentă.

@goldenapples: Clasa ta Walker nu funcționează. Dar ideea este foarte bună. Am creat un walker bazat pe ideea ta:
class Selective_Walker extends Walker_Nav_Menu
{
function walk( $elements, $max_depth) {
$args = array_slice(func_get_args(), 2);
$output = '';
if ($max_depth < -1) //parametru invalid
return $output;
if (empty($elements)) //nimic de parcurs
return $output;
$id_field = $this->db_fields['id'];
$parent_field = $this->db_fields['parent'];
// afișare plată
if ( -1 == $max_depth ) {
$empty_array = array();
foreach ( $elements as $e )
$this->display_element( $e, $empty_array, 1, 0, $args, $output );
return $output;
}
/*
* necesar pentru afișarea ierarhică
* separă elementele în două categorii: de nivel superior și elemente copil
* children_elements este un array bidimensional, ex.
* children_elements[10][] conține toate sub-elementele al căror părinte este 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;
}
/*
* când niciun element nu este de nivel superior
* presupunem că primul trebuie să fie rădăcina sub-elementelor
*/
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' ); //adăugat de continent7
foreach ( $top_level_elements as $e ){ //modificat de continent7
// coboară doar în arborele curent
$descend_test = array_intersect( $current_element_markers, $e->classes );
if ( !empty( $descend_test ) )
$this->display_element( $e, $children_elements, 2, 0, $args, $output );
}
/*
* dacă afișăm toate nivelurile și children_elements rămași nu este gol,
* atunci avem orfani, care ar trebui afișați oricum
*/
/* eliminat de 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;
}
}
Acum poți folosi:
<?php wp_nav_menu(
array(
'theme_location'=>'test',
'walker'=>new Selective_Walker() )
); ?>
Ieșirea este o listă care conține elementul rădăcină curent și copiii acestuia (dar nu și copiii copiilor). Def: Element rădăcină := Elementul de nivel superior din meniu care corespunde paginii curente sau este părinte al unei pagini curente sau părinte al unui părinte...
Acest lucru nu răspunde exact la întrebarea originală, dar aproape, deoarece încă există elementul de nivel superior. Pentru mine este în regulă, pentru că vreau elementul de nivel superior ca titlu în bara laterală. Dacă doriți să scăpați de acesta, ar putea fi necesar să suprascrieți display_element sau să folosiți un HTML-Parser.

Salut @jessegavin:
Meniurile de navigare sunt stocate într-o combinație de tipuri de postare personalizate și taxonomii personalizate. Fiecare meniu este stocat ca un Termen (adică "Meniu Despre", găsit în wp_terms
) al unei Taxonomii Personalizate (adică nav_menu
, găsit în wp_term_taxonomy
).
Fiecare element de meniu de navigare este stocat ca o postare de tip post_type=='nav_menu_item'
(adică "Despre Firmă", găsit în wp_posts
) cu atributele sale stocate ca meta post (în wp_postmeta
) folosind un prefix meta_key
de _menu_item_*
unde _menu_item_menu_item_parent
este ID-ul postului părinte al elementului de meniu.
Relația dintre meniuri și elementele de meniu este stocată în wp_term_relationships
unde object_id
se referă la $post->ID
pentru elementul de meniu de navigare, iar $term_relationships->term_taxonomy_id
se referă la meniul definit colectiv în wp_term_taxonomy
și wp_terms
.
Sunt destul de sigur că ar fi posibil să atasezi atât 'wp_update_nav_menu'
cât și 'wp_update_nav_menu_item'
pentru a crea meniuri reale în wp_terms
și un set paralel de relații în wp_term_taxonomy
și wp_term_relationships
unde fiecare element de meniu de navigare care are sub-elemente devine la rândul său propriul meniu.
Ai vrea, de asemenea, să atasezi 'wp_get_nav_menus'
(pe care l-am sugerat să fie adăugat în WP 3.0 bazat pe o lucrare similară pe care o făceam acum câteva luni) pentru a te asigura că meniurile generate nu sunt afișate pentru manipulare de către utilizator în admin, altfel s-ar desincroniza foarte repede și ai avea un coșmar de date pe cap.
Sună ca un proiect distractiv și util, dar este un pic mai mult cod și testare decât îmi permit să abordez acum, în parte pentru că orice lucru care sincronizează date tinde să fie o bătaie de cap când vine vorba de eliminarea tuturor bug-urilor (și pentru că clienții care plătesc mă presează să termin lucrurile. :) Dar, înarmați cu informațiile de mai sus, sunt destul de sigur că un dezvoltator motivat de plugin-uri WordPress ar putea să-l codeze dacă ar dori.
Desigur, realizezi acum că dacă îl codezi, ești obligat să-l postezi aici ca să putem beneficia cu toții de bunătatea ta! :-)

Nu sunt sigur că înțeleg exact ce spui. Caut o soluție doar pentru afișare (read-only) a "sub-meniurilor" legate de pagina curentă pe care se află un utilizator. Vorbim despre același lucru? - Apreciez totuși explicația detaliată despre schema bazei de date.

@jessegavin - Da, dacă vrei să folosești wp_nav_menu()
atunci va trebui să clonezi meniurile deoarece wp_nav_menu()
este strâns legat de structura meniului. Cealaltă opțiune este să copiezi codul wp_nav_menu()
și să faci modificările necesare pentru afișarea ca submeniu.

Aceasta este o extensie Walker care ar trebui să facă ceea ce cauți:
class Selective_Walker extends Walker_Nav_Menu
{
function walk( $elements, $max_depth) {
$args = array_slice(func_get_args(), 2);
$output = '';
if ($max_depth < -1) //parametru invalid
return $output;
if (empty($elements)) //nimic de parcurs
return $output;
$id_field = $this->db_fields['id'];
$parent_field = $this->db_fields['parent'];
// afișare plată
if ( -1 == $max_depth ) {
$empty_array = array();
foreach ( $elements as $e )
$this->display_element( $e, $empty_array, 1, 0, $args, $output );
return $output;
}
/*
* este necesară afișarea în ordine ierarhică
* separă elementele în două categorii: elemente de nivel superior și elemente copil
* children_elements este un array bidimensional, ex.
* children_elements[10][] conține toate sub-elementele al căror părinte este 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;
}
/*
* când niciunul dintre elemente nu este de nivel superior
* presupunem că primul trebuie să fie rădăcina sub-elementelor
*/
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 ) {
// coboară doar în arborele curent
$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 );
}
/*
* dacă afișăm toate nivelurile, iar children_elements rămas nu este gol,
* atunci avem orfani, care ar trebui afișați indiferent
*/
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;
}
}
Bazat vag pe codul lui mfields pe care l-am menționat mai devreme în comentariu. Tot ce face este să verifice, în timp ce parcurge meniul, dacă elementul curent este (1) elementul curent din meniu sau (2) un strămoș al elementului curent din meniu și extinde subarborele de dedesubt doar dacă una dintre aceste condiții este adevărată. Sper că funcționează pentru tine.
Pentru a-l utiliza, adaugă doar un argument "walker" când apelezi meniul, adică:
<?php wp_nav_menu(
array(
'theme_location'=>'test',
'walker'=>new Selective_Walker() )
); ?>

Oh... Tocmai am recitit întrebarea ta și am realizat că am înțeles-o greșit la început. Acest walker va afișa toate celelalte elemente de meniu de nivel superior, dar nu le va extinde. Nu era exact ceea ce doreai să faci. Totuși, acest cod poate fi modificat în orice mod dorești. Uită-te doar la bucla prin $top_level_elements
și adaugă-ți propriul test înainte de apelul la $this->display_element
.

Este posibil să obținem această clasă să afișeze adâncimea subpagina curentă? Adică... Dacă am o adâncime de trei sau mai multe niveluri, ca nivelurile a treia și următoare să fie afișate pentru (sub)pagina curentă? În acest moment, afișează doar A > B, și nu > C (C fiind al treilea nivel)

@Zolomon - Nu sunt sigur că înțeleg întrebarea ta. Acest walker ar trebui să extindă întreaga structură sub orice element de meniu care are clasele 'current-menu-item', 'current-menu-parent' sau 'current-menu-ancestor'. Când am testat, afișează toate nivelurile de subpagini din meniu. Ce anume încerci să obții?

Actualizare: Am transformat acest lucru într-un plugin. Descarcă aici.
A trebuit să rezolv această problemă singur și am ajuns să scriu un filtru pe rezultatele căutării din meniu. Acesta îți permite să folosești wp_nav_menu
în mod normal, dar să alegi o sub-secțiune a meniului bazată pe titlul elementului părinte. Adaugă un parametru submenu
în meniu astfel:
wp_nav_menu(array(
'menu' => 'header',
'submenu' => 'Despre Noi',
));
Poți merge chiar și mai multe niveluri adânc punând slash-uri:
wp_nav_menu(array(
'menu' => 'header',
'submenu' => 'Despre Noi/Consiliul de Administrație'
));
Sau dacă preferi cu un array:
wp_nav_menu(array(
'menu' => 'header',
'submenu' => array('Despre Noi', 'Consiliul de Administrație')
));
Folosește o versiune slug a titlului, care ar trebui să fie tolerantă la lucruri precum majuscule și punctuație.

Este posibil să accesezi un submeniu prin id? Adică prin id-ul paginii sau postării.

split() este învechit, înlocuiește $loc = split( "/", $loc );
în plugin cu $loc = preg_split( "~/~", $loc );

Am creat următoarea clasă pentru mine. Aceasta va găsi părintele principal din navigația curentă pentru pagina actuală, sau poți specifica un ID țintă pentru navigația principală în constructorul walker-ului.
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();
// dacă părintele nu este setat, îl setăm pe baza postului
if (!$target_id) {
global $post;
foreach ($items as $item) {
if ($item->object_id == $post->ID) {
$target_id = $item->ID;
}
}
}
// dacă nu există un părinte, afișăm un meniu obișnuit
if (!$target_id) return parent::walk($items, $depth, $args);
// obține elementul principal din navigație
$target_id = $this->top_level_id($items, $target_id);
// include doar elementele de sub părinte
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);
}
// obține ID-ul nivelului superior pentru un ID de element
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;
}
}
// găsește elementul de nivel superior
while (array_key_exists($item_id, $parents)) {
$item_id = $parents[$item_id];
}
return $item_id;
}
}
Apelul navigației:
wp_nav_menu(array(
'theme_location' => 'main_menu',
'walker' => new Walker_SubNav_Menu(22), // cu ID
));

@davidn @hakre Bună, am o soluție neelegantă fără un HTML-Parser sau suprascrierea 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) //parametru invalid
return $output;
if (empty($elements)) //nimic de parcurs
return $output;
$id_field = $this->db_fields['id'];
$parent_field = $this->db_fields['parent'];
// afișare plată
if ( -1 == $max_depth ) {
$empty_array = array();
foreach ( $elements as $e )
$this->display_element( $e, $empty_array, 1, 0, $args, $output );
return $output;
}
/*
* necesar pentru afișare ierarhică
* separă elementele în două categorii: de nivel superior și elemente copil
* children_elements este un array bidimensional, ex.
* children_elements[10][] conține toate sub-elementele al căror părinte este 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;
}
/*
* când niciun element nu este de nivel superior
* presupune că primul trebuie să fie rădăcina sub-elementelor
*/
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' ); //adaugat de continent7
foreach ( $top_level_elements as $e ){ //modificat de continent7
// coboară doar în arborele curent
$descend_test = array_intersect( $current_element_markers, $e->classes );
if ( !empty( $descend_test ) )
$this->display_element( $e, $children_elements, 2, 0, $args, $output );
}
/*
* dacă afișăm toate nivelurile, iar children_elements rămase nu sunt goale,
* atunci avem orfani, care ar trebui afișați oricum
*/
/* eliminat de 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 );
}
*/
/*adaugat de 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;
}
}

După ce le-am încercat pe toate, soluția lui Alp a fost singura care a funcționat pentru mine. Totuși, există o problemă cu ea. Aceasta afișează doar copiii de prim nivel, dar nu arată copiii de al treilea sau al patrulea nivel. Am încercat de zile întregi să fac asta. Știe cineva cum să modifice soluția lui în acest sens? PS. Nu mă lasă să adaug comentarii, așa că trebuie să o fac ca răspuns.

Ieșirea meniului de navigare include multe clase pentru elementul curent, strămoșul elementului curent etc. În unele situații, am reușit să fac ceea ce doriți să faceți prin afișarea întregului arbore de navigare și apoi folosind CSS pentru a-l reduce doar la copiii paginii curente etc.

Am creat un walker modificat care ar trebui să ajute! Nu este perfect - lasă câteva elemente goale, dar își face treaba. Modificarea constă practic în acele bucăți cu $current_branch. Sper să ajute pe cineva!
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 Passed by reference. Used to append additional content.
* @param int $depth Depth of page. Used for 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 Passed by reference. Used to append additional content.
* @param int $depth Depth of page. Used for 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 Passed by reference. Used to append additional content.
* @param object $item Menu item data object.
* @param int $depth Depth of menu item. Used for padding.
* @param int $current_page Menu item ID.
* @param object $args
*/
function start_el(&$output, $item, $depth, $args) {
global $wp_query;
global $current_branch;
// Este acest element de meniu în ramura curentă?
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 Passed by reference. Used to append additional content.
* @param object $item Page data object. Not used.
* @param int $depth Depth of page. Not Used.
*/
function end_el(&$output, $item, $depth) {
global $current_branch;
if($current_branch && $depth > 0) $output .= "</li>\n";
if($depth == 0) $current_branch = 0;
}
}

Verifică codul din pluginul meu sau folosește-l în scopul tău ;)
Acest plugin adaugă un widget "Meniu de Navigare" îmbunătățit. Oferă multe opțiuni care pot fi setate pentru a personaliza afișarea meniului personalizat prin widget.
Caracteristici includ:
- Ierarhie personalizată - "Doar sub-elemente conexe" sau "Doar sub-elemente strict conexe".
- Adâncime de început și nivel maxim de afișare + afișare plană.
- Afișează toate elementele meniului începând cu cel selectat.
- Afișează doar calea directă către elementul curent sau doar copiii elementului selectat (opțiune de a include elementul părinte).
- Clasă personalizată pentru blocul widget.
- Și aproape toți parametrii pentru funcția wp_nav_menu.

Răspunsul acceptat recunoaște că necesită date de intrare și nu se bazează pe context. Iată o versiune care acceptă transmiterea unui context sau poate utiliza clasele încorporate în WordPress current-x
pentru a determina contextul:
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 ) {
// Această condiție poate fi ajustată dacă nu doriți să includeți părintele
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;
}
Și utilizarea:
wp_nav_menu([
'theme_location' => 'foo-bar',
'context' => 'current',
]);
Sau...
wp_nav_menu([
'theme_location' => 'foo-bar',
'context' => get_queried_object_id(), // sau un ID de post arbitrar
]);
