Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

As part of a theme for a client, I want to be able to show a custom menu (defined via the admin) in a select box that automatically changes pages after changing the selection.

Is there a plugin (or a handy code snippet) that will accomplish this?

share|improve this question
add comment

1 Answer

up vote 8 down vote accepted

Hi @Keith S.:

WordPress' new menu system is both wondrous and infinitely frustrating, depending on what you are trying to do and what day of the week it happens to be. :) It's a great idea but far from mature so while it's a feature I applaud I'll be happier when v3.3 or v3.4 of WordPress rolls out and we get a lot more use-cases directly supported by the menu system's API.

That said, not sure if there is an existing plugin to do what you are looking for, but how about the code you need to write you own plugin? Or you could just include it in your theme's functions.php file; whatever your preference.

What I'm providing is a fully self-contained example that you can save as test.phpin your website's root directory in order to test it. If your domain were example.com you'd load to test at:

http://example.com/test.php

Here's what it look's like in action:

Inactive drop down of Pages from WordPress 3.0 Menu Active drop down of Pages from WordPress 3.0 Menu

From the code below it should be easy to incorporate the get_page_selector() function into your theme and to call it whenever you need this functionality:

<?php

  include "wp-load.php";
  echo 'Jump to:';
  echo get_page_selector('My Select Menu');

function get_page_selector($menu) {
  $page_menu_items = wp_get_nav_menu_items($menu,array(
    'meta_key'=>'_menu_item_object',
    'meta_value'=>'page',
  ));
  $selector = array();
  if (is_array($page_menu_items) && count($page_menu_items)>0) {
    $selector[] =<<<HTML
<select id="page-selector" name="page-selector"
    onchange="location.href = document.getElementById('page-selector').value;">
HTML;
    $selector[] = '<option value="">Select a Page</option>';
    foreach($page_menu_items as $page_menu_item) {
      $link = get_page_link($page_menu_item->object_id);
      $selector[] =<<<HTML
<option value="{$link}">{$page_menu_item->title}</option>
HTML;
  }
    $selector[] = '</select>';
  }
  return implode("\n",$selector);
}

So you might wonder how it works?

The wp_get_nav_menu_items() function

WordPress 3.0 stores it's menus in the wp_posts table as post_type type of nav_menu_item. The wp_get_nav_menu_items() indirectly just calls the get_posts() function. The first parameter to wp_get_nav_menu_items() is either 1.) a menu name (which is what I used: "My Select Menu"), 2.) a menu item ID (i.e. the menu item's post ID the database) or 3.) a menu slug (the slug from the menu's taxonomy term; yes menus are implemented using taxonomy terms with a taxonomy of 'nav_menu'.)

Menu Configuration in WordPress 3.0

Beyond the first parameter it forwards on to get_posts() most (if not all?) of the $args you pass to wp_get_nav_menu_items() thus you can treat it like a custom post type (even though longer term when they improve the menu API that probably won't be such a great idea. But today? Make hay while the sun shines!)

Filtering Menu Items with meta_key and meta_value

WordPress' underlying use of posts for menu items is why we can query for meta_key and meta_value; WordPress uses a series of meta_keys prefixed with _menu_item for the additional information it needs for each menu item. _menu_item_object will contain page for every menu item that corresponds to a WordPress "Page" post type. (If you want to include items besides Pages you you'll need to do a bit more research than I did here but at least I gave you the tools you need to do the research yourself.)

Here's a screenshot using Navicat for MySQL of a query showing the meta records for several nav_menu_items:

Menu Item Configuration found in wp_postmeta with WordPress 3.0

Grabbing the Page's URL with get_post_link()

Next I'll point out that get the page's URL from the get_post_link() function and that I'm setting the HTML <option>'s value to be the URL...

<?php
    $link = get_page_link($page_menu_item->object_id);
    $selector[] =<<<HTML
<option value="{$link}">{$page_menu_item->title}</option>
HTML;

Using Javascript's onchange to Navigate to our Selected Page

...So that I can grab it from the value property of the 'page-selector' <select> element and assign it to location.href. Assigning location.href causes the browser to immediately navigate to the new URL, and that, in a nutshell, is how it's all done:

<?php
  $selector[] =<<<HTML
<select id="page-selector" name="page-selector"
    onchange="location.href = document.getElementById('page-selector').value;">
HTML;

An Empty value="" as the Default Option

You might note that the "Select a Page" default option has an empty value; that's not a mistake but instead by design. When it is selected and the "onchange" is triggered1 setting location.href to an empty string will have no effect, which is exactly what we want and it doesn't require us to write an exception code. Viola!

<?php
    $selector[] = '<option value="">Select a Page</option>';
  1. Having selection of "Select a Page" trigger "onchange" can only happen on a browser back navigation to a page that doesn't trigger a page reload where another option had previously been selected, but it can still happen so we should address it.
share|improve this answer
    
Holy crap! :) Thanks for the lesson Mike. I think this will work just fine in my case. I don't know about wrapping it in a plugin at this point, but who knows...it may just end up there. If it does, you'll of course get credit... :) Thanks for the title edit too...I was a bit frazzled when I wrote it, so I wasn't exactly thinking clearly... :) –  Keith S. Aug 25 '10 at 14:39
    
Hmmm...apparently, something is wrong here...when I add the function to my functions.php file, I get the following: Parse error: syntax error, unexpected ']', expecting T_STRING or T_VARIABLE or T_NUM_STRING in /media/storage/swd/wp-content/themes/theme2/functions.php on line 55 line 55 is the $selector[] line in the foreach... –  Keith S. Aug 25 '10 at 14:54
    
@Keith S.: Do you have any menu items for pages defined in your site yet? My code didn't protect against having zero menu items for pages (but I just updated the code to address that.) Did you make sure you used the correct menu name from your site? Did you ensure that the HTML; lines are NOT INDENTED?, i.e. that they are flush left with no spaces to the left of the HTML? Any chance your site is running on PHP4? (I don't know if this would matter, but it might.) In case you had a cut and paste error, here the code is where you can more easily copy it. gist.github.com/550217 –  MikeSchinkel Aug 25 '10 at 20:33
    
I had menu items set up, tried all sorts of indentation, but in the end, I would up doing this (which works fine...and for the record, I'm running php 5.3 on my dev server)... pastie.textmate.org/private/haynxduumjwxn8jdjtktq –  Keith S. Aug 26 '10 at 3:18
    
@Keith S. - Look like you just dropped the filter on post_type=='page' which wasn't required by I did ironically to simplify things. But since it works for you without, go for it! –  MikeSchinkel Aug 26 '10 at 11:34
show 4 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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