Tutorials UPDATED: 18 July 2023

The WordPress Navigation Menu: How It Works

Tassos Antoniou

8 min read

As you already know, the navigation menu is a key part of how well your website works and how people like to use it. A website menu should be easy to use and consistent across all pages to help the visitor easily find and access the content they want. Otherwise, they are likely to bounce off and look for other websites.

In this article, we’ll look at how WordPress handles menus from a developer’s perspective.

Add a WordPress menu

Let’s say that you have created the pages “Sample Page 1” and “Sample Page 2” in the admin area of your WordPress website. If no menus are created in the admin menu screen, you probably see a default menu in the front view with all the pages available.

Once you add a menu under Appearance->Menu and select one of the default locations (Primary or Secondary) a new tab “Location” will appear next to the “Edit Menu” tab.

You can use the left sidebar to add the menu items of your choice by selecting from the available content.

If you add a custom menu from inside the admin menu screen, it will display instead of the default one.

If you’ve activated a block theme like Twenty Twenty-Three that has a full site editor, you can easily add navigation to the layout by going to the editor under the Appearance->Editor admin menu item.

The WordPress register_nav_menus function

The register_nav_menus function is used to register navigation menus in your WordPress theme. It accepts an array of menu locations as an argument, and each location is associated with a unique identifier or theme location name.

register_nav_menus( string[] $locations = array() )

For example:

function my_theme_register_menus() {
    register_nav_menus( array(
        'primary-menu' => __( 'Primary Menu', 'my-theme' ),
        'footer-menu'  => __( 'Footer Menu', 'my-theme' ),
    ) );
add_action( 'after_setup_theme', 'my_theme_register_menus' );

In the functions.php file of your activated theme, you can see the slugs for your menu locations. In the GeneratePress theme, for example, around line 57 in the functions.php file:

// Register primary menu.
        'primary' => __( 'Primary Menu', 'generatepress' ),

These are the menu name you can work with in the wp_nav_menu function’s arguments we will examine next.

The WordPress wp_nav_menu function

In WordPress websites, the way to be flexible enough with the menus and personalize them in a way suitable to your project is by making use of the WordPress-related built-in function, the wp_nav_menu function.

The register_nav_menus function works with the wp_nav_menu function in order to display the navigation menus.

Try our Award-Winning WordPress Hosting today!

The goal of this function is to let you make menu links on your WordPress pages that will look and work in a personalized manner.

The structure

The wp_nav_menu function arguments that control its appearance and behavior are the following:

wp_nav_menu( array $args = array(
	'menu'				=> "", // (int|string|WP_Term) Desired menu. Accepts a menu ID, slug, name, or object.
	'menu_class'		=> "", // (string) CSS class to use for the ul element which forms the menu. Default 'menu'.
	'menu_id'			=> "", // (string) The ID that is applied to the ul element which forms the menu. Default is the menu slug, incremented.
	'container'			=> "", // (string) Whether to wrap the ul, and what to wrap it with. Default 'div'.
	'container_class'	=> "", // (string) Class that is applied to the container. Default 'menu-{menu slug}-container'.
	'container_id'		=> "", // (string) The ID that is applied to the container.
	'fallback_cb'		=> "", // (callable|bool) If the menu doesn't exists, a callback function will fire. Default is 'wp_page_menu'. Set to false for no fallback.
	'before'			=> "", // (string) Text before the link markup.
	'after'				=> "", // (string) Text after the link markup.
	'link_before'		=> "", // (string) Text before the link text.
	'link_after'		=> "", // (string) Text after the link text.
	'echo'				=> "", // (bool) Whether to echo the menu or return it. Default true.
	'depth'				=> "", // (int) How many levels of the hierarchy are to be included. 0 means all. Default 0.
	'walker'			=> "", // (object) Instance of a custom walker class.
	'theme_location'	=> "", // (string) Theme location to be used. Must be registered with register_nav_menu() in order to be selectable by the user.
	'items_wrap'		=> "", // (string) How the list items should be wrapped. Default is a ul with an id and class. Uses printf() format with numbered placeholders.
	'item_spacing'		=> "", // (string) Whether to preserve whitespace within the menu's HTML. Accepts 'preserve' or 'discard'. Default 'preserve'.
) );

NOTE: If you want to find and study the original wp_nav_menu code, you can open the wp-includes/nav-menu-template.php file and go to line 57.


So, let’s see some cases about what you can accomplish by modifying these arguments. The default values are:

$defaults = array(
  'menu'            => '',
  'container'       => 'div',
  'container_class' => 'menu-{menu slug}-container',
  'container_id'    => '',
  'menu_class'      => 'menu',
  'menu_id'         => '',
  'echo'            => true,
  'fallback_cb'     => 'wp_page_menu',
  'before'          => '',
  'after'           => '',
  'link_before'     => '',
  'link_after'      => '',
  'items_wrap'      => '<ul id="%1$s" class="%2$s">%3$s</ul>',
  'depth'           => 0,
  'walker'          => '',
  'theme_location'  => ''

NOTE: To follow along with what’s coming up next and be able to reproduce it, you need FTP access to a WordPress installation. Under the active theme’s folder on your website, find the functions.php file and open it with your favorite editor.
Also, in order to test safety, make sure you know your way on how to create a child theme.


Let’s run through some worked examples.

Show menu only to logged-in users

wp_nav_menu( array(
    'theme_location' => is_user_logged_in() ? 'logged-in-menu' : 'logged-out-menu'
) );

Here, we used the is_user_logged_in function in combination with the wp_nav_menu function. The is_user_logged_in function returns true or false and determines whether the current visitor is a logged-in user.

Customize menu CSS

wp_nav_menu( array(
  'theme_location' => 'primary',
  'menu_class'     => 'custom-menu-class',
) );

‘menu_class’ is set to ‘custom-menu-class’, which sets the CSS class for the menu’s container element. This allows you to add your own CSS to the menu by editing your child theme‘s CSS like this:

// container class
header .my-menu-class{}
// container class first unordered lists
header .my-menu-class ul {}
header .my-menu-class ul ul {}
// navigation items
header .my-menu-class li {}

and so on.

Wrap the menu?

wp_nav_menu( array( 'container' => false, ) );

The container argument is used to control whether the menu should be wrapped in a container element. Whether to wrap the ul and what to wrap it with.

The same way you can override container_class and container_id:

wp_nav_menu( array(
  'theme_location' => 'primary',
  'container'      => 'nav',
  'container_class'=> 'custom-container-class',
  'container_id'   => 'custom-container-id',
) );

Wrap Items

You can do the same to change the HTML structure that surrounds the list of menu items by using this example:

wp_nav_menu( array(
  'theme_location' => 'primary',
  'items_wrap'     => '<ul class="custom-menu">%3$s</ul>',
) );

Text before or after the link text

You can benefit from this if you want to add just text or even wrap the link with an HTML element, like a span:

wp_nav_menu( array(
  'theme_location' => 'primary',
  'link_before'    => '<span>',
  'link_after'     => '</span>',
) );

Walker Class

In WordPress 2.1, the WordPress Walker Class was added to give developers a way to walk through tree-like data structures in order to render HTML. It has since proven to be a great feature for menu customization. Luckily, we have a great article dedicated to this topic that we recommend you take your time and study. In our Walker Class article, you will get familiar with how the walker parameter works and how to customize the outputs in your own way.


The wp_nav_menu function allows you to modify and personalize the default menu’s behavior by overriding its arguments. By studying the code and consulting the examples we provided, you can play around and eventually create unique menus that match your WordPress website, and offer a user-friendly navigation experience for your users.

Start Your 14 Day Free Trial

Try our award winning WordPress Hosting!


See how Pressidium can help you scale
your business with ease.