Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I have a need to make the Loop run through all of the children of a parent, all of the children of each child, etc. The reason I need the Loop instead of a listing tag like wp_list_pages is so that I can display any information associated with the pages using WP template tags and functions. It's for a showcase-style display that has hierarchical content and gets rearranged, so pages > posts for this usage.

I've gotten as far as getting the loop to show children of the current page and an inner loop going to show grandchildren, but this is just a brute-force prototype, and I need to take it to the next level.

What I think I need to do is use 1 loop that starts with post_parent (so that it shows child pages) but insert a function to change the post ID to each child page found so that the loop continues to drill down until it runs out, then backs out 1 level, goes to the next available ID, etc.

My problem is that I'm not enough of a WP programmer (or real programmer at all) to get that going. If it were all out in code I bet I could work it out, but WP has obviously got hidden functions going with have_post and the_post to cycle through the available post IDs, and that has me lost as to how to integrate what I need.

Here's where I am at the moment. Any help will be greatly appreciated!

<?php   
$args = array(
'posts_per_page' => -1,
'post_parent' => $post->ID,
'post_type' => 'page',
'post_status' => '',
'orderby' => 'title',
'order' => 'ASC',);

query_posts($args); ?>

<?php if(have_posts()) : while (have_posts()) : the_post(); ?>

<a href="<?php the_permalink();?>"><?php the_title();?>:</a>

<?php     $inner_query = new WP_Query("post_type=page&posts_per_page=-1&post_parent={$id}&order_by=title&order=ASC"); ?>

<?php while ($inner_query->have_posts()) : $inner_query->the_post(); ?>

<a href="<?php the_permalink();?>"><?php the_title();?>:</a>

<?php endwhile; // end inner loop ?>
<?php endwhile; //end outer loop ?>     
<?php endif; // end outer if have_posts?>
share|improve this question
add comment

1 Answer

up vote 4 down vote accepted

Sounds like you're looking for a recursive function, ie a function that calls itself. Here's a rough outline of how it can be done:

function wpse13669_show_all_children( $post_id, $current_level ) {
    $children = get_posts( array(
        'post_type' =>'page',
        'posts_per_page' =>-1,
        'post_parent' => $post_id,
        'order_by' => 'title',
        'order' => 'ASC' ) );
    if ( empty($children) ) return;

    echo '<ul class="children level-'.$current_level.'-children">';

    foreach ($children as $child) {

        /* Here would be the point where you
            do whatever you want to display the 
            posts. The variable $current_level can
            be used if you want to style different 
            levels in the hierarchy differently */

            echo '<li>';

        echo '<a href="'.get_permalink($child->ID).'">';
        echo apply_filters( 'the_title', $child->post_title );
        echo '</a>';

        // now call the same function for child of this child
        wpse13669_show_all_children( $child->ID, $current_level+1 );

            echo '</li>';

        }

    echo '</ul>';

    }

Note: edited my code to show the kind of nested <ul> lists it sounds like you're looking for. If you want to see how WordPress does stuff like this internally (its a lot more complicated than this, but worth figuring out if you need to do anything really custom in your code), you should look through the source code for the class-wp-walker.php file, where the Walker class that handles all the various nested lists (menus, comments, page lists, etc) throughout WP.

If you define that function with the output structure you want and just call it from within your loop, it should do what you're looking for. I put a $current_level variable in there just so that you can easily style children different from grand-children, and so on.

(within your main loop)

wpse13669_show_all_children( $post->ID, 1 );
share|improve this answer
    
Now see? Unlike WP's Loop, THIS I understand! Thank you Apples! –  dains Apr 1 '11 at 18:51
    
Ok next question - how do I accept this answer / give you karma points / send you cookies? –  dains Apr 1 '11 at 18:55
    
Ha, I know what you mean. I find it much easier to use foreach statements for any secondary loops... the globals that are overridden in the standard the_post() loop always confuse me. There should be a checkbox next to the answer where you can accept it... –  goldenapples Apr 1 '11 at 19:38
    
Oops, problemo! I found that even though this function is being called from within the loop, apparently standard WP tags don't work in it (i.e. the_permalink(), the_title(), comments_number(), etc.). –  dains Apr 4 '11 at 16:59
    
Re the above - I tried adding 'setup_postdata($child);' to the foreach loop but that didn't help. I fished around for hours trying to figure it out myself (tried replacing foreach with another Loop, which worked for the tags but failed to pass the post ID as needed). So I'm really stuck :( Might you have any advice on how I can fix this? –  dains Apr 4 '11 at 17:08
show 10 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.