I'm using the following inside the wp_nav_menu function to create a select dropdown menu where each menu item is an option in the select dropdown...

'items_wrap' => '<select>%3$s</select>'
'before'     => '<option value="">'
'after'      => '</option>'

How do I add the link value in the 'before' declaration? Is there a better way to go about this? I know about wp_dropdown_pages, but that doesn't work because I want users to be able to control the menu from the "Menus" page.


You can't do this with wp_nav_menu, because it outputs list items, and you'll generate invalid markup with your code.

Try using wp_get_nav_menu_items() instead.

A quick solution for a drop down menu with a custom walker:

class Walker_Nav_Menu_Dropdown extends Walker_Nav_Menu{

    // don't output children opening tag (`<ul>`)
    public function start_lvl(&$output, $depth){}

    // don't output children closing tag    
    public function end_lvl(&$output, $depth){}

    public function start_el(&$output, $item, $depth, $args){

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

      // call the prototype and replace the <li> tag
      // from the generated markup...
      parent::start_el(&$output, $item, $depth, $args);
      $output = str_replace('<li', '<option', $output);

    // replace closing </li> with the closing option tag
    public function end_el(&$output, $item, $depth){
      $output .= "</option>\n";

In your templates use it like this:

  'theme_location' => 'primary', // your theme location here
  'walker'         => new Walker_Nav_Menu_Dropdown(),
  'items_wrap'     => '<select>%3$s</select>',
  • 1
    Actually, when using the "items_wrap" part, that removes the list items, so the markup is ok. I'll check out the link though. Thanks! – Chris Molitor Sep 1 '11 at 21:01
  • yes, but that doesn't handle the nested <UL>s :) – onetrickpony Sep 1 '11 at 21:02
  • It actually does :-) – Chris Molitor Sep 1 '11 at 21:09
  • 1
    According to the source it doesn't, unless you're using a custom walker... – onetrickpony Sep 1 '11 at 21:21
  • Does this work or not? – chrisjlee Dec 13 '11 at 16:38

I have found that useful:

You can follow any responses to simplify css code dropdovn menu.

  1. Add a class parent for items that have a submenu
  2. add depth class (depth0 , depth1, depth2 ...)

add to function.php your theme

class DD_Wolker_Menu extends Walker_Nav_Menu {
    function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ){
        $GLOBALS['dd_children'] = ( isset($children_elements[$element->ID]) )? 1:0;
        $GLOBALS['dd_depth'] = (int) $depth;
        parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
function  add_parent_css($classes, $item){
     global  $dd_depth, $dd_children;
     $classes[] = 'depth'.$dd_depth;
         $classes[] = 'parent';
    return $classes;

now in header.php

wp_nav_menu( array( 'container_class' => '','container' => '',  'menu' => 'header-menu', 'walker'=> new DD_Wolker_Menu ) );

header-menu replaced by the name of your menu

CSS example code may be the

    margin: 0;
    padding: 0;
#menu-header-menu  ul{


#menu-header-menu> li{
    display: inline;
    margin-left: 1.618em;
#menu-header-menu  li{
    list-style: none;
#menu-header-menu  li a{
    text-decoration: none;
    font-size:  1em;
    font-family:    'Lato',Helvetica,Arial,sans-serif ;
    letter-spacing: 1px;
#menu-header-menu li.parent::after{

#menu-header-menu  .sub-menu {
   display: none;
   position: absolute;
   background-color: #fff;

#menu-header-menu  li:hover>.sub-menu{
    display: inline;
    width: auto;
    height: auto;
    border: solid 1px #BBBBBB;
    z-index: +1;

where #menu-header-menu - id the main UL list (you need to update that as well)


Dropdown Menus plugin does answer the question: wp_nav_menu can't be used to create select menu dropdown, whereas plugin provides nifty dropdown_menu() function that does the job admirably.

protected by Community Dec 20 '12 at 2:28

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.