How to use WP_Term with (menu) argument in the wp_nav_menu?

Background

As you already know, wp_nav_menu() function takes an array $args as argument & menu is one of the keys to that $args array.

The key menu for the argument $args is defined as:

(int|string|WP_Term) Desired menu. Accepts (matching in order) id, slug, name, menu object.

Now, if you look deep into the implementation of wp_nav_menu() function, you’ll see that, no matter what value you provide, whether it is an int id, a string name, a string slug or an object WP_Term, it’ll always retrieve the WP_Term object for the corresponding menu id | name | slug before creating the menu.

For example: if you have a menu with id 3, name My Menu and slug my-menu; you can add that menu using any of the following CODE:

    // with id: 3
    wp_nav_menu( array(
        'menu'           => 3
    ) );

    // with name: My Menu
    wp_nav_menu( array(
        'menu'           => "My Menu"
    ) );

    // with slug: my-menu
    wp_nav_menu( array(
        'menu'           => "my-menu"
    ) );

Even if you don’t provide the menu argument, it’ll try to get the WP_Term object from other arguments like theme_location.

For example: say the menu location top was registered using register_nav_menus() function in your theme’s functions.php file & the menu named My Menu was asigned to the top location from your WP admin panel. In that case, you can get the same menu using:

    wp_nav_menu( array(
        'theme_location' => 'top'
    ) );

In each of the above cases, wp_nav_menu() function retrieves the WP_Term object before generating the menu. It uses the wp_get_nav_menu_object() function to do so.

Implementation

So instead of theme_location argument, or menu argument as int id or string name | slug, you can directly provide the corresponding WP_Term object.

One way get the WP_Term object is by using the WP_Term::get_instance() method:

    // get the WP_Term object using menu id 3
    $menu_obj = WP_Term::get_instance( 3, 'nav_menu' );

You can also get the WP_Term object with menu name | slug using get_term_by() function:

    // by menu slug
    $menu_obj = get_term_by( 'slug', 'my-menu', 'nav_menu' );

    // or, by menu name
    $menu_obj = get_term_by( 'name', 'My Menu', 'nav_menu' );

Now that you’ve got the WP_Term object $menu_obj, you can use that to generate the menu:

    wp_nav_menu( array(
        'menu'           => $menu_obj
    ) );

Use case:

So you know how to generate a menu using WP_Term object as an argument to wp_nav_menu() function. Now the question is: why will you want to use it? Apart from the fact that it’s just another option, you may want to use it because it may be a slightly faster option.

For example, if you want to use the same menu twice, once in the header & then in the footer, in that case, instead of using menu id | slug | name, you may create WP_Term object in your template for header menu:

    global $menu_obj;
    $menu_obj = WP_Term::get_instance( 3, 'nav_menu' );

    wp_nav_menu( array(
        'menu'           => $menu_obj,
        'menu_id'        => 'header_menu'
    ) );

and then simply use $menu_obj in the footer template as well:

    // global declaration is needed to access the global variable from another template
    global $menu_obj;
    wp_nav_menu( array(
        'menu'           => $menu_obj,
        'menu_id'        => 'footer_menu'
    ) );

If you look into the implementation of wp_nav_menu() function, you’ll see that by doing it this way, you will avoid a few extra function calls in WordPress core, thus the total execution will be slightly faster.

However, please remember that using theme_location argument or other options may be more convenient & better for maintenance. So whether or not you should use it totally depends on your own particular scenario. I just explained that you can & how, nothing more.