Spring Sale! Save 30% on all books w/ code: PLANET24
Web Dev + WordPress + Security

Horizontally Sequenced Display Order for WordPress Posts in Two Columns

Most WordPress-powered blogs display posts in sequential order within a single column. Like this, for example:

[ Diagram: Default WordPress Post Display Order ]

But what if you wanted to display your posts in two columns, sequentially ordered from left to right? For example:

[ Diagram: Horizontally Sequenced WordPress Post Display Order ]

This is easily accomplished using two default loops and the rewind_posts() function. The first loop will display the posts in the first column, while the second loop will display the posts in the second column. To do this, we use PHP’s modulus operator to filter out every other post from the first loop, which will display posts as follows:

  • the first most recent post
  • the third most recent post
  • the fifth most recent post

..and so on. Meanwhile, the second loop will feature all of the posts that were filtered out of the first loop:

  • the second most recent post
  • the fourth most recent post
  • the sixth most recent post

and so on, depending on the specified number of displayed posts. As you can see, this configuration divides the posts into “odd” and “even” groups. Note that there is nothing inherently “odd” or “even” about the posts in either group; we are arbitrarily assigning “oddness” and “evenness” based on location of each post within the default sequence. Thus, posts with odd-numbered IDs may appear in the “even” loop and vice versa. having said that, let’s examine the code that will make this happen:

<?php if (have_posts()) : while(have_posts()) : $i++; if(($i % 2) == 0) : $wp_query->next_post(); else : the_post(); ?>

<div id="left-column">
<h1><?php the_permalink(); ?></h1>
<?php the_content(); ?>
</div>

<?php endif; endwhile; else: ?>
<div>Alternate content</div>
<?php endif; ?>

<?php $i = 0; rewind_posts(); ?>

<?php if (have_posts()) : while(have_posts()) : $i++; if(($i % 2) !== 0) : $wp_query->next_post(); else : the_post(); ?>

<div id="right-column">
<h1><?php the_permalink(); ?></h1>
<?php the_content(); ?>
</div>

<?php endif; endwhile; else: ?>
<div>Alternate content</div>
<?php endif; ?>

With that code in place, oddly numbered posts will appear within a division identified with an attribute of id="left-column". Likewise, even-numbered posts will appear within a division identified with an attribute of id="right-column". Thus, we may apply the following CSS to position the divisions as two adjacent columns:

div#left-column {
	width: 333px;
	float: left;
	clear: none;
	}
div#right-column {
	width: 333px;
	float: right;
	clear: none;
	}

Of course, when it comes to configuring the WordPress loop and styling your page with CSS, anything is possible. Feel free to experiment and adapt this technique to suit your own diabolical purposes ;) For now, let’s continue with an explanation of the functionality behind this dual-loop technique.

Technical Breakdown

Perhaps the most straightforward way to explain the dual-loop code is to break it down line-by-line via comments placed within the code itself:

// initiate the default wordpress loop as usual
<?php if (have_posts()) : while(have_posts()) : 

// set a count variable to increase with each loop
$i++; 

// test the variable modulus against a zero value
// odd values return true, even values return false
// see proceding discussion for more information
if(($i % 2) == 0) : 

// skip to next post if variable is an even number
$wp_query->next_post(); 

// display the post if variable is an odd number
else : the_post(); ?>

// open a division for the left column
<div id="left-column">

// display the title of the post
<h1><?php the_permalink(); ?></h1>

// display the post content
<?php the_content(); ?>

// close the division
</div>

// close the first if statement
<?php endif; 

// close the loop
endwhile; 

// if there are no posts that meet the criteria
else: ?>

// display some alternate content
<div>Alternate content</div>

// close the second if statement
<?php endif; ?>

// reset the count variable to zero
<?php $i = 0; 

// reset the loop
rewind_posts(); ?>

// the second loop is essentially the same as the first
// the only difference is that we are testing the count variable against a non-zero value to display only even numbers
<?php if (have_posts()) : while(have_posts()) : $i++; if(($i % 2) !== 0) : $wp_query->next_post(); else : the_post(); ?>

// and of course a unique div id for the right column
<div id="right-column">
<h1><?php the_permalink(); ?></h1>
<?php the_content(); ?>
</div>

<?php endif; endwhile; else: ?>
<div>Alternate content</div>
<?php endif; ?>

As for the crazy PHP modulus operator ( % ), suffice it to say that its purpose is to test the oddness or evenness of the $i variable. The modulus operator returns the numerical remainder resulting from the division of the $i variable by the specified number (“2” in this case). In the first loop, because all even post numbers are evenly divisible by two, the modulus is equal to zero and thus the evenly numbered posts are skipped until the next loop. In the second loop, the odd post numbers are not evenly divisible by two, resulting in a non-zero numerical remainder. Thus, in the second loop, we test that the modulus is not equal to zero, thereby skipping the oddly numbered posts. Perhaps this numerical pattern will help clarify the concept:

  • Post #1: $i = 1 [remainder of 1/2 = 1]
  • Post #2: $i = 2 [remainder of 2/2 = 0]
  • Post #3: $i = 3 [remainder of 3/2 = 1]
  • Post #4: $i = 4 [remainder of 4/2 = 0]
  • Post #5: $i = 5 [remainder of 5/2 = 1]
  • Post #6: $i = 6 [remainder of 6/2 = 0]
  • Post #7: $i = 7 [remainder of 7/2 = 1]
  • Post #8: $i = 8 [remainder of 8/2 = 0]

From this we can see how testing the modulus against zero (or non-zero) results in two groups of (odd and even) numbers. For more mental torture, here is more information on the PHP modulus operator. But enough of this boring math stuff — let’s move on, shall we?

Pure CSS Method

As the astute reader may have observed, displaying two columns of horizontally sequenced posts is also possible using a single, default WordPress loop and a little bit of CSS. Consider the following code:

<div id="container_division">
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>

<div class="post-block">
<h1><?php the_permalink(); ?></h1>
<?php the_content(); ?>


</div>

<?php endwhile; else: ?>
<?php endif; ?>
</div>

With each post enclosed within a “post-block” division (i.e., <div class="post-block">), we can achieve a two-column post-display similar to that generated via the dual-loop method by declaring a width for each of the post blocks and then placing them within a fixed-width container division. Or, to express this idea visually:

[ Diagram: Two Columns of Horizontally Sequenced Divs ]

With all of the post-block divisions floated to the left, they will automatically “stack” according to the diagram. Here’s an example of CSS that would make this work:

div.post-block {
	width: 333px;
	float: left;
	clear: none;
	}
div#container_division {
	width: 700px;
	}

As useful as this “pure-CSS” technique happens to be, it is not as flexible as the dual-loop version. Independently functioning loops provide greater control over layout and thus greater design flexibility. For example, using two individual loops, the post columns need not appear side-by-side, but may be placed anywhere on the page.

Peace Out

That’s it for this Perishable Press tutorial. If you have any questions, concerns, or criticisms, please share them in the comments section for this article. As always, thanks for reading! :)

About the Author
Jeff Starr = Web Developer. Book Author. Secretly Important.
.htaccess made easy: Improve site performance and security.

58 responses to “Horizontally Sequenced Display Order for WordPress Posts in Two Columns”

  1. Just want to thank you. This was the most useful post about this subject. So it helped me a lot to create our webpage http://www.solooyun.com. I’ll will also subscribe to your RSS. Thanks again…

  2. Jeff Starr 2009/01/03 6:35 pm

    @tolga: It is my pleasure — I am glad the article was able to help you. I see what you have done with the technique on your site and I think it looks great. Well done, and thanks for subscribing! Cheers! :)

  3. Hi Jeff, first thanks for your tutorials , those and the entire blog are very usable, congratulations for this great proyect you have, so, im displaying 10 post per page and im using the second metod (two columns) and it works fine exept for one thing, one of the posts breack on the page, ok explained = in the first page the first 2 posts are in the same row so the follow 3 and 4 in the second row but the post number 5 is in one row and the 6 and 7 in the follow row , 8 and 9 in the follow and then the post number 10 in the last row.

    Is there something i can do to avoid this and to get the posts ordered correctly in both columns, 2 in each row.

    This is my code :

    <a href="" title="">
    <img src="ID, "Thumbnail", true);?>" width="50" height="50" border="0" align="left" hspace="4" />
    </b></a>

    this is the page , you can see the example there and in the pages
    http://muyatractivo.com/magazine/

    Thanks a lot
    Greetings from Mexico

  4. I suspect that on non-CSS, text based browsers, you have sacrificed the order. I bet they will appear 1 3 2 4 or something. You should add a statement about that, or ensure a browser independent solution, that while not delivering two columns (thank God,) will preserve the intended order.

  5. @jidanni: Only the first, PHP method will produce non-sequential post order on non-CSS browsers. The second, CSS-only method does not alter the underlying post order and will thus display the posts correctly when CSS is not available. Good point!

  6. Ok.. I’m not entirely sure that I can explain this so it makes sense, but I’m going to try.

    In my sidebar I have a separate category of posts pulled out from the main posts, and want to use this loop method to display them instead of having them in a single line, but for some reason it’s not working. I’m sure it’s something entirely stupid I’ve messed up, but I can’t figure it out and I am desperate to get this thing finished. Help?

  7. Kim Woodbridge 2009/03/19 5:57 am

    Hi Jeff,

    Thanks! This is exactly what I needed. I was unsure if I would have trouble using a query before the loop to only pull posts from one category but it’s working great! I do have a question and I’m not sure if it’s related to my code or yours.

    I can use the_content or the_excerpt but I can’t get the_content(‘Read More…’) to work. And I did double-check to make sure the more tag was actually in the posts. Any ideas?

    Thanks again!

    Kim

  8. Jeff Starr 2009/03/22 7:50 am

    Hi Kim,

    Not sure, but I do know that I have encountered this issue as well. One easy workaround is to simply create your own “more” links. Something like:

    <a href="<?php the_permalink(); ?>" title="Continue reading this article">Read more</a>

    Does the same thing, and you could even target the more tag directly by appending a “pound-more-dash-ID” to the permalink:

    <a href="<?php the_permalink(); ?>#more-<?php the_ID(); ?>" title="Continue reading this article">Read more</a>

    Regards,
    Jeff

  9. Kim Woodbridge 2009/03/22 8:31 am

    Hi Jeff – Thanks! That’s what I ended up doing. :-) I am also using the Advanced Excerpts plugin with this so there is more control over the excerpts.

    Thanks again for a great tutorial.

  10. Jeff Starr 2009/03/22 8:44 am

    Anytime, Kim — it is my pleasure to help! :)

Comments are closed for this post. Something to add? Let me know.
Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
The Tao of WordPress: Master the art of WordPress.
Thoughts
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
2024 is going to make 2020 look like a vacation. Prepare accordingly.
First snow of the year :)
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.