Dynamic Menus

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' => '',
                               'id' => 'menu_item_isol_2',
                               'class'=> 'menu-item menu-item-type-custom menu-item-object-custom'),
                         array('title'=>'ISOl Chicago',
                               'url' => '',
                               'id' => 'menu_item_isol_3',
                               'class'=> 'menu-item menu-item-type-custom menu-item-object-custom')),
                  'class'=>'menu-item-has-children left-sub-menu',
                  'sub-menu'=>array(array('title'=>'ISOl 2015',
                                             'url' => '',
                                             'id' => 'menu_item_isol_2',
                                             'class'=> 'menu-item menu-item-type-custom menu-item-object-custom'),
                                       array('title'=>'ISOl Chicago',
                                             'url' => '',
                                             '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…

Want to share your thoughts?

Leave a Reply

Your email address will not be published. Required fields are marked *