How to build a custom Walker for WordPress menus

n WordPress, custom menus are essential when developing advanced themes. While the wp_nav_menu()function is flexible, there are cases where you need full control over the generated HTML. For those scenarios, WordPress provides the Walker_Nav_Menuclass, which you can extend to create a custom walker.

In this guide, we’ll cover:

  • What is a Walker in WordPress?
  • When to use a custom walker
  • How to build your own walker step by step
  • How to apply it to your menu
  • Full working example

 

What is a Walker in WordPress?

A Walker is a class used by WordPress to loop through hierarchical data structures (like menus or nested taxonomies) and generate the appropriate HTML.

When using wp_nav_menu(), WordPress uses the Walker_Nav_Menuclass to create the HTML structure for <ul>, <li>, and submenus.

To customize this structure, you can extend Walker_Nav_Menuand override certain methods to change the output.

 

When should you use a custom Walker?

You should create a custom walker when:

  • You need to add custom classes or attributes to menu items.
  • You want full control over the HTML structure of menus.
  • You’re using a CSS framework like Bootstrap or Tailwind and need specific markup.
  • You want to insert icons, <div>s, or custom structures inside the menu.

 

Key methods to override

When extending Walker_Nav_Menu, these are the most commonly overridden methods:

<?php
start_lvl()     // Starts a submenu (<ul>)
end_lvl()       // Ends a submenu
start_el()      // Starts a menu item (<li>)
end_el()        // Ends a menu item

 

How to create a custom Walker

Create a file called CustomMenuWalker.phpinside your theme or a plugin.

<?php

class CustomMenuWalker extends Walker_Nav_Menu {

    public function startLvl( &$output, $depth = 0, $args = [] ) {
        $indent  = str_repeat( "\t", $depth );
        $output .= "\n$indent<ul class=\"submenu-level-$depth\">\n";
    }

    public function endLvl( &$output, $depth = 0, $args = [] ) {
        $indent  = str_repeat( "\t", $depth );
        $output .= "$indent</ul>\n";
    }

    public function startEl( &$output, $item, $depth = 0, $args = [], $id = 0 ) {
        $indent      = ( $depth ) ? str_repeat( "\t", $depth ) : '';
        $classNames  = implode( ' ', $item->classes );
        $classAttr   = $classNames ? ' class="' . esc_attr( $classNames ) . '"' : '';
        $output     .= "$indent<li$classAttr>";

        $title      = apply_filters( 'the_title', $item->title, $item->ID );
        $attributes = ' href="' . esc_attr( $item->url ) . '"';

        $output .= '<a' . $attributes . '>';
        $output .= esc_html( $title );
        $output .= '</a>';
    }

    public function endEl( &$output, $item, $depth = 0, $args = [] ) {
        $output .= "</li>\n";
    }
}

 

How to use the Walker in wp_nav_menu()

Inside header.phpor wherever you output the menu:

<?php
wp_nav_menu([
    'theme_location' => 'main_menu',
    'container'      => false,
    'menu_class'     => 'main-nav',
    'walker'         => new CustomMenuWalker()
]);
?>

 

How to register the menu

In your functions.phpfile or a plugin:

<?php
function registerThemeMenus() {
    register_nav_menus([
        'main_menu' => 'Main Menu'
    ]);
}
add_action( 'after_setup_theme', 'registerThemeMenus' );

 

Suggested file structure

/wp-content/themes/your-theme/
│
├── functions.php
├── header.php
├── inc/
│   └── CustomMenuWalker.php

 

And inside functions.php, include the class:

<?php
require_once get_template_directory() . '/inc/CustomMenuWalker.php';

 

Example: Walker for Bootstrap 5

If you’re using Bootstrap, submenu <ul>elements need the class dropdown-menu, and the parent <li>elements should use the class dropdownwith data-bs-toggle.

Here’s a custom startEl()for Bootstrap:

<?php
public function startEl( &$output, $item, $depth = 0, $args = [], $id = 0 ) {
    $hasChildren = in_array( 'menu-item-has-children', $item->classes );

    $classes   = $hasChildren ? 'dropdown' : '';
    $output   .= '<li class="nav-item ' . $classes . '">';

    $linkClass = $hasChildren ? 'nav-link dropdown-toggle' : 'nav-link';
    $attrs     = 'class="' . $linkClass . '"';
    $attrs    .= $hasChildren ? ' data-bs-toggle="dropdown" role="button" aria-expanded="false"' : '';
    $attrs    .= ' href="' . esc_url( $item->url ) . '"';

    $output .= '<a ' . $attrs . '>' . esc_html( $item->title ) . '</a>';
}

 

Extra tips

  • Always use esc_html() and esc_attr() for security.
  • Use the $depth parameter to customize submenu levels differently.
  • Test your walker with different themes and CSS classes.

 

Creating a custom walker in WordPress gives you full control over the HTML structure of your menus. It’s a powerful tool when working with custom designs or CSS frameworks.

 

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to Top
0
Would love your thoughts, please comment.x
()
x