How to make a list that displays the top level subpages, and any subpages or siblings off of the current page

Lets say we are displaying a few family trees. We are currently on the family tree top-page,and we need our list to look like this:

Family Trees

Read More
  • The Smiths
  • The Joneses
  • The Does

When the user clicks the Smiths, we want the list to look like this:

The Smiths

  • The Smiths
    • Dave
    • Steve
    • Dolly
  • The Joneses
  • The Does

And when a user clicks on Steve, we want the list to also look like this:

Dave Smith

  • The Smiths
    • Dave
    • Steve
    • Dolly
  • The Joneses
  • The Does

So, we need to display a list of all subpages and siblings of the current page, as well as all siblings of every step in the hierarchy.

Any ideas?

Related posts

Leave a Reply

4 comments

  1. Forget plugins, i had the same problem and plugins created a whole raft of mess and too many db calls.

    This code will do the business for you – for ease of use, stick it in a content part and include it like so:

    get_template_part( 'subnav', 'pagename' );
    

    The problem is, you already know your children, and you know your parents. I tried using the wp-list-pages function , with echo set to false andincluding id’s but that got a little messy. This solution isnt perfect but it’s far cleaner than using a plugin or two.

    In a nutshell – you want the absolute top parent id, then you want to get all the children of the current posts ancestors:

    function get_top_id($id){
       $parents = get_post_ancestors( $post );
       return $parents[count($parents)-1]; 
    }
    
    
    function get_sub_pages($id){
    
        global $post;
    
        // get the ancestors for this depth
        $parents = get_post_ancestors( $post );
    
        //add the post id to the list in order to get the children
        array_unshift($parents, $post->ID);
    
        //reverse the order of the array
        $parents = array_reverse($parents);
    
        // specify to get all children of the top level parent
        $args = array( 'child_of' => $id); 
    
        if($subPages = get_pages($args)):
    
            // start at the first  $parents array key
           $curParent = 0;
           $childList = '<ul>';
    
           if($id == $post->ID) $class = ' class="selected"';
           $childList .= "<li" . $class ."><a href='". get_page_link( $id )."'>Introduction</a></li>" ;
    
           foreach( $subPages as $page ) :
    
                // only add the item if:
                // a: the pages parent is in the ancestors array
    
                if(in_array($page->post_parent, $parents)){ 
    
                    // get the key of the page parent within the $parents array 
                    // this helps us check if we are going to a deeper/higher level
                    $pageParent = array_search($page->post_parent, $parents);
    
                    if($curParent != $pageParent){
    
                        // if we are going deeper, add a new list for the children
                        if($pageParent > $curParent){
                            $childList .= '<ul>';
                        }
    
                        // if we are going higher, check how many depth changes                        
                        if($pageParent < $curParent){                            
                            $depthChange = $curParent - $pageParent;
    
                            // close off all the children of higher depths
                            while($depthChange > 0){
                                $childList .= '</li></ul>';
                                $depthChange --;
                            }                            
                        }
    
                        // set the new parent level
                        $curParent = $pageParent;                        
                    }
    
                    $class = '';
                    if($page->ID == $post->ID) $class = ' class="selected"';
                    if($page->ID == $post->post_parent) $class = ' class="parent"';
    
                    // leave off the trailing <li> in case there are children to be added to this
                    $childList .= "<li" . $class . "><a href='". get_page_link( $page->ID )."'>". $page->post_title . "</a>" ;
    
                }
    
           endforeach;
    
           $childList .= '</ul>';
    
        endif;
    
        return $childList;
    }
    
    // get the absolute top level parent of this page
    $topID = get_top_id();
    
    // if no parent, we are ar the top
    if(!$topID) $topID = $post->ID;
    
    echo get_sub_pages($topID);
    

    This code also adds the class ‘selected’ to the current post, and ‘parent’ to the current post parent within the list.

    Hope that helps someone!