Kecualikan item menu dari wp_nav_menu secara dinamis

17

Saya mencoba mencari info tentang cara mengecualikan / menghapus item menu nav dari menu kustom, dan satu-satunya utas yang saya temukan tidak memiliki jawaban yang berguna bagi saya.

1. Latar Belakang:

Saya mengumpulkan menu Dock menggunakan menu khusus WP (wp_nav_menu) dan jqDock di situs saya. Karena jqDock membutuhkan gambar terus menerus atau tautan gambar untuk menjalankan keajaibannya, saya menggunakan walker khusus sehingga keluaran menu HTML nav terlihat seperti ini:

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

Kode untuk alat bantu khusus saya adalah:

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 .= "";
    }

}

Skrip jqDock kemudian menangkap ID menu ('menu-first') dan menggantikan output wp_nav_menu dengan menu Dock. Output HTML menu Dock berubah berdasarkan opsi yang ditentukan saat memuat jqDock.

2. Pertanyaan:

Saya ingin tidak menampilkan (yaitu, mengecualikan) item menu tertentu sesuai dengan di mana pengguna berada di situs. Misalnya, saya hanya ingin menampilkan item Beranda saat pengguna tidak ada di Beranda, dan item posting Acak hanya ketika dia berada.

3. Solusi yang dibuang:

Sebuah. Menu muliple: Mendaftarkan dan membuat beberapa menu dan kemudian memanggilnya secara kondisional dapat bekerja; Namun, saya tidak berpikir ini adalah solusi ideal atau bersih sama sekali karena berbagai alasan. Selain itu, banyak menu tidak mudah dipelihara atau diperbarui.

b. Regex Search and Replace: Ini mungkin memaksa saya untuk mengubah parameter jarum setiap kali saya mengubah opsi jqDock karena output HTML dimodifikasi.

c. Properti 'display' CSS: Menyembunyikan item melalui properti display CSS berfungsi, tetapi karena itu harus diterapkan pada output menu jqDock, itu mempengaruhi rendering visual menu.

4. Solusi Gagal:

Sebuah. Memfilter ke wp_nav_menu_items : Saya mencoba menangkap variabel '$ items' (string) dan menetapkan nilai yang berbeda melalui tag kondisional dengan kode berikut:

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

Ini hanya berfungsi sebagian, karena item menu memang berubah, tetapi tag kondisional diabaikan. Saya kira ini masuk akal karena saat di mana filter diterapkan.

b. Fungsi menu nav kustom : Saya mencoba membuat fungsi menu kustom nav saya sendiri untuk dapat menambahkan argumen kecualikan ke array $ default dan menggunakan kode yang sedikit dimodifikasi ini wp_list_pagesuntuk mengisi argumen tambahan:

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

Ada ide?

Marventus
sumber
Bisakah Anda menunjukkan kepada kami kelas anak walker khusus Anda?
soulseekah
Hai Souleseekah, saya baru saja menambahkannya ke posting asli saya. Terima kasih!
Marventus
Saya berpikir untuk menyampaikan excludeargumen juga, tetapi, berlawanan dengan wp_list_pagesdan banyak fungsi WP lainnya, wp_nav_menutidak termasuk satu. Jadi, bahkan jika saya menentukan satu ketika memanggil menu atau di walker, itu tidak akan dijemput di dalam wp_nav_menu, bukan?
Marventus
Maaf, tidak berpikir jernih ketika saya menulis itu, segera dihapus.
soulseekah
Jangan khawatir tentang itu!
Marventus

Jawaban:

26

Metode 1

Anda dapat menambahkan konstruktor ke Walker kustom Anda untuk menyimpan beberapa argumen pengecualian tambahan, seperti:

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

Atau jatuhkan konstruktor dan atur $excludepropertinya sebelum melewatinya sebagai alat bantu jalan agar wp_nav_menu()suka:

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

Bergantung pada apa yang Anda kecualikan, berikan formulir yang benar untuk pengecualian.

Metode 2

Ini adalah bagaimana Anda akan melakukan ini dengan menghubungkan ke wp_get_nav_menu_itemsfilter.

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

Catatan: object_idadalah objek yang ditunjukkan menu, sedangkan IDID menu berbeda.

Beri tau aku isi pikiranmu.

soulseekah
sumber
Terima kasih! Itu mungkin berhasil. Saya akan mencobanya dan memberi tahu Anda.
Marventus
Saya mencoba pendekatan konstruktor dan, tidak peduli apa yang saya coba, saya terus mendapatkan kesalahan "datatype untuk argumen kedua" kesalahan untuk in_arrayfungsi. Apakah saya melakukan sesuatu yang salah?
Marventus
The $excludeproperti harus array. Jadi pastikan Anda mengirimkan array ke konstruktor, atau perhatikan kode yang diperbarui dalam jawaban saya. Khusus typecast untuk $this->exclude, kalau-kalau array tidak lulus.
soulseekah
Maaf soal itu: Saya salah ketik. Saya hanya mencoba $exclude = array ('4', '7');dan menggunakan siput juga, tetapi tidak memiliki efek pada output walker. Saya akan mencoba pendekatan kedua dan memberi tahu Anda.
Marventus
Tidak, itu juga tidak berhasil. Saya pikir saya otak mati karena mencoba mencari tahu ini, sehingga mungkin mempengaruhi ... "kinerja" saya, :-)
Marventus
0

Apakah ini membantu

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

sebagai contoh

< ?php wp_nav_menu( array( 'container_class' => 'menu-header', 'theme_location' => 'primary', 'exclude' => '66' ) ); ?>
saq
sumber
Hai Saq, saya lupa menyebutkan bahwa salah satu solusi yang tidak berfungsi adalah membuat fungsi nav_menu khusus dan menambahkan kode itu sebagai argumen tambahan ke default fungsi. Sayangnya, itu tidak berhasil. Saya tidak mencoba memasukkannya ke dalam walker, tetapi saya tidak berpikir itu akan berhasil karena alasan yang sama seperti yang saya sebutkan di atas, terutama karena wp_nav_menutidak memiliki argumen "mengecualikan", tetapi saya bisa saja salah.
Marventus
Saya memperbarui posting asli saya untuk memasukkan ini agar lebih jelas.
Marventus
bagaimana jika Anda tidak menggunakan walker khusus, alih-alih Anda menggunakan nav_menu biasa dan mengekstrak item dengan wp_get_nav_menu_items () dengan gambar khusus Anda
saq
Itu akan menjadi solusi yang baik secara umum, tetapi dalam kasus khusus ini, wp_get_nav_menu_itemstidak akan mengambil gambar karena tag img tidak disimpan dalam menu kustom yang sebenarnya (hanya nama file mereka di bidang deskripsi, misalnya, "image1.png" ). Walker kustom adalah yang memungkinkan saya untuk memasukkan tag img di output menu.
Marventus