Display Always All Subpages in Sidebar

We hope you had a great start in 2010 and some relaxing holidays the last couple days. Our first post in 2010 is about displaying subpages in a sidebar. Anyone who uses WordPress for company websites, has mostly to do with static pages that are in an hierarchical tree. To access these pages for the user, there are many possibilities.

In this article I want to show an example in which are the main pages in a horizontal navigation. The related sub-pages are displayed in the sidebar when you click on the main page.

For better understanding we take the following page structure:

  • Home
  • Software
    • Image Editor
      • Adobe Photoshop
      • Gimp
    • Content Managment Systems
      • WordPress
      • Drupal
      • Joomla
  • Hardware
  • About us

The pages Home, Software, Hardware and About us are in the horizontal navigation. When the user clicks on Software, for example, all the subpages of Software should be shown in the sidebar.

WordPress provides for such a task the template tag wp_list_pages() with several parameters. Since we don't want to display all pages, only the parameter child_of is interesting for our purpose. The parameter child_of followed by an ID lists all subpages of the current page, if there exist subpages.

<?php wp_list_pages('child_of='.get_the_ID().'&title_li=<h5>'.__('Pages').'</h5>'); ?>

Now we come to the real problem. If you click on Content Management Systems in the sidebar, only the pages WordPress, Drupal and Joomla will be displayed. The Parent Pages are gone. Logically, since it displays only the children of the current page, which is Content Management Systems. But we always like to have to top page displayed too. Fortunately there is a function get_post_ancestors, which returns all parent pages in an array. Try the following:

<?php
$my_page = get_the_ID();
$anchestors = get_post_ancestors($my_page);
var_dump($anchestors);

// click on Software
array(0) { }

// click on Content Management Systems
array(1) { [0]=>  string(2) "63" }
// 63 is the ID of Software

// click on WordPress
array(2) { [0]=>  string(2) "65" [1]=>  string(2) "63" }
// 65 iis the ID of WordPress
?>

This would go on forever, even in more deeply nested hierarchy. Important for us are 2 things: the top page is always at the end of the array and it can return an empty array. So we just go to the end of the array and for the case that there is no parent page, we display all the subpages of this page. We write a function in our functions.php because it is easier to maintain, and may also be used in several sidebars:

function wpe_highest_ancestor(){
    global $post;

    $ancestors = array($post->ancestors);
    $page_ancestors = end( $ancestors );
    if ( !empty($page_ancestors) ) {
        $child_of = $page_ancestors;
    } else {
        $child_of = $post->ID;
    }

    return $child_of;
}

Now we use this function in our sidebar:

<ul class="sidebar">
  <?php wp_list_pages('child_of=' . wpe_highest_ancestor()); ?>
</ul>

If you want to have the name of the top-level page in the sidebar, you can use the following code:

<ul class="sidebar">
  <?php
  $child_of = wpe_highest_ancestor();
  wp_list_pages('child_of='.$child_of.'&title_li=<h5>'.esc_attr(get_the_title($child_of)).'</h5>');
  ?>
</ul>

As you can see, it is relatively easy to achieve appropriate solutions with WordPress.

Comments are closed.

8 comments

  1. Denzel Chia

    Thanks for showing how to use WordPress Functions to always list all Subpages.

    I did not know about get_post_ancestors function, I used to code my own function with multiple database queries to check for page ancestors, which is not very efficient.

    Now I can easily achieve this by using your tutorial examples! And the codes are efficient, short and neat too!

    Thanks again!

  2. matt mcinvale

    Why not use end() on the ancestors array? Then you don't have to call get_post_ancestors() and hit the database again for info you should already have.

  3. Michael

    @matt: Thanks for the tip. Post updated.

  4. Noname

    I always got different need
    1. if page got subpages, show subpages (1 level)
    2. if not, but has parrent, show siblings
    3. if not, show something different (in that case i'am on the top page, so showing the top menu on sidebar is not a good idea, as top menu is typicaly also somewhere else
    So I got 3 wdigets and widget rules plugin

    For hierarchical menu it is far more difficult and i had to solve it with very complex wp_list_pages filters - i do not want to hide the non-current pages with css and i want to show only one level of subpages and only my direct ascendants + my siblings - i thinkt this is the most natural need which solve the complexity problems. But doing this is pain in the ass

  5. Adal Design

    Clean and well written. Thanks for showing me how to to do that 🙂

  6. Richard

    Hi There

    I am currently building a wordpress CMS.

    This tutorial is very good and almost does exactly as I need it to...

    ...The next question from me would be:

    I needed to just show the children of the page I am on in the side bar, but just the immediate children, not the children of the sub pages too.

    Is there any way to show the immediate children of the page you are on? I tried to implement 'depth=1' but I could not get it to work:

    <?php wp_list_pages('child_of='.get_the_ID('depth=1').'&title_li='.__('Next Steps').''); ?>

    Any chance you can help with this at all? I have been asking Google all morning, but so far it has come up short 🙂

    I look forward to your response 🙂

  7. Richard

    Hello Again

    I have been thinking about it and it may also be beneficial to show siblings of the child I am on.

    any chance you can help me work that out too?

    thanks

    Richard

One pingback

  1. Subpagina’s samen met hoofdpagina’s tonen in sidebar | WordPress Dimensie