Nav Menu Generator
Menu locations for Appearance → Menus, plus the wp_nav_menu() call with a fallback that stays quiet instead of listing every page you have.
// Generated with WP CodeKit — powered by GrowQuest (https://growquest.io). /** * Register the theme’s menu locations. */ function mytheme_nav_menus() { register_nav_menus( array( 'primary' => __( 'Primary Menu', 'mytheme' ), 'footer' => __( 'Footer Menu', 'mytheme' ), ) ); } add_action( 'after_setup_theme', 'mytheme_nav_menus' );
About this generator
Nav Menu Location Generator Online
Register your theme's menu locations with register_nav_menus() and get the matching wp_nav_menu() call in the same pass. Every argument that decides what the markup looks like — theme_location, container, items_wrap, depth, fallback_cb — is a field here, and the generated template code comes with the has_nav_menu() guard and a labelled <nav> landmark already in place.
A sample menu renders live from your settings, complete with a current item and a sub-menu, so you can see the exact classes your CSS will have to target before you write any. Free, no account, and nothing you type leaves the browser.
Reviewed Output tested on WordPress 6.8 · PHP 8.3
Why the register_nav_menus generator beats a two-line snippet
Registering the location is the easy half. The half that goes wrong is the output call: a missing %3$s in items_wrap renders a list with no items in it, the default fallback_cb of wp_page_menu dumps every published page onto a site that has no menu assigned yet, and two unlabelled <nav> elements on one page are indistinguishable to a screen reader. This generator writes both halves and audits them together.
items_wrap is validated for %3$s
A custom items_wrap without %3$s produces a <ul> containing nothing at all — the most confusing failure in wp_nav_menu(). That is an error with a one-click restore of the default. Dropping %1$s while a menu_id is set is flagged too, because the id then never reaches the markup.
The wp_page_menu fallback is called out
Leaving fallback_cb at its default means a site with no menu assigned prints a link to every published page, including the ones nobody meant to publicise. The generator warns and can set it to false, or write you a proper fallback that only shows admins a link to the Menus screen.
Location slugs that match theme_location
Slugs are checked for safe lowercase-and-dash form, missing slugs are errors, and duplicate slugs are flagged because the second registration replaces the first. One click derives clean slugs from the location names.
Accessibility built into the template output
The optional wrapper emits a real <nav> with a translated aria-label from the location name, and the generator recommends it when you turn it off. It also warns when you have both a container and your own <nav> — two nested elements doing one job.
The has_nav_menu() guard
Without it an unassigned location still prints your nav wrapper and runs the fallback inside it. The guard is on by default, and turning it off raises a warning you can fix in one click.
Depth advice that matches what editors do
depth 1 silently drops any child item an editor adds in the admin, and depth 0 allows unlimited nesting when most themes only style two levels. Both are flagged as notes rather than left for you to discover on a client site.
How does the Nav Menu Generator work?
Four steps. The sample menu redraws on every change, so the class names you are about to style are visible the whole time.
- 01
Add the menu locations
Start from a preset — primary only, header plus footer, or a full theme set with social and legal links — then edit each slug, display name and the template file it belongs in.
- 02
Configure the wp_nav_menu() call
Set
container(orfalseto write your own markup),container_class,menu_class,menu_id,depth,items_wrapand the fallback behaviour. Each change is reflected in the sample markup immediately. - 03
Set the naming and shape
Pick the function prefix and text domain, choose procedural or a small class, and decide whether registration runs on
after_setup_themeorinit. Toggle thehas_nav_menu()guard and the labelled<nav>wrapper. - 04
Clear the checks, then export
Resolve the flagged slug and markup issues, copy the registration and the template call from their tabs, or download as a snippet, a
functions.phpblock or a plugin file.
Worked example — a primary and a footer location
Two locations registered on after_setup_theme. This is the whole snippet, formatted exactly as it copies out.
/**
* Register the theme’s menu locations.
*/
function mytheme_nav_menus() {
register_nav_menus(
array(
'primary' => __( 'Primary Menu', 'mytheme' ),
'footer' => __( 'Footer Menu', 'mytheme' ),
)
);
}
add_action( 'after_setup_theme', 'mytheme_nav_menus' );The Template tab pairs this with a has_nav_menu( 'primary' ) guard around a <nav aria-label="…"> wrapping wp_nav_menu() with theme_location, menu_id, menu_class, container => false, depth => 2 and fallback_cb => false.
Navigation menus — frequently asked questions
The questions that come up most often when a theme location or a wp_nav_menu() call does not do what you expected.
Why does my menu show the wrong items, or every page on the site?
Two different causes. If you omitted theme_location, wp_nav_menu() falls back to the first menu it can find, which is why menus sometimes appear in the wrong place. If a location is registered but nothing has been assigned to it in Appearance › Menus, the default fallback_cb of wp_page_menu runs and lists every published page. Set theme_location explicitly, and set fallback_cb to false unless you have written a fallback you actually want.
What is the difference between register_nav_menus() and wp_nav_menu()?
register_nav_menus() declares the slots your theme has, which is what makes the checkboxes appear in Appearance › Menus. wp_nav_menu() prints whichever menu the site owner assigned to one of those slots. Registration belongs in functions.php on after_setup_theme; the output call belongs in the template file. Registering without calling means the location exists but nothing renders.
How do I remove the wrapper div wp_nav_menu() adds?
Pass 'container' => false. That drops the <div class="menu-…"> entirely and leaves you with just the <ul>, which is usually cleaner than fighting the default markup with CSS. If you want a semantic landmark instead, write your own <nav> around the call and give it an aria-label — do not use both, or you end up with two nested elements doing one job.
What do %1$s, %2$s and %3$s mean in items_wrap?
They are sprintf() placeholders that core fills in: %1$s is the menu_id, %2$s is the menu_class, and %3$s is the menu items themselves. The default is <ul id="%1$s" class="%2$s">%3$s</ul>. Omitting %3$s is the classic mistake — the list renders with no items inside it at all, which looks like the menu is empty rather than like a template bug.
Should register_nav_menus() run on after_setup_theme or init?
Use after_setup_theme. It works on init too, but after_setup_theme is where theme features belong and it runs earlier, so anything that inspects registered locations sees them in time. The exception is a plugin registering locations for a theme it does not own — init is the safer hook there, since the theme may not be loaded when after_setup_theme fires for the plugin.
How do I add a class to the current menu item?
You do not need to — WordPress already adds current-menu-item, current-menu-ancestor and current_page_parent to the relevant <li> elements, and menu-item-has-children to any item with a sub-menu. Style those. Reach for a custom Walker_Nav_Menu subclass only when you need to change the element structure itself, not just its classes.
Where do I paste the code from the Nav Menu generator?
You have three good options and one bad one. Best is a small site-specific plugin — the generator can output one for you, and it keeps working when you change theme. A code-snippets plugin is fine too. A child theme's functions.php works but ties the code to that theme. Never edit the parent theme: the next update overwrites it and your code is gone.
Can I use the generated code in client work or a commercial plugin?
Yes. The output is ordinary WordPress API calls that you configured — there is no licence attached to it and no attribution required. Use it in client sites, commercial plugins and themes, or products you sell. The generated file carries a short credit comment you are free to delete.
The other Design generators in the library, plus the WordPress tools most often used alongside this one.