The new navigation menu module in WordPress 3.0 is great. It’s a piece of cake to add and remove menu items from the admin interface. But what if you want to add pages automatically when a new page is created. There’s an option to add top level pages automatically, but what if you want to add subpages automatically? Read on to find out how to do just that. It’s easier than you think.
Creating navigation menus programmatically (yes, it’s a real word) is particularly useful when testing your theme or plugin and for websites that have a large number of pages. Instead of having to manually create your menus, you can write a small code snippet to do it for you.
The function you need for this operation is wp_update_nav_menu_item
and it’s defined in /wp-includes/nav-menu.php.
wp_update_nav_menu_item( $menu_id = 0, $menu_item_db_id = 0, $menu_item_data = array() )
$menu_id
is the id of the menu you are adding a new item to.
$menu_item_db_id
Use 0 to create a new menu item.
$menu_item_data
is an array containing data about the new menu item. See below.
Example
In the code below, I am adding a new menu item for the page titled “About Us” to the menu named “Main Navigation Menu”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $mymenu = wp_get_nav_menu_object('Main Navigation Menu'); $menuID = (int) $mymenu->term_id; $myPage = get_page_by_title('About Us'); itemData = array( 'menu-item-object-id' => $myPage->ID, 'menu-item-parent-id' => 0, 'menu-item-position' => 2, 'menu-item-object' => 'page', 'menu-item-type' => 'post_type', 'menu-item-status' => 'publish' ); wp_update_nav_menu_item($menuID, 0, $itemData); |
First we need to get the id of the menu we are adding a new item to. You can either look it up by name using wp_get_nav_menu_object()
and passing the name of the menu (not the unique id) as in the example above or you can hover over the menu’s tab in the admin interface and look at the status bar of your browser. This only works if the menu’s tab is inactive (i.e. you’re looking at another menu).
Next we need to get the ID of the page we are creating a menu item for. This too can be done in code (see line 3 above) or using the same hover trick described in the last paragraph. On the Pages page, simply hover over the name of the page to see the id in the status bar.
On line 5, we have to create an array containing information about the new menu item. Each field is described below.
menu-item-object-id
This is the page id we are creating a menu item for.
menu-item-parent-id
Pass in 0 to create a top level menu item.
If you want to nest this menu item under another menu item to create a sub menu, pass the parent menu item’s id. To get an existing menu item’s id, hover over the menu item on the Menu’s screen and look in the status bar of your browser. You have to hover over the arrow on the right side of the menu item to see the id.
menu-item-position
This sets the the position of the menu item. Strangely, the number represents the position from the top of the menu regardless of whether it is a nested item or not. See the image below. The first position is 1. Setting this field to 0 will append the item to the end of the menu, or to the last child element if nesting this item in a sub menu. I expect this to change in the future. It would be much more useful if this were relative to items on the same sub menu.
menu-item-object
Specifies that the menu item represents a page. Omitting this will not prevent the menu item from being created, but it does remove the word “Page” from the menu item and I’m sure there are other consequences. If anyone knows more about this field, let me know in the comments. Hopefully, we’ll see some documentation soon that will better describe this property.
menu-item-type
Passing in ‘post-type’ for this field instructs WordPress to fill in details such as page url and title from the existing page or post.
I haven’t experimented with any other menu-item-type’s, but apparently, you can pass in ‘custom’ or ‘taxonomy’ to create different types of menu items. If using these other types, you would need to provide more information such as url and title. See nav-menu.php to find out what else is needed in this case.
menu-item-status
If not set to ‘publish’, WordPress will add the menu item as a “draft” item and the menu would need to be saved manually on the menu screen before it is visible on your menu.
Finally, on line 13 we call wp_update_nav_menu_item()
to create the menu item. The page should now appear in your menu. Make sure you only execute this once. If you don’t comment out this call after running it, it will continue to create new menu items every time you refresh a page on your site.
And that’s it. Let me know if this was helpful by leaving a comment.
Excellent article! The WP documentation definitely falls short on the topic.
One quick note on the ‘menu-item-object’ key – I believe that it’s value is meant to be an actual post-type.
In my own implementation based on your example, I’m adding menu items for a custom ‘product’ post-type. The post-type itself is internally recognized as ‘ar_product’ while being recognized by the label ‘product’ or ‘products’ externally. Supplying ‘ar_product’ to ‘menu-item-object’ correctly labels the new menu items with ‘Product’.
Apart from that, though, I’m not sure as to any other consequences.
Hi there, there’s not a lot of information on real world usage of custom menus. Thanks for this. My question is: how do you programmatically hook this menu to your theme’s registered nav menu?
There’s an easy way to do that using wp_nav_menu() and register_nav_menus() you can find those functions in WordPress.org.
wp_nav_menu() allow you to get created menus and register_nav_menus() allows you to register menus
Hope it helps.
i’m new to wordpress but not php programming and other cms’.
1) how do you “run one time”. do you just inssert the code you want in functions.php and then reload any page on your site (one time) or is there some other procedure.
2) this function seems helpful but if you have to look up all your page info before you create your arrays, it’s probably just as fast to do this by drag n drop (by hand) in the admin menu. what would be better is to import a bunch of pages from scratch where you create them as you create the menu. i guess we’d need a loop and a nested array to do this.
any thoughts welcome
btw, nice post
This was super-helpful. Thanks!
Couple of quick notes. If you want to add a URL, you can do this:
$itemData = array(
‘menu-item-status’ => ‘publish’,
‘menu-item-url’ => “http://www.foo.com/”,
‘menu-item-title’ => “Visit foo.com”,
);
For pages, position and parent are optional, and you can do this:
$menuItem = array(
‘menu-item-object-id’ => $post_id,
‘menu-item-object’ => ‘page’,
‘menu-item-type’ => ‘post_type’,
‘menu-item-status’ => ‘publish’,
‘menu-item-title’ => “Excitement”
);
Thank you so much for this post..:) ive got mine wnroikg now for my subscribe link..:)Good Job!
Hello,
Thank you for this useful post.
I don’t find how to do the opposite: remove item menu from the custom menu programmatically.
For instance if I remove a page, I would like to remove the corresponding item menu from the custom menu.
Any idea ?
No words to express less than “Excellent Post…”