THE DIGITAL BLOG

Advanced WordPress sub-navigation using wp_list_pages

I present a technique for layered navigation/split menus in WordPress.

Posted on November 23, 2010 15 comments

More Articles...

We recently worked on a site development for evolveOD which needed a 3-level navigation structure, the top-level being the main navigation menu, with levels 2 and 3 displayed in the sidebar.

Whilst wp_nav_menu allows us to build such complex multi-tiered menus, it unfortunately doesn't (yet) let us have as much flexibility as we sometimes need – for building more flexible split-level menus, for example.

Evolve OD

For this method we use a combination of careful page-hierarchy assignments and wp_list_pages to render the output in the sidebar.

Building the Hierarchy

First, you will need to make sure your pages are correctly assigned for this to work. This is done by simply assigning your sub-navigation pages as child pages of the top-level page (navigation parent).

For example, our navigation structure might be this:

Products
    – Toy Cars
    – Lego
            – Technic
            – Atlantis
            – Lego City
    – Dolls

Our page hierarchy must then echo this same structure by assigning your pages to the appropriate parent page.

Pre-requisites

This code uses the is_subpage() function to determine the parent page ID. To install this, simply copy the code below into your template's functions.php file:

function is_subpage() {
global $post;
if ( is_page() && $post->post_parent ) {
$parentID = $post->post_parent;
return $parentID;
} else {
return false;
};
};

The Code

Here's the code that generates the sub-navigation (level 2-3). It should be placed in the sidebar, or wherever you want the sub-navigation to appear:

<?php
$subPage = is_subpage();
$ancestor = $post->ancestors[1];
if ($subPage) : // we're on a sub-page:
if ($ancestor) : // we're a sub-sub nav item...
echo "<ul class=\"page-list\">";
wp_list_pages("title_li=&child_of=$ancestor&sort_column=menu_order");
echo "</ul>";
else :
echo "<ul class=\"page-list\">";
wp_list_pages("title_li=&child_of=$subPage&sort_column=menu_order");
echo "</ul>";
endif;
endif;
?>

Don't forget to style the menu list as you need to via the main stylesheet.

Alternative Plug-in

There's a great little plug-in you might want to try first, called "Gecka Submenu":

http://gecka-apps.com/wordpress-plugins/gecka-submenu-pro/

It utilised the wp_nav_menu function to generate split menus, so in some ways is easier to organize and change your navigation. Unfortunately though, what it cannot seem to do is give a persistent split menu on the bottom-level menu – so if you are browsing the 3rd level menu, since there are no menus in the structure beyond this level, the menu disappears.

Our solution enables the 3rd level to always remain active, which in most cases, is what you need it to do.

Have any ideas or feedback? We'd love to hear from you, so leave us a comment.

There are 15 awesome comments...

  1. John Crumpton - November 24, 2010 at 1:37 pm

    This is definitely a problem for lots of site using WP as a CMS.

    Unfortunately I couldn’t get your code to work – are there too many ” in there? Or could you check it?

  2. Dan Luton - November 24, 2010 at 3:07 pm

    Hi John,

    Thanks for commenting and spotting this error – seems like the code replacement script didn’t like the syntax and added some extra bits in there!

    Now corrected…

  3. Laurent - November 24, 2010 at 11:33 pm

    Hi,

    It is possible to use Gecka Submenu for your purpose. Simply add the advanced custom menu widget with the “start from” parameter set to “Current’s page top parent”. Having the hierarchy you wrote about, when you’ll browse any “Products” child page you will always get that menu:

    – Toy Cars
    – Lego
    – Technic
    – Atlantis
    – Lego City
    – Dolls

  4. Dan Luton - November 25, 2010 at 10:31 am

    Thanks Laurent.

    Yes – you’re right.

    I had problems more recently, a site I’m working on requires only the submenu in context to be shown, rather than the whole nav structure displayed as a whole, and in this case, Gecka Submenu didn’t work for me no matter what I tried in the config.

    Basically, to use my example menu:

    – User clicks “Products” and is shown ONLY the child items of this list – “Toy Cars” , “Lego” and “Dolls”.

    – User then clicks “Lego”, and is shown ONLY the child items – so “Technic”, “Atlantis” and “Lego City”.

    Up to this point, Gecka worked perfectly – but when you then click a 3rd level item (for example, “Technic”), because there are no 4th level items attached to “Technic”, the menu ceases to display, whereas my solution still displays the bottom set of nav items.

    It almost needs a test in Gecka to see if you are on the bottom level of a nav tree, and if so, show the child objects of the parent up one level.

    Hope that makes sense – I’m sure this would be a piece of cake for a genius like you!

    Love the plug-in, should be written into WP Core.

  5. Laurent - November 25, 2010 at 3:52 pm

    True. Submenu plugin can only show the menu starting from the current page OR from its first parent.

    I may add the behavior you talk about as an option, something like a ‘fallback’ parameter.

  6. Dan Luton - November 25, 2010 at 3:58 pm

    That would be awesome. Be sure to let us know if you do!

  7. dimitri - December 5, 2010 at 1:01 pm

    Hi!

    Is it correct the code above?

    I’m trying to use it bu it doesn’t work.

    Thank you for the usefull solution.

  8. Flo - February 10, 2011 at 10:05 am

    hi, I would like to display the 3rd level items only when I’m on the 2nd level. is this possible with this code, I can’t get it to work.

  9. Cybertramp - March 10, 2011 at 1:49 pm

    wow works like a dream and looks like it will be easily customised. Thanks a bunch you just saved me a lot of time.

  10. Patrick Samphire - May 4, 2011 at 11:26 am

    Nice. I was trying to do something like this and I couldn’t quite get it to work perfectly. I’ve simply added another case where we’re not on a subpage to display the sub-navigation in that case too (so that you can see the sub-nav from the top-level page), and it’s just what I want. Thanks.

  11. Jeff Lin - January 13, 2012 at 7:28 am

    This post helped get me over the hump. We have a site that has 4 levels of navigation, and your method definitely helped! Thanks!

  12. Jeff - January 22, 2014 at 5:59 pm

    This is close to what I am looking for and if anyone can help me, I’d be very grateful. I want a plugin similar to Gecka Submenu, except that instead of using wp_nav_menu to generate the subnav from a particular menu. I want the plugin to list subpages for a specified page id. So, for example, I want a subnav on all pages to show my “Services” menu. I could select the services page in the plugin and it would display the pages in their proper hierarchy. I am a PHP beginner and I can’t figure out how to do this.

    Thanks,

    /jk

  13. Dan Luton - January 22, 2014 at 6:24 pm

    Jeff – you should be able to do this using the code I’ve provided for listing sub-pages using wp_list_pages. You don’t need a plugin for this as it’s a native function.

  14. Suchita - January 29, 2015 at 6:32 am

    Thanks a lot. it really solved my problem. I was searching for this solution last 2-3 days but didn’t got any. But at first attempt it works.

  15. Daniel Roberts - February 18, 2016 at 12:08 pm

    Hello,

    I know this is an old post, but I thought I would right to say thank you.
    I didn’t want to go down the plugin solution so searching the internet, I found this article. and applied the solution to a theme I am working on. Very nice solution to an inherent limitation of wordpress. Thanks again

Leave a comment:

I consent to Toolbox Digital collecting and storing my data from this form, as detailed in the Privacy Notice.

Previous:

Next up: