Latest TweetsNew version of Disable Gutenberg includes options to disable for specific theme templates and/or post/page IDs. wordpress.org/plugins/disable-…
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. Book Author. Secretly Important.
Archives
27 responses
  1. as you can see here

    http://www.gjcn.org/category/desktop-wallpapers/bible-wallpapers/

    I just get 3 lists of items, i would like them to go across

  2. Jeff Starr

    Hi brian, it looks like you worked it out, yes? I checked the page and it looks like the items are displayed in a single horizontal row (at least in Firefox)..

  3. wpthemegenerator July 1, 2009 @ 9:09 pm

    3 Column style is nice and good. I will try this.

    But now others also make WP Theme in few clicks at online web check it…

  4. jeff,

    No for the life of me i can’t get items to list in three columns! lol

  5. Is there a way to organize the lists so that they are ordered by name instead of date? I tried inserting the ‘orderby=name’ call in there, but then it just three long identical lists, instead of wrapping them.

    I’d really appreciate any help with this!

  6. Hi Jeff,

    I like the approach of using the offset in query_posts to achieve columns.
    But how would query_posts pagination work with offset applied?

  7. Hi Jeff,

    Thank you very much for the great script! It works flawlessly and does everything it should.

    Unfortunately I would like my archive to be on a monthly basis – basically like the build-in WP functionality “wp_get_archives('type=monthly&show_post_count=1')”, only put into three dynamic tables. Is there a way to implement that with your script?

    I’m not well versed in PHP, so maybe it’s impossible after all.. But if it seems possible to you, could you give me a hint? Thank you again!

  8. *bump*

  9. Jeff Starr

    Hi slurm23,

    I think you might be able to replace each of the query_posts tags with something like this:

    wp_get_archives('type=monthly&limit='.$columnOneTwoPosts.'&show_post_count=1')

    But the wp_get_archives doesn’t include an offset parameter, so it might only work on a per-month basis.

    There might, however, be a parameter for query_posts that enables you to specify “monthly” posts. Not sure though..

  10. Hi Jeff,

    Thank you again for the quick response and the interesting idea! It didn’t work though – I guess since your script still counts the posts at the beginning and the resulting number is much larger then the number of months.

    With your input in mind I looked around a little bit and found two possible solutions. One would be to add an offset to the wp_get_archives function (like so: http://wordpress.org/support/topic/221888). It didn’t work with the current WP version so I won’t pursue this further.

    The other solution seems to be this: http://wordpress.org/extend/plugins/lj-multi-column-archive/ … If I was able to “extract” the code from this widget it would solve my problem in no time. But my PHP skills are by no means adequate for such a task.

    Therefore I’ll give it up for the time being, but maybe the links can be of use to other people with the same problem. They can certainly provide a pointer in the right direction…

  11. This is really great, thanks.

    Is there a way to do the same over 4 columns instead of 3?

    Thank you

  12. My site shows posts by day. I changed my 3 column structure to Jeff’s and limited it by date.

    My archive function was no longer displaying by day, so I added the following code. Maybe someone can improve on it.

    <?php $count_posts = wp_count_posts();
           $numposts = $postscount;

    then the rest of Jeff’s code

    then add this to your columns.

    Not sure if it’s a great fix, but it’s working for me.

[ Comments are closed for this post ]