Skip to main content

Course Progress

Loading...

Learning Objectives

  • Register menu locations in your theme
  • Display menus with wp_nav_menu()
  • Understand menu parameters and options
  • Create custom Walker classes
  • Build responsive mobile menus
  • Style menus with CSS classes
  • Handle fallback menus

Understanding WordPress Menus

WordPress menus allow users to create custom navigation without touching code. As a theme developer, you define where menus can appear (menu locations) and how they're displayed.

💡
Key Concept
WordPress separates menu locations (defined by the theme) from menu content (created by users). This gives users complete control over their navigation structure.

Menu Implementation Flow

1. Register

Define menu locations

2. Create

User creates menu

3. Assign

User assigns to location

4. Display

Theme displays menu

Registering Menu Locations

Basic Menu Registration

<?php
// In functions.php
function mytheme_register_menus() {
    register_nav_menus( array(
        'primary'   => esc_html__( 'Primary Menu', 'mytheme' ),
        'secondary' => esc_html__( 'Secondary Menu', 'mytheme' ),
        'footer'    => esc_html__( 'Footer Menu', 'mytheme' ),
        'social'    => esc_html__( 'Social Links Menu', 'mytheme' ),
        'mobile'    => esc_html__( 'Mobile Menu', 'mytheme' ),
    ) );
}
add_action( 'after_setup_theme', 'mytheme_register_menus' );

// Alternative: Register single menu
register_nav_menu( 'primary', __( 'Primary Menu', 'mytheme' ) );

Displaying Menus with wp_nav_menu()

Basic Menu Display

<?php
// Simple menu display
wp_nav_menu( array(
    'theme_location' => 'primary',
) );

// Full parameters example
wp_nav_menu( array(
    'theme_location'  => 'primary',                // Location registered
    'menu'            => '',                       // Menu name, ID, or slug
    'menu_class'      => 'nav-menu',              // CSS class for ul element
    'menu_id'         => 'primary-menu',          // ID for ul element
    'container'       => 'nav',                   // Container element
    'container_class' => 'primary-navigation',    // Container CSS class
    'container_id'    => 'site-navigation',       // Container ID
    'fallback_cb'     => 'wp_page_menu',         // Fallback function
    'before'          => '',                      // Before link text
    'after'           => '',                      // After link text
    'link_before'     => '',                      // Before link markup
    'link_after'      => '',                      // After link markup
    'echo'            => true,                    // Echo or return
    'depth'           => 0,                       // How many levels (0 = all)
    'walker'          => '',                      // Custom walker class
    'items_wrap'      => '<ul id="%1$s" class="%2$s">%3$s</ul>',
) );

wp_nav_menu() Parameters Reference

Parameter Type Default Description
theme_location string '' Registered menu location identifier
menu string '' Menu name, ID, slug, or object
container string 'div' Container element (nav, div, or false)
container_class string '' CSS class for container
container_id string '' ID for container
menu_class string 'menu' CSS class for ul element
menu_id string '' ID for ul element
fallback_cb string 'wp_page_menu' Fallback function if menu doesn't exist
depth int 0 How many hierarchy levels (0 = all)
walker object '' Custom Walker class instance
echo bool true Echo or return the menu

Custom Walker Class

Create custom menu markup with a Walker class for advanced customization.

Simple Bootstrap Walker Example

<?php
/**
 * Custom Nav Walker for Bootstrap
 */
class My_Walker_Nav_Menu extends Walker_Nav_Menu {
    
    // Start Level
    public function start_lvl( &$output, $depth = 0, $args = null ) {
        $indent = str_repeat( "\t", $depth );
        $output .= "\n$indent<ul class=\"dropdown-menu\">\n";
    }
    
    // Start Element
    public function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) {
        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
        
        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $classes[] = 'menu-item-' . $item->ID;
        
        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
        $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
        
        $id = apply_filters( 'nav_menu_item_id', 'menu-item-' . $item->ID, $item, $args );
        $id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
        
        $output .= $indent . '<li' . $id . $class_names . '>';
        
        $atts = array();
        $atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
        $atts['target'] = ! empty( $item->target ) ? $item->target : '';
        $atts['rel']    = ! empty( $item->xfn ) ? $item->xfn : '';
        $atts['href']   = ! empty( $item->url ) ? $item->url : '';
        
        $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args );
        
        $attributes = '';
        foreach ( $atts as $attr => $value ) {
            if ( ! empty( $value ) ) {
                $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
                $attributes .= ' ' . $attr . '="' . $value . '"';
            }
        }
        
        $item_output = $args->before;
        $item_output .= '<a' . $attributes . '>';
        $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;
        
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }
}

// Usage
wp_nav_menu( array(
    'theme_location' => 'primary',
    'walker'         => new My_Walker_Nav_Menu(),
) );

Menu Best Practices

Development Best Practices

  • Always check if menu exists: Use has_nav_menu() before displaying
  • Provide fallbacks: Show something useful when no menu is set
  • Use semantic HTML: Use nav element for navigation
  • Add ARIA labels: Improve accessibility with proper ARIA attributes
  • Make it responsive: Ensure menus work on all devices
  • Limit depth on mobile: Consider limiting menu depth for mobile
  • Use descriptive location names: Make it clear where menus will appear
  • Document menu locations: Help users understand menu purposes
Don't hardcode menu items in templates. Always use the WordPress menu system to allow user customization.

Practice Exercise

💻
Build Complete Navigation System

Create a comprehensive navigation system that includes:

  1. Register 4 menu locations (primary, secondary, footer, mobile)
  2. Display primary menu with custom CSS classes
  3. Create a responsive mobile menu with hamburger toggle
  4. Implement a custom Walker for Bootstrap styling
  5. Add a social links menu with icon support
  6. Create custom fallback function for missing menus
  7. Style current menu items and dropdowns
  8. Add smooth animations for menu interactions
  9. Implement keyboard navigation support
  10. Test on multiple devices and screen sizes

Additional Resources