wp_list_pages() but only show children on the branch you are on

Lets say I have this menu:

Top
    |___    Sub 1
            |___    Sub Sub 1
            |___    Sub Sub 2
            |___    Sub Sub 3
            |___    Sub Sub 4
    |___    Sub 2
            |___    Sub Sub 1
            |___    Sub Sub 2
            |___    Sub Sub 3
            |___    Sub Sub 4
    |___    Sub 3
            |___    Sub Sub 1
            |___    Sub Sub 2
            |___    Sub Sub 3
            |___    Sub Sub 4
    |___    Sub 4
            |___    Sub Sub 1
            |___    Sub Sub 2
            |___    Sub Sub 3
            |___    Sub Sub 4

I can list that menu using this:

Read More
    if( 0 == $post->post_parent && 0 == count( $children ) )
        return;

    if( 0 == $post->post_parent )
    {
        $child_of = $post->ID;
    }
    else {
        $parents = get_post_ancestors( $post->ID );
        $child_of = end( $parents );
    }

    $args = array
    (
        'child_of' => $child_of,
        'echo' => 0,
        'title_li' => ''
    );

    $pages = wp_list_pages( $args );

This is fine but I don’t want to show all page items. What I want is that only imediate children of the page you are on is shown.

So if I’m on page Top the menu should appear like so:

Top
    |___    Sub 1
    |___    Sub 2
    |___    Sub 3
    |___    Sub 4

If I’m on page Top/Sub 3 the menu should appear like so:

Top
    |___    Sub 1
    |___    Sub 2
    |___    Sub 3
            |___    Sub Sub 1
            |___    Sub Sub 2
            |___    Sub Sub 3
            |___    Sub Sub 4
    |___    Sub 4

And so on, so that it can work to any depth.

Rarst put up a nice answer but this was for when using WordPress menus. I’m looking for the same for wp_list_pages(). Looking for an answer that uses a Walker or filters/hooks. I know how to solve this problem with CSS but this doesn’t fix the problem of unnecessary HTML being sent to the browser.

Related posts

Leave a Reply

3 comments

  1. I have come up with my own solution but I’m not convinced it’s the best.

        $parents = array( $post->ID );
        if( 0 != $post->post_parent )
        {
            $parents = array_merge( $parents, get_post_ancestors( $post->ID ) );
        }
        $child_of = end( $parents );
    
        $args = array
        (
            'child_of' => $child_of,
            'echo' => 0,
            'title_li' => '',
            'walker' => new chg_Sub_Page_Navigation_Walker( $parents )
        );
    
        $pages = wp_list_pages( $args );
    

    Walker:

    class chg_Sub_Page_Navigation_Walker extends Walker_Page
    {
        var $parents = array();
    
        function __construct( $parents )
        {
            $this->parents = $parents;
        }
    
        function start_el( &$output, $page, $depth, $args, $current_page )
        {
            if( in_array( $page->post_parent, $this->parents ) )
                parent::start_el( &$output, $page, $depth, $args, $current_page );
        }
    
        function end_el( &$output, $page, $depth )
        {
            if( in_array( $page->post_parent, $this->parents ) )
                parent::end_el( &$output, $page, $depth );
        }
    }
    
  2. You can consider using a mixture of get_children() for the children of the page and page siblings and get_post_ancestors() for the ancestors:

    global $post;
    
    $pages =& get_children(array(
      'post_type' => 'page',
      'post_parent' => $post->ID,
    ));
    
    $siblings = get_children(array(
      'post_type' => 'page',
      'post_parent' => $post->post_parent,
    ));
    
    $ancestors = get_post_ancestors($post->ID);
    

    Edit – a quick demonstration of the idea which can use some clean up:

    <ul>
    <?php
        global $post;
    
        $children =& get_children(array(
            'post_type' => 'page',
            'post_parent' => $post->ID,
        ));
    
        $siblings = get_children(array(
            'post_type' => 'page',
            'post_parent' => $post->post_parent,
        ));
    
        $ancestors = get_post_ancestors($post->ID);
    
        if(!empty($ancestors)):
            $ancestors = array_reverse($ancestors);
            foreach($ancestors as $aid):
                $p = get_post($aid);
                ?>
                <li>
                    <?php echo $p->post_title ?>
                    <ul>
            <?php endforeach?>
    
            <?php if(!empty($siblings)): ?>
                <?php foreach($siblings as $sibling): ?>
                    <li>
                        <?php echo $sibling->post_title?>
                        <?php if($sibling->ID == $post->ID && !empty($children)): ?>
                            <ul>
                                <?php foreach($children as $child): ?>
                                    <li><?php echo $child->ID ?></li>
                                <?php endforeach?>
                            </ul>
                        <?php endif ?>
                    </li>
                <?php endforeach ?>
            <?php endif ?>
    
            <?php foreach ($ancestors as $aid):?>
                </ul></li>
            <?php endforeach ?>
        <?php endif  ?>
    </ul>