WordPress: Create a dropdown select menu with wp_nav_menu()

With fluid layouts, and all the talk about mobile device compatibility, you may find that you're needing a way to display your menus as select boxes, instead of the default ul scheme that Wordpress uses.

In order to do this, we need to assume that you are already using the WordPress menuing feature, if you are not, simple add the code below to your functions.php file, and create yourself a menu:

add_theme_support( 'menus' );
add_action( 'init', 'register_my_menus' );

function register_my_menus() {
    register_nav_menus(
        array(
            'mobile-nav' => 'Mobile Navigation'
        ));
}

Now in order to get this menu to display, we use wp_nav_menu(), but to get it to display as a select box we need to customize it a bit. First, we need to add the select wrapper, and an empty first item – so that the select box can ‘rest’ there until a page is selected. Then we have to point it to a new Walker. The walker is responsible for traversing the menu data, and actually creating the menu. So, add this block of code to the area in your theme where you want the select box to appear:

*Remember to change main-nav to whatever your menus’ name is.

if ( has_nav_menu( 'mobile-nav' ) ) {
    wp_nav_menu( array(
        'theme_location' => 'mobile-nav',
        'items_wrap'     => '<select id="drop-nav"><option value="">Select a page...</option>{257ff5eee955dcce42a38bc16956f0ac3408a79bb49aa45fe4d698fd01d3deb6}3$s</select>',
        'walker'  => new Walker_Nav_Menu_Dropdown()));
}

We then need to create the new Walker, Walker_Nav_Menu_Dropdown, to make this happen. Good thing WordPress has one we can piggyback on. Copy the following to your functions.php file:

class Walker_Nav_Menu_Dropdown extends Walker_Nav_Menu {

    function start_lvl($output, $depth) {    }

    function end_lvl($output, $depth) {    }

    function start_el($output, $item, $depth, $args) {
        // Here is where we create each option.
        $item_output = '';

        // add spacing to the title based on the depth
        $item->title = str_repeat("&amp;nbsp;", $depth * 4) . $item->title;

        // Get the attributes.. Though we likely don't need them for this...
        $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
        $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
        $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
        $attributes .= ! empty( $item->url )        ? ' value="'   . esc_attr( $item->url        ) .'"' : '';

        // Add the html
        $item_output .= '<option'. $attributes .'>';
        $item_output .= apply_filters( 'the_title_attribute', $item->title );

        // Add this new item to the output string.
        $output .= $item_output;

    }

    function end_el($output, $item, $depth) {
        // Close the item.
        $output .= "</option>\n";

    }

}

Viola! Now you can output your menus into select boxes!

In order to use this as a navigation tool however, we need to add a few lines of Javascript, so that when a user selects a page from the dropdown, we can redirect them to that page. We will use jQuery for this, so you can add the event handler to your Document Ready function, or paste the whole thing in functions.php:

add_action('wp_footer', 'dropdown_menu_scripts');
function dropdown_menu_scripts() {
    ?>
        <script>
          jQuery(document).ready(function ($) {
            $("#drop-nav").change( function() {
                    document.location.href =  $(this).val();
            });
          });
        </script>
    <?php
}