How to split a loop into multiple columns

If I have a loop running from a category query like :

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

How would I create an if clause that breaks the list at a certain interval, and starts a new one. So for example at the 10th post, return a </ul> and start a new one <ul> at 11.

Read More

This is incorrect but to illustrate my objective:

<?php $count =0;
    while($count <=50){
        if ($count == 9){
            echo "<li><a href='<?php the_permalink(); ?>'>
                      <?php the_title(); ?></a></li></ul>";
            } 
        elseif ($count == 10){
        echo "<ul><li><a href='<?php the_permalink(); ?>'>
                          <?php the_title(); ?></a></li>";
        }
        else {
        echo "<li><a href='<?php the_permalink(); ?>'><?php the_title(); ?></a></li>";
        }

What is the correct way to include this logic into the loop?

Related posts

Leave a Reply

5 comments

  1. 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="<?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="<?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: %dn", $column-1);
        }
    
        if ($isStartOfNewColum) {
            printf("<start of Column: %dn", $column);
        }
    
        printf(" * item %dn", $count);
    }
    if ($count && !$isEndOfColumn && --$count === $itemsTotal) {
        printf("/End of Column: %dn", $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.)

  2. This is more a general programming question, but here is the basic idea:

    <?php $the_query = new WP_Query('cat=1&showposts=50&orderby=title&order=asc');?>
    <ul>
    <?php
    $post_counter = 0;
    while ($the_query->have_posts()) :
        $the_query->the_post();
        $post_counter++;
    ?>
        <li>.. </li>
    <?php
        if ( 0 == $post_counter % 10 ) {
            echo '</ul><ul>';
        }
    endwhile;
    ?>
    </ul>
    <?php
    // You don't have to do this in every loop, just once at the end should be enough
    wp_reset_query();
    ?>
    
  3. There’s no need to create a separate var for counting, as the query var already counts it at: $wp_query->current_post. Also, you need to account for the final entry in the list so you don’t have empty <ul></ul> in your markup.

    <?php 
    $the_query = new WP_Query('showposts=21&orderby=title&order=asc'); 
    echo "<ul>";
    while ($the_query->have_posts()) :
        $the_query->the_post();
        echo "<li>{$the_query->current_post}</li>";
    
        // Note that the post is already counted in the $the_query->current_post variable when in the loop. Add one to translate array counting to real counts.
        // Jan's example didn't account for the final entry in the list. Don't want empty <ul>'s hanging around
        if ((($the_query->current_post+1) % 10 == 0) && ($the_query->current_post+1 !== count($the_query->posts))):
            echo "</ul><ul>";
        endif;
    endwhile;
    echo "</ul>";
    ?>
    
  4. Add the get_columns_array() function to your function.php. You can then easily iterate over your columns:

    In your theme you then foreach loop over the columns:

    <?php $the_query = new WP_Query('cat=1&showposts=50&orderby=title&order=asc');?>
    <?php foreach(get_columns_array($post_count) as $column_count) : ?>
        <ul>
            <?php while ($column_count--) : $the_query->the_post(); ?>
            <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
            <?php endwhile; ?>
        </ul>
    <?php endforeach; wp_reset_postdata(); ?>
    

    I set the default size of a column to 10. You can use the second parameter to set the size of a column on your own. Like to 7: get_columns_array($post_count, 7);.

  5. Here is another approach you can take:

    $article = 0;
    
    <?php if (have_posts()) : ?>
        <?php while (have_posts()) : the_post(); ?>
            <?php $article = $article + 1; ?>
            <?php if ($article % 3 == 1) echo '<div class="row-fluid">';  ?>
                <div class="span4">
                <h2><a href="<?php esc_url( the_permalink() ); ?>" title="Permalink to <?php the_title(); ?>" rel="bookmark"><?php the_title(); ?></a></h2>
                </div><!--/span-->
            <?php if ($article % 3 == 0) echo '</div><!--/row-->';  ?>
        <?php endwhile;?>
    <?php else: ?>
    <h2>...</h2>
    <?php endif; ?>