Folding menu for WordPress pages using jQuery

jQuery folding menu for WordPress

Let’s talk about a simple technique to create folding or collapsible menus for the WordPress Pages widget. A while ago I was doing some coding for a IT Solutions site and they had a large ‘Services’ page with an introduction and 6 sections. They needed a parent page for the intro and 6 child pages and they didn’t wanted to show all the pages and subpages at once. I thought this would be an excellent job for jQuery and a collapsible or folding menu.

We’ll be creating here a folding menu using only jQuery, no CSS no special markup, and enqueueing the script with the recommended technique for WordPress.  Keep reading to see the solution…
This is what is going to happen after we enable our folding menu when someone clicks on a page that has subpages:

folding

Let’s start by looking at the structure and see which selectors we could use. WordPress assigns a current_page_item class to the current page and a page_item class to any other page. When a page has children, the nesting is ‘.page_item ul‘ and ‘.current_page_item ul‘. We can start writing this:

jQuery(document).ready(function(){

jQuery(".page_item ul").hide();

jQuery(".current_page_item ul").slideDown();

});

After the document is ready we hide every instance of children pages, and then, if the current page has children, we slideDown the list. That’s it, but wait, what happens if we click in one of the children? now we’re in trouble, we’re inside the ‘.current_page_item ul‘ nesting so jQuery won’t find it and therefore it won’t slide down the menu. Luckily, WordPress adds another class, which is current_page_ancestor, so we nest it with ul, the list that holds the current page, and now we can trigger the slide down effect.

jQuery(document).ready(function(){

jQuery(".page_item ul").hide();

jQuery(".current_page_item ul, .current_page_ancestor ul").slideDown();

});

Enough for the jQuery code. Let’s enqueue it using the proper technique. WordPress has a function named wp_enqueue_script that will enqueue our script and it will test if it is already enqueued. If it depends on a library, like jQuery in this case, it will check to see if it’s already enqueued too.


function ilc_addFolding_init(){
wp_enqueue_script('jquery_folding', '/wp-content/themes/default/js/folding.js', array('jquery'));
}
add_action('init', 'ilc_addFolding_init');

The first parameter is a handle name and the second is the path to the script. The third parameter is an array of handles that this script depends on. In this case, we only need jQuery, but for example, your script could depend on jQuery and jQuery UI. So, when do we ask WP to call the enqueue? you should call it from an ‘init‘ action. A wp_head hook is too late to enqueue. A template_redirect could work too but I’d rather stick to the action hook recommended in the reference. That’s all, you can now test it. You will see the parent pages visible with their children pages hidden. As soon as you click on the parent pages and the page loads, the children pages list will be shown.

Now, one more thing before we end. In the third caption there’s a Page 4 > Page 4.2 title, the parent page and the child page. We can easily display the parent using this code within the loop instead of the typical the_title:


<h2>
<?php
if ( is_page() && $post->post_parent ) {
$page = get_page($post->post_parent);
echo get_the_title($page->ID);
echo ' > ';
} else {
// This is not a subpage
}
the_title(); ?>
</h2>

If this is a page, we grab the post_parent. Then we get the page, and from that page, we retrieve the_title. We render it, add a separator ‘>’ or ” could work, and we end the conditional. Now we can display the current page title using the_title as usual.

Final thoughts

This collapsible menu is in no way perfect. Both jQuery script and parent page title display will only work for one level of nesting. Most of the times this will be enough but you can always extend the script and the php code to display more levels of nesting, to animate the children pages when they are displayed, for example, with fadeIn, or move them from right to left. jQuery always delivers a bit more.

UPDATE: March 11, 2009

Thanks to Kretzschmar bug reports I’ve modified the script so it will work on all levels of a Pages widget hierarchy. Download the WordPress plugin in the ILC Folding Menu page.


“Folding menu for WordPress pages using jQuery” received 23 comments! Add yours.

  1. Mike February 25th, 2009

    Very interesting. I was looking for a way to do this. Thanks for sharing.

  2. Ann Hyung February 26th, 2009

    Now I know why my wp_enqueue_script doesn’t work, I was using wp_head as the hook. I changed it to init and it’s working.
    Thanks for sharing this, I was looking for something completely unrelated to this post but thanks to it now I’ve the answer.

  3. Kretzschmar March 11th, 2009

    Thanks for this one. But I just can’t get it to work with more than one level of nesting.

  4. Elliot March 11th, 2009

    This will work for all levels:
    jQuery(document).ready(function(){

    jQuery(".page_item ul").hide();

    jQuery(".current_page_item ul:first, .current_page_ancestor ul").slideDown();

    });
    in fact, I think I will be coding a quick plugin. I will let you know when it’s posted.

  5. Kretzschmar^ March 11th, 2009

    Thanks Elliot. This works better but still doesn’t work 100%.

    For example:
    1. page
    1.1 subpage1
    1.1.1 subsubpage 1
    1.1.2 subsubpage 2
    1.2 subpage2

    Clicking on subpage2 opens all subsubpages of subpage1 too.

  6. Elliot March 11th, 2009

    Ok, I think it’s done now. Check the post, I’ve updated it with the plugin download. The code is:

    jQuery(document).ready(function(){
    jQuery(".page_item ul").hide();
    jQuery(".current_page_item").parents("ul, li")
    .map(function () {
    jQuery(this).slideDown();
    });
    jQuery(".current_page_item ul:first").slideDown();
    });

    Download the WordPress pages folding plugin.

  7. Michael Castilla March 11th, 2009

    Do you have a demo?

  8. Kretzschmar March 12th, 2009

    Looks like you really did it. Fantastic.
    Thank you very much.

  9. Elliot March 12th, 2009

    Michael, I don’t have a demo at the moment.
    Kretzschmar, thanks. Maybe this would have ended in a box if you hadn’t asked for a two level feature. Now it’s multilevel. Grab the wordpress plugin here
    http://www.ilovecolors.com.ar/folding-menu-plugin-wordpress/

  10. :: Folding menu for WordPress pages using jQuery :: July 4th, 2009

    [...] :: Folding menu for WordPress pages using jQuery :: Tags: Comments0 Leave a Reply Click here to cancel [...]

  11. James July 30th, 2009

    Nice work sir!

    Question – could it remember it’s state – so that if you already have children visible, and you click another child from that branch, the menu doesn’t collapse and open again needlessly?

    Cheers.

  12. Elliot August 4th, 2009

    I haven’t worked on this since I have last published them. It could be, but I really don’t have time right now :P I remember there was a guy that created another plugin based on this one and wrote me an email, you can see the pingback here at the updated plugin at the bottom of the comment list.

  13. Digital Nomad September 13th, 2009

    I am gonna try this folding menu! Thanks for sharing!

  14. Elliot September 13th, 2009

    Go ahead and try it. Let me know if you have any issues.

  15. rhinoplasty September 24th, 2009

    Nice site!

  16. Cla-ude September 29th, 2009

    Thanks for this article.
    I’ve used it to hide my subcategories in a menu using the Shopp e-commerce plugin.
    As my usual plugin wasn’t working (Shopp don’t use the normal WP categories, posts or pages but has it’s own menu), I’ve customized your code and it’s working great :-)
    Thanks one more time.

  17. Dkulagin December 2nd, 2009

    Hi! You have a good style description.

  18. ostrov December 2nd, 2009

    Thank you,
    very interesting article

  19. Rob December 21st, 2009

    I’m looking for exactly this feature but for Categories

    Have tried FoCal but it’s not working as it shouold

  20. Annedorte December 27th, 2010

    A really great and useful plugin. However I have trouble on my site because there are two menus and it unfolds both. The top menu is a dropdown and should remain that way so only the parent is showing. In the sidebar I have a widget with my pages and I want that to fold/unfold. It works well. Except that when the plugin is activated it unfolds the top menu too. How do I change that?

  21. Elio December 27th, 2010

    Annedorte, you’re going to have to add more specificity by including, for example, the ID of the sidebar where the widget is loaded or the ID of the widget, here:

    jQuery(".page_item ul").hide();
    jQuery(".current_page_item ul").slideDown();

    For instance, if the widget is loaded in a sidebar with id=”secondary” add this:

    jQuery("#secondary .page_item ul").hide();
    jQuery("#secondary .current_page_item ul").slideDown();

    Otherwise you need to enter the ID of the widget, so that it works more specifically, for instance:

    jQuery("#pages-2 .page_item ul").hide();
    jQuery("#pages-2 .current_page_item ul").slideDown();

    BTW, make sure you’re using the updated version of this code (which is actually a WordPress plugin) located in this page.

  22. Annedorte January 2nd, 2011

    Dear Elio,

    Thank you for your quick reply. I will try that.

    Happy new year.
    Kind regards,
    Annedorte

  23. Mark February 18th, 2011

    Instead of the Pages widget, we use Custom Menus (WP 3) which uses classes like menu-item, menu-item-type-TYPE, menu-item-ID, current-menu-item, current-menu-ancestor. Is there a way to modify this plugin/script to work with custom menus instead of a Pages widget?

Leave a comment