wp_nav_menuからメニュー項目を動的に除外する


17

カスタムメニューからnavメニュー項目を除外/削除する方法についての情報を探してみましたが、見つけた唯一のスレッドには私にとって有用な答えがありませんでした。

1.背景:

私のサイトでは、WPカスタムメニュー(wp_nav_menu)とjqDockを使用してDockメニューを作成しました。jqDockは、その魔法を機能させるために連続した画像または画像リンクを必要とするため、カスタムウォーカーを使用して、navメニューのHTML出力を次のようにします。

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

カスタムウォーカーのコードは次のとおりです。

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

}

次に、jqDockスクリプトはメニューID( 'menu-first')をキャッチし、wp_nav_menuの出力をDockメニューのものに置き換えます。DockメニューのHTML出力は、jqDockのロード時に指定されたオプションに基づいて変わります。

2.質問:

ユーザーがサイトのどこにいるかに応じて、特定のメニュー項目を表示(除外)しません。たとえば、ユーザーがホームにいないときにのみホームアイテムを表示し、ユーザーがホームにいるときにのみランダムポストアイテムを表示したいとします。

3.破棄されたソリューション:

a。複数のメニュー:複数のメニューを登録して作成し、条件付きで呼び出すことができます。ただし、これは多くの理由で理想的でもクリーンなソリューションでもないと思います。また、複数のメニューを維持または更新するのは簡単ではありません。

b。正規表現の検索と置換:これにより、HTML出力が変更されるため、jqDockオプションを変更するたびにパラメーターを変更しなければならない場合があります。

c。CSSの 'display'プロパティ: CSSのdisplayプロパティでアイテムを非表示にしますが、jqDockメニュー出力に適用する必要があるため、メニューの視覚的なレンダリングに影響します。

4.失敗したソリューション:

a。wp_nav_menu_itemsへのフィルター: '$ items'変数(文字列)をキャッチし、次のコードで条件タグを使用して異なる値を割り当ててみました:

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

メニュー項目は変更されますが、条件タグは無視されるため、これは部分的にしか機能しません。フィルターが適用される瞬間のため、これは理にかなっていると思います。

b。カスタムnavメニュー関数:私は独自のカスタムnavメニュー関数を作成して、$ defaults配列にexclude引数を追加し、このわずかに変更されたコードを使用して追加の引数を設定できるようにしましたwp_list_pages

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

何か案は?


カスタムウォーカーの子クラスを見せてもらえますか?
-soulseekah

こんにちはSouleseekah、元の投稿に追加しました。ありがとう!
マルベントゥス

exclude引数を渡すことも考えましたが、wp_list_pages他の多くのWP関数とは異なり、引数wp_nav_menuは含まれていません。だから、メニューを呼び出すときやウォーカーで1つを指定しても、内部wp_nav_menuでピックアップされませんか?
マーベントゥス

申し訳ありませんが、私がそれを書いたとき、まっすぐに考えていなかったので、すぐに削除しました。
-soulseekah

心配しないでください!
マルベントゥス

回答:


26

方法1

カスタムWalkerにコンストラクターを追加して、次のような追加の除外引数を保存できます。

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

または、コンストラクターをドロップし、その$excludeプロパティを設定してから、ウォーカーとして渡すwp_nav_menu()ようにしてください:

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

除外対象に応じて、正しいフォームを除外対象に指定します。

方法2

これは、wp_get_nav_menu_itemsフィルターにフックしてこれを行う方法です。

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

注:object_idはメニューが指すオブジェクトIDですが、メニューIDは異なります。

あなたの考えを聞かせてください。


ありがとう!それはうまくいくかもしれません。試してみて、お知らせします。
マーベントゥス

コンストラクターアプローチを試してみましたが、何を試しても、in_array関数に対して「間違ったデータ型の2番目の引数」エラーが発生し続けます。私は何か間違っていますか?
マーベンタス

$excludeプロパティが配列でなければなりません。そのため、コンストラクターに配列を渡していることを確認するか、回答で更新されたコードを確認してください。具体的には$this->exclude、配列が渡されない場合のためのの型キャストです。
-soulseekah

申し訳ありませんが、機能にタイプミスがありました。私$exclude = array ('4', '7');もナメクジを使ってみましたが、ウォーカーの出力には何の影響もありません。2番目のアプローチを試して、お知らせします。
マルベントゥス

いいえ、それも機能しませんでした。私はこれを理解しようとして
頭がおかしい

0

これは役立ちますか

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

例として

< ?php wp_nav_menu( array( 'container_class' => 'menu-header', 'theme_location' => 'primary', 'exclude' => '66' ) ); ?>

こんにちは、私は機能しなかった解決策の1つがカスタムnav_menu関数を作成し、そのコードを追加の引数として関数のデフォルトに追加することであることを忘れていました。残念ながら、うまくいきませんでした。私はそれをウォーカーに含めようとしwp_nav_menuませんでしたが、上記と同じ理由で、主に「除外」引数がないのでうまくいかないと思いますが、間違っている可能性があります。
マルベントゥス

明確にするために、元の投稿を更新してこれを含めました。
マルベントゥス

カスタムウォーカーを使用していけない場合何を、代わりにあなたは定期的にnav_menuを使用してカスタムイメージをwp_get_nav_menu_itemsを持つアイテムを()を抽出
SAQ

これは一般的には適切な回避策ですが、この特定のケースでwp_get_nav_menu_itemsは、imgタグは実際のカスタムメニューに保存されないため、画像を取得しません(「image1.png」などの説明フィールドにはファイル名のみ)。カスタムウォーカーにより、メニュー出力にimgタグを挿入できます。
マルベントゥス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.