How to list child pages with thumbnails in a Wordpress theme

By , last updated September 24, 2016

So we had an idea of people earning money by making tutorials for our textures site. All those tutorials needed to be listed automatic when they are approved on a tutorials page. The only problem was that we couldn’t find any plugin that could list child pages with thumbnails in WordPress like we wanted. So we wrote our own code that you can copy and use on your sites.

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();
<?php	 
}

4. 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');

Senior Software Engineer developing all kinds of stuff.

Comments

  1. chris October 2, 2015 Leave a Reply

    Is it possible to list the parent site of these childs to in the list?

    • Tatyana October 5, 2015 Leave a Reply

      Hi,
      yes, I have updated the post. Please, see section 2.

  2. Deo June 26, 2016 Leave a Reply

    Hi,

    I have followed the tutorial above and everything is working fine but my output is displayed at the top of the page instead of been displayed after the content where i have added the shortcode.

    • Tatyana June 26, 2016 Leave a Reply

      A cause to this problem is using echo to output the code from the shortcode. If you need to wrap the output in some content, you need to return a string containing the output in order for it to appear in the correct spot.

      Let me know if you struggle with it and I’ll update the post.

  3. Jerry Pflugh September 23, 2016 Leave a Reply

    Great work – What if you wanted to list the grandchild pages as well?

    • Tatyana September 24, 2016 Leave a Reply

      Hello, you may use the function get_pages. I have updated the post with a code example, see section 3.

  4. Рамиль January 23, 2017 Leave a Reply

    How to display only child pages of the first level. I tried to insert in the function value $depth=1, but it’s not working

    • Tatyana January 23, 2017 Leave a Reply

      Hello,
      not sure I understand the problem. The first section of the article “List child pages” shows how to list only child pages of the first level. Where did you try to insert depth? Which code example?

      • Рамиль January 23, 2017 Leave a Reply

        I tried pasting code taken from here, but get a 500 error. The latest version of the code is displayed correctly, but with child pages of all levels

        • Tatyana January 24, 2017 Leave a Reply

          What is the structure of your child pages?

          • Рамиль January 24, 2017

            Example:
            parent
            -child
            -child
            —-child
            —-child
            -child
            I need to leave only the first level

        • Tatyana January 24, 2017 Leave a Reply

          When you visit one of the 2 child pages – what URL do you see? I’m using this code on my tutorials page with the same structure as yours and it works.
          First level children: https://sftextures.com/tutorials
          Second level children: https://sftextures.com/tutorials/graphic-design-tutorials/

          • Рамиль January 24, 2017

            Could you send your code from functions.php to my mail. I tried to insert the function code on different sites, but everywhere the result is HTTP ERROR 500. Sorry for bothering

  5. jps July 25, 2017 Leave a Reply

    Hello. List child pages code doesn’t work. I always have HTTP ERROR 500.
    I just have copy/paste your code. I can’t find where is the problem 🙁 Please could you help me ?

    • jps July 25, 2017 Leave a Reply

      sorry for previous post. Then the code which give me ERROR 500.

      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 );

      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
      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() ) :
      ?>

      have_posts() ) : $child_pages->the_post();
      ?>
      <a href="">
      ID, 'Desc', true); ?>
      <a href="">@

      <?php
      endif;

      wp_reset_postdata();
      <?php
      }
      add_shortcode('show_child_pages', 'my_function');

      • Tatyana July 26, 2017 Leave a Reply

        Hello,
        the reason it doesn’t work for you is that you have copied and pasted all the code from my post. You shouldn’t do it as parts 1.1-1.4 are just explanations. Please remove 1.1 and 1.2 and use only part 1.3 and 1.4 in your PHP file – it will at least fix the 500 error.

Leave a Reply


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*