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

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!

About the Author
Jeff Starr = Web Developer. Security Specialist. WordPress Buff.
The Tao of WordPress: Master the art of WordPress.

27 responses to “Better WordPress Archives via Dynamic Triple Column Layout”

  1. Patterson 2009/10/22 8:28 pm

    Sorry, I posted the above at the end of the long day, here is my code integrated with jeff’s. His code does the heavy lifting:

    <?php $count_posts = wp_count_posts();
    $numposts = $postscount;
    $columnOneTwoPosts = round($numposts / 3);
    if(3*$columnOneTwoPosts $numposts) {
           $columnThreePosts = $columnOneTwoPosts - 1;
    } elseif(3*$columnOneTwoPosts == $numposts) {
           $columnThreePosts = $columnOneTwoPosts;
    }
    $columnOneOffset = 0;
    $columnTwoOffset = $columnOneTwoPosts;
    $columnThreeOffset = 2*$columnOneTwoPosts;
    ?>

    and then your column headers look like this:

    Column1

    Column2

    Column3

  2. Jeff Starr 2009/10/28 6:36 pm

    Thanks for following up with the code, Patterson! :)

  3. Alan Scott 2011/02/21 10:36 am

    As a non programmer I am so chuffed to have slightly adapted the brilliant dynamic triple column layout solution by Jeff Starr of Perishable Press to suit my needs. I’m sharing the adaption here.

    My pride is only marginally dampened by the fact that what took me hours over days nibbling away like a dog on a bone would take a real programmer ten minutes or so without even giving it a second thought. That’s why I’m not able to support it if goes wrong. Sorry.

    I wanted the 3 col fix to list my blog entries by year. Not the total amount. And also to list it in pairs by date and title. My blog titles are only one word long. You can see the result here. http://www.stooryduster.co.uk/stooryduster-archives using the Comicpress theme.

    I edited the archive-comic-year.php file by first php commenting out the code that created the existing one long single column table of a year’s worth of entries.

    I then pasted into that file the perishable press solution by Jeff Star http://tinyurl.com/coa5v2 which gave me all my blog titles for the entire blog as three divs ready to make into a layout using CSS. It worked fine first time.

    By a process of trial and error I found that adding this to the Perishable Press code:

    'year='.$yearselect.'&showposts=' . $columnThreePosts

    got me my posts by year.

    In effect replacing this, the original code:

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

    with this, the new code:

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

    I then wanted to show my year blog entries by date title pairs. (Which should be a pair list but I was lazy and did it as a table. I’ll fix it later.)

    Again after trial and error I found the code changes required. Replacing this code:

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

    with (bearing in mind I’m using tables) this code:

    <tr><td class="archive-date"><?php the_time('M j') ?></td><td class="archive-title"><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></td></tr>

    When it is all together it looks like this code:

    <table class="month-table">
    <?php query_posts('year='.$yearselect.'&showposts='.$columnThreePosts.'&offset=' . $columnThreeOffset); ?>
    <?php if (have_posts()) : while (have_posts()) : the_post(); ?>
    <tr>
    <td class="archive-date"><?php the_time('M j') ?></td>
    <td class="archive-title"><a href="<?php the_permalink() ?>">
    <?php th e_title(); ?></a>
    </td></tr>
    <?php endwhile; endif; ?>
    </table>

    Ignore the html and CSS and look at the php and you should be able to work out the differences.

    'year='.$yearselect.'&showposts and
    <?php the_time('M j') ?> are it.

    Originally I had a number for the column division since I knew roughly the amount of posts per year. This was ugly so to get the post count numbers to do the division into an even three columns, after much trial and error, I replaced this code:

    $count_posts = wp_count_posts();
    $numposts = $count_posts->publish;

    with this code:

    $posts = &query_posts('showposts=-1&cat='.comicpress_all_comic_categories_string().'&year='.(int)$archive_year);
    $numposts = count($posts);

    To do the layout I wrapped the three divs that defined the columns in another div to act as a wrap and gave it a unique name.

    In the CSS I set my layout to have column-01 float left, column-03 float right giving them widths to fit within a width set for the wrap div leaving enough room for the content of column-02 in between.

    Finally before the closing of the wrap div and after all the column divs you need a class or a div that declares clear-both. Most themes have this style somewhere in their CSS.

    Any other styling was to get it looking good to taste.

    Again you can see the finished pages here http://www.stooryduster.co.uk/stooryduster-archives and analyse the styling if you want.

    I typed this a month after I got it working so apologies if I’ve remembered what I did wrong. If I did I hope some PHP wizard will step in and correct the error.

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 »
Blackhole Pro: Trap bad bots in a virtual black hole.
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.