There are many good tutorials to build custom menus for logged in/logged out users, see also our own post on the ajax login menu. There are more complex approaches in order to customise the individual menu items using a the wordpress Walker class. An excellent review of a custom walker can be found on the WordPress StackExchange.
However, I was looking to actually add menu items dynamically depending on the state of the site. In this case, we have a client, a research centre at a university who asked us to redevelop their site as a portal of all their conference sites. We created a WordPress MU portal which we customised to enable them to create new conference sites based on a template site that is pre-configured, enabling registration forms, abstract submission forms, payment gateways to be created for each new conference at the press of a button in the Dashboard.
One of the challenges was to dynamically add new conference sites to the main site menu as when they are created. Furthermore, the conference menu has a Past sub-menu in which old conferences need to be listed.
I decided to use the Walker extension solution by adding a little customisation. I created a new class,
AddExtraMenuItems_Walker, which extends the WordPress core Walker_Nav_Menu class.
So the Walker class is simply called in the wordpress function to display a menu structure,
wp_nav_menu( array('walker'=> new AddExtraMenuItems_Walker($extra_menu), 'theme_location' => 'primary-menu', 'container' => '', 'fallback_cb' => '', 'menu_class' => 'my-menu-class', 'menu_id' => 'top-menu', 'echo' => false ) );
Remains to define the $extra_menu array arguments that are passed to the walker in order to insert it into the right menu. Here is an example. It assumes that there is a primary menu created in the Dashboard with the top level menu item ‘Conferences’ and a sub-item below this called ‘Past’,
$extra_menu = array( 'Conferences'=>array(array('title'=>'ISOl 2015', 'url' => 'http://syllogic.asia/2015/', 'id' => 'menu_item_isol_2', 'class'=> 'menu-item menu-item-type-custom menu-item-object-custom'), array('title'=>'ISOl Chicago', 'url' => 'http://syllogic.asia/2015/', 'id' => 'menu_item_isol_3', 'class'=> 'menu-item menu-item-type-custom menu-item-object-custom')), 'Past'=>array('ul-class'=>'sub-menu', 'class'=>'menu-item-has-children left-sub-menu', 'sub-menu'=>array(array('title'=>'ISOl 2015', 'url' => 'http://syllogic.asia/2015/', 'id' => 'menu_item_isol_2', 'class'=> 'menu-item menu-item-type-custom menu-item-object-custom'), array('title'=>'ISOl Chicago', 'url' => 'http://syllogic.asia/2015/', 'id' => 'menu_item_isol_3', 'class'=> 'menu-item menu-item-type-custom menu-item-object-custom'))));
There is 2 type of menu being inserted here, the first one under ‘Conferences’ menu item, are 2 extra sub-item which are simply listed within the existing sub-menu list of ‘Conferences’.
The second set of menu is an entire sub-menu structure being replaced instead of an existing menu-item. In other words, ‘Past’ is a sub-item of top menu item ‘Conferences’. As such ‘Past’ does not have any children. This 2nd set of dynamic menu are placed below the ‘Past’, making it into a sub-menu.
Menu structures are dined as an array with,
array('title'=>the text of the menu item, 'url' => the permalink for the menu, 'id' => a css id for the <li> element, 'class'=> css classes for the <li> element)
To add an entire sub-menu to a given item, you need to specify some extra arguments, namely the classes that changes an item into a sub-menu (on hover the sub-menu will appear) if you are using pure CSS for your menus. This is done using the following structure,
array('ul-class'=>the css class for the sub-menu
element, 'class'=>the css class for the menu item that will change to a sub-menu structure, 'sub-menu'=>array( sub-menu items as arrays, as defined above )
That’s it. Feel free to comment, query, clarify below…