How to list child pages with thumbnails in a Wordpress theme

By , last updated July 10, 2019

In this tutorial we will show you how to get child pages in WordPress with WP Query. We will show how to loop though all child pages of a current page and print out the result.

List child pages

The easiest way to do this is with functions (the correct way will be with plugins). In function.php of our theme we’ve added code to make the output we wanted.

1. Get all child pages

global $post;
$child_pages_query_args = array(
    'post_type'   => 'page',
    'post_parent' => $post->ID,
    'orderby'     => 'date DESC'
);

$child_pages = new WP_Query( $child_pages_query_args );

2. Loop through child pages

while ( $child_pages->have_posts() ) : $child_pages->the_post();
   the_post_thumbnail('thumbnail'); //lists thumbnails
   the_title(); // shows titles
   the_permalink(); //link to the current page

wp_reset_postdata(); //remember to reset data

NB! Remember to set thumbnails in the page’s “Set featured image” window!

3. Style the list

We’ve styled the list right in the function, but you can use it with CSS as well. Here is how our function looks like:

function my_function() {
	
global $post;
$child_pages_query_args = array(
    'post_type'   => 'page',
    'post_parent' => $post->ID,
    'orderby'     => 'date DESC'
);

$child_pages = new WP_Query( $child_pages_query_args );

if ( $child_pages->have_posts() ) :
?>
<ul class="child_page_row">
<?php 
while ( $child_pages->have_posts() ) : $child_pages->the_post();
    ?>
	<li><a href="<?php the_permalink(); ?>">
	<?php if(has_post_thumbnail()): ?>
		<div class="child_page_thumb">
			<?php the_post_thumbnail(array(240, 240)); ?>
		</div>
	<?php endif; ?>
		<div class="child_page_name">
			<?php the_title(); ?>
		</div>
		<?php if(has_post_custom_meta('Desc')) : ?>
			<div class="child_page_desc">
				<?php echo get_post_meta($post->ID, 'Desc', true); ?>
			</div>
		<?php endif; ?>
		<div class="child_page_author">
			<a href="<?php echo get_author_posts_url( get_the_author_meta( 'ID' ) ); ?>">@ <?php the_author(); ?></a>
		</div>
	</a></li>
<?php
endwhile; 
?>
</ul>
<?php	
endif;

wp_reset_postdata();
}

Here is a basic CSS code for this example that will make it look like in the “tutorials” example:

ul.child_page_row {
    list-style: none;
}
ul.child_page_row li {
    display: inline-block;
    margin: 0 0 20px 20px;
    border: 1px solid rgba(127,127,127,.1);
}
ul.child_page_row li a {
    text-decoration: none;
}
ul.child_page_row li .child_page_thumb {
    height: 240px;
}
ul.child_page_row li .child_page_name {
    margin: 15px;
    font-weight: 700;
    color: #000;
    font-size: .9em;
}

Return Child Pages

Listing Child Pages directly will print them at the top of your page. If you want to show your pages in the middle of the post or at the end, you will need to return the resulting HTML from the function.

In order to return HTML you will need to create HTML code inside the function and store it in a temporary variable $result before returning at the end.

Here’s a simple code how to get and return Child Pages from a function:

$args = array(
    'post_type'   => 'page',
    'post_status' => 'publish',
	'parent' => $parent,
	'hierarchical' => 0
);

$children = get_pages($args); 

$result = "<ul>";
foreach ( $children as $child )
{
	$child_id = $child->ID;
	$url  = get_permalink( $child_id );
	$thumb = get_the_post_thumbnail($child_id, array(240, 240));
	$title= $child->post_title;

	$link = "<a href='$url'><div class='child_page_thumb'>$thumb</div><div class='child_page_title'>$title</div></a>";

	$result .= "<li>$link</li>";
}

$result .= "</ul>";

return $result;

Make a shortcode

Easiest way to call the function from the parent page is to make a shortcode:

add_shortcode('show_child_pages', 'my_function');

Then the parent page would have just one line of code that will list all it’s child pages like you want:

[show_child_pages]

And the result: Tutorials

Show parent

In some cases we would like to list the parent along with child pages. In this case we need to add the parent page to our list.

1. Move repeatable code

In our example we will be showing the top-level page along with all its child pages styled with the same CSS. We won’t be duplicating any code specially for the parent page, but move the repeatable chunk into its own function list_page:

function list_page() {
    ?>
	<li><a href="<?php the_permalink(); ?>">
	<?php if(has_post_thumbnail()): ?>
		<div class="child_page_thumb">
			<?php the_post_thumbnail(array(240, 240)); ?>
		</div>
	<?php endif; ?>
		<div class="child_page_name">
			<?php the_title(); ?>
		</div>
		<?php if(has_post_custom_meta('Desc')) : ?>
			<div class="child_page_desc">
				<?php echo get_post_meta($post->ID, 'Desc', true); ?>
			</div>
		<?php endif; ?>
		<div class="child_page_author">
			<a href="<?php echo get_author_posts_url( get_the_author_meta( 'ID' ) ); ?>">@ <?php the_author(); ?></a>
		</div>
	</a></li>
   <?php
}

Now, we will call this function from the loop as before:

while ( $child_pages->have_posts() ) : $child_pages->the_post();
	list_page();
endwhile; 

2. Add the top-level page

To add a top-level page or parent page we will need to get it first:

$parent_page = get_page($post->ID);

Now, call our new function list_page().

That’s it!

Here is the new version of the code with a parent page:

function my_function() {
	global $post;
	$child_pages_query_args = array(
		'post_type'   => 'page',
		'post_parent' => $post->ID,
		'orderby'     => 'date DESC'
	);

	$child_pages = new WP_Query( $child_pages_query_args );

	if ( $child_pages->have_posts() ) :
		?>
		<ul class="child_page_row">
		<?php 
		$parent_page = get_page($post->ID);
		list_page();
			
		while ( $child_pages->have_posts() ) : $child_pages->the_post();
			list_page();
		endwhile; 
		?>
		</ul>
		<?php	
	endif;
	wp_reset_postdata();

}

function list_page() {
    ?>
	<li><a href="<?php the_permalink(); ?>">
	<?php if(has_post_thumbnail()): ?>
		<div class="child_page_thumb">
			<?php the_post_thumbnail(array(240, 240)); ?>
		</div>
	<?php endif; ?>
		<div class="child_page_name">
			<?php the_title(); ?>
		</div>
		<?php if(has_post_custom_meta('Desc')) : ?>
			<div class="child_page_desc">
				<?php echo get_post_meta($post->ID, 'Desc', true); ?>
			</div>
		<?php endif; ?>
		<div class="child_page_author">
			<a href="<?php echo get_author_posts_url( get_the_author_meta( 'ID' ) ); ?>">@ <?php the_author(); ?></a>
		</div>
	</a></li>
   <?php
}

List grandchild pages

In order to list grandchild pages we need to use a recursive function where we get children for one level at a time. Another approach is a bit easier. We are going to use a WordPress function get_pages to get all children and grandchildren at once.

  1. Modify the args of the query and use child_of parameter:
    $child_pages_query_args = array(
    	'post_type'   => 'page',
    	'child_of' => $post->ID,
    	'orderby'     => 'date DESC'
    );
    
    $child_pages = get_pages( $child_pages_query_args );
    
  2. Change the list_page function to get the post:
    function list_page($page) {
        ?>
        <li><a href="<?php echo get_permalink($page->ID); ?>">
        <?php if(has_post_thumbnail($page->ID)): ?>
            <div class="child_page_thumb">
                <?php echo get_the_post_thumbnail($page->ID, array(240, 240)); ?>
            </div>
        <?php endif; ?>
            <div class="child_page_name">
                <?php echo get_the_title($page->ID); ?>
            </div>
        </a></li>
       <?php
    }
    
  3. Traverse all the pages and send them to the list_page function to print the result:
    foreach($child_pages as $page) {
    	list_page($page);
    }
    

Here is the latest version of the code with parent page and all children and grandchildren:

function my_function() {
    global $post;
    $child_pages_query_args = array(
        'post_type'   => 'page',
        'child_of' => $post->ID,
        'orderby'     => 'date DESC'
    );
 
	$child_pages = get_pages( $child_pages_query_args );
 
    if ( $child_pages) :
        ?>
        <ul class="child_page_row">
        <?php 
        $parent_page = get_page($post->ID);
        list_page($parent_page);
             
        foreach($child_pages as $page) {
            list_page($page);
		}
        ?>
        </ul>
        <?php    
    endif;
    wp_reset_postdata();
 
}
	
function list_page($page) {
    ?>
    <li><a href="<?php echo get_permalink($page->ID); ?>">
    <?php if(has_post_thumbnail($page->ID)): ?>
        <div class="child_page_thumb">
            <?php echo get_the_post_thumbnail($page->ID, array(240, 240)); ?>
        </div>
    <?php endif; ?>
        <div class="child_page_name">
            <?php echo get_the_title($page->ID); ?>
        </div>
    </a></li>
   <?php
}

add_shortcode('show_child_pages_custom', 'my_function');

Errors and crashes

If your site crashes while trying some of the code samples above, then it’s probably some kind of PHP error. You need to take a look at your PHP error log file. Check out debugging options in WP.

Senior Software Engineer developing all kinds of stuff.