How to split a loop into multiple columns

Create Columns for your query and easy display

In themes is probably more useful to have something that fits well into template tags and the loop. My first answer didn’t focus on that much. Additionally I thought it’s a bit too complicated for a quick adoption.

An easier approach that popped into my mind was to extend “the loop” with columns and came to this solution so far:

A WP_Query_Columns object “extends” any standard WP query with colums that can be easily iterated over. The first parameter is the query variable and the second parameter is the number of items to be displayed per column:

<?php $the_query = new WP_Query('cat=1&showposts=50&orderby=title&order=asc');?>
<?php foreach(new WP_Query_Columns($the_query, 10) as $column_count) : ?>
    <ul>
        <?php while ($column_count--) : $the_query->the_post(); ?>
        <li><a href="https://wordpress.stackexchange.com/questions/9308/<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
        <?php endwhile; ?>
    </ul>
<?php endforeach; ?>

To use it, just add the WP_Query_Columns class from this gist to your themes function.php.

Advanced Usage

If you need the column number you’re currently displaying (e.g. for some even/odd CSS classes, you can get that from the foreach as well:

<?php foreach(new WP_Query_Columns($the_query, 10) as $column => $column_count) : ?>

And the total number of columns is available as well:

<?php 
    $the_columns = new WP_Query_Columns($the_query, 10);
    foreach($the_columns as $column => $column_count) : 
?>
    <h2>Column <?php echo $column; ?>/<?php echo sizeof($the_columns); ?></h2>
    <ul>...

Twenty Ten Example

I could quickly hack twenty ten theme for a test and adding headlines above any loop this way. It’s inserted into loop.php, the beginning is the theme’s code:

<?php /* If there are no posts to display, such as an empty archive page */ ?>
<?php if ( ! have_posts() ) : ?>
    <div id="post-0" class="post error404 not-found">
        <h1 class="entry-title"><?php _e( 'Not Found', 'twentyten' ); ?></h1>
        <div class="entry-content">
            <p><?php _e( 'Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post.', 'twentyten' ); ?></p>
            <?php get_search_form(); ?>
        </div><!-- .entry-content -->
    </div><!-- #post-0 -->
<?php endif; ?>

<!-- WP_Query_Columns -->
<?php 
    ### Needs WP_Query_Columns --- see http://wordpress.stackexchange.com/q/9308/178
    $query_copy = clone $wp_query; // save to restore later
    foreach( new WP_Query_Columns($wp_query, 3) as $columns_index => $column_count ) : ?>
    <ul>
        <?php 
        while ( $column_count-- ) : the_post(); ?>
            <li><h2 class="entry-title"><a href="https://wordpress.stackexchange.com/questions/9308/<?php the_permalink(); ?>" title="<?php printf( esc_attr__( 'Permalink to %s', 'twentyten' ), the_title_attribute( 'echo=0' ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h2></li>
        <?php endwhile; ?>
    </ul>       
<?php endforeach; ?>
<?php $wp_query = $query_copy;?>

<?php
    /* Start the Loop.
    ...

For a longer answer:

(that is basically how I came to the stuff above, but explains better how to actually solve the problem with simple mathematic operations. My new solution is to iterate over something pre-calculated.)

It depends a bit how much you actually need to solve the problem.

For example, if the number of items per column equals one, this is very simple:

<?php $the_query = new WP_Query('cat=1&showposts=50&orderby=title&order=asc');?>    
<?php while ($the_query->have_posts()) : $the_query->the_post();?>
<ul>
    <li>.. </li>
<ul>
<?php endwhile;  wp_reset_query(); ?>
</ul>

Even with that simple code, it can be seen that there are multiple decisions to be made:

  • How many items are in one column?
  • How many items are there in total?
  • Is there a new column to start?
  • And is there a column to end?

The last question is pretty interestering for HTML output as you probably want to enclose not only items but also the column with html elements.

Luckily with code, we can set all these in variables and create code that always computes to our needs.

And sometimes even, we can not even answer every question from the beginning. For exmaple, the count of total items: Are there any, some, multiple, an exact count that matches up with an integer number of columns in total?

Even Jan Fabry’s answer might work in some cases (as my example above does for the one-item-per-column scenario), you might be interested in something that works for any number of items returned by WP_Query.

First for the math:

//
// arithmetical example:
//
# configuration:
$colSize = 20;  // number of items in a column
$itemsTotal = 50; // number of items (total)

# calculation:
$count = 0; // a zero-based counter variable
$isStartOfNewColum = 0 === ($count % $colSize); // modulo operation
$isEndOfColumn = ($count && $isStartOfNewColum) || $count === $itemsTotal; // encapsulation

That code doesn’t run, so let’s put that up into a simple text example

//
// simple-text example:
//
$column = 0; // init a column counter
for($count=0; $count<= $itemsTotal; $count++) {
    $isStartOfNewColum = 0 === ($count % $colSize); // modulo
    $isEndOfColumn = ($count && $isStartOfNewColum);
    $isStartOfNewColum && $column++; // update column counter

    if ($isEndOfColumn) {
        printf("/End of Column: %d\n", $column-1);
    }

    if ($isStartOfNewColum) {
        printf("<start of Column: %d\n", $column);
    }

    printf(" * item %d\n", $count);
}
if ($count && !$isEndOfColumn && --$count === $itemsTotal) {
    printf("/End of Column: %d\n", $column);
}

printf("Done. Total Number of Columns: %d.\n", $column);

This actually runs and does some output already:

<start of Column: 1
 * item 0
 * item 1
 * item 2
 * item 3
...
 * item 17
 * item 18
 * item 19
/End of Column: 1
<start of Column: 2
 * item 20
 * item 21
 * item 22
...
 * item 37
 * item 38
 * item 39
/End of Column: 2
<start of Column: 3
 * item 40
 * item 41
 * item 42
...
 * item 48
 * item 49
 * item 50
/End of Column: 3
Done. Total Number of Columns: 3.

This simulates already pretty well how it could look like in a wordpress template:

//
// wordpress example:
//
$count = 0; // init item counter
$column = 0; // init column counter
$colSize = 10; // column size of ten this time
$the_query = new WP_Query('cat=1&showposts=50&orderby=title&order=asc');
$itemsTotal = $the_query->post_count;
?>
<?php while ($the_query->have_posts()) : $the_query->the_post();?>
<?php
    # columns display variables 
    $isStartOfNewColum = 0 === ($count % $colSize); // modulo
    $isEndOfColumn = ($count && $isStartOfNewColum);
    $isStartOfNewColum && $column++; // update column counter

    if ($isEndOfColumn) {
        print('</ul>');
    }

    if ($isStartOfNewColum) {
        printf('<ul class="col-%d">', $column);
    }
?>
    <li> ... make your day ...
    </li>
<?php endwhile; ?>
<?php
if ($count && !$isEndOfColumn && --$count === $itemsTotal) {
    print('</ul>');
}
// You don't have to do this in every loop, just once at the end should be enough
wp_reset_query();
?>

(I have not executed the last example in a WP environment, but it should be at least syntactically correct.)

Leave a Comment