nav_menuアイテムの出力をツリーのような多次元配列に変換します


11

navメニュー項目をフラット配列ではなく多次元配列として取得する方法はありますか?

ツリーのような構造とは、子アイテムと親アイテムの関係を維持するようなものを意味します(これは単なる例です)…

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()、パフォーマンスの観点から、ツリーのような構造として多次元配列に入れる最良の方法は何ですか?


3
その1次元配列には、再帰関数を使用する場合にツリーを構築するために必要なすべてのデータが含まれています。各メニュー項目IDについて、オブジェクトの親フィールドで一致するIDを持つ他のメニュー項目を探します。これらはその子になります。
Milo

私はそれから木を作ることができることを知っていますが、wpにそのようなオプションがすでにあるかどうか疑問に思っていました。
YemSalat 14

あなたのユースケースは何ですか?Walkerクラスは、アレイが平坦であっても、自動的にソートされたNAVのメニュー項目の深さを扱います。
Matt van Andel、2015

1
あなたの編集は間違っています。タイトルを編集し直しました(いくつかの単語を変更しました)nav_itemsの出力はフラット配列であり、いかなる意味でもツリーではありません。私の使用例は-ナビゲーションアイテムをツリーとして欲しいので、WPの壊れた抽象化を使用せずに、自分でそれを使用してシンを実行できます。
YemSalat 2015

質問を少し明確にし、自分が何を望んでいるかをより明確にしました。
YemSalat 2015

回答:


21

問題平らな配列からツリーを構築するには、解決されているここでは、わずかに変更され、これを再帰的なソリューションを:

/**
 * 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名前の衝突を避けるためにprefixed 属性を追加しました。

これで、単純なヘルパー関数を定義するだけで済みます。

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

属性を厳選したわずかに異なるバージョンについては、この回答の最初のリビジョンをこちらで確認してください

更新:ウォーカークラス

ここでdisplay_element()は、抽象Walkerクラスのメソッドの再帰部分にフックする方法について、かなり大雑把なアイデアを示します。

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

これが機能する場合は、別の方法が考えられます。


おかげで、問題解決へのさまざまなアプローチを見るのはいつも面白くて楽しいです-あなたの見た目はかなりクールに見えます+1。@ialocin
バージリー2015

1
ここでも同じですが、誰が投票したかはすでにわかっていました:)可能性を探ることは楽しいです!残りは、多くの場合、組み立てラインの作業に似ています。つまり、...面白くないと言いましょう。
Nicolai

おかげで、このための「ネイティブな」WP関数があることを望んでいました。誰かが他の解決策を投稿するかどうか、もう少し待ってみます。そうでなければ、これが選ばれた答えになります。
YemSalat 2015

私は別の種類のアプローチ@YemSalatで答えを更新しました
バージリー

うわあ!それは私の心を渦巻かせます。私はこれまでウォーカークラスを扱ったことはありませんでした(ただし、存在することはわかっています)いくつかのSQLクエリを使用してパフォーマンスを向上させる方法があることを望んでいましたが、WP db構造には入りたくありません。今のところ、wp_get_nav_menu_items再帰的に循環する最初のアプローチをお勧めします。
YemSalat 2015

3

つまり、次の関数は、親オブジェクト内の新しい子プロパティに子を配置することで、オブジェクトのツリーを作成します。

コード:

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

WordPressのツリーのような構造は、多次元配列ではありません。これは、親子関係情報を持つオブジェクトの配列です。
Matt van Andel、2015

この問題について約10種類のソリューションを試しました。この素晴らしい解決策をありがとう、それはそれを素晴らしいWPオブジェクト構造に保ちます。これは実際に受け入れられる必要があります!
Drmzindec 2017

@JohanPretoriusありがとうございます。まあ人々は別のものを探しています。OPは他の回答がより役に立ったと思います。大丈夫だよー。
Nicolai

1

menu_order元のフラットアレイの適切な順序を維持するためにメニュー項目のプロパティを考慮に入れる、受け入れられた回答の修正バージョン。menu_orderWordPressによって自動的に設定されるため、何もチェックする必要はありません。

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

-2

ここでは、WordPressのナビゲーションメニュー項目をツリー状の構造として誤解している可能性があります。

WordPressのツリーのような構造は多次元配列ではありません!

返されるメニューアイテムの配列はフラットですが、各アイテムにはその親子関係に関する情報が含まれているため、ツリーのような構造です(アイテムに親がない場合、親の値は0または親アイテムのIDである場合)。します)。

そのような配列をWalkerクラスに渡すと、結果がループして2つの配列が作成されます。1つはトップレベルの項目を含み、もう1つ$parent_id => array()はその要素の直接の子であるメニュー項目を含む形式の子項目を含みます。

次に、walkerは最上位のitems配列をループし、その項目を処理してから、children配列をチェックして、現在の要素に子があるかどうかを確認し、それぞれを同じ方法で再帰的に処理します。

WordPressのツリーのような構造を多次元配列に変換する方法を知りたい場合、それはまったく別の質問です(技術的にはWordPressの質問ではありません)。しかしによって返された情報がwp_get_nav_menu_items() あるツリー状の構造...あなたが使用することができWalker、それを処理するためにそのまま。

WordPressのWalkerクラスが配列をウォークするために実行する正確なコードを確認したい場合は、行213-258からWordPress TracのWalker-> walk()を見てください。そのコードが必要な場合は、そのコードをそのまま使用して多次元配列を構築できます。

ウォーカー

WordPressは、Walkerクラスを使用してツリーのような構造を処理するように設計されています。メニューをレンダリングするだけの場合、または本当に最終的な出力が必要なだけの場合は、を使用wp_nav_menu()してメニューを出力することを検討してください。

例:

wp_nav_menu(array(
    'menu' => 6, // your menu id, name, or slug
    'echo' => true, // set this to false if you want a string back instead
    'walker' => new Your_Walker(),
));

Walkerクラス(例:)を拡張して、Your_Walker()必要な出力を取得します。例については、コーデックスのこのエントリを参照してください


2
オプションAでは、$sorted_menu_itemsは依然として「フラット」配列であり、オプションBの出力は文字列です。
バージィ2015

WordPressが「ツリーのような構造」を定義する方法について誤解があると思います。wp_get_nav_menu_items()ツリーのような構造、つまり、各アイテムに親子関係のデータが含まれる配列を返します。これらの構造は、Walkerクラスで。ここでのユースケースが「フラット」配列を親子関係データに基づく多次元配列に変換するだけの場合(例:)'post_parent' => 123、この質問は技術的にWordPressに関するものではなく、スタックオーバーフローに移動する必要があります。
Matt van Andel、2015

1
見て、WordPressが「ツリーのような構造」を定義していることは気にしません(私はこの文章が意味をなしていても意味がないと思います)私が気にしているのは、多次元配列を持っていることです。
YemSalat 2015

あなたはそれをWordPressのデフォルトの動作として取得するつもりはありません。他の人が述べたように、あなたはあなたが望むように配列を再構成するために必要なすべての情報を持っています、そして私はリファレンスとして使用するためにWordPressコアの特定の領域にあなたをリンクしました。これは実際にはPHPの質問ほどWordPressの質問ではありません。Walkerクラスをそのまま使用するか、前述のように関連する行をWalker :: walk()からコピーして、配列を作成できます。
Matt van Andel、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.