WordPress loop with x big posts in one column then a grid of y smaller posts in z columns

Here’s how I managed to get this loop to work for the custom WordPress theme I whacked off for my friend and erstwhile colleague Phil Morse AKA Digital DJ Tips

The challenge I set myself was to get the loop to display posts in two formats: first a certain number of posts with large excerpts and any images via the_content then a grid of 3 rows of mini-posts showing just the title… it may not sound tricky but the devil is in the detail: stepping in and out of the loop to open and close container divs is not widely documented (well not that I could find)…

Couple of catches

  • using multiple loop solutions causes the pagination to fail: link to older posts would reload the same content. To get proper pagination you need to stick with one loop.
  • I needed to inject some HTML in and around the mini posts to keep formatting and layout controllable:
    • need to add a class of “last” on the last item in a row to make use of the full width available with margin right on all except the last element of the row
    • beware the dreaded...

      each row of x mini-posts had to be wrapped in a div as these mini-posts are of unequal height (a design decision). With uneven heights floating them all within a single div causes the dreaded float-stack-horror.
  • As we’re injecting extra HTML markup every x items we also need to be able to close this markup prematurely if we run out of posts before the row is finished. Therefore we need to know the total number of posts in the loop so this thing can close itself early if need be.

In the end I also decided that I wanted the logic to be easily adaptable to allow changes to the number of full excerpt posts and the number of columns in the following rows. Thats easily changed with the variable set at the outset here and by varying the denominator in the integer test bit (simplerer than it sounds).

Cut-n-paste to the chase already…


get_header(); ?>

	<div id="content">

	<?php if (have_posts()) : ?>
		/* Custom loop to show n main posts (title + excerpt) then
		   finish with remainder as small posts (just title) in markup that allows
		   columns of unequal mini-posts in rows.

		   Here one main post then subsequent mini-posts in rows of 3.
		   Total number per page defined in WP options

 		$count = 0; //start the counter
		$main_posts = 1; //set the number of main posts

	<?php // find out how many posts so we can close this thing properly at the last post
	$totalposts = sizeof($posts); ?>

	<?php while (have_posts()) : the_post(); ?>
	<?php $count++; //increment counter by 1 ?>
	<?php $small_posts_count = ($count - $main_posts) ; // calculate the number of small posts ?>
	  <?php if ($count < ($main_posts + 1)) : // if within the range of main post set above then...  ?>
				<div <?php post_class('sheet') ?> id="post-<?php the_ID(); ?>">
					<h2><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h2>
					<div class="entry">
						<?php the_content('Read more') ; ?>
		<?php else : // if loop is at small_posts start a wrapper div.loop2 for next row of posts ?>
			<?php // if (count-1)/3 is an integer then it's first in the row: open the wrapper
				if (($small_posts_count - 1) % 3 == 0 ) { echo '<div class="loop2 clearfix">';} ?>
				<div class="sheet<?php if ((isset($small_posts_count)) && ($small_posts_count % 3 == 0 )) { echo ' last';} // same logic to add class of last to last item in row of three ?>" id="post-<?php the_ID(); ?>">
					<h4><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></h4>
			<?php //close the row if multiple of three (using same logic as above) or if it's the last post
				if (($count == $totalposts) || ($small_posts_count % 3 == 0 )) { echo '</div><!-- .loop2 -->';} // if is multiple of three ?>

	  <?php endif; ?>

		<?php endwhile; ?>

		<?php if (!is_page()) { // get older and/or newer posts links (not for single posts) ?>
		<?php include( TEMPLATEPATH . '/tpl.nav.posts.php' );  ?>
		<?php ; } ?>

		<?php else : ?>
		<?php include( TEMPLATEPATH . '/tpl.search.404.php' ); // get 404 error message ?>
	<?php endif; ?>


<?php get_sidebar(); ?>

<?php get_footer(); ?>


  1. No comments yet.

You must be logged in to post a comment.