Dynamicznie wyklucz pozycje menu z menu wp_nav_menu

17

Próbowałem znaleźć informacje o tym, jak wykluczyć / usunąć elementy menu nawigacyjnego z niestandardowych menu, a jedyny znaleziony wątek nie zawierał żadnych przydatnych odpowiedzi.

1. Tło:

Złożyłem menu Docka za pomocą niestandardowych menu WP ( wp_nav_menu ) i jqDock na mojej stronie. Ponieważ jqDock potrzebuje ciągłych obrazów lub linków graficznych do działania swojej magii, używam niestandardowego walkera, aby wyjście HTML menu nawigacji wyglądało mniej więcej tak:

<div id="menu-first" class="nav">
<a><img src="http://path/to/image-1.png"/></a>
<a><img src="http://path/to/image-2.png"/></a>
<a><img src="http://path/to/image-3.png"/></a>
etc...
</div>

Kod mojego niestandardowego chodzika to:

class custom_nav_walker extends Walker_Nav_Menu 
{
    var $tree_type = array( 'post_type', 'taxonomy', 'custom' );
    var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );

    function start_lvl(&$output, $depth) {
        $indent = str_repeat("\t", $depth);
        $output .= "\n$indent<ul class=\"sub-menu\">\n";
    }

    function end_lvl(&$output, $depth) {
        $indent = str_repeat("\t", $depth);
        $output .= "$indent</ul>\n";
    }

    function start_el(&$output, $item, $depth, $args) {
        global $wp_query;
        $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, $args ) );
        $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        ) .'"' : '';

        $description  = ! empty( $item->description ) ? esc_attr( strtolower( $item->description )) : '';
        $item_title   = ! empty( $item->attr_title )  ? esc_attr( $item->attr_title ) : '';

        if ( strpos($description, ';') !== false ) {
        $description_array = explode (';', $description);
            $image_name = $description_array[0];
            $image_alt = $description_array[1];
        } else {
            $image_name = $description;
            $image_alt = $item_title;
        }

        $item_output = $args->before;
        $item_output .= '<a'. $attributes .'>';
        $item_output .= $args->link_before .'<img src="'.get_bloginfo('template_url').'/images/skin1/'.$image_name.'" alt="'.$image_alt.'" title="'.$item_title.'" />'.$args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }

    function end_el(&$output, $item, $depth) {
        $output .= "";
    }

}

Następnie skrypt jqDock przechwytuje identyfikator menu („menu-first”) i zastępuje dane wyjściowe wp_nav_menu menu menu Dock. Dane wyjściowe HTML menu Docka zmieniają się w zależności od opcji określonych podczas ładowania jqDock.

2. Pytanie:

Chciałbym nie wyświetlać (tzn. Wykluczać) niektórych pozycji menu w zależności od tego, gdzie użytkownik jest na stronie. Na przykład chciałbym wyświetlać element domowy tylko wtedy, gdy użytkownika nie ma w domu, a element losowy - tylko wtedy, gdy on jest.

3. Odrzucone rozwiązania:

za. Wiele menu: rejestrowanie i tworzenie wielu menu, a następnie wywoływanie ich warunkowo, może działać; nie sądzę jednak, aby było to idealne ani czyste rozwiązanie z wielu powodów. Ponadto wiele menu nie jest łatwych w utrzymaniu lub aktualizacji.

b. Wyszukiwanie i zamiana wyrażenia regularnego : może to zmusić mnie do zmiany parametru igły za każdym razem, gdy zmieniam opcje jqDock, ponieważ dane wyjściowe HTML są modyfikowane.

do. Właściwość „display” CSS: Ukrywanie elementów za pomocą właściwości display CSS działa, ale ponieważ należy ją zastosować do danych wyjściowych menu jqDock, wpływa to na wizualne renderowanie menu.

4. Nieudane rozwiązania:

za. Filtruj do wp_nav_menu_items : Próbowałem złapać zmienną „$ items” (ciąg) i przypisać jej różne wartości za pomocą tagów warunkowych z następującym kodem:

function userf_dynamic_nav_menu ($items) {
    $items_array_home = explode('<a', $items);
    $items_array_nothome = $items_array_home;

    unset($items_array_home[1]);
    unset($items_array_nothome[2]);

    $items_home = implode('<a', $items_array_home);
    $items_nothome = implode('<a', $items_array_nothome);

    if ( is_home() ) {
        $items = $items_home;
    } else {
        $items = $items_nothome;
    }
    return $items;
}
add_filter('wp_nav_menu_first_items', 'userf_dynamic_nav_menu');

Działa to tylko częściowo, ponieważ elementy menu się zmieniają, ale tagi warunkowe są ignorowane. Myślę, że ma to sens ze względu na moment, w którym zastosowano filtr.

b. Niestandardowa funkcja menu nawigacyjnego : Próbowałem utworzyć własną niestandardową funkcję menu nawigacyjnego, aby móc dodać argument wykluczenia do tablicy $ defaults i użyć tego nieco zmodyfikowanego kodu z, wp_list_pagesaby wypełnić dodatkowy argument:

$exclude_array = ( $args->exclude ) ? explode(',', $args->exclude) : array();
$args->exclude = implode( ',', apply_filters('wp_nav_menu_excludes', $exclude_array) );

Jakieś pomysły?

Marventus
źródło
Czy możesz pokazać nam swoją niestandardową klasę dla dzieci z walkerem?
soulseekah
Cześć Souleseekah, właśnie dodałem go do mojego oryginalnego postu. Dzięki!
Marventus
Myślałem też o przekazaniu excludeargumentu, ale w przeciwieństwie do wp_list_pageswielu innych funkcji WP, wp_nav_menunie zawiera żadnej. Więc nawet jeśli wybiorę jeden, gdy dzwonię do menu lub w walkerze, nie zostanie odebrany w środku wp_nav_menu, prawda?
Marventus
Przepraszam, nie myślałem prosto, kiedy to napisałem, natychmiast usunięte.
soulseekah
Nie martw się o to!
Marventus

Odpowiedzi:

26

Metoda 1

Możesz dodać konstruktor do niestandardowego Walkera, aby przechowywać dodatkowe argumenty wykluczające, takie jak:

class custom_nav_walker extends Walker_Nav_Menu {
    function __construct( $exclude = null ) {
        $this->exclude = $exclude;
    }

    function skip( $item ) {
        return in_array($item->ID, (array)$this->exclude);
        // or
        return in_array($item->title, (array)$this->exclude);
        // etc.
    }

    // ...inside start_el, end_el
    if ( $this->skip( $item ) ) return;
}

Lub upuść konstruktor i ustaw jego $excludewłaściwość przed przekazaniem go jako walkera, aby wp_nav_menu():

$my_custom_nav_walker = new custom_nav_walker;
$my_custom_nav_walker->exclude = array( ... );

W zależności od tego, co wykluczasz, podaj prawidłowy formularz do wykluczenia.

Metoda 2

W ten sposób powinieneś to zrobić, podpinając się do wp_get_nav_menu_itemsfiltra.

function wpse31748_exclude_menu_items( $items, $menu, $args ) {
    // Iterate over the items to search and destroy
    foreach ( $items as $key => $item ) {
        if ( $item->object_id == 168 ) unset( $items[$key] );
    }

    return $items;
}

add_filter( 'wp_get_nav_menu_items', 'wpse31748_exclude_menu_items', null, 3 );

Uwaga: object_idto obiekt wskazywany przez menu, chociaż IDjest to identyfikator menu, są one różne.

Powiedz mi o czym myślisz.

soulseekah
źródło
Dzięki! To może zadziałać. Spróbuję i dam ci znać.
Marventus
Próbowałem podejścia konstruktora i bez względu na to, co próbuję, ciągle pojawia się błąd in_arrayfunkcji „Nieprawidłowy typ danych dla drugiego argumentu” . czy robię coś źle?
Marventus
$excludeNieruchomość musi być tablicą. Upewnij się więc, że przekazujesz tablicę do konstruktora lub obejrzyj zaktualizowany kod w mojej odpowiedzi. W szczególności typecast dla $this->exclude, na wypadek gdyby tablica nie została przekazana.
soulseekah
Przepraszam za to: miałem literówkę w swojej funkcji. Właśnie próbowałem $exclude = array ('4', '7');i używam ślimaków, ale nie ma to żadnego wpływu na wydajność walkera. Spróbuję drugiego podejścia i dam ci znać.
Marventus
Nie, to też nie działało.
Wydaje
0

czy to pomaga

$exclude_array = ( $args->exclude ) ? explode(',', $args->exclude) : array();
$args->exclude = implode( ',', apply_filters('wp_nav_menu_excludes', $exclude_array) );

jako przykład

< ?php wp_nav_menu( array( 'container_class' => 'menu-header', 'theme_location' => 'primary', 'exclude' => '66' ) ); ?>
saq
źródło
Cześć Saq, zapomniałem wspomnieć, że jednym z rozwiązań, które nie działały, było utworzenie niestandardowej funkcji nav_menu i dodanie tego kodu jako dodatkowego argumentu do wartości domyślnych funkcji. Niestety nie zadziałało. Nie próbowałem włączyć go do walkera, ale nie sądzę, żeby to zadziałało z tego samego powodu, o którym wspomniałem powyżej, głównie dlatego, że wp_nav_menunie ma argumentu „wykluczenia”, ale mogę się mylić.
Marventus
Zaktualizowałem swój pierwotny post, aby dodać go dla jasności.
Marventus
co jeśli nie użyjesz niestandardowego chodzika, zamiast tego użyjesz zwykłego menu nav_menu i wyodrębnisz elementy za pomocą wp_get_nav_menu_items () swoim niestandardowym obrazem
saq
To byłoby ogólnie dobre obejście, ale w tym konkretnym przypadku wp_get_nav_menu_itemsobrazy nie będą pobierane, ponieważ tagi img nie są przechowywane w rzeczywistym niestandardowym menu (tylko ich nazwy plików znajdują się w polu opisu, np. „Image1.png” ). Niestandardowy walker pozwala mi wstawiać tagi img w wynikach menu.
Marventus