Niestandardowy walker Nav wyświetla bieżące pozycje menu dzieci lub rodzeństwo bez dzieci


14

Grzebałam / szukałam godzinami i wciąż nie mogę tego zrobić, więc w końcu poddaję się i proszę o pomoc.

Próbuję napisać niestandardowy walker, który pokazuje tylko bieżące strony potomne, lub jeśli nie ma dzieci wyświetlających rodzeństwo stron.

Na przykład weź następujące drzewo menu:

  • 1.0
    • 1.2.0
      • 1.3.0
      • 1.3.1
      • 1.3.2
    • 1.2.1
    • 1.2.2
  • 2.0

Załóżmy, że jestem na bieżącej stronie 1.2.0. Na tej stronie chcę wyświetlić jego dzieci (1.3.0, 1.3.1, 1.3.2)

jednak jeśli jestem na stronie 1.2.2, ponieważ nie ma żadnych dzieci, powinien wyświetlić swoje rodzeństwo na obecnym poziomie, więc powinien mi to pokazać (1.2.0, 1.2.1, 1.2.2).


4
Przenieś swoje rozwiązanie do odpowiedzi, aby było bardziej zrozumiałe dla innych, a pytania nie prześladują witryny jako odpowiedzi.
Rarst

Co powiedział @Rarst! Prawie tęskniłem za tym, że wpadłeś na rozwiązanie.
Chris Krycho,

Odpowiedź Necro. Zadałem mniej więcej to samo pytanie na SO około 2 lata temu z bardzo dobrą odpowiedzią. stackoverflow.com/questions/5826609/…
Stoosh,

Przeniesiono odpowiedź do pytania na osobną odpowiedź. OP: Proszę śledzić tam.
kaiser

Odpowiedzi:


4

To jest walker, w którym wyświetlałem tylko elementy potomne bieżącego elementu menu. Lub rodzeństwo elementów menu, jeśli nie ma własnych dzieci.

W całej klasie znajdują się komentarze wyjaśniające każdą sekcję

<?php

class SH_Child_Only_Walker extends Walker_Nav_Menu {

private $ID;
private $depth;
private $classes = array();
private $child_count = 0;
private $have_current = false;


// Don't start the top level
function start_lvl(&$output, $depth=0, $args=array()) {

    if( 0 == $depth || $this->depth != $depth )
        return;

    parent::start_lvl($output, $depth,$args);
}

// Don't end the top level
function end_lvl(&$output, $depth=0, $args=array()) {
    if( 0 == $depth || $this->depth != $depth )
        return;

    parent::end_lvl($output, $depth,$args);
}

// Don't print top-level elements
function start_el(&$output, $item, $depth=0, $args=array()) {

    $is_current = in_array('current-menu-item', $this->classes);

    if( 0 == $depth || ! $is_current )
        return;

    parent::start_el($output, $item, $depth, $args);
}

function end_el(&$output, $item, $depth=0, $args=array()) {
    if( 0 == $depth )
        return;

    parent::end_el($output, $item, $depth, $args);
}

// Only follow down one branch
function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {

    // Check if element is in the current tree to display
    $current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' );
    $this->classes = array_intersect( $current_element_markers, $element->classes );

    // If element has a 'current' class, it is an ancestor of the current element
    $ancestor_of_current = !empty($this->classes);

    // check if the element is the actual page element we are on.
    $is_current = in_array('current-menu-item', $this->classes);

    // if it is the current element
    if($is_current) {

        // set the count / ID / and depth to use in the other functions.
        $this->child_count = ( isset($children_elements[$element->ID]) ) ? count($children_elements[$element->ID]) : 0;
        $this->ID = $element->ID;
        $this->depth = $depth;
        $this->have_current = true;

        if($this->child_count > 0) {

            // if there are children loop through them and display the kids.
            foreach( $children_elements[$element->ID] as $child ) {
                parent::display_element( $child, $children_elements, $max_depth, $depth, $args, $output );
            }

        } else {
            // no children so loop through kids of parent item.
            foreach( $children_elements[$element->menu_item_parent] as $child ) {
                parent::display_element( $child, $children_elements, $max_depth, $depth, $args, $output );
            }

        }
    }

    // if depth is zero and not in current tree go to the next element
    if ( 0 == $depth && !$ancestor_of_current)
        return;

    // if we aren't on the current element proceed as normal
    if(! $this->have_current )
        parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}
}

Dołącz go tak, jak w przypadku każdego innego niestandardowego walkera w menu wp_nav_menu

<?php
wp_nav_menu( array(
    'menu' => 'primary-menu'
    ,'container' => 'nav'
    ,'container_class' => 'subpages'
    ,'depth' => 0
    ,'walker' => new SH_Child_Only_Walker()
 ));
?>

Chcę zwrócić uwagę na komentarz @ Stoosha, który tutaj wskazuje. stackoverflow.com/questions/5826609/…, ponieważ jest to kolejne dobre rozwiązanie
jchamb

0

Miałem podobne doświadczenie. Możesz pomyśleć o przeniesieniu logiki stron poza walker. Zasadniczo skompiluj bieżącą hierarchię stron jako obiekt. Następnie użyj parametru „wyklucz” w funkcji wp_nav_menu. Teraz wykluczone strony zależą od tego, czy bieżąca strona ma elementy potomne. Jeśli żadne dzieci nie pokazują braci; jeśli dzieci i te dzieci są na końcu linii, pokażcie bracia i dzieci; jeśli istnieją dzieci, dzieci i wnuki, wyklucz braci i pokaż dzieci i wnuki.


Do jakiego excludeparametru się odnosisz? Patrzę na dokumentację i nie widzę żadnych odniesień do niej.
Chris Krycho,

1
Przepraszam, że się pomyliłem. Masz rację, że nie ma parametru „wyklucz”. Chciałem użyć funkcji „wp_list_pages”.
Steve Fischer

Bardzo dobrze i bez obaw. Byłem tylko ciekawy, czy istnieje coś nieudokumentowanego, ale z tyłu - widziałem to wcześniej. Dzięki za wyjaśnienie! Nie myślałem o użyciu wp_list_pages()w tym kontekście, więc to ciekawy pomysł.
Chris Krycho
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.