For a long time building a menu in WordPress was an exercise in stupid hackery with wp_list_pages()
. The lack of an easy way to create menus certainly held WordPress back as a fully fledged CMS until version 3.0 when the killer menu feature was introduce.
###Functions
Making a WordPress menu consists of two functions.
<?php /* * * Add WordPress Navigation Menus * */ add_action('init','theme_t_wp_register_nav_menus'); function theme_t_wp_register_nav_menus(){ register_nav_menus( array( 'main-menu' => _('Main Menu'), ) ); } ?>The function above creates a new menu called Main Menu and is found in wp-includes/nav-menu.php or in the Codex. It would be placed in your theme functions files, and don’t forget to change the function prefix above to your own special prefix to reduce the likelihood of function conflicts.. Notice I’m not wrapping it in
if( function_exists( 'register_nav_menus' ) )
I think it’s a pretty safe assumption that you’re going to be working on a WordPress install after 3.0 but if you’re not sure then make sure you check for the function and handle your menu in cases where the function doesn’t exist.The first parameter is the slug of the menu and is used later when we call it. The second parameter is the description and can be whatever it needs to be so that our theme menu area is easily identified by it’s users.
<?php // adding menu wp_nav_menu( array( 'theme_location' => 'main-menu', ) ); // end wp_nav_menu ?>This function is place in our theme template file where we want our menu to show. We’ve only used one of the possible parameters available to us, we’ve simply told WordPress which menu we’d like in this location. All it does is present a UI for the WordPress admin so you can place a menu in the location. Even this isn’t a required parameter, in fact none of the parameters listed below are required.
wp_nav_menu()
Parameters
- theme_location
- This is an optional string and is the location in the theme to be used. The location must first be registered with `register_nav_menu()` if you want the user to have the ability to select this location. Defaults to none.
- menu
- An optional string that is the name of the desired menu. It accepts and matches in order id, slug, name. Defaults to none.
- container
- An option string that determines whether to wrap the ul and what to wrap it with. If you’d like no container then use _false_ Defaults to the div html tag.
- container_class
- An optional string that is the class applied to the container of the menu. Defaults to `menu-[menu-slug]-container`.
- container_id
- An optional string that is the id of the menu container
- menu_class
- An optional string which is the CSS class applied to the ul of the menu. Defaults to _menu_
- menu_id
- An optional string that is the id applied to the ul element that forms the menu. Defaults to menu slug, incremented
- echo
- A boolean optional that decides whether to echo the html output of the menu or to just return it. Default to true (echo the HTML). Use 0 to return the menu
- fallback_cb
- An optional string which provides the name of a fallback function if the menu doesn’t exist. Defaults to wp_page_menu.
- before
- An optional string that tells WordPress what text to output before the `a` of the link. Defaults to none.
- after
- An optional string that tells WordPress what text to output after the `/a` of the link. Defaults to none.
- link_before
- An optional string that tells the menu what to output before the linke text. Defaults to none.
- link_after
- An optional string that tells the menu what to output after the link text. Defaults to none.
- items_wrap
- An optional string. Defines what the list items are wrapped in. Unless you know what you’re doing it’s unlikely you should touch this. It could be used to remove the class with the string
<ul id="%1$s" class="%2$s">%3$s</ul>
- depth
- An optional integer. Tells WordPress how many levels of hierarchy are to be included where 0 means all. Defaults to 0.
- walker
- Optional object. Custom walker object to use. You can’t just pass a string to this, it must be an actual object. Defaults to new Walker_Nav_Menu
###UI
Now that we’ve got our new menu setup in our theme lets look at the UI we’ve got. Inside your theme you’ll find the menu’s located under Appearance/Menu.
Start by entering a new menu name and saving it.
Now that you have a new menu you can start putting items in it. You should basically have any post, category, tag, custom post type, or taxonomy available to you. If you don’t see things that you feel you should then open the screen options in the upper right hand corner to see what options can be shown.
Once you’ve made your menu you can display it in a few different ways. If your theme has menu areas defined then you can select which one you’d like to place in which area. You can also build custom menus and use a widget to display them in any widget area that is available to you.
###CSS
Everything we’ve done so far has just been building the menu and displaying it, which I think is the easy part of any menu. Once you’ve got it displaying on your page you’ve got to start styling it and there are a number of styles that are required to account for all of the scenarios in a menu. I’ll leave the general menu styling to you and just highlight the special stuff.
- .current_menu_item
- This CSS class is applied to the currrent menu item. So if you’re on the home page the ‘home’ navigation item will have the class. Don’t forget to show your users where they are in your site with this.
- .current_page_item
- Similar to the first class we talked about but if you have no menu placed in your menu area in a theme the default wp_list_pages will show and this class will be applied to the current page.
- :hover :active and :focus
- Normal CSS pseudo classes. Don’t forget to style them, and take keyboard navigation in to account.
- .children
- If you’re building a dropdown menu then the secondary menu items will be wrapped in list with the class of chidren applied. They will also have all of the above classes and pseudo classes listed above as they apply to the menu.
I acknowledge that I didn’t mention all of the classes that get applied to menu items, but I’ve never had cause to use more than what I’ve listed above. There are other classes applied to menus so if you need something and I haven’t listed it take a look at the generated code and see if it’s already there.
###Examples
Now that we’ve covered all the basics of menus lets actually dig in to some examples.
####Basic Menu
We looked at it above but I’ll put it together here just to keep things in one place.
<?php /* * * Add WordPress Navigation Menus * */ add_action('init','theme_t_wp_register_nav_menus'); function theme_t_wp_register_nav_menus(){ register_nav_menus( array( 'main-menu' => _('Main Menu'), ) ); } ?>####Different Containers
Now lets play around a bit with switching up the containers for our menu.
<?php /* * * Add WordPress Navigation Menus * */ add_action('init','theme_t_wp_register_nav_menus'); function theme_t_wp_register_nav_menus(){ register_nav_menus( array( 'main-menu' => _('Main Menu'), 'container' => 'nav', ) ); } ?>The code above will render our HTML inside a nav element. I prefer this way but if you use nav make sure you’ve accounted for older browsers that don’t support HTML 5.
#####Custom Fallback
If you’ve been developing custom themes for a while then you probably rolled your own menu function at some point which you’ll still support for users that don’t update their content to the new menu system. Simply call your old menu function in the callback and if there isn’t a menu present it will show your old one.
<?php /* * * Add WordPress Navigation Menus * */ add_action('init','theme_t_wp_register_nav_menus'); function theme_t_wp_register_nav_menus(){ register_nav_menus( array( 'main-menu' => _('Main Menu'), 'fallback_cb' => 'theme_t_wp_old_menu_function', ) ); } ?>There is much more you can do with your menus in WordPress so get out there and experiment. Since it’s been introduced I haven’t had to roll my own menu ever.