Navigation Menu Generator
Register theme menu locations and generate the wp_nav_menu() call with its container, classes, depth and fallback already set.
<?php
/**
* Menu locations for the theme.
*/
/**
* Registers the locations. The menus that fill them are chosen in the admin.
*/
function my_theme_register_menus() {
register_nav_menus(
array(
'primary' => __( 'Primary Menu', 'my-theme' ),
'footer' => __( 'Footer Menu', 'my-theme' ),
)
);
}
add_action( 'after_setup_theme', 'my_theme_register_menus' );
/*
* Output. Put this in header.php, or wherever the menu belongs.
*/
if ( has_nav_menu( 'primary' ) ) {
wp_nav_menu(
array(
'theme_location' => 'primary',
'container' => 'nav',
'container_class' => 'site-navigation',
'container_aria_label' => __( 'Primary', 'my-theme' ),
'menu_class' => 'menu',
'depth' => 2,
// false, not an empty string: an empty string still lists pages.
'fallback_cb' => false,
)
);
}
Output is valid and updates as you type.
Fix the highlighted fields to update the output.
Name the locations your theme offers, and the generator writes the registration plus the wp_nav_menu() call with the container, classes, depth and fallback already decided.
How to use
- Add one location per slot in the theme. A location is the slot; the menu that fills it is picked in Appearance, Menus.
- Keep slugs short and stable. Changing a slug later unassigns every menu already attached to it.
- Set the accessible label. Two
navelements on a page with no labels are two identical landmarks to a screen reader. - Leave the fallback on “show nothing” unless you want WordPress listing every page when no menu is assigned.
- Put the registration in
functions.phpand the output where the menu belongs, usuallyheader.php.
Example
Two locations, with the primary one printed only when a menu is actually assigned:
function acme_register_menus() {
register_nav_menus(
array(
'primary' => __( 'Primary Menu', 'acme' ),
'footer' => __( 'Footer Menu', 'acme' ),
)
);
}
add_action( 'after_setup_theme', 'acme_register_menus' );
if ( has_nav_menu( 'primary' ) ) {
wp_nav_menu(
array(
'theme_location' => 'primary',
'container' => 'nav',
'container_class' => 'site-navigation',
'container_aria_label' => __( 'Primary', 'acme' ),
'menu_class' => 'menu',
'depth' => 2,
'fallback_cb' => false,
)
);
}
'fallback_cb' => false is the line people forget. Without it, a site with no menu assigned prints a list of every published page.
Pitfalls
register_nav_menus()belongs onafter_setup_theme. Earlier and the theme is not ready; later and the locations never appear in the admin.- The default fallback is
wp_page_menu, which lists pages. On a new site that looks like a menu nobody created. 'fallback_cb' => ''is not the same as false. An empty string still runs the default.- A location with no assigned menu still outputs the container when you do not guard with
has_nav_menu(), leaving an emptynavin the markup. - Changing a location slug unassigns the menus using it. The menu still exists; the slot it filled does not.
container_aria_labelneeds WordPress 5.5. On older versions add the attribute yourself with a walker or a filter.depth => 1hides submenus rather than flattening them. Children are dropped, not promoted.- Registering a location does not create a menu. A fresh install has locations and no menus, which is why the fallback matters.
Compatibility
register_nav_menus() and wp_nav_menu() have been stable since WordPress 3.0. container_aria_label needs WordPress 5.5 or later and is ignored on older versions. Block themes use the Navigation block instead, though these functions still work in a classic template. The generated code targets PHP 7.0 and up, and the tool runs entirely in your browser.
Frequently asked questions
Why does my site show a list of pages?
fallback_cb to false.What is the difference between a location and a menu?
Does this work in a block theme?
wp_navigation post instead.How do I style the submenus?
sub-menu class WordPress adds to nested lists. A custom walker is only needed when you want different markup, not different styles.