Day 14: Posts Within Posts – Playing With The Loop

When I started 24 Days of WordPress I put out a call to my followers on Twitter and asked what they wanted me to write about. I got several responses asking for a tutorial on how to mess with the loop, so that’s what I’m going to give you today on this 14th Day of WordPress.

Displaying posts from the same category within a post

In this tutorial I’m going to give you a very specific example of a method that is open to a wide variety of configurations and outcomes. It is based on the loop I created to serve up the featured images pointing to other video posts within the same category in the Philip Lanyon website mentioned in Day 13’s tutorial on Featured Images. The basic idea is this: When you open a single post WordPress displays selected content from the most recent published posts from the same category at the bottom. I say “selected content” because with this method you can call any part of the content you want, from just the title or the featured image to the entire post. This is accomplished by setting up an extra loop within the post that jumps out of the post, finds the other posts in the same category and lists them.

Setting up the loop

Before we set up the loop we need to create a bacup of the current post ID so that we can call it and WordPress doesn’t get confused about what to display:


<?php
	$backup = $post; //backup current object
	$current = $post->ID; //current page ID
?>

The first line creates a new variable called $backup and fills it with the content of $post which is the current post you are on. The second line creates a new varialbe called $current that is set to the post ID of the current object. We’ll use this variable to make sure the current post isn’t listed again.

Now we need to set up a loop. I’ll give you the code first and then explain what it does:


<?php
	global $post;
	$thisCat = get_the_category();
	$currentCategory = $thisCat[0]->cat_ID;
	$myposts = get_posts('numberposts=2&order=DESC&orderby=ID&category=' . $currentCategory);
	foreach($myposts as $post) :
	setup_postdata($post);
?>

... do something with the loop output ...

<?php endforeach; ?>

From top to bottom this pile of code (1) tells WordPress we want all the data related to the current post, (2) creates a new variable called $thisCat that is filled with the category ID(s) for the current post, (3) creates a new variable called $currentCategory that is filled with the first category ID from the list, (4) creates a new variable called $myposts that makes a loop that displays two posts in decending order based on their ID numbers from the category defined in $currentCategory, (5) creates a loop that sets the ID value of $post to the ID value of $mypost and finally (6) sets up the postdata (so all the content) of the new post.

Still with me? Good.

OK, so now we have a loop that finds the other posts in the category and displays them. The key funciton here is actually the get_posts() function and to change something (like the number of posts displayed or the order) you tweak the variables of that function.

Resetting the $post ID

Before we get deeper into this, let’s reset the $post ID so WordPress doesn’t get confused about what’s going on. You’ll remember at the beginning we created a variable called $backup? Now we need to set $post back to $backup. That way we can call things like comments from the main post after the loop has run it’s course:


<?php
	$post = $backup; //restore current object
	wp_reset_query();
?>

Making it work

If you run this script in your single.php file now you should get two sets of the text “… do something with the loop output …” appearing in your post. That means it’s working. Now all that’s left is to call some of the post content and display it. The following code goes in place of “… do something with the loop output …” and displays the post title, post date and excerpt with the post title as a link:


<h2><a href="<?php the_permalink() ?>" title="<?php the_title() ?>" rel="bookmark"><?php the_title() ?></a></h2>
<div class="date"><?php the_time('F j, Y'); ?></div>
<div class="theExcerpt"><?php the_excerpt(); ?></div>

Run this in WordPress and you’ll see that now you get a listing of the two most recent posts in this category with title, publication date and excerpt right inside your current post. Cool, eh? But there is still one problem: If your current post is one of the two most recent posts, it’ll be displayed twice. That’s just confusing, so we have to fix it.

Excluding your current post from the loop

At the very beginning of this tutorial we created a backup for the current post item and we also grabbed the current post ID. Now we’re going to use that current post ID to exclude the current post from the new loop. To do this we have to change the get_posts() variable to add an exclude variable:


$myposts = get_posts('numberposts=2&order=DESC&orderby=ID&category=' . $currentCategory . '&exclude=' . $current);

With the exclude in place we now have a fully functional loop that doesn’t create duplicate content.

OK, so where do I put this thing?

You probably have a pretty good idea what I am thinking here: In the twentyten theme you currently have a link to the previous and next post at the top and the bottom of each post. I find this quite unuseful and it’s also a bit of a pleonasm. So here’s what I suggest (and a warning here: You’re going to have to do some styling on your own to make this look decent): In your twentyten child theme create a duplicate of the single.php file, find and comment out lines 57 to 60 and paste in this new block of code instead. That way when people land on your pages they’ll get a preview of the two most recent articles written within this same category. If that’s not added value I don’t know what is.

Here, in case you got confused, is the entire loop code:


<?php
	$backup = $post; //backup current object
	$current = $post->ID; //current page ID
?>
<?php
	global $post;
	$thisCat = get_the_category();
	$currentCategory = $thisCat[0]->cat_ID;
	$myposts = get_posts('numberposts=2&order=DESC&orderby=ID&category=' . $currentCategory . '&exclude=' . $current);
	foreach($myposts as $post) :
	setup_postdata($post);
?>
<div>
	<h2><a href="<?php the_permalink() ?>" title="<?php the_title() ?>" rel="bookmark"><?php the_title() ?></a></h2>
	<div class="date"><?php the_time('F j, Y'); ?></div>
	<div class="theExcerpt"><?php the_excerpt(); ?></div>
</div>

<?php endforeach; ?>

<?php
	$post = $backup; //restore current object
	wp_reset_query();
?>

Go forth and create loops my friends!

This tutorial is part of the 24 Days of WordPress series. If you want to learn more about WordPress and Expression Web check out the Sams Teach Yourself Microsoft Expression Web in 24 Hours series (version 2, 3 and 4), Lynda.com’s WordPress 3.0 Essential Training course and Microsoft Expression Web 4 LiveLessons.

4 thoughts on “Day 14: Posts Within Posts – Playing With The Loop

  1. Been occasionally using this for a long time, and loving it. But then all of the sudden it stopped “working”, either around WP 3.5 or 3.5.1 (my current version).

    The problem is that other queries lower on (such as in the footer) that use this code now do not work. $post is messed up or something. When commenting this out, those queries work fine again. Odd.

    Can you confirm?? Will dig in and see what’s not working.

    Thanks!

Comments are closed.