Afișarea unei porțiuni/ramuri din arborele meniului folosind wp_nav_menu()

12 oct. 2010, 00:50:29
Vizualizări: 48.3K
Voturi: 113

Am un meniu definit în WP Admin care arată astfel:

structură meniu WordPress cu submeniuri

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.

4
Comentarii

Deci dorești să menții întregul meniu ca un meniu personalizat, dar să creezi un walker personalizat care îl afișează extinzând doar subarborele activ? Ca în acest cod, dar extinzând wp_nav_menu în loc de wp_list_pages? Recent am făcut ceva similar și aș putea posta codul dacă asta cauți...

goldenapples goldenapples
12 oct. 2010 04:51:36

@goldenapples, exact la asta mă refer. Dacă nu te deranjează să postezi codul tău ca răspuns, aș fi foarte recunoscător.

jessegavin jessegavin
12 oct. 2010 17:26:41

Mă mir că o funcționalitate atât de evident utilă nu este deja integrată. Este foarte utilă pentru orice site care funcționează ca un "CMS".

hakre hakre
9 feb. 2011 17:54:53

Încerc să rezolv problema menționată mai sus sau ceva similar. Ca alternativă, am venit cu o soluție CSS aici: http://stackoverflow.com/q/7640837/518169

hyperknot hyperknot
4 oct. 2011 02:52:14
Toate răspunsurile la întrebare 11
16
78

Î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 );
12 oct. 2010 12:00:11
Comentarii

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 daniel.tosaba
22 aug. 2012 08:09:15

@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?

Rarst Rarst
22 aug. 2012 14:18:19

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

dotty dotty
11 sept. 2012 14:19:34

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 dotty
11 sept. 2012 19:04:34

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

Rarst Rarst
11 sept. 2012 19:33:12

scuze, nu sunt sigur ce vrei să spui. Poți să clarifici, te rog?

dotty dotty
13 sept. 2012 14:08:50

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

Rarst Rarst
13 sept. 2012 14:12:35

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 gdaniel
5 sept. 2014 18:13:58

@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 :)

Rarst Rarst
5 sept. 2014 18:26:46

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.

gdaniel gdaniel
5 sept. 2014 18:36:02

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.

gdaniel gdaniel
5 sept. 2014 19:25:04

Soluție fantastică, @Rarst! Ca întotdeauna.

Eric Holmes Eric Holmes
24 feb. 2015 17:03:30

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.

Imperative Ideas Imperative Ideas
10 mar. 2015 03:26:00

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

Rarst Rarst
10 mar. 2015 08:47:20

Foarte elegant. Dacă cineva este interesat, pentru a face același lucru dar după ID-ul paginii, modificați linia wp_filter_object_list în wp_filter_object_list( $items, array( 'object_id' => $args->submenu ), 'and', 'ID' );

Ben Ben
30 apr. 2015 13:25:17
Arată celelalte 11 comentarii
0
14

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

7 feb. 2011 16:15:28
3
13

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! :-)

12 oct. 2010 10:50:41
Comentarii

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 jessegavin
14 oct. 2010 04:24:47

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

MikeSchinkel MikeSchinkel
14 oct. 2010 05:34:14

Acesta este răspunsul pe care l-am căutat toată ziua, îți mulțumesc foarte mult!

Chris Haas Chris Haas
13 dec. 2019 22:39:44
4
10

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() ) 
   ); ?>
15 oct. 2010 23:06:30
Comentarii

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.

goldenapples goldenapples
16 oct. 2010 22:46:34

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 Zolomon
20 feb. 2011 22:10:29

@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?

goldenapples goldenapples
21 feb. 2011 22:39:20

Poate doriți să transmiteți un parametru depth la apelul către wp_nav_menu, în cazul în care tema dumneavoastră suprascrie cumva valoarea implicită de 0 (afișează toate nivelurile)?

goldenapples goldenapples
21 feb. 2011 22:41:09
3

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.

21 apr. 2011 14:41:12
Comentarii

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

Digerkam Digerkam
28 feb. 2013 18:28:45

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

Floris Floris
4 sept. 2018 13:29:51

Aș sugera și să faci $submenu opțional. Astfel încât să poți obține întregul meniu când este necesar. Adaugă acest filtru la început: if ( ! isset( $args->submenu ) ) { return $items; }

Floris Floris
4 sept. 2018 13:43:48
0

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
));
1 feb. 2012 01:19:49
1

@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;
        }
    }
15 mar. 2011 20:07:17
Comentarii

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.

TechRemarker TechRemarker
24 mai 2011 04:30:45
0

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.

8 feb. 2011 23:39:06
0

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

}

20 apr. 2011 21:46:33
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.

http://wordpress.org/extend/plugins/advanced-menu-widget/

10 ian. 2012 02:59:05
0

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
]);
21 oct. 2021 00:59:53