Wordpress - Convert output of nav_menu items into a tree-like multidimensional array
The problem of building a tree from a flat array has been solved here with this, slightly modified, recursive solution:
/**
* 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;
}
where we added the prefixed wpse_children
attribute to avoid name collision.
Now we only have to define a simple helper function:
/**
* 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;
}
Now it becomes super easy to transform a navigational menu into it's tree structure with:
$tree = wpse_nav_menu_2_tree( 'my_menu' ); // <-- Modify this to your needs!
print_r( $tree );
For JSON, we can simply use:
$json = json_encode( $tree );
For a slightly different version, where we handpicked the attributes, check out the first revision of this answer here.
Update: Walker Class
Here's a rather sketchy idea how we could try to hook into the recursive part of the the display_element()
method of the abstract Walker
class.
$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 );
where WPSE_Nav_Menu_Tree
is an extension of the Walker_Nav_Menu
class:
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);
}
}
This might give us an alternative approach if it works.
In short the function bellow does create the tree of objects by putting children into a new children property inside the parent object.
Code:
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;
}
Usage:
$nav_menu_items = wp_get_nav_menu_items( 'main-menu' );
wpse170033_nav_menu_object_tree( $nav_menu_items );
Output:
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
(
)
)
)
)
)
)
)
)
)
)
)