How to set wordpress menu if you have menu arrays

Let’s say I have an array that I got by outputting wp_get_nav_menus() (and some modifications), and I want to import it to a new installation of wordpress. The array looks like this (let’s call it $menu_array):

Array
(
    [0] => Array
        (
            [term_id] => 5
            [name] => my second menu
            [slug] => my-second-menu
            [term_group] => 0
            [term_taxonomy_id] => 5
            [taxonomy] => nav_menu
            [description] => 
            [parent] => 0
            [count] => 2
            [items] => Array
                (
                    [0] => Array
                        (
                            [ID] => 14
                            [post_author] => 1
                            [post_date] => 2015-10-06 07:32:03
                            [post_date_gmt] => 2015-10-06 07:32:03
                            [post_content] => 
                            [post_title] => This is my menu
                            [post_excerpt] => 
                            [post_status] => publish
                            [comment_status] => closed
                            [ping_status] => closed
                            [post_password] => 
                            [post_name] => this-is-my-menu
                            [to_ping] => 
                            [pinged] => 
                            [post_modified] => 2015-10-12 10:31:23
                            [post_modified_gmt] => 2015-10-12 10:31:23
                            [post_content_filtered] => 
                            [post_parent] => 0
                            [guid] => http://www.example.com/?p=14
                            [menu_order] => 1
                            [post_type] => nav_menu_item
                            [post_mime_type] => 
                            [comment_count] => 0
                            [filter] => raw
                            [db_id] => 14
                            [menu_item_parent] => 0
                            [object_id] => 14
                            [object] => custom
                            [type] => custom
                            [type_label] => Custom Link
                            [title] => This is my menu
                            [url] => #
                            [target] => 
                            [attr_title] => 
                            [description] => 
                            [classes] => Array
                                (
                                    [0] => 
                                )

                            [xfn] => 
                        )

                    [1] => Array
                        (
                            [ID] => 15
                            [post_author] => 1
                            [post_date] => 2015-10-06 07:32:03
                            [post_date_gmt] => 2015-10-06 07:32:03
                            [post_content] => 
                            [post_title] => second menu
                            [post_excerpt] => 
                            [post_status] => publish
                            [comment_status] => closed
                            [ping_status] => closed
                            [post_password] => 
                            [post_name] => second-menu
                            [to_ping] => 
                            [pinged] => 
                            [post_modified] => 2015-10-12 10:31:23
                            [post_modified_gmt] => 2015-10-12 10:31:23
                            [post_content_filtered] => 
                            [post_parent] => 0
                            [guid] => http://www.example.com/?p=15
                            [menu_order] => 2
                            [post_type] => nav_menu_item
                            [post_mime_type] => 
                            [comment_count] => 0
                            [filter] => raw
                            [db_id] => 15
                            [menu_item_parent] => 0
                            [object_id] => 15
                            [object] => custom
                            [type] => custom
                            [type_label] => Custom Link
                            [title] => second menu
                            [url] => #
                            [target] => 
                            [attr_title] => 
                            [description] => 
                            [classes] => Array
                                (
                                    [0] => 
                                )

                            [xfn] => 
                        )

                )

        )

    [1] => Array
        (
            [term_id] => 2
            [name] => My Menu
            [slug] => my-menu
            [term_group] => 0
            [term_taxonomy_id] => 2
            [taxonomy] => nav_menu
            [description] => 
            [parent] => 0
            [count] => 3
            [items] => Array
                (
                    [0] => Array
                        (
                            [ID] => 1104
                            [post_author] => 1
                            [post_date] => 2015-10-19 13:31:48
                            [post_date_gmt] => 2015-10-19 13:31:48
                            [post_content] =>  
                            [post_title] => 
                            [post_excerpt] => 
                            [post_status] => publish
                            [comment_status] => closed
                            [ping_status] => closed
                            [post_password] => 
                            [post_name] => 1104
                            [to_ping] => 
                            [pinged] => 
                            [post_modified] => 2015-10-19 13:31:48
                            [post_modified_gmt] => 2015-10-19 13:31:48
                            [post_content_filtered] => 
                            [post_parent] => 0
                            [guid] => http://www.example.com/?p=1104
                            [menu_order] => 1
                            [post_type] => nav_menu_item
                            [post_mime_type] => 
                            [comment_count] => 0
                            [filter] => raw
                            [db_id] => 1104
                            [menu_item_parent] => 0
                            [object_id] => 1016
                            [object] => page
                            [type] => post_type
                            [type_label] => Page
                            [url] => http://www.example.com/Test-page
                            [title] => Test page
                            [target] => 
                            [attr_title] => 
                            [description] =>  
                            [classes] => Array
                                (
                                    [0] => 
                                )

                            [xfn] => 
                        )

                    [1] => Array
                        (
                            [ID] => 12
                            [post_author] => 1
                            [post_date] => 2015-10-05 13:52:35
                            [post_date_gmt] => 2015-10-05 13:52:35
                            [post_content] => 
                            [post_title] => Google
                            [post_excerpt] => 
                            [post_status] => publish
                            [comment_status] => closed
                            [ping_status] => closed
                            [post_password] => 
                            [post_name] => google
                            [to_ping] => 
                            [pinged] => 
                            [post_modified] => 2015-10-19 13:31:48
                            [post_modified_gmt] => 2015-10-19 13:31:48
                            [post_content_filtered] => 
                            [post_parent] => 0
                            [guid] => http://www.example.com/?p=12
                            [menu_order] => 2
                            [post_type] => nav_menu_item
                            [post_mime_type] => 
                            [comment_count] => 0
                            [filter] => raw
                            [db_id] => 12
                            [menu_item_parent] => 0
                            [object_id] => 12
                            [object] => custom
                            [type] => custom
                            [type_label] => Custom Link
                            [title] => Google
                            [url] => http://google.com
                            [target] => 
                            [attr_title] => 
                            [description] => 
                            [classes] => Array
                                (
                                    [0] => 
                                )

                            [xfn] => 
                        )

                    [2] => Array
                        (
                            [ID] => 13
                            [post_author] => 1
                            [post_date] => 2015-10-06 07:22:39
                            [post_date_gmt] => 2015-10-06 07:22:39
                            [post_content] => 
                            [post_title] => Gmail
                            [post_excerpt] => 
                            [post_status] => publish
                            [comment_status] => closed
                            [ping_status] => closed
                            [post_password] => 
                            [post_name] => gmail
                            [to_ping] => 
                            [pinged] => 
                            [post_modified] => 2015-10-19 13:31:48
                            [post_modified_gmt] => 2015-10-19 13:31:48
                            [post_content_filtered] => 
                            [post_parent] => 0
                            [guid] => http://www.example.com/?p=13
                            [menu_order] => 3
                            [post_type] => nav_menu_item
                            [post_mime_type] => 
                            [comment_count] => 0
                            [filter] => raw
                            [db_id] => 13
                            [menu_item_parent] => 12
                            [object_id] => 13
                            [object] => custom
                            [type] => custom
                            [type_label] => Custom Link
                            [title] => Gmail
                            [url] => #
                            [target] => 
                            [attr_title] => 
                            [description] => 
                            [classes] => Array
                                (
                                    [0] => 
                                )

                            [xfn] => 
                        )

                )

        )

)

This is for one menu called ‘my menu’ that has 2 pages in it, I can have multiple arrays for multiple menus, and the hierarchy follows that of the menu.

Read More

I looked a bit into how wordpress handles importing it, and it uses wp_update_nav_menu_item() and wp_nav_menu_update_menu_items().

I tried that, but so far I didn’t have any luck.

But since wordpress menus are post type nav_menu_item with custom taxonomy nav_menu, can I just use wp_insert_post to import my menus, or is there some complicated way to do it (like do I need to set object terms for each menu)?

I just need some pointers on how to insert menus in the correct way.

PARTIAL SOLUTION

So I found this link, and I’m close to achieving what I need. I did it like this

foreach ($menu_array as $menu => $menu_val) {
    // Check if the menu exists
    $old_menu_id = $menu_val['term_id'];
    $menu_location = '';
    foreach (get_theme_mod('nav_menu_locations') as $old_menu_loc => $loc_id) {
        if ($old_menu_id == $loc_id) {
            $menu_location .= $old_menu_loc;
        }
    }
    $menu_name = $menu_val['name'];
    $menu_exists = wp_get_nav_menu_object( $menu_name );
    // If it doesn't exist, let's create it.
    if( !$menu_exists){
        $menu_id = wp_create_nav_menu($menu_name);
        $old_object_id = array();
        // Set up default menu items
        foreach ($menu_val['items'] as $item => $item_value) {

            $old_url = $item_value['url'];
            $old_object_id[] .= $item_value['object_id'];

            $new_url = (isset($url_relation_table[$old_url]) && $url_relation_table[$old_url]>0) ? $url_relation_table[$old_url] : $old_url;

            $menu_data = array(
                'menu-item-db-id' => 0,
                'menu-item-object-id' => '',
                'menu-item-object' => $item_value['object'],
                'menu-item-parent-id' => 0,
                'menu-item-position' => $item_value['menu_order'],
                'menu-item-title' => $item_value['title'],
                'menu-item-type' =>  $item_value['type'], //when removed no error but also no menu type!
                'menu-item-url' => ($new_url != '') ? $new_url : '#',
                'menu-item-description' => $item_value['description'],
                'menu-item-attr-title' => $item_value['attr_title'],
                'menu-item-target' => $item_value['target'],
                'menu-item-classes' => implode(' ', $item_value['classes']),
                'menu-item-xfn' => $item_value['xfn'],
                'menu-item-status' => $item_value['post_status'],
                );
            wp_update_nav_menu_item($menu_id, 0, $menu_data);

        }

        $new_menu_item = wp_get_nav_menu_items($menu_id);
        $new_object_id = array();
        foreach ($new_menu_item as $new_item => $new_item_value) {
            $new_object_id[] .= $new_item_value->ID;
        }
        $object_id_relation_array = array_combine($old_object_id, $new_object_id);

        $menu_obj_data = array(
            'description' => $menu_val['description'],
            'menu-name' => $menu_val['name'],
            'parent' => $menu_val['parent'],
            );
        wp_update_nav_menu_object($menu_id, $menu_obj_data);
    }

    $locations = array();
    if ($menu_location != '') {
        $locations[$menu_location] = $menu_id;
        set_theme_mod( 'nav_menu_locations', $locations );
    }

}

EDIT: This last piece of code will set my menu to one of the locations (I don’t think it’s the correct one). The $menu_location array is just location name slug as a key and name as a value (they are defined in the theme so they exist).

This code creates menus, and assigns the first one to one location, but no pages are linked.

EDIT2: I’ve edited the foreach a bit, included the menu location that actually works. But there are some things that aren’t working. I cannot get the urls to show on my menus, and menu hierarchy isn’t working (parent->child relation).

The thing that bothers me is the array $menu_data. I put all these keys that I’m not sure are even valid. For instance url and parent-id. All the developer page says about it is that it’s an array of menu item’s data (well duuuh). It would be helpful if I could see what keys I need and can put inside…

EDIT3: So I got rid of my errors (classes need to be a string separated by a space), but I’m not sure why my hierarchy won’t work, and why I don’t get an url field. I need to go through nav-menus.php in more detail and see what I’m missing.

EDIT4: Ok, so it almost works! For some reason I get notices:

Notice: Trying to get property of non-object in C:xampphtdocstestwp-includesnav-menu.php on line 404

Notice: Trying to get property of non-object in C:xampphtdocstestwp-includesnav-menu.php on line 405

Notice: Trying to get property of non-object in C:xampphtdocstestwp-includesnav-menu.php on line 712

When I remove $item_value['type'] everything works, but I don’t get the post types for my menues so all are custom, without links, so in a nutshell, it doesn’t work xD

The other thing that is really bothering me is that I can’t get the hierarchy to work. So when I import my menu, I’ll get that the menu_item_parent is ID of the menu item object (if it is). In my example, the last menu with object id 13 is the child of menu item with object id 12, so his menu_item_parent is 12. This changes when you create a new menu. So I’ve created a relational table that relates old menu id’s with the new ones. But I’m stuck on how to update just that. When I try updating the menu again, I wreck everything out. I managed to replace urls (I have url relation table that has old and new urls in it), and this works, but since menu items are created from nothing, I cannot just go and check what id they have now, unless they’re done with it. So I’m stuck here atm…

Related posts

1 comment

  1. Ok so I sloved it, after a lot of messing around with it.

    <?php
    
    foreach ($menu_array as $menu => $menu_val) {
        // Check if the menu exists
        $old_menu_id = $menu_val['term_id'];
        $menu_location = '';
        foreach (get_theme_mod('nav_menu_locations') as $old_menu_loc => $loc_id) {
            if ($old_menu_id == $loc_id) {
                $menu_location .= $old_menu_loc;
            }
        }
        $menu_name = $menu_val['name'];
        $menu_exists = wp_get_nav_menu_object( $menu_name );
        // If it doesn't exist, let's create it.
        if( !$menu_exists){
            $menu_id = wp_create_nav_menu($menu_name);
            $old_object_id = array();
    
            //Set up default menu items
            foreach ($menu_val['items'] as $item => $item_value) {
    
                $old_url = $item_value['url'];
                $old_object_id[] .= $item_value['object_id'];
    
                $new_url = (isset($url_relation_table[$old_url])) ? $url_relation_table[$old_url] : $old_url;
    
                $obj_ID = url_to_postid($new_url);
    
                $menu_data = array(
                    'menu-item-db-id' => '',
                    'menu-item-object-id' => ( $obj_ID != 0 ) ? $obj_ID : '',
                    'menu-item-object' => $item_value['object'],
                    'menu-item-parent-id' => $item_value['menu_item_parent'],
                    'menu-item-position' => $item_value['menu_order'],
                    'menu-item-title' => $item_value['title'],
                    'menu-item-type' =>  $item_value['type'],
                    'menu-item-url' => ($new_url != '') ? $new_url : '#',
                    'menu-item-description' => $item_value['description'],
                    'menu-item-attr-title' => $item_value['attr_title'],
                    'menu-item-target' => $item_value['target'],
                    'menu-item-classes' => implode(' ', $item_value['classes']),
                    'menu-item-xfn' => $item_value['xfn'],
                    'menu-item-status' => $item_value['post_status'],
                    );
                wp_update_nav_menu_item($menu_id, 0, $menu_data);
    
            }
    
            $new_menu_item = wp_get_nav_menu_items($menu_id);
            $new_object_id = array();
            $parent_id = array();
    
            foreach ($new_menu_item as $new_item => $new_item_value) {
                $new_object_id[] .= $new_item_value->ID;
                $parent_id[] .= $new_item_value->menu_item_parent;
            }
    
            $object_id_relation_array = array_combine($old_object_id, $new_object_id);
            $parent_relation_array = array_combine($new_object_id, $parent_id);
    
            foreach ($object_id_relation_array as $object_id_relation_key => $object_id_relation_value) {
                foreach ($parent_id as $parent_id_key => $parent_id_value) {
                    if ($object_id_relation_key == $parent_id_value) {
                        $new_parent_id = $object_id_relation_value;
                        $item_id = array_search($parent_id_value, $parent_relation_array);
    
                        foreach ($new_menu_item as $single_item => $single_item_value) {
                            if ($single_item_value->ID == $item_id) {
                                $object = $single_item_value->object;
                                $object_ID = $single_item_value->object_id;
                                $position = $single_item_value->menu_order;
                                $title = $single_item_value->title;
                                $type = $single_item_value->type;
                                $url = $single_item_value->url;
                                $description = $single_item_value->description;
                                $attr_title = $single_item_value->attr_title;
                                $target = $single_item_value->target;
                                $classes = implode(' ', $single_item_value->classes);
                                $xfn = $single_item_value->xfn;
                                $status = $single_item_value->post_status;
    
                                $update_parent_id = array(
                                        'menu-item-db-id' => $item_id,
                                        'menu-item-object-id' => $object_ID,
                                        'menu-item-object' => $object,
                                        'menu-item-parent-id' => $new_parent_id,
                                        'menu-item-position' => $position ,
                                        'menu-item-title' => $title ,
                                        'menu-item-type' =>  $type ,
                                        'menu-item-url' => $url ,
                                        'menu-item-description' => $description ,
                                        'menu-item-attr-title' => $attr_title ,
                                        'menu-item-target' => $target ,
                                        'menu-item-classes' => $classes ,
                                        'menu-item-xfn' => $xfn ,
                                        'menu-item-status' => $status ,
                                    );
                                wp_update_nav_menu_item($menu_id, $item_id, $update_parent_id);
                            }
                        }
    
    
                    }
                }
            }
    
            $menu_obj_data = array(
                'description' => $menu_val['description'],
                'menu-name' => $menu_val['name'],
                'parent' => $menu_val['parent'],
                );
            wp_update_nav_menu_object($menu_id, $menu_obj_data);
        }
    
        $locations = array();
        if ($menu_location != '') {
            $locations[$menu_location] = $menu_id;
            set_theme_mod( 'nav_menu_locations', $locations );
        }
    
    }
    

    So to explain a bit.

    First you need to get the menu locations (which are available from theme mods that you can also put in an array), then you create a menu. Creating a menu, even if from pre existing names will create a brand new menu with new ID. And more importantly, the menu items will also have new ID’s. Which complicates things a bit.

    After that, you list through your existing items, and start updating new items one by one in a foreach loop. But you also need to have some kind of relation table that will have relations between old urls and new ones. This is very important, since the posts on your previous export don’t have the same url as the new place.

    But if you have it, then you just pull those relations, and place new url in a menu item. Also if your menu item is a page, then you need to put it’s ID where menu-item-object-id is. This is really important, because if you don’t do that you’ll get a notice thrown about not being able to get the property of non object from wordpress nav-menu.php. This is where url_to_postid() function comes in handy. Just put your url there and you’ll get the id of the post, or if it doesn’t you’ll get 0.

    Now you’ve build your menu, and you’re happy. But wait! What about hierarchy?

    What you put in the new menus is the old relations between menus. With old ID’s. And that clearly won’t work, since when you update menu items, you get new ID’s. So you need a new relational table that will connect old with the new ID’s, and you’ll also need a way to see what menu items have those parent-id‘s in them, so that you can pull all the information anew.

    The thing is, you’ve already created your menu, so you need to check again for those relations, and replace them, and the best thing is just to see what menus have such relations, and only update those menus (this is why you have 2 wp_update_nav_menu_item() calls).

    After that you can update nav menu objects (altho I’m not sure this is really needed, but I see no errors so why not), and set the menu to the correct location.

    I only need to check for multiple submenues, and some specifics. But for now this works 🙂

Comments are closed.