Development, WordPress

A Responsive Menu Solution for WordPress

Edited 01/14/14 to work with WordPress 3.8

A few months ago I modified a really cool WordPress template and started using it for my own clients.  As part of the overhaul, I realized that there was no really good way (included) to turn a WordPress unordered list into a menu that would work on a mobile device.  I tried a few different solutions, but in the end went for the simple one.  A selection (drop-down) menu works well, allows for an infinite number of parent and child categories, and is easily done with a simple jQuery script.

I’ve since modified that script, and wanted to share it as a snippit with you.  Make sure you have jQuery loaded somewhere before this script:

<script>
// Create the dropdown base
jQuery(".menu-main-container li a").addClass("top-level");
jQuery(".menu-main-container .sub-menu li a").addClass("second-level");
jQuery("<select class='main-drop' />").appendTo(".menu-main-container");

// Create default option "Go to..."
jQuery("<option />", {
"selected": "selected",
"value" : "",
"text" : "Main Navigation"
}).appendTo(".menu-main-container select");

// Populate dropdown with menu items
jQuery(".menu-main-container li a").each(function() {
var el = jQuery(this);
jQuery("<option />", {
"value" : el.attr("href"),
"text" : el.text(),
"class" : el.attr("class")
}).appendTo(".menu-main-container select");
});

// Allows user to automatically "submit" selection and travel to page
jQuery(".menu-main-container select").change(function() {
window.location = jQuery(this).find("option:selected").val();
});

// adds a dash to second-level classes
jQuery('<p>- </p>').prependTo('option.second-level');

</script>

There’s one bit of code you need to include in your stylesheet (or responsive stylesheet):

.main-drop{
display: none;
}

/* All Mobile Sizes (devices and browser) */
@media only screen and (max-width: 767px) {

.main-drop{
display: block;
width: 94%;
margin: 10px 3% 10px;
}

}

This should work on most themes with a dynamic menu system.  There’s a bit of margin included with the drop downs, but you can adjust as needed.

So, what’s actually going on?

// Create the dropdown base
jQuery(".menu-main-container li a").addClass("top-level");
jQuery(".menu-main-container .sub-menu li a").addClass("second-level");
jQuery("<select class='main-drop' />").appendTo(".menu-main-container");

This code is adding classes to the links of the menu.  Typically, only the list items have a class attached to them, and this will allow us to differentiate between top level and second level navigation.  It also creates the base for the drop-downs (a “select” input) that we’ll soon populate with links.

// Create default option "Go to..."
jQuery("<option />", {
"selected": "selected",
"value" : "",
"text" : "Main Navigation"
}).appendTo(".menu-main-container select");

This creates a default option.  You can change the “text” value to whatever you want.  It becomes the default option.

// Populate dropdown with menu items
jQuery(".menu-main-container li a").each(function() {
var el = jQuery(this);
jQuery("<option />", {
"value" : el.attr("href"),
"text" : el.text(),
"class" : el.attr("class")
}).appendTo(".menu-main-container select");
});

This code searches each list item in the menu container and creates an option in the select box for each.  It pulls the link (href), the text, and the class we assigned earlier.

// Allows user to automatically "submit" selection and travel to page
jQuery(".menu-main-container select").change(function() {
window.location = jQuery(this).find("option:selected").val();
});

// adds a dash to second-level classes
jQuery('<p>- </p>').prependTo('option.second-level');

Since there’s no form element, selecting the drop-down options by themselves would do nothing.  This causes the browser to automatically go to whichever link in the drop-down is selected.  The second bit adds a dash to all second level classes – that will allow you to have a differentiates multi-level navigation.

This snippit has proven useful time and time again, and even though it’s built for WordPress, it can be adapted to any content management system that uses some sort of a semantic menu structure.