
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_Menu
class, 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_Menu
class to create the HTML structure for <ul>
, <li>
, and submenus.
To customize this structure, you can extend Walker_Nav_Menu
and 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.php
inside 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.php
or 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.php
file 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 dropdown
with 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()
andesc_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.