Better WordPress Archives via Dynamic Triple Column Layout
by Jeff Starr on Tuesday, February 10, 2009 – 26 Responses
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.
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:
![Hypothetical archive example showing posts listed in three category-specific columns [ Screenshot: Triple Archive Columns ]](http://perishablepress.com/press/wp-content/images/2009/vertical-loops/triple-column.gif)
Hypothetical Archive example 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 fuller 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, fullness, and completion.
We may also apply this reasoning 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. ;)
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..
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
// http://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() function*. The script then mathematically manipulates the total post value until the following variables have been assigned:
$columnOneTwoPosts— provides theshowpostsparameter with the number of posts displayed in the first and second column$columnThreePosts— provides theshowpostsparameter with the number of posts displayed in the third column$columnOneOffset— provides theoffsetparameter for the first column$columnTwoOffset— provides theoffsetparameter for the second column$columnThreeOffset— provides theoffsetparameter 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
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 the following 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!
Focused on clean code and quality content, Perishable Press is the online home of Jeff Starr, author, artist, designer, developer, and all-around swell guy. 





26 Responses
Add a comment
Ajay – #1
Can you provide a WordPress Page template with this inbuilt. Would be great to plug and play into WordPress Themes.
Patternhead – #2
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 :)
Aldo – #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!
dvg – #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.)
Jeff Starr – #5
@Aldo: We can do this with additional
query_postsparameters. For example, to display only posts from category 4, we would include thecatparameter 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
tagparameter 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_postsfunction. Check out the WordPress Codex for a complete list.Jeff Starr – #6
@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! :)
Aldo – #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?
Jeff Starr – #8
@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_poststag or else with the number generation.Aldo – #9
The problem is in the
$count_postsvariable.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 = 0I 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! ;)
Aldo – #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 = 202Your 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.Jeff Starr – #11
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 :)brian – #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…
brian – #13
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
Jeff Starr – #14
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)..
wpthemegenerator – #15
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…
brian – #16
jeff,
No for the life of me i can’t get items to list in three columns! lol
Amanda – #17
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!
Ray – #18
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?
slurm23 – #19
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!
slurm23 – #20
*bump*
Jeff Starr – #21
Hi slurm23,
I think you might be able to replace each of the
query_poststags with something like this:wp_get_archives('type=monthly&limit='.$columnOneTwoPosts.'&show_post_count=1')But the
wp_get_archivesdoesn’t include anoffsetparameter, so it might only work on a per-month basis.There might, however, be a parameter for
query_poststhat enables you to specify “monthly” posts. Not sure though..slurm23 – #22
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…
Dave – #23
This is really great, thanks.
Is there a way to do the same over 4 columns instead of 3?
Thank you
Patterson – #24
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.
Patterson – #25
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;$columnThreeOffset = 2*$columnOneTwoPosts;?>and then your column headers look like this:
Column1
Column2
Column3
Jeff Starr – #26
Thanks for following up with the code, Patterson! :)