One of our responsibilities as developers is not only to make things work, but to make things work well (read: easily) for the end-user.
I was recently handed a project where the client had a page that needed to display a drop-down menu of its sub-pages. There were 5+ pages like this.
The seemingly easiest thing to do was make a template for each of these “special cases” and register a menu for each one.
Making so many one-off page templates feels like a poor development practice. That’s a lot of repeated code. Not only that but any time the client wants to add a sub-page they then have to go find an update the corresponding menu.
What if they want page that is a brand new category? Do they come back to us? We can do better than this.
What We’re Making
Regardless of the method we use to populate the list, what gets shown to the user is the same: a drop-down list. Here’s a static demo.
Doing It Better
Instead of doing this with WordPress’ menus we’re going to use the wp_list_pages
function. Then we’re going to use some CSS and a little JavaScript to make it a pretty, functioning drop-down menu.
The first step is to list the sub-pages on your template.
<?php $args = array( 'child_of' => get_the_ID(), 'depth' => 1, 'title_li' => '' ); ?> <div class="menu-wrap"> <ul class="sweet-menu hoverable"> <li><a href="#" class="toggle">Choose an Adventure</a></li> <?php wp_list_pages( $args ); ?> </ul> </div>
Let’s break down our arguments array.
child_of
This is how we tell wp_list_pages
which sub-pages we want to list by passing in the ID of a parent page. In our case the current page id the parent we are using, so we call get_the_ID()
to get its ID.
depth
This tells WordPress how far down the lineage we want to go. By assigning the value 1
we say we want only direct children of this page.
title_li
If we didn’t include this WordPress would start the list with “Pages”. Passing in a blank string lets WordPress know to omit the title list-item. This way we can manually create an li
with a class and an anchor instead of just text.
With that small amount of code we’ve done our part to make the reusable in different contexts and easy to use for the end user. At this point, WordPress is done with all of its work. It fetched the relevant pages and put them on the page.
Now we’ll use CSS to make it look good.
Styling the Menu
What we’ll do here is make the list look nice and hide all of the options except the first list-item.
.menu-wrap { position: relative; height: 40px; overflow-y: show; margin-bottom: 1em; } .sweet-menu { height: 40px; width: 250px; border-top: 1px solid #bbb; overflow: hidden; padding: 0; margin: 0; } .hoverable:hover, .open { height: auto; } .sweet-menu a, .sweet-menu a:visited{ display: block; line-height: 39px; background: #eee; border: solid 1px #bbb; border-top: none; padding: 0 15px; color: #444444; text-decoration: none; } .sweet-menu a:hover { background: #cccccc; color:#222222; } .toggle:after{ display: block; content: "▼"; float: right; font-size: 80%; }
Why do we have position: absolute
inside of position: relative
? The short of it is: it’s so the menu flows on top of the content instead of pushing it down.
For more about absolute positioning inside of relative, here’s an article from CSS Tricks.
We’re hiding the menu options by setting the height equal to one item and making the overflow hidden. The .open
class makes the list show all of the options.
Right now the list has the .hoverable
class which shows the whole list when the cursor is on the list. This is a fallback for browsers with JavaScript disabled.
In the next section, we’ll use JavaScript to remove .hoverable
and put .open
on our sweet menu when we click it.
The JavaScript
(function ($) { $sweetMenu = $('.sweet-menu'); $sweetMenu.on('click', function (event) { $this = $(this); if ($(event.target).hasClass('toggle')) { event.preventDefault(); $this.toggleClass('open'); } }); $sweetMenu.hover(null,function () { $(this).removeClass('open'); }); }(jQuery));
This only job that our JavaScript has is to add or remove the .open
class. We let CSS handle what is and isn’t seen.
There are 2 instances where the JavaScript does something: When the user clicks on the menu and when the user hovers off of the menu, each of which is handled by the jQuery .click()
and .hover()
methods respectively.
That’s All We Need
We’ve written everything we need to make a drop-down menu that’s easily extendable for the user. And as an added bonus: it’s not that much code.
We’re really just leveraging one of WordPress’ built-in functions to do the work that we would have had to repeat 5+ times.
Remember to take time to think about your options for implementing features and to put yourself in the user’s chair. It could save you, and them, a lot of work.
Extra Credit
One thing you may notice about the result of the provided code is that the menu appears when clicked instead of the slide down effect that happens in the demo.
At one point it was common practice to achieve this with jQuery’s .slideDown()
method, but now we can do this with CSS3’s transition
property. CSS can animate your menu’s height to achieve the opening effect, but you have to declare the height and this can be a problem because you don’t know how many items will be in it.
To go into the options available for implementing this would take more words than I would like to put in this post, but I encourage you to break down how it was achieved in the code pen demo.
No Comments