Adding a Nav menu to post admin

To see how such a list can be created look at the code in wp-admin/includes/nav-menu.php. Unfortunately, it is hard coded there, so you have to re-create the code.

First, let’s create two menus:

enter image description here

We can get these menus in PHP with wp_get_nav_menus() (a wrapper for get_terms()):

$menus = wp_get_nav_menus();
print '<pre>' . htmlspecialchars( print_r( $menus, TRUE ) ) . '</pre>';

Output:

Array
(
    [0] => stdClass Object
        (
            [term_id] => 5
            [name] => Paradigmatic Inconvenience
            [slug] => paradigmatic-inconvenience
            [term_group] => 0
            [term_taxonomy_id] => 5
            [taxonomy] => nav_menu
            Adding a Nav menu to post admin => 
            [parent] => 0
            [count] => 0
        )

    [1] => stdClass Object
        (
            [term_id] => 6
            [name] => Paul
            [slug] => paul
            [term_group] => 0
            [term_taxonomy_id] => 6
            [taxonomy] => nav_menu
            Adding a Nav menu to post admin => 
            [parent] => 0
            [count] => 0
        )
)

Now we build the selector function:

/**
 * Build a dropdown selector for all existing nav menus.
 *
 * @author Thomas Scholz, toscho.de
 * @param  string $name     Used as name attribute for the select element.
 * @param  string $selected Slug of the selected menu
 * @param  bool   $print    Print output or just return the HTML.
 * @return string
 */
function t5_nav_menu_drop_down( $name, $selected = '', $print = TRUE )
{
    // array of menu objects
    $menus = wp_get_nav_menus();
    $out="";

    // No menu found.
    if ( empty ( $menus ) or is_a( $menus, 'WP_Error' )  )
    {
        // Give some feedback …
        $out .= __( 'There are no menus.', 't5_nav_menu_per_post' );

        // … and make it usable …
        if ( current_user_can( 'edit_theme_options' ) )
        {
            $out .= sprintf(
                __( ' <a href="https://wordpress.stackexchange.com/questions/41695/%s">Create one</a>.', 't5_nav_menu_per_post' ),
                admin_url( 'nav-menus.php' )
            );
        }
        // … and stop.
        $print and print $out;
        return $out;
    }

    // Set name and ID to let you use a <label for="id_$name">
    $out = "<select name="$name" id='id_$name'>\n";

    foreach ( $menus as $menu )
    {
        // Preselect the active menu
        $active = $selected == $menu->slug ? 'selected' : '';
        // Show the description
        $title  = empty ( $menu->description ) ? '' : esc_attr( $menu->description );

        $out .= "\t<option value="$menu->slug" $active $title>$menu->name</option>\n";
    }

    $out .= '</select>';

    $print and print $out;
    return $out;
}

Calling this function …

t5_nav_menu_drop_down( 'my_nav_select', 'paul' );

… will give us a nice, simple select element with 'paul' pre-selected:

enter image description here

Now we need a meta box to offer the selector to our post authors. To keep this short, I just use a child class of my Basic Meta Box. Basically, you call the function in the meta box and save the menu slug as post meta.

enter image description here

Then you can access the selected nav menu slug in your theme per:

get_post_meta( get_the_ID(), '_t5_nav_menu_per_post', TRUE );

Another way to get the full nav menu in your theme:

// Print a wp_nav_menu
do_action( 
    't5_custom_nav_menu', 
    // an array of wp_nav_menu() arguments.
    array ( 
        'menu' => 'default-menu',
        // you may set a custom post ID
        'post_id' => get_the_ID() 
    ) 
);

Because I like your idea very much I’ve added a theme helper function and mangled everything into a plugin. Get it on GitHub: T5 Nav Menu Per Post.

Oh, and welcome to WordPress Stack Exchange. Don’t worry about your English as long as you ask – and answer – interesting questions. 🙂

Update

To use the plugin with a custom post type like your portfolio just install the plugin, activate it and add the following code to the file where you register the custom post type:

add_filter( 't5_nav_menu_per_post_post_types', 'wpse41695_add_post_type' );

function wpse41695_add_post_type( $post_types )
{
    $post_types[] = 'portfolios';
    return $post_types;
}

Your code still has many problems: global variables, missing prefixes, weird indentation. Recommended reading: Coding Standards and prefix everything.

Leave a Comment