Navigation Menu Generator

Register theme menu locations and generate the wp_nav_menu() call with its container, classes, depth and fallback already set.

Live output

Enable JavaScript to customise; default output below.

Menu locations

A location is a slot in the theme. The menu that fills it is chosen in the admin, not here.

Live preview nav-menus.php
<?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.

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

  1. Add one location per slot in the theme. A location is the slot; the menu that fills it is picked in Appearance, Menus.
  2. Keep slugs short and stable. Changing a slug later unassigns every menu already attached to it.
  3. Set the accessible label. Two nav elements on a page with no labels are two identical landmarks to a screen reader.
  4. Leave the fallback on “show nothing” unless you want WordPress listing every page when no menu is assigned.
  5. Put the registration in functions.php and the output where the menu belongs, usually header.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 on after_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 empty nav in the markup.
  • Changing a location slug unassigns the menus using it. The menu still exists; the slot it filled does not.
  • container_aria_label needs WordPress 5.5. On older versions add the attribute yourself with a walker or a filter.
  • depth => 1 hides 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?
That is the default fallback with no menu assigned. Set fallback_cb to false.
What is the difference between a location and a menu?
The location is the slot the theme offers. The menu is the list of links an editor builds and drops into that slot.
Does this work in a block theme?
The functions still work in a template file, but a block theme normally uses the Navigation block and a wp_navigation post instead.
How do I style the submenus?
Target the sub-menu class WordPress adds to nested lists. A custom walker is only needed when you want different markup, not different styles.
Can one menu be in two locations?
Yes. Locations are slots, and the same menu can be assigned to as many of them as you like.

From the people who built this tool

WP Adminify

The WordPress admin, rebuilt: a dashboard worth looking at, menu and column control, a real file manager and the login page your client sees.

See WP Adminify Free version on WordPress.org

Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.