Latest TweetsHeads up: Blasty (DMCA service) MIA: perishablepress.com/avoid-blas…
Perishable Press

Better WordPress Archives via Dynamic Triple Column Layout

Here at Perishable Press, the number of posts listed in my archives is rapidly approaching the 700 mark. While this is good news in general, displaying such a large number of posts in an effective, user-friendly fashion continues to prove challenging. Unfortunately, my current strategy of simply dumping all posts into an unordered list just isn’t working. I think it’s fair to say that archive lists containing more than like 50 or 100 post titles are effectively useless and nothing more than a usability nightmare. With growing numbers of blogs building up massive collections of posts, finding better ways to display vast quantities of archived material becomes increasingly important.

Finding a solution

One solution that seems popular involves breaking the archives down into various categories, tags, and time periods. This provides meta-context to each list of titles and usually eliminates the need for any hideously long post listings. This solution works well, especially when the different category lists are displayed adjacently in multiple vertical columns. For example, a blog with three categories would do well to display each category’s archive listings in its own vertical column. Something like this:

[ Screenshot: Triple Archive Columns ]
Example Archive showing posts listed in three category-specific columns

This is a much more convenient presentation of content because it enables users to browse larger portions of content with less effort. Such layout also fosters understanding of the site’s overall three-category structure, as well as providing visual cues as to the amount of content available in each category relative to the others. Further, using multiple columns to display lists of archive content results in an aesthetically cleaner and richer-looking page. Rather than an awkward left-aligned list that descends endlessly down the page, we balance the composition efficiently with an appearance of order and completion.

WordPress to the rescue

We may also apply the previous strategy to the display of all archived posts. Instead of just dumping a million posts into a single, left-aligned list, let’s create a couple of extra columns, divide our posts evenly among them, and restore a sense of harmony to our site’s Archive page. To do this, we must embrace the magical powers of CSS, (X)HTML, PHP, and of course WordPress.

By default, WordPress provides a way to list all of our posts using the wp_get_archives() template tag, parameterized as follows:

<?php wp_get_archives('type=postbypost&limit='); ?>

Many sites use this method to display their entire collection of posts on their site’s Archive page. This certainly does the job, but unfortunately does not allow us to implement the improved, three-column layout discussed above. To accomplish this, we need a way to divide the archive post list into three sections, such that an even (or similar) number of posts are available to each of our three columns. As far as I know, there is no “built-in” way to acheive this with WordPress, but it is easily accomplished using a bit of customized functionality. ;)

Multiple Loops

At this point, you may be thinking that multiple loops are the way to go. If so, you are partially correct. For any known number of posts, we may easily configure a triple-loop script to display all of our posts. For example, if we know we have 300 posts to display, we can write this and be done with it:

<div id="column-01">
   <ul>
      <?php query_posts('showposts=100&offset=0); ?>
      <?php if (have_posts()) : while (have_posts()) : the_post(); ?>

      <li><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></li>

      <?php endwhile; endif; ?>
   </ul>
</div>
<div id="column-02">
   <ul>
      <?php query_posts('showposts=100&offset=100); ?>
      <?php if (have_posts()) : while (have_posts()) : the_post(); ?>

      <li><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></li>

      <?php endwhile; endif; ?>
   </ul>
</div>
<div id="column-03">
   <ul>
      <?php query_posts('showposts=100&offset=200); ?>
      <?php if (have_posts()) : while (have_posts()) : the_post(); ?>

      <li><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></li>

      <?php endwhile; endif; ?>
   </ul>
</div>

For fixed post quantities, this technique works perfectly, displaying 100 posts in each of our three columns. Each column is uniquely identified and includes its own customized loop. Each loop is customized via the query_posts() function, which utilizes its showposts and offset parameters to modify loop behavior. The showposts parameter remains the same in each loop, however the offset parameter begins at zero and increases by increments of 100 to prevent duplicate post display. So far so good..

PHP to the rescue

The “real-world” problem, of course, is that the total number of posts generally changes frequently, making it necessary to continually edit the query_posts() parameters to ensure proper archive display. Thus, for the triple-loop solution to work effectively and efficiently, we need to automate the process by using dynamically assigned parameter values. Fortunately, this is easily accomplished using some built-in WordPress functionality and a bit of “hand-rolled” PHP:

<?php // calculate triple-column post-display variables
// https://perishablepress.com/press/2009/02/10/better-wordpress-archives-via-dynamic-triple-column-layout/

// get published post count in WordPress 2.5+
$count_posts = wp_count_posts();
$numposts = $count_posts->publish;

// number of posts in columns one and two
$columnOneTwoPosts = round($numposts / 3);

// number of posts in column three
if(3*$columnOneTwoPosts < $numposts) {
	$columnThreePosts = $columnOneTwoPosts + 1;
} elseif(3*$columnOneTwoPosts > $numposts) {
	$columnThreePosts = $columnOneTwoPosts - 1;
} elseif(3*$columnOneTwoPosts == $numposts) {
	$columnThreePosts = $columnOneTwoPosts;
}

// post offset for column one
$columnOneOffset = 0;

// post offset for column two
$columnTwoOffset = $columnOneTwoPosts;

// post offset for column three
$columnThreeOffset = 2*$columnOneTwoPosts;

?>

This script dynamically assigns values for our showposts and offset parameters, based on the current total number of posts. Following along with the comments included in the code, we see that the script first determines the total number of posts using WordPress’ relatively new wp_count_posts() function1. The script then mathematically manipulates the total post value until the following variables have been assigned:

  • $columnOneTwoPosts — provides the showposts parameter with the number of posts displayed in the first and second column
  • $columnThreePosts — provides the showposts parameter with the number of posts displayed in the third column
  • $columnOneOffset — provides the offset parameter for the first column
  • $columnTwoOffset — provides the offset parameter for the second column
  • $columnThreeOffset — provides the offset parameter for the third column

Once this script has been included in your Archive page, seal the deal by editing the previously discussed triple-loop configuration with the newly established variables:

<div id="column-01">
   <ul>
      <?php query_posts('showposts='.$columnOneTwoPosts.'&offset='.$columnOneOffset); ?>
      <?php if (have_posts()) : while (have_posts()) : the_post(); ?>

      <li><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></li>

      <?php endwhile; endif; ?>
   </ul>
</div>
<div id="column-02">
   <ul>
      <?php query_posts('showposts='.$columnOneTwoPosts.'&offset='.$columnTwoOffset); ?>
      <?php if (have_posts()) : while (have_posts()) : the_post(); ?>

      <li><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></li>

      <?php endwhile; endif; ?>
   </ul>
</div>
<div id="column-03">
   <ul>
      <?php query_posts('showposts='.$columnThreePosts.'&offset='.$columnThreeOffset); ?>
      <?php if (have_posts()) : while (have_posts()) : the_post(); ?>

      <li><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></li>

      <?php endwhile; endif; ?>
   </ul>
</div>

And done! Nothing needs to be edited, updated, or configured — ever!! With this triple-column method in place, your Archive page will now feature a well-balanced, three-column post-listing of your entire collection of articles. By evenly dividing your total post number and calculating the proper offset values, the script ensures that all posts are displayed without any duplicates. Best of all, the three columns will always be within one line of the same size, regardless of the total number of posts.

Notes

1 There are several ways to retrieve the total number of posts from WordPress. Currently, the triple-column script employs the wp_count_posts() function to get this information, however this function is not available in versions of WordPress older than 2.5. Thus, you will want to use the “classic” method of getting the total post count for older versions. To do so, replace these lines:

// get published post count in WordPress 2.5+
$count_posts = wp_count_posts();
$numposts = $count_posts->publish;

..with these:

// get published post count in old WordPress versions < 2.5
$numposts = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE post_status = 'publish'");
if (0 < $numposts) $numposts = number_format($numposts); 

Further, if you are running WordPress 2.5 or better and PHP 5, you may use this shortcut in place of the current function:

// PHP5 shortcut for published post count in WordPress 2.5+
$numposts = wp_count_posts()->publish;

Also, if you want to display only the number of posts specified in the WordPress Admin Options settings, you may use this fine little function:

$numposts = get_option('posts_per_page');

And finally, to specify a custom number of posts to display, simply use this:

$numposts = 15;

Get out

As always, any suggestions, questions, or comments are welcome! Is there an easier way to achieve dynamic triple-column post display? Perhaps using only CSS? Some other WordPress function? Black magic? Chime in and contribute your knowledge!

Jeff Starr
About the Author Jeff Starr = Web Developer. Security Specialist. WordPress Buff.
Archives
27 responses
  1. Can you provide a WordPress Page template with this inbuilt. Would be great to plug and play into WordPress Themes.

  2. Patternhead February 10, 2009 @ 1:59 pm

    Interesting idea. I’ve got quite a new blog and I’m trying to figure out the best way to display archives in the future. This article has given me a few ideas so… thanks :)

  3. As usual, Jeff, a wonderful article! Well done! :D

    A question. Would you show us how to use this method for creating archive pages of a particular tag (for example, featured posts)? And even for a category archive page?

    Thank you!

  4. I’ve been blogging continuously for just under nine *years* now, so there’s no way I could ever display an archives page with post titles like this.

    I really like the kottke-style archives WP plugin for a simple date-based display of archives. (It’s what I use on my site.)

  5. Jeff Starr

    @Aldo: We can do this with additional query_posts parameters. For example, to display only posts from category 4, we would include the cat parameter in each of the loops, like so:

    <?php query_posts('cat=4&showposts='.$columnOneTwoPosts.'&offset='.$columnOneOffset); ?>

    Likewise to display only the posts from, say, the “cooking” tag, we would include the tag parameter like so:

    <?php query_posts('tag=cooking&showposts='.$columnOneTwoPosts.'&offset='.$columnOneOffset); ?>

    Of course, there are many more ways to modify loop behavior via the query_posts function. Check out the WordPress Codex for a complete list.

  6. Jeff Starr

    @dvg: Well there is if you applied a little creativity to the method. For example, you can use the triple-column script to display the most recent three years of your content; or perhaps display all posts of your favorite category in three columns; or even randomly display a reasonable number of posts from your entire nine-year collection. The possibilities are endless if you put your mind to it! :)

  7. @Jeff
    Thanks for your reply :)

    But… should I add in this line
    $count_posts = wp_count_posts();
    something like:
    $count_posts = wp_count_posts('tag=featured');
    Otherwise it counts *all* my posts. Or doesn’t?

    Anyway, I’d like to show you my source code:
    http://aldolat.pastebin.com/f55a3cb3
    it returns three columns but the content is *the same* in every column.
    Could you help me?

  8. Jeff Starr

    @Aldo: Hmmm.. That is interesting. Could you find out what the variable values are being set to by echoing them to your browser? This will tell us if the problem is with the query_posts tag or else with the number generation.

  9. The problem is in the $count_posts variable.
    I echoed the variables and got instantly an error:
    "$count_posts = Catchable fatal error: Object of class stdClass could not be converted to string in [URI of the file with error]"

    I tried to substitute
    $count_posts = wp_count_posts('tag=featured');

    with this (my actual number of featured posts)
    $count_posts = 27;

    and it returns:
    Echoing variables
    $count_posts = 27
    $numposts =
    $columnOneTwoPosts = 0
    $columnThreePosts = 0
    $columnOneOffset = 0
    $columnTwoOffset = 0
    $columnThreeOffset = 0

    I also tried to count ALL my posts changing
    wp_count_posts('tag=featured');

    with
    wp_count_posts();

    but I still get the same error.

    I use PHP5 and… thanks for your patience! ;)

  10. Update

    I found a mistake on my source and got the correct output.
    Here te values for *all* my posts:

    $count_posts = 303
    $numposts = 303
    $columnOneTwoPosts = 101
    $columnThreePosts = 101
    $columnOneOffset = 0
    $columnTwoOffset = 101
    $columnThreeOffset = 202

    Your code, Jeff, works like a charm. :)

    Also found that wp_count_posts() does not accept parameters like 'tag=featured' or 'tag=123'. I think I’d use a DB query instead.

  11. Jeff Starr

    Hi Aldo, great to hear you got it working! Thanks for following up and also thanks for the information about wp_count_posts(), of which I wasn’t aware. Cheers :)

  12. I don’t get 3 columns i get just 3 lists all down under each other, i don’t get the 3 columns across…

[ Comments are closed for this post ]