🔗 Implementing Menus in Themes
Display navigation menus in your WordPress theme
Master wp_nav_menu() and create responsive navigation systems
Learning Objectives
- Understand wp_nav_menu() function and parameters
- Display menus in theme templates
- Configure menu containers and classes
- Style navigation menus with CSS
- Create responsive mobile menus
- Handle menu item classes and IDs
- Implement dropdown/submenu navigation
- Add menu item descriptions and icons
The wp_nav_menu() Function
The wp_nav_menu() function is the primary way to display navigation menus in WordPress themes. It provides extensive customization options through its parameters.
Key Concept
Basic Menu Implementation
Simple Menu Display
<?php
// In header.php - Basic menu display
wp_nav_menu( array(
'theme_location' => 'primary'
) );
// With more parameters
wp_nav_menu( array(
'theme_location' => 'primary',
'menu_id' => 'primary-menu',
'menu_class' => 'nav-menu',
'container' => 'nav',
'container_class' => 'main-navigation',
'container_id' => 'site-navigation',
) );
Complete Menu Implementation in header.php
<header id="masthead" class="site-header">
<div class="container">
<div class="site-branding">
<h1 class="site-title">
<a href="<?php echo esc_url( home_url( '/' ) ); ?>">
<?php bloginfo( 'name' ); ?>
</a>
</h1>
</div>
<?php if ( has_nav_menu( 'primary' ) ) : ?>
<nav id="site-navigation" class="main-navigation" role="navigation">
<button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false">
<?php esc_html_e( 'Menu', 'mytheme' ); ?>
</button>
<?php
wp_nav_menu( array(
'theme_location' => 'primary',
'menu_id' => 'primary-menu',
'menu_class' => 'menu nav-menu',
'container_class' => 'menu-primary-container',
'fallback_cb' => 'mytheme_primary_menu_fallback',
'depth' => 3,
'link_before' => '<span>',
'link_after' => '</span>',
) );
?>
</nav>
<?php endif; ?>
</div>
</header>
wp_nav_menu() Parameters
| Parameter | Description | Default Value |
|---|---|---|
theme_location |
Registered menu location to use | '' |
menu |
Menu ID, slug, or name | '' |
container |
Container element (div, nav, etc.) | 'div' |
container_class |
CSS class for container | 'menu-{menu slug}-container' |
container_id |
ID for container | '' |
menu_class |
CSS class for the menu | 'menu' |
menu_id |
ID for the menu | '{menu slug}' |
echo |
Whether to echo or return | true |
fallback_cb |
Fallback function if menu doesn't exist | 'wp_page_menu' |
before |
Text before link markup | '' |
after |
Text after link markup | '' |
link_before |
Text before link text | '' |
link_after |
Text after link text | '' |
items_wrap |
How items should be wrapped | '<ul id="%1$s" class="%2$s">%3$s</ul>' |
depth |
How many levels of hierarchy | 0 (all) |
walker |
Custom walker class | '' |
Common Menu Implementations
Header Navigation Menu
<?php
// Primary navigation with all options
function mytheme_primary_navigation() {
if ( has_nav_menu( 'primary' ) ) {
?>
<nav id="site-navigation" class="main-navigation" role="navigation" aria-label="<?php esc_attr_e( 'Primary Menu', 'mytheme' ); ?>">
<button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false">
<span class="screen-reader-text"><?php _e( 'Menu', 'mytheme' ); ?></span>
<span class="menu-toggle-icon">
<span></span>
<span></span>
<span></span>
</span>
</button>
<?php
wp_nav_menu( array(
'theme_location' => 'primary',
'menu_id' => 'primary-menu',
'menu_class' => 'nav-menu',
'container' => 'div',
'container_class' => 'primary-menu-container',
'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
'fallback_cb' => false,
) );
?>
</nav>
<?php
}
}
Footer Menu Implementation
<?php
// Footer navigation - single level
function mytheme_footer_navigation() {
if ( has_nav_menu( 'footer' ) ) {
wp_nav_menu( array(
'theme_location' => 'footer',
'menu_id' => 'footer-menu',
'menu_class' => 'footer-menu',
'container' => 'nav',
'container_class' => 'footer-navigation',
'container_aria_label' => __( 'Footer Menu', 'mytheme' ),
'depth' => 1, // Only one level
'fallback_cb' => false,
'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
) );
}
}
// In footer.php
?>
<footer class="site-footer">
<div class="footer-content">
<?php mytheme_footer_navigation(); ?>
<div class="copyright">
<p>© <?php echo date('Y'); ?> <?php bloginfo( 'name' ); ?></p>
</div>
</div>
</footer>
Social Links Menu
<?php
// Social links menu with icons
function mytheme_social_menu() {
if ( has_nav_menu( 'social' ) ) {
wp_nav_menu( array(
'theme_location' => 'social',
'menu_id' => 'social-menu',
'menu_class' => 'social-links',
'container' => 'nav',
'container_class' => 'social-navigation',
'container_aria_label' => __( 'Social Links', 'mytheme' ),
'link_before' => '<span class="screen-reader-text">',
'link_after' => '</span>',
'depth' => 1,
'fallback_cb' => false,
'items_wrap' => '<ul id="%1$s" class="%2$s" aria-label="' . esc_attr__( 'Social links', 'mytheme' ) . '">%3$s</ul>',
) );
}
}
Menu Styling Examples
Advanced Menu Techniques
Adding Custom Classes and Attributes
<?php
// Add custom classes to menu items
function mytheme_nav_menu_css_class( $classes, $item, $args ) {
// Add class to specific menu location
if ( $args->theme_location == 'primary' ) {
$classes[] = 'primary-menu-item';
}
// Add class based on post type
if ( $item->object == 'page' ) {
$classes[] = 'menu-page-item';
}
// Add class for external links
if ( strpos( $item->url, home_url() ) === false ) {
$classes[] = 'external-link';
}
return $classes;
}
add_filter( 'nav_menu_css_class', 'mytheme_nav_menu_css_class', 10, 3 );
// Add attributes to menu links
function mytheme_nav_menu_link_attributes( $atts, $item, $args ) {
// Add target="_blank" to external links
if ( strpos( $item->url, home_url() ) === false ) {
$atts['target'] = '_blank';
$atts['rel'] = 'noopener noreferrer';
}
// Add data attributes
$atts['data-menu-item-id'] = $item->ID;
return $atts;
}
add_filter( 'nav_menu_link_attributes', 'mytheme_nav_menu_link_attributes', 10, 3 );
// Add menu item description
function mytheme_nav_menu_item_description( $item_output, $item, $depth, $args ) {
if ( $item->description ) {
$item_output = str_replace(
$args->link_after . '',
'<span class="menu-item-description">' . $item->description . '</span>' . $args->link_after . '',
$item_output
);
}
return $item_output;
}
add_filter( 'walker_nav_menu_start_el', 'mytheme_nav_menu_item_description', 10, 4 );
Best Practices
Menu Implementation Best Practices
- Always check for menu existence: Use has_nav_menu() before displaying
- Provide semantic HTML: Use nav element and proper ARIA labels
- Make menus keyboard accessible: Ensure tab navigation works
- Add mobile toggle: Implement responsive menu for small screens
- Use proper fallbacks: Handle cases when no menu is assigned
- Cache complex menus: Use transients for performance
- Test with screen readers: Ensure accessibility compliance
- Minimize depth: Limit to 2-3 levels for usability
Avoid hardcoding menu HTML. Always use wp_nav_menu() to ensure users can manage menus through the WordPress admin.
Practice Exercise
Implement Complete Navigation System