Himanshu SharmaSoftware engineer
Let’s talk

WordPress · Lesson 9 of 45

Navigation menus

Build site navigation in WordPress with the Navigation block in block themes and classic menus in older themes, and keep menus clear, short and accessible.

11 minContentUpdated 23 October 2026

By the end of this lessonCreate and edit menus in block and classic themes, and understand where WordPress stores them.

Two systems

WordPress has two ways of building menus, depending on the theme:

  • Block themes (the default since 2022, including Twenty Twenty-Five) use the Navigation block, edited in Appearance → Editor.
  • Classic themes use Appearance → Menus, where you build a menu and assign it to a location defined by the theme.

You only need the system your theme uses, but you will meet both on real sites.

In the Site Editor, open Navigation to see your menus, or select the Navigation block in the header template. Add links to pages, posts, categories or custom addresses, drag them into order, and nest links to create submenus. On narrow screens the block becomes a menu button that opens an overlay; you can choose when that happens.

Each menu is saved as a post of the type wp_navigation. A fresh site already has one, created automatically: when the theme's header first shows a Navigation block that has no menu, WordPress builds a fallback listing your published pages and saves it. Let's look at the home page and then at that menu:

http
GET /
result
My WordPress Site
Sample Page
php
<?php
$menu = get_posts( [ 'post_type' => 'wp_navigation', 'numberposts' => 1 ] )[0];
echo "menu: {$menu->post_title} (ID {$menu->ID})\n";
echo $menu->post_content, "\n";
result
menu: Navigation (ID 4)
<!-- wp:page-list /-->

The fallback menu contains a single Page List block, which lists all published pages automatically. That is convenient on a tiny site, but on a real site you want to choose the links yourself.

Building a menu

Replacing the Page List with specific Navigation Link blocks gives you full control, including a submenu. This is what the Site Editor saves when you build a menu by hand:

php
<?php
$services = wp_insert_post( [ 'post_type' => 'page', 'post_title' => 'Services', 'post_status' => 'publish' ] );
$contact  = wp_insert_post( [ 'post_type' => 'page', 'post_title' => 'Contact', 'post_status' => 'publish' ] );

$link = fn( $label, $url, $id = 0 ) => sprintf(
	'<!-- wp:navigation-link {"label":"%s","url":"%s"%s} /-->',
	$label, $url, $id ? ',"type":"page","id":' . $id . ',"kind":"post-type"' : ''
);

$content  = $link( 'Home', '/' );
$content .= '<!-- wp:navigation-submenu {"label":"Services","url":"' . get_permalink( $services ) . '","type":"page","id":' . $services . ',"kind":"post-type"} -->';
$content .= $link( 'Web design', '/services/web-design/' ) . $link( 'Hosting', '/services/hosting/' );
$content .= '<!-- /wp:navigation-submenu -->';
$content .= $link( 'Contact', get_permalink( $contact ), $contact );

$menu = get_posts( [ 'post_type' => 'wp_navigation', 'numberposts' => 1 ] )[0];
wp_update_post( [ 'ID' => $menu->ID, 'post_content' => $content ] );
echo "menu updated\n";
result
menu updated
http
GET /
result
My WordPress Site
Home
Services
Web design
Hosting
Contact

The header now shows exactly the links we chose, with Web design and Hosting in a submenu under Services. Links of the "page" kind keep working if you later change a page's slug, because they store the page ID as well as its address.

Classic themes declare menu locations in their code, and you assign menus to them. The menus themselves are stored as a taxonomy (nav_menu) whose items are posts of the type nav_menu_item. WP-CLI manages them the same way the Appearance → Menus screen does:

bash
wp menu create "Footer menu"
wp menu item add-custom footer-menu "Privacy" /privacy-policy/
wp menu item add-custom footer-menu "Contact" /contact/
wp menu item list footer-menu --fields=position,title,link
result
Success: Created menu 2.
Success: Menu item added.
Success: Menu item added.
+----------+---------+------------------+
| position | title   | link             |
+----------+---------+------------------+
| 1        | Privacy | /privacy-policy/ |
| 2        | Contact | /contact/        |
+----------+---------+------------------+

In a classic theme, the theme's code then registers a location and prints the assigned menu:

php
// functions.php
register_nav_menus( [ 'footer' => 'Footer menu' ] );

// footer.php
wp_nav_menu( [ 'theme_location' => 'footer' ] );

Twenty Twenty-Five is a block theme, so it has no classic locations and this menu would only appear if a block or widget displays it. Block themes can import a classic menu: the Navigation block offers your classic menus as a starting point.

Good menus

  • Keep the main menu short: five to seven top-level items for most sites. Put less important links in the footer.
  • Use clear labels: "Pricing" beats "Solutions"; never "Click here".
  • Put the most important item, often Contact or a call to action, where people expect it (usually last).
  • Avoid deep nesting; two levels is plenty.
  • Test with a keyboard (Tab, Enter, Escape) and on a phone.

Common mistakes

  • Leaving the automatic page list on a site with many pages, so every page lands in the menu.
  • Editing Appearance → Menus on a block theme and wondering why nothing changes.
  • Huge menus that hide the important pages.
  • Linking to drafts or deleted pages, which gives visitors errors.

Exercise

On your local site, replace the automatic menu with: Home, About, Blog and Contact, and a submenu under About with two pages. Check the result at phone width.

Show one possible answer

Create the pages first. In Appearance → Editor → Navigation, open the menu, delete the Page List block, and add Page Link items for Home, About, Blog and Contact. Select About and add a submenu with the two child pages. Save. In the editor's preview (or your browser at a narrow width), the menu collapses into a button that opens the overlay.

Key points

  • Block themes use the Navigation block, edited in the Site Editor; each menu is stored as a wp_navigation post.
  • If a Navigation block has no menu yet, WordPress shows a fallback (a list of your pages) and saves it as a menu.
  • Classic themes use menus from Appearance → Menus, placed in menu locations the theme registers.
  • Keep main menus short, label links clearly, and make sure they work with a keyboard and on phones.

Check yourself

1. Where do you edit the main menu of a block theme such as Twenty Twenty-Five?
2. How is a block theme menu stored?
3. What is a menu location in a classic theme?
4. Which menu is the most usable?