私はwalker関数を作成するか、それともカスタム出力を生成できるように現在のwp_nav_menus
を修正したいと思います。この構造を想像してみましょう:
menu item 1
menu item 2
submenu item a
submenu item b
menu item 3
submenu item c
submenu item d
submenu item e
最も簡単なのは、メインメニュー項目(メインメニュー1,2,3)だけを1か所に表示することです。これはwp_nav_menusで実行できるので、コーディングする必要はありません。
問題のある部分は、現在メイン項目のサブメニュー項目を他の場所に表示することです...したがって、ユーザーが「メニュー項目1」ページにいる場合、何も表示されません。ユーザーが「メニュー項目2」ページにいる場合は、「新しい」カスタムメニューが表示されます。
submenu item a
submenu item b
ユーザーが上記の2つのページ(メニュー項目)のどちらかにいる場合、同じメニュー項目が表示されます。
ユーザーが「メニュー項目3」をクリックしてそのターゲットページにアクセスすると、それらのサブメニュー項目のいずれかをクリックした後と同じように、サブメニュー項目c、d、eが表示されます。
メニューに3番目のレベルの要素がある場合(およびそれより深い場合)、カスタムメニューには、現在の最上位のmenu要素のすべての子要素が、その最上位要素自体の横に表示されます。
そのような機能を作成する方法はありますか?
メニューの一部/ブランチを表示する 現在のメニューブランチの子エレメント/トップメニューブランチエレメントのすべての子エレメントが存在する場合はそれを表示することだけが必要です。
私はget_ancestors
を使用することはできません。なぜなら、それは階層的分類法でのみ機能するからです。ここではpost/pages階層構造から作成されたメニューについてではなく、メニューエディタを使用します。
SOLVED:いくつかの方法を組み合わせて正しい関数を作成できたようです。
/**
* The API function, just a wrap for wp_nav_menu adding filter first and removing after
*/
function filtered_nav_menu( $args = array() ) {
$echo = isset($args['echo']) ? (bool)$args['echo'] : true;
$args['echo'] = false;
add_filter( 'wp_nav_menu_objects', 'gmfnv_filter', 999 );
$menu = wp_nav_menu( $args );
remove_filter( 'wp_nav_menu_objects', 'gmfnv_filter', 999 );
if ( $echo ) echo $menu;
else return $menu;
}
/**
* The filter callback, return the filtered elements
*/
function gmfnv_filter( $items ) {
$found_top_parent_ID = false;
foreach ($items as $item) {
if ( ($item->menu_item_parent == 0 && $item->current_item_ancestor == 1) || ($item->menu_item_parent == 0 && $item->current == 1) ) {
$found_top_parent_ID = $item->ID;
}
}
$children = submenu_get_children_ids( $found_top_parent_ID, $items );
foreach ( $items as $key => $item ) {
if ( ! in_array( $item->ID, $children ) )
unset($items[$key]);
}
return $items;
}
/**
* Helper function: return children of an element using wp_filter_object_list
*/
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;
}
それは何をしますか - それは各$ items要素を通過してチェックすることで現在のブランチのトップの祖先を検索します。
($item->menu_item_parent == 0 && $item->current_item_ancestor == 1) || ($item->menu_item_parent == 0 && $item->current == 1)
最上位レベルのメニュー要素も現在のものである可能性があるため、この条件は2部構成にする必要があります。
トップレベルの$ itemが見つかると、関数submenu_get_children_ids
がそのすべての子要素をリストするのに使われます。
カスタムウォーカーを作成する代わりに、フィルターwp_nav_menu_objects
フックを使用してアイテムをフィルター処理する方が簡単だと思いました。
このフックは /wp-includes/nav-menu-templates.php
で定義され、起動されると、関数がその配列を変更し、アイテムを追加または削除する場合、印刷されるメニューのすべての要素を含む配列$sorted_menu_items
をフックする関数に渡します、結果のメニューが変更されます。
wp_nav_menu_objects
へのフィルターが直接適用される場合、allメニューがフィルターされるので、関数を作成する方がよいと考えましたこれはwp_nav_menu
をラップしてフィルターを追加しますbeforewp_nav_menu
を呼び出して削除しますafter:このようにして、必要なメニューのみがフィルターされます。
wp_nav_menu_objects
filterフックによって渡されたすべてのアイテムを循環させます$itemid => $parentid
のようなアイテムを持つ私がそのために書いたコードは5つの関数を使用するので、ここにコードをすべて含むプラグインを作成します。
<?php
/**
* Plugin Name: Filtered Nav Menus
* Author: Giuseppe Mazzapica
* Plugin URI: http://wordpress.stackexchange.com/questions/118720/
* Author URI: http://wordpress.stackexchange.com/users/35541/
*/
/**
* The API function, just a wrap for wp_nav_menu adding filter first and removing after
*/
function filtered_nav_menu( $args = array() ) {
$echo = isset($args['echo']) ? (bool)$args['echo'] : true;
$args['echo'] = false;
add_filter( 'wp_nav_menu_objects', 'gmfnv_filter', 999 );
$menu = wp_nav_menu( $args );
remove_filter( 'wp_nav_menu_objects', 'gmfnv_filter', 999 );
if ( $echo ) echo $menu;
else return $menu;
}
/**
* The filter callback, return the filtered elements
*/
function gmfnv_filter( $items ) {
$found = false;
$parents = $items_tree = $allowed = array();
$all_items = $items;
while ( ! empty( $items ) ) {
$item = array_shift( $items );
$items_tree[$item->ID] = $item->menu_item_parent;
if ( (int) $item->menu_item_parent == 0 ) $parents[] = $item->ID;
if ( isset($item->current) && $item->current ) $found = $item->ID;
}
if ( ! $found ) {
$ids = $parents;
} else {
$tree = gmfnv_get_tree( $found, $all_items, $items_tree );
$ids = array_merge( $parents, $tree );
}
foreach ( $all_items as $item ) {
if ( in_array( $item->ID, $ids ) ) $allowed[] = $item;
}
return $allowed;
}
/**
* Helper function: take the matched element if and the helper array and
* return the item ancestors by gmfnv_get_parents,
* and the children of these ancestors returned by gmfnv_get_parents
* using gmfnv_get_parents
*/
function gmfnv_get_tree( $test, $items, $tree ) {
$parents = gmfnv_get_parents( $test, $items );
$parents[] = $test;
$n = array();
foreach ( $parents as $parent ) {
$n = array_merge( $n, gmfnv_get_childrens( $parent, $tree ) );
}
return array_unique( $n );
}
/**
* Helper function: return ancestors of an element using the helper array
*/
function gmfnv_get_parents( $test, $items ) {
$parents = array();
foreach( $items as $item ) {
if (
(isset($item->current_item_ancestor) && $item->current_item_ancestor)
|| (isset($item->current_item_ancestor) && $item->current_item_ancestor)
) $parents[] = $item->ID;
}
return $parents;
}
/**
* Helper function: return children of an element using the helper array
*/
function gmfnv_get_childrens( $test, $tree ) {
$children = array();
foreach ( $tree as $child => $parent ) {
if ( $parent == $test ) $children[] = $child;
}
return $children;
}
このプラグインを含むファイルを作成し、pluginsフォルダーに入れてアクティブにします。
必要に応じてメニューをフィルタリングする場合は、代わりにwp_nav_menu( $args )
を使用します
filtered_nav_menu( $args );
提供されているコード現状のまま、保証なし、ただしすぐにPHP 5.4、WP 3.7でテストされ、20のテーマがアクティブで、他のプラグインはありません。この場合。