Menu’s are one of the most important aspects of a site. Choosing the right elements, the positioning, it can make a huge difference in the user experience. In WordPress there is a menu system, which you’re probably familiar with already. It enables you to build the menu structure through the WP Admin, under WP Admin > Appearance > Menu. Most themes then provide menu location(s), and most have at least a few. There are also many plugins that provide various forms of menu integration and customization.
If you rely entirely on themes and plugins to provide menu handling for you, then you miss out on the opportunity to create custom menus. For instance although many “mega menu” plugins exist, it can be very difficult to get the exact result you might want using 3rd party solutions.
It’s important to understand that a Menu and a Menu Location are 2 different things in WordPress. Themes are required to “register locations” rather than specifying menu’s directly. This makes themes more versatile because admin users can make any menu they want and then drop it into a location for display. In practice however the relationship between a menu and it’s location is almost always 1:1 because when would you ever want to stack a menu on top of another menu? Even in an area like the footer where you might want multiple menu’s to display, odds are these will be separate menu’s in separate locations because you need some markup around each one, like for instance the common approach of have multiple columns with a vertical menu in each.
The function we use in the theme to register nav menus is
register_nav_menus(). This function takes an array as it’s only argument, and this array should be an associative array where the keys represent the menu location ID and the value is the display label. Notice the display labels are wrapped in the localization function __() to enable translation.
register_nav_menus( array( 'primary_menu' => __( 'Primary Menu', 'text_domain' ), 'footer_menu' => __( 'Footer Menu', 'text_domain' ), ));
In practice “text_domain” should be replaced with the text domain for your theme which is a unique string, often a lowercased form of the theme name. This is used by translators to target your theme’s text.
Rendering Menu’s with wp_nav_menu()
The next function we’ll use is wp_nav_menu() which is used to render menu locations. A minimal example is shown below:
wp_nav_menu( array( 'theme_location' => 'header-menu' ) );
Notice that ‘theme_location’ is specified inside an array. There are many other array arguments that can be used in this display function. This allows themes to do customization to the the render of the navigation menu, but the majority of the HTML and CSS classes are still automatically rendered by WordPress. Which is why later we’ll cover making a custom Menu Walker Class, which will give us full control over the output. For many situation however, simply rendering the menu will be sufficient because you can create the styling needed for basic menus entirely with CSS and just by implementing the various classes that WordPress applies to the menu markup.
Let’s take a look at what a mostly unstyled menu might look like from our own project here at WPCode.org this was our primary menu being rendered in the header: