Wyświetl część / gałąź drzewa menu za pomocą wp_nav_menu ()

109

Mam zdefiniowane menu w WP Admin, które wygląda następująco:

alternatywny tekst

Chcę móc wyświetlać wszystkie podrzędne linki na pasku bocznym za każdym razem, gdy jestem na stronie nadrzędnej. Na przykład, jeśli użytkownik jest na mojej stronie „O nas”, chcę, aby lista 4 linków podświetlonych na zielono pojawiła się na pasku bocznym.

Przejrzałem dokumentację dla wp_nav_menu () i wydaje się, że nie ma ona żadnego wbudowanego sposobu określania konkretnego węzła danego menu, który miałby być punktem początkowym podczas generowania linków.

Stworzyłem rozwiązanie dla podobnej sytuacji, które opierało się na relacjach tworzonych przez rodzica strony, ale szukam takiego, który będzie korzystał z systemu menu. Każda pomoc będzie mile widziana.

jessegavin
źródło
2
Czy chcesz zachować całe menu jako menu niestandardowe, ale utworzyć niestandardowy walker, który wyświetla go rozwijając tylko aktywne poddrzewo? Podoba ci się ten kod , ale rozszerzenie wp_nav_menu zamiast wp_list_pages? Niedawno zrobiłem coś podobnego i mógłbym opublikować kod, jeśli tego właśnie szukasz ...
goldenapples
1
@goldenapples, właśnie tego szukam. Jeśli nie masz nic przeciwko opublikowaniu kodu jako odpowiedzi, byłbym bardzo wdzięczny.
jessegavin
1
Zastanawiam się, że tak oczywista użyteczna funkcjonalność jeszcze jej nie buduje. Jest to ogólnie bardzo przydatne dla każdej witryny obsługującej „CMS”.
hakre
Próbuję rozwiązać powyższy problem lub coś podobnego. Jako alternatywę wymyśliłem tutaj rozwiązanie CSS: stackoverflow.com/q/7640837/518169
hyperknot

Odpowiedzi:

75

Wciąż o tym myślałem, więc ponownie go przejrzałem i opracowałem to rozwiązanie, które nie opiera się tak bardzo na kontekście:

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

Stosowanie

$args = array(
    'theme_location' => 'slug-of-the-menu', // the one used on register_nav_menus
    'submenu' => 'About Us', // could be used __() for translations
);

wp_nav_menu( $args );
Rarst
źródło
Urocza technika! Czy mogę zapytać o coś, co może być związane z tym: Jak wyświetliłbyś zawartość wymienionych stron podmenu w szablonie?
daniel.tosaba
2
@ daniel.tosaba będziesz musiał podklasować lub używać filtrów w Walker_Nav_Menuklasie. Jak wszystkie rzeczy w menu zbyt wiele do komentowania - zadaj nowe pytanie?
Rarst
3
Taka fantastyczna odpowiedź. Dziękuję bardzo. To naprawdę powinna być domyślna opcja w WordPress.
dotty,
3
Naprawdę fajnie. Jeśli ktoś jest zainteresowany, zrób to samo, ale według identyfikatora strony, zmień wp_filter_object_listwiersz nawp_filter_object_list( $items, array( 'object_id' => $args->submenu ), 'and', 'ID' );
Ben
14

@goldenapples: Twoja klasa Walker nie działa. Ale pomysł jest naprawdę dobry. Stworzyłem walkera na podstawie twojego pomysłu:

class Selective_Walker extends Walker_Nav_Menu
{
    function walk( $elements, $max_depth) {

        $args = array_slice(func_get_args(), 2);
        $output = '';

        if ($max_depth < -1) //invalid parameter
            return $output;

        if (empty($elements)) //nothing to walk
            return $output;

        $id_field = $this->db_fields['id'];
        $parent_field = $this->db_fields['parent'];

        // flat display
        if ( -1 == $max_depth ) {
            $empty_array = array();
            foreach ( $elements as $e )
                $this->display_element( $e, $empty_array, 1, 0, $args, $output );
            return $output;
        }

        /*
         * need to display in hierarchical order
         * separate elements into two buckets: top level and children elements
         * children_elements is two dimensional array, eg.
         * children_elements[10][] contains all sub-elements whose parent is 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;
        }

        /*
         * when none of the elements is top level
         * assume the first one must be root of the sub elements
         */
        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' );  //added by continent7
        foreach ( $top_level_elements as $e ){  //changed by continent7
            // descend only on current tree
            $descend_test = array_intersect( $current_element_markers, $e->classes );
            if ( !empty( $descend_test ) ) 
                $this->display_element( $e, $children_elements, 2, 0, $args, $output );
        }

        /*
         * if we are displaying all levels, and remaining children_elements is not empty,
         * then we got orphans, which should be displayed regardless
         */
         /* removed by 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;
    }
}

Teraz możesz użyć:

<?php wp_nav_menu( 
   array(
       'theme_location'=>'test', 
       'walker'=>new Selective_Walker() ) 
   ); ?>

Dane wyjściowe to lista zawierająca bieżący element główny i jego elementy potomne (nie ich elementy potomne). Def: Element główny: = Element menu najwyższego poziomu, który odpowiada bieżącej stronie lub jest rodzicem bieżącej strony lub rodzicem rodzica ...

To nie odpowiada dokładnie na pierwotne pytanie, ale prawie, ponieważ wciąż istnieje element najwyższego poziomu. Jest to dla mnie w porządku, ponieważ chcę element najwyższego poziomu jako nagłówek paska bocznego. Jeśli chcesz się tego pozbyć, może być konieczne zastąpienie elementu display_element lub użycie parsera HTML.

David
źródło
12

Cześć @jessegavin :

Menu Nav są przechowywane w kombinacji niestandardowych typów postów i niestandardowych systematyk. Każde menu jest przechowywane jako termin (tj. „Informacje o menu” , znaleziony w wp_terms) w niestandardowej taksonomii (tj. nav_menuZnaleziony w wp_term_taxonomy.)

Każdy element menu Nav jest przechowywany jako post post_type=='nav_menu_item'(tj. „O firmie” , znaleziono w wp_posts), a jego atrybuty są przechowywane jako meta post (in wp_postmeta) z meta_keyprefiksem _menu_item_*gdzie _menu_item_menu_item_parentjest identyfikator nadrzędnego elementu menu Nav post.

Zależność między menu i elementami menu jest przechowywana wp_term_relationshipstam, gdzie object_idodnosi się $post->IDdo pozycji menu nawigacji i $term_relationships->term_taxonomy_idodnosi się do menu zdefiniowanego zbiorczo w wp_term_taxonomyi wp_terms.

Jestem prawie pewien, że byłoby to możliwe, aby zaczepić zarówno 'wp_update_nav_menu'i 'wp_update_nav_menu_item'stworzyć menu w rzeczywistych wp_termsi równoległym układzie stosunków w wp_term_taxonomyi wp_term_relationshipsgdzie każdy Nav elementu menu, który ma sub-Nav elementy Menu również staje się swoją własną Nav Menu.

Chciałbyś także przechwycić 'wp_get_nav_menus' (który sugerowałem dodanie do WP 3.0 w oparciu o podobną pracę, którą wykonywałem kilka miesięcy temu), aby upewnić się, że wygenerowane menu Nav nie są wyświetlane do manipulacji przez użytkownika w adminie, w przeciwnym razie naprawdę szybko zsynchronizowałeś się, a wtedy miałbyś koszmar danych.

Brzmi jak fajny i użyteczny projekt, ale jest to trochę więcej kodu i testów, na które nie mogę sobie teraz pozwolić częściowo, ponieważ wszystko, co synchronizuje dane, zwykle jest PITA, jeśli chodzi o usuwanie wszystkich błędów (i ponieważ klienci płacący naciskają na mnie, aby załatwić sprawę :) Ale uzbrojony w powyższe informacje jestem dość zmotywowanym deweloperem wtyczek WordPress, który mógłby to napisać, gdyby chcieli.

Oczywiście teraz zdajesz sobie sprawę, że jeśli go kodujesz, masz obowiązek opublikować go tutaj, abyśmy wszyscy mogli skorzystać z Twojej hojności! :-)

MikeSchinkel
źródło
Nie jestem pewien, czy podążam za tym, co mówisz. Szukam rozwiązania tylko do odczytu do wyświetlania „podmenu” związanych z bieżącą stroną, na której znajduje się użytkownik. Czy mówimy o tym samym? - Doceniam jednak twoje głębsze wyjaśnienie dotyczące schematu bazy danych.
jessegavin
@jessegavin - Tak, jeśli chcesz zadzwonić wp_nav_menu(), musisz sklonować menu, ponieważ wp_nav_menu()jest ściśle powiązane ze strukturą menu . Inną opcją jest skopiowanie wp_nav_menu()kodu i dokonanie modyfikacji wymaganych do wyświetlenia jako podmenu.
MikeSchinkel,
10

To jest rozszerzenie Walkera, które powinno robić to, czego szukasz:

class Selective_Walker extends Walker_Nav_Menu
{

    function walk( $elements, $max_depth) {

        $args = array_slice(func_get_args(), 2);
        $output = '';

        if ($max_depth < -1) //invalid parameter
            return $output;

        if (empty($elements)) //nothing to walk
            return $output;

        $id_field = $this->db_fields['id'];
        $parent_field = $this->db_fields['parent'];

        // flat display
        if ( -1 == $max_depth ) {
            $empty_array = array();
            foreach ( $elements as $e )
                $this->display_element( $e, $empty_array, 1, 0, $args, $output );
            return $output;
        }

        /*
         * need to display in hierarchical order
         * separate elements into two buckets: top level and children elements
         * children_elements is two dimensional array, eg.
         * children_elements[10][] contains all sub-elements whose parent is 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;
        }

        /*
         * when none of the elements is top level
         * assume the first one must be root of the sub elements
         */
        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 ) {

            // descend only on current tree
            $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 );
        }

        /*
         * if we are displaying all levels, and remaining children_elements is not empty,
         * then we got orphans, which should be displayed regardless
         */
        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;
    }

}

Opierając się luźno na kodzie mfields, do którego odwoływałem się wcześniej w moim komentarzu. Podczas chodzenia po menu sprawdza tylko, czy bieżący element jest (1) bieżącym elementem menu lub (2) przodkiem bieżącego elementu menu, i rozwija poddrzewa pod nim tylko wtedy, gdy spełniony jest jeden z tych warunków . Mam nadzieję, że to Ci odpowiada.

Aby z niego skorzystać, wystarczy dodać argument „walker” podczas wywoływania menu, tj .:

<?php wp_nav_menu( 
   array(
       'theme_location'=>'test', 
       'walker'=>new Selective_Walker() ) 
   ); ?>
Złote Jabłka
źródło
Och ... Właśnie przeczytałem twoje pytanie i zdałem sobie sprawę, że na początku źle je zrozumiałem. Ten walker pokaże wszystkie inne elementy menu najwyższego poziomu, tylko ich nie rozwijaj. To nie było dokładnie to, co chciałeś zrobić. Mimo to ten kod można modyfikować w dowolny sposób. Wystarczy spojrzeć na pętlę $top_level_elementsi dodać własny test przed połączeniem z $this->display_element.
goldenapples
Czy jest możliwe, aby ta klasa pokazała głębokość bieżącej podstrony? To znaczy .. Jeśli mam głębokość trzech lub więcej poziomów, to trzeci i kolejne poziomy są wyświetlane dla bieżącej (pod) strony? W tej chwili pokazuje tylko A> B, a nie> C (C jest trzecim (poziom)
Zolomon
@Zolomon - Nie jestem pewien, czy rozumiem twoje pytanie. Powinno to rozwinąć całe drzewo pod dowolnym elementem menu o klasy „bieżący element menu”, „bieżący element menu” lub „bieżący element menu”. Kiedy go testuję, wyświetla wszystkie poziomy podstron w menu. Co chcesz robić
goldenapples
Może chcesz przekazać depthparametr do wywołania wp_nav_menu, na wypadek gdyby Twój motyw przekroczył domyślną wartość 0 (pokaż wszystkie poziomy)?
goldenapples
8

Aktualizacja: Zrobiłem to we wtyczce. Pobierz tutaj .


Musiałem to rozwiązać sam i ostatecznie napisałem filtr wyników wyszukiwania menu. Pozwala wp_nav_menunormalnie używać , ale wybierz podsekcję menu na podstawie tytułu elementu nadrzędnego. Dodaj submenuparametr do menu w następujący sposób:

wp_nav_menu(array(
  'menu' => 'header',
  'submenu' => 'About Us',
));

Możesz nawet przejść kilka poziomów w głąb, wprowadzając ukośniki:

wp_nav_menu(array(
  'menu' => 'header',
  'submenu' => 'About Us/Board of Directors'
));

Lub jeśli wolisz z tablicą:

wp_nav_menu(array(
  'menu' => 'header',
  'submenu' => array('About Us', 'Board of Directors')
));

Używa ślimakowej wersji tytułu, co powinno sprawić, że wybaczy takie litery, jak wielkie litery i interpunkcja.

Marcus Downing
źródło
Czy można przejść do podmenu za pomocą identyfikatora? Mam na myśli identyfikator strony lub identyfikator wpisu.
Digerkam
split () jest przestarzałe, zamień $loc = split( "/", $loc );we wtyczce na$loc = preg_split( "~/~", $loc );
Floris
Sugerowałbym również włączenie opcjonalnego podmenu $. Dzięki temu możesz w razie potrzeby pobrać całe menu. Dodaj to do filtra na górze: `if (! Isset ($ args-> submenu)) {return $ items; } `
Floris,
8

Przygotowałem dla siebie następującą klasę. Znajduje najwyższego nadrzędnego elementu nawigacyjnego bieżącej strony lub możesz nadać mu docelowy górny identyfikator nawigacji w konstruktorze walkera.

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();

        // if the parent is not set, set it based on the post
        if (!$target_id) {
            global $post;
            foreach ($items as $item) {
                if ($item->object_id == $post->ID) {
                    $target_id = $item->ID;
                }
            }
        }

        // if there isn't a parent, do a regular menu
        if (!$target_id) return parent::walk($items, $depth, $args);

        // get the top nav item
        $target_id = $this->top_level_id($items, $target_id);

        // only include items under the parent
        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);
    }

    // gets the top level ID for an item ID
    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;
            }
        }

        // find the top level item
        while (array_key_exists($item_id, $parents)) {
            $item_id = $parents[$item_id];
        }

        return $item_id;
    }
}

Nawigacja Nav:

wp_nav_menu(array(
    'theme_location' => 'main_menu',
    'walker' => new Walker_SubNav_Menu(22), // with ID
));
Matt
źródło
4

@davidn @hakre Cześć, mam brzydkie rozwiązanie bez parsera HTML lub przesłonięcia elementu 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) //invalid parameter
                return $output;

            if (empty($elements)) //nothing to walk
                return $output;

            $id_field = $this->db_fields['id'];
            $parent_field = $this->db_fields['parent'];

            // flat display
            if ( -1 == $max_depth ) {
                $empty_array = array();
                foreach ( $elements as $e )
                    $this->display_element( $e, $empty_array, 1, 0, $args, $output );
                return $output;
            }

            /*
             * need to display in hierarchical order
             * separate elements into two buckets: top level and children elements
             * children_elements is two dimensional array, eg.
             * children_elements[10][] contains all sub-elements whose parent is 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;
            }

            /*
             * when none of the elements is top level
             * assume the first one must be root of the sub elements
             */
            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' );  //added by continent7
            foreach ( $top_level_elements as $e ){  //changed by continent7
                // descend only on current tree
                $descend_test = array_intersect( $current_element_markers, $e->classes );
                if ( !empty( $descend_test ) ) 
                    $this->display_element( $e, $children_elements, 2, 0, $args, $output );
            }

            /*
             * if we are displaying all levels, and remaining children_elements is not empty,
             * then we got orphans, which should be displayed regardless
             */
             /* removed by 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 );
             }
            */

/*added by 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;
        }
    }
Alp Güneysel
źródło
Po wypróbowaniu wszystkich rozwiązań Alp było to jedyne, które działało dla mnie. Jednak jeden problem z tym. Tylko w programie są dzieci pierwszego poziomu, ale nie pokazuje dzieci trzeciego lub czwartego poziomu. Od kilku dni staram się to zrobić. Czy ktoś wie, jak zmodyfikować swoje rozwiązanie jako takie? PS. Nie pozwoli mi dodawać komentarzy, więc musisz to zrobić jako odpowiedź.
cchiera
3

Dane wyjściowe menu nawigacyjnego zawierają wiele klas dla bieżącego elementu, przodka bieżącego elementu itp. W niektórych sytuacjach byłem w stanie zrobić to, co chcesz zrobić, pozwalając na wyjście całego drzewa nawigacyjnego, a następnie używając css, aby go pauzować tylko dzieci bieżącej strony itp.


źródło
3

Zrobiłem zmodyfikowany walker, który powinien pomóc! Nie idealnie - pozostawia kilka pustych elementów, ale robi to samo. Modyfikacja to w zasadzie te bity $ current_branch. Mam nadzieję, że to komuś pomaga!

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;

    // Is this menu item in the current branch?
    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;
}

}


źródło
3

Sprawdź kod w mojej wtyczce lub użyj go do swoich celów;)

Ta wtyczka dodaje ulepszony widżet „Menu nawigacji”. Oferuje wiele opcji, które można ustawić w celu dostosowania wyjścia niestandardowego menu za pośrednictwem widżetu.

Dodatki zawarte:

  • Hierarchia niestandardowa - „Tylko powiązane elementy podrzędne” lub „Tylko ściśle powiązane elementy podrzędne”.
  • Początkowa głębokość i maksymalny poziom do wyświetlenia + płaski wyświetlacz.
  • Wyświetl wszystkie elementy menu, zaczynając od wybranego.
  • Wyświetla tylko bezpośrednią ścieżkę do bieżącego elementu lub tylko elementy potomne
    wybranego elementu (opcja dołączenia elementu nadrzędnego).
  • Klasa niestandardowa dla bloku widżetów.
  • I prawie wszystkie parametry funkcji wp_nav_menu.

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

Ján Bočínec
źródło