Multiple loops, post formats, and content types in a single home page template

Wow. That title is a mouthful. And given the improbable combination of different content types, I’m actually somewhat surprised that I did, in fact, pull off just that. In working on a client site for a Christian ministry in the Democratic Republic of Ghana, I set out today to create this:

ibm homepage Multiple loops, post formats, and content types in a single home page template

What we have here is a Dynamic Content Gallery at the top, a YouTube video, some static content, and then two different areas for recent posts in different formats. The key here is that everything should be dynamic. We’re not looking to slap a YouTube embed in a home page template; I want to be able to use the new WordPress Post Formats to send the most recent video post to that slot whilst juggling all sorts of other dynamic content from everywhere else and — if at all possible — avoid duplicating anything. Here’s to proving it’s not impossible.

So, the first step is to take care of the DCG. This is the easy part.

	/* first, if we have dcg installed, display dcg inside it's own div */ 
if (function_exists ('dynamic_content_gallery')){ ?>
	<div id="dcg">
		<?php dynamic_content_gallery(); ?>	
<?php } ?>

I’ve actually got featured images set up on my other pages in this theme, so if you wanted to do an else for the case where DCG didn’t exist, you could do something like this:

	/* first, if we have dcg installed, display dcg inside it's own div */ 
if (function_exists ('dynamic_content_gallery')){ ?>
	<div id="dcg">
		<?php dynamic_content_gallery(); ?>	
<?php } else {	
// if you don't have dynamic content gallery, maybe a featured image would work?
// this is borrowing the code pretty much straight from Twentyten, so you'll need to add this to your functions.php, too
// so check with Twentyten and get that sorted first
	if ( is_singular() && current_theme_supports( 'post-thumbnails' ) &&
			has_post_thumbnail( $post->ID ) &&
			( /* $src, $width, $height */ $image = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'post-thumbnail' ) ) &&
			$image[1] >= HEADER_IMAGE_WIDTH ) :
		// Houston, we have a new header image!
		echo get_the_post_thumbnail( $post->ID );
	elseif ( get_header_image() ) : ?>
		<img src="<?php header_image(); ?>" width="<?php echo HEADER_IMAGE_WIDTH; ?>" height="<?php echo HEADER_IMAGE_HEIGHT; ?>" alt="" />
<?php } ?>

(Note: this part isn’t tested, per se…I’m just combining two different things I have going on in this theme. It should work, but if if borks your theme let me know, and I’ll fix my code.)

Okay, back to my code.

After DCG, I’ve got a video and static content. The static content is going to be whatever they have on their Home page. The video is the most recent video post. We’re using Post Formats so — like the featured image snippet above — you’ll need to enable that in your functions.php to get that working before you try this.

<div class="content home">
<?php /* this is the main home page stuff...there's a lot going on here 
	     first of all, we're displaying the most recent VIDEO post */ 
	query_posts( 'showposts=1' );
		if (have_posts()) : while (have_posts()) : the_post(); 
			if (has_post_format( 'video' )) { ?>	
				<div <?php post_class(); ?> id="post-<?php the_ID(); ?>"><?php the_content(); ?></div>
        <?php } endwhile; endif; rewind_posts();

So far, so good, and nothing too complex yet, right? All we’re doing here is running a loop that’s limited to 1 post, and making sure that post is a video post. Here’s where it gets fun.

		/* next, we're displaying the regular home page content.  That's right, you heard me, we're adding page content in between a bunch of dynamic post stuff */
		$ibm_home_page = new WP_Query('post_type=page&name=home'); 
		while ($ibm_home_page->have_posts()) : $ibm_home_page->the_post(); ?>
			<div <?php post_class('home-content'); ?>>
				<?php the_content(); ?>
		<?php endwhile; rewind_posts(); ?>
	<div class="clear"></div>
	<hr />

I’ve completely switched over to WP_Query to be able to grab a Page with the slug ‘home’. But since I did rewind_posts, the Loop isn’t completely freaking out. Underneath this, we’ve got even more fun times.

	<?php /* down here, we're doing two more things.  First order of business is to display the next post making sure that the next post ISN'T the video post above. we're also excluding sticky posts here to get a more linear order going on. */ 
	query_posts( 'caller_get_posts=1&showposts=1' );
		if (have_posts()) : while (have_posts()) : the_post(); if (has_post_format( 'video' )) { query_posts('offset=1&caller_get_posts=1&showposts=1'); } else { ?>
			<div <?php post_class('home-excerpt'); ?> id="post-<?php the_ID(); ?>">
				<a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><h2 class="the_title"><?php the_title(); ?></h2></a>
				<?php the_excerpt(); ?>
		<?php } endwhile; endif; rewind_posts(); ?>

Woah there. It was at this point that I started running into a couple snags. First of all, I kept getting any sticky posts popping up at the top of the list, above my single post I was trying to display. This is only supposed to be a single post excerpt, so that was not going to work. Second, the next post, under my sticky post, just happened to be my video post which I created to test the video Post Format. Which is ridiculous, right? You don’t want your video and then a big empty space under your video (because I’m using the_excerpt rather than the_content) with the title of the post for…your video. And that would be bound to happen anytime you posted a video. Ninja coding skills needed to be summoned. Or, barring that, ninja Googling skills…

The first half of the query is straightforward. caller_get_posts gets the next posts in the loop sans sticky posts. Golden. And we only want one, so that part’s obvious. Next, after we do our normal loop stuff, I throw in this if (has_post_format( 'video' )) stuff that looks like it does pretty much the same thing. Well…it does. With one exception: if the next post is a video post, we’re going to offset the query by one and grab the one after that, effectively skipping your video. It’s ugly but it works, and that’s all I wanted.

This last bit is just recent updates. With all the querying and offsetting, I know we’re going to have some issues here. But I don’t care too much about this section because all I’m looking to do here is display some links from some recent posts. On another site, I might do random posts or popular posts or most commented posts here, and none of the stuff we’ve done up to now would even matter for these. Instead, what I’m doing is adding an extra offset, and if I skip a post, no big deal — chances are, that post will be featured in the DCG above, anyway.

	<div class="home-updates">
		<h2>Recent Updates</h2>
		<?php /* finally, this last section is just a recent posts area.  we care a bit less here about sticky posts or video posts, so really the only thing I'm concerned about is the offset, which i've incremented by 1 extra just in case.  this may result in some duplicates, or, alternately, some posts missing, but, again, they're just links and they're not taking up much real estate and I'm not too concerned about it */
		query_posts( 'showposts=5&offset=2' );		
			if (have_posts()) : while (have_posts()) : the_post(); ?>			
				<a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><strong><?php the_title(); ?></strong></a><br />
			<?php endwhile; endif; rewind_posts(); ?>
<div class="clear"></div>

And there you have it. The real star of the show here is rewind_posts. If you’ve ever done multiple loops before rewind_posts came along, you’ll know that all sorts of wacky stuff can come up that throws your loop(s) off. rewind_posts allows you to use multiple loops in the same template, and then go on and do some more loops somewhere else, and nothing goes horribly awry.

Hopefully this gives someone out there some ideas of what you can do with multiple loops using query_posts. There isn’t a lot of stuff out there yet on Post Formats — particularly excluding post formats, so that was one area I sort of had to wing it. If anyone has some awesome ideas, I’d love to hear them.

(By the way, all the example text used in the mockup above comes courtesy of F*** Lorem Ipsum, which I’ve been using as an alternative to the Lorem Ipsum Generator I’ve used for years. F*** Lorem Ipsum pulls text from TV shows and commercials and is able to throw in links and line and paragraph breaks, too.)