ナビゲーションメニュー項目をフラット配列ではなく多次元配列として取得する方法はありますか?
木のような構造によって、私は子と親のアイテム間の関係を維持するものを意味します。
array(
array(
'post_type' => 'page',
'post_name' => 'Home',
'children' => array()
),
array(
'post_type' => 'page',
'post_name' => 'About Us',
'children' => array(
array(
'post_type' => 'page',
'post_name' => 'Our History',
'children' => array()
)
)
)
)
wp_get_nav_menu_items()
関数がありますが、それは私が欲しいものではない同じレベルのすべての項目を持つ1次元配列を返します。 WordPressには、メニュー項目の多次元配列を取得するための組み込みの方法がありますか?そうでない場合、パフォーマンスの観点から、wp_get_nav_menu_items()
をツリーのような構造体として多次元配列にするための最良の方法は何ですか?
フラットな配列からツリーを構築する の問題は解決されました ここ この、わずかに修正された再帰的な解決策では:
/**
* Modification of "Build a tree from a flat array in PHP"
*
* Authors: @DSkinner, @ImmortalFirefly and @SteveEdson
*
* @link https://stackoverflow.com/a/28429487/2078474
*/
function buildTree( array &$elements, $parentId = 0 )
{
$branch = array();
foreach ( $elements as &$element )
{
if ( $element->menu_item_parent == $parentId )
{
$children = buildTree( $elements, $element->ID );
if ( $children )
$element->wpse_children = $children;
$branch[$element->ID] = $element;
unset( $element );
}
}
return $branch;
}
名前の衝突を避けるために、接頭辞wpse_children
属性を追加しました。
これで、単純なヘルパー関数を定義するだけで済みます。
/**
* Transform a navigational menu to it's tree structure
*
* @uses buildTree()
* @uses wp_get_nav_menu_items()
*
* @param String $menud_id
* @return Array|null $tree
*/
function wpse_nav_menu_2_tree( $menu_id )
{
$items = wp_get_nav_menu_items( $menu_id );
return $items ? buildTree( $items, 0 ) : null;
}
これでナビゲーションメニューをツリー構造に変換するのがとても簡単になります。
$tree = wpse_nav_menu_2_tree( 'my_menu' ); // <-- Modify this to your needs!
print_r( $tree );
JSONの場合は、単純に次のように使用できます。
$json = json_encode( $tree );
属性を厳選したわずかに異なるバージョンについては、この答えの最初のリビジョンをチェックしてください ここ 。
抽象的なWalker
クラスのdisplay_element()
メソッドの再帰的な部分にどのようにフックしようと試みることができるかについてのかなりざっと考えがあります。
$w = new WPSE_Nav_Menu_Tree;
$args = (object) [ 'items_wrap' => '', 'depth' => 0, 'walker' => $w ];
$items = wp_get_nav_menu_items( 'my_menu' );
walk_nav_menu_tree( $items, $args->depth, $args );
print_r( $w->branch );
WPSE_Nav_Menu_Tree
はWalker_Nav_Menu
クラスの拡張です。
class WPSE_Nav_Menu_Tree extends Walker_Nav_Menu
{
public $branch = [];
public function display_element($element, &$children, $max_depth, $depth = 0, $args, &$output )
{
if( 0 == $depth )
$this->branch[$element->ID] = $element;
if ( isset($children[$element->ID] ) )
$element->wpse_children = $children[$element->ID];
parent::display_element($element, $children, $max_depth, $depth, $args, $output);
}
}
それがうまくいけば、これは私たちに代替アプローチを与えるかもしれません。
手短に言うと、関数bellowは、子を親オブジェクト内の新しいchildrenプロパティに入れることによってオブジェクトのツリーを作成します。
function wpse170033_nav_menu_object_tree( $nav_menu_items_array ) {
foreach ( $nav_menu_items_array as $key => $value ) {
$value->children = array();
$nav_menu_items_array[ $key ] = $value;
}
$nav_menu_levels = array();
$index = 0;
if ( ! empty( $nav_menu_items_array ) ) do {
if ( $index == 0 ) {
foreach ( $nav_menu_items_array as $key => $obj ) {
if ( $obj->menu_item_parent == 0 ) {
$nav_menu_levels[ $index ][] = $obj;
unset( $nav_menu_items_array[ $key ] );
}
}
} else {
foreach ( $nav_menu_items_array as $key => $obj ) {
if ( in_array( $obj->menu_item_parent, $last_level_ids ) ) {
$nav_menu_levels[ $index ][] = $obj;
unset( $nav_menu_items_array[ $key ] );
}
}
}
$last_level_ids = wp_list_pluck( $nav_menu_levels[ $index ], 'db_id' );
$index++;
} while ( ! empty( $nav_menu_items_array ) );
$nav_menu_levels_reverse = array_reverse( $nav_menu_levels );
$nav_menu_tree_build = array();
$index = 0;
if ( ! empty( $nav_menu_levels_reverse ) ) do {
if ( count( $nav_menu_levels_reverse ) == 1 ) {
$nav_menu_tree_build = $nav_menu_levels_reverse;
}
$current_level = array_shift( $nav_menu_levels_reverse );
if ( isset( $nav_menu_levels_reverse[ $index ] ) ) {
$next_level = $nav_menu_levels_reverse[ $index ];
foreach ( $next_level as $nkey => $nval ) {
foreach ( $current_level as $ckey => $cval ) {
if ( $nval->db_id == $cval->menu_item_parent ) {
$nval->children[] = $cval;
}
}
}
}
} while ( ! empty( $nav_menu_levels_reverse ) );
$nav_menu_object_tree = $nav_menu_tree_build[ 0 ];
return $nav_menu_object_tree;
}
$nav_menu_items = wp_get_nav_menu_items( 'main-menu' );
wpse170033_nav_menu_object_tree( $nav_menu_items );
Array
(
[0] => WP_Post Object
(
[ID] => 51
[post_author] => 1
[post_date] => 2015-06-26 21:13:23
[post_date_gmt] => 2015-06-26 19:13:23
[post_content] =>
[post_title] =>
[post_excerpt] =>
[post_status] => publish
[comment_status] => open
[ping_status] => open
[post_password] =>
[post_name] => 51
[to_ping] =>
[pinged] =>
[post_modified] => 2015-07-29 20:55:10
[post_modified_gmt] => 2015-07-29 18:55:10
[post_content_filtered] =>
[post_parent] => 0
[guid] => http://example.com/?p=51
[menu_order] => 1
[post_type] => nav_menu_item
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
[db_id] => 51
[menu_item_parent] => 0
[object_id] => 2
[object] => page
[type] => post_type
[type_label] => Page
[url] => http://example.com/example-page/
[title] => Example-Page-1
[target] =>
[attr_title] =>
[description] =>
[classes] => Array
(
[0] =>
)
[xfn] =>
[children] => Array
(
[0] => WP_Post Object
(
[ID] => 80
[post_author] => 1
[post_date] => 2015-06-27 14:03:31
[post_date_gmt] => 2015-06-27 12:03:31
[post_content] =>
[post_title] =>
[post_excerpt] =>
[post_status] => publish
[comment_status] => open
[ping_status] => open
[post_password] =>
[post_name] => 80
[to_ping] =>
[pinged] =>
[post_modified] => 2015-07-29 20:55:10
[post_modified_gmt] => 2015-07-29 18:55:10
[post_content_filtered] =>
[post_parent] => 2
[guid] => http://example.com/?p=80
[menu_order] => 2
[post_type] => nav_menu_item
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
[db_id] => 80
[menu_item_parent] => 51
[object_id] => 69
[object] => page
[type] => post_type
[type_label] => Page
[url] => http://example.com/example-page/subpage-1/
[title] => Subpage-1
[target] =>
[attr_title] =>
[description] =>
[classes] => Array
(
[0] =>
)
[xfn] =>
[children] => Array
(
)
)
)
)
[1] => WP_Post Object
(
[ID] => 49
[post_author] => 1
[post_date] => 2015-06-26 21:13:23
[post_date_gmt] => 2015-06-26 19:13:23
[post_content] =>
[post_title] =>
[post_excerpt] =>
[post_status] => publish
[comment_status] => open
[ping_status] => open
[post_password] =>
[post_name] => 49
[to_ping] =>
[pinged] =>
[post_modified] => 2015-07-29 20:55:10
[post_modified_gmt] => 2015-07-29 18:55:10
[post_content_filtered] =>
[post_parent] => 0
[guid] => http://example.com/?p=49
[menu_order] => 3
[post_type] => nav_menu_item
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
[db_id] => 49
[menu_item_parent] => 0
[object_id] => 41
[object] => page
[type] => post_type
[type_label] => Page
[url] => http://example.com/example-page-2/
[title] => Example-Page-2
[target] =>
[attr_title] =>
[description] =>
[classes] => Array
(
[0] =>
)
[xfn] =>
[children] => Array
(
)
)
[2] => WP_Post Object
(
[ID] => 48
[post_author] => 1
[post_date] => 2015-06-26 21:13:23
[post_date_gmt] => 2015-06-26 19:13:23
[post_content] =>
[post_title] =>
[post_excerpt] =>
[post_status] => publish
[comment_status] => open
[ping_status] => open
[post_password] =>
[post_name] => 48
[to_ping] =>
[pinged] =>
[post_modified] => 2015-07-29 20:55:10
[post_modified_gmt] => 2015-07-29 18:55:10
[post_content_filtered] =>
[post_parent] => 0
[guid] => http://example.com/?p=48
[menu_order] => 4
[post_type] => nav_menu_item
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
[db_id] => 48
[menu_item_parent] => 0
[object_id] => 42
[object] => page
[type] => post_type
[type_label] => Page
[url] => http://example.com/example-page-3/
[title] => Example-Page-3
[target] =>
[attr_title] =>
[description] =>
[classes] => Array
(
[0] =>
)
[xfn] =>
[children] => Array
(
[0] => WP_Post Object
(
[ID] => 79
[post_author] => 1
[post_date] => 2015-06-27 14:03:31
[post_date_gmt] => 2015-06-27 12:03:31
[post_content] =>
[post_title] =>
[post_excerpt] =>
[post_status] => publish
[comment_status] => open
[ping_status] => open
[post_password] =>
[post_name] => 79
[to_ping] =>
[pinged] =>
[post_modified] => 2015-07-29 20:55:10
[post_modified_gmt] => 2015-07-29 18:55:10
[post_content_filtered] =>
[post_parent] => 42
[guid] => http://example.com/?p=79
[menu_order] => 5
[post_type] => nav_menu_item
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
[db_id] => 79
[menu_item_parent] => 48
[object_id] => 70
[object] => page
[type] => post_type
[type_label] => Page
[url] => http://example.com/example-page-3/subpage-2/
[title] => Subpage-2
[target] =>
[attr_title] =>
[description] =>
[classes] => Array
(
[0] =>
)
[xfn] =>
[children] => Array
(
[0] => WP_Post Object
(
[ID] => 78
[post_author] => 1
[post_date] => 2015-06-27 14:03:31
[post_date_gmt] => 2015-06-27 12:03:31
[post_content] =>
[post_title] =>
[post_excerpt] =>
[post_status] => publish
[comment_status] => open
[ping_status] => open
[post_password] =>
[post_name] => 78
[to_ping] =>
[pinged] =>
[post_modified] => 2015-07-29 20:55:10
[post_modified_gmt] => 2015-07-29 18:55:10
[post_content_filtered] =>
[post_parent] => 70
[guid] => http://example.com/?p=78
[menu_order] => 6
[post_type] => nav_menu_item
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
[db_id] => 78
[menu_item_parent] => 79
[object_id] => 76
[object] => page
[type] => post_type
[type_label] => Page
[url] => http://example.com/example-page-3/subpage-2/subpage-3/
[title] => Subpage-3
[target] =>
[attr_title] =>
[description] =>
[classes] => Array
(
[0] =>
)
[xfn] =>
[children] => Array
(
[0] => WP_Post Object
(
[ID] => 87
[post_author] => 1
[post_date] => 2015-06-27 15:27:08
[post_date_gmt] => 2015-06-27 13:27:08
[post_content] =>
[post_title] =>
[post_excerpt] =>
[post_status] => publish
[comment_status] => open
[ping_status] => open
[post_password] =>
[post_name] => 87
[to_ping] =>
[pinged] =>
[post_modified] => 2015-07-29 20:55:10
[post_modified_gmt] => 2015-07-29 18:55:10
[post_content_filtered] =>
[post_parent] => 76
[guid] => http://example.com/?p=87
[menu_order] => 7
[post_type] => nav_menu_item
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
[db_id] => 87
[menu_item_parent] => 78
[object_id] => 85
[object] => page
[type] => post_type
[type_label] => Page
[url] => http://example.com/example-page-3/subpage-2/subpage-3/subpage-4/
[title] => Subpage-4
[target] =>
[attr_title] =>
[description] =>
[classes] => Array
(
[0] =>
)
[xfn] =>
[children] => Array
(
[0] => WP_Post Object
(
[ID] => 366
[post_author] => 1
[post_date] => 2015-07-29 20:52:46
[post_date_gmt] => 2015-07-29 18:52:46
[post_content] =>
[post_title] =>
[post_excerpt] =>
[post_status] => publish
[comment_status] => open
[ping_status] => open
[post_password] =>
[post_name] => 366
[to_ping] =>
[pinged] =>
[post_modified] => 2015-07-29 20:55:10
[post_modified_gmt] => 2015-07-29 18:55:10
[post_content_filtered] =>
[post_parent] => 85
[guid] => http://example.com/?p=366
[menu_order] => 8
[post_type] => nav_menu_item
[post_mime_type] =>
[comment_count] => 0
[filter] => raw
[db_id] => 366
[menu_item_parent] => 87
[object_id] => 112
[object] => page
[type] => post_type
[type_label] => Page
[url] => http://example.com/example-page-3/subpage-2/subpage-3/subpage-4/subpage-5/
[title] => Subpage-5
[target] =>
[attr_title] =>
[description] =>
[classes] => Array
(
[0] =>
)
[xfn] =>
[children] => Array
(
)
)
)
)
)
)
)
)
)
)
)
元のフラット配列の正しい順序を維持するためにメニュー項目のmenu_order
プロパティを考慮に入れた、受け入れられた回答の修正版。 menu_order
はWordPressによって自動的に設定されるので、何もチェックする必要はありません。
function buildTree(array &$flatNav, $parentId = 0) {
$branch = [];
foreach ($flatNav as &$navItem) {
if($navItem->menu_item_parent == $parentId) {
$children = buildTree($flatNav, $navItem->ID);
if($children) {
$navItem->children = $children;
}
$branch[$navItem->menu_order] = $navItem;
unset($navItem);
}
}
return $branch;
}
使用法:
// get navs
$locations = get_nav_menu_locations();
// get menu items by menu name
$flatMainNav = wp_get_nav_menu_items($locations['main']);
$mainNav = buildTree($flatMainNav);