Alternate loop output every three posts (within the same original loop)

The question:

I have a (relatively) tricky situation where my code requires changing the loop output every three posts, and within those three posts there are divs around two of the posts.

The code below displays 6 posts and I would want to loop though a total of 24 posts, repeating this four times.

Can anyone help? Thanks!

FIRST THREE

<div class="layer">

<div class="large left">
    <div class="item">
    <?php the_title(); ?>
    <?php the_content(); ?>
    </div><!--item-->
</div>

<div class="small left">
    <div class="item">
    <?php the_title(); ?>
    <?php the_content(); ?>
    </div><!--item-->

    <div class="item">
    <?php the_title(); ?>
    <?php the_content(); ?>
    </div><!--item-->
</div>

</div><!--layer-->

SECOND THREE

<div class="layer">

<div class="small left">
    <div class="item">
    <?php the_title(); ?>
    <?php the_content(); ?>
    </div><!--item-->

    <div class="item">
    <?php the_title(); ?>
    <?php the_content(); ?>
    </div><!--item-->
</div>

<div class="large right">
    <div class="item">
    <?php the_title(); ?>
    <?php the_content(); ?>
    </div><!--item-->
</div>

</div><!--layer-->

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

You can do this with much less code, using the modulo operator.

The modulo sign in PHP is %, and works like this: it gives you the remainder of a division, for example

5 % 2 = 1
9 % 3 = 0
11 % 7 = 4

So your code would look like this (I think you have a typo in your question, in the “First Three” the second block should be labeled small right. If I am wrong here, just edit the code below.)

For a better Overview, I start my Counter at 1, not as usual at 0, because it is easier to see which iteration is targeted by the conditionals. I also increase the counter at the last conditional – be sure you do not increment it twice!

So, before the Loop:

$counter = 1;

Then insinde the Loop:

<?php
    if ( $counter % 3 == 1 ) { // use this line for the first and the fourth iteration
        echo '<div class="layer">';
    }
        if ( $counter % 6 == 1 ) { // use this line for the first iteration only
            echo '<div class="large left">';
        } else if ( $counter % 6 == 2 ) { // use this line for the second iteration only
            echo '<div class="small right">';
        } else if ( $counter % 6 == 4 ) { // use this line for the fourth iteration only
            echo '<div class="small left">';
        } else if ( $counter % 6 == 5 ) { // use this line for the fifth iteration only
            echo '<div class="large right">';
        }
        //nothing to do for the sixth and the third iteration
        // the item is the same all the time
?>
        <div class="item">
            <?php the_title(); ?>
            <?php the_content(); ?>
        </div><!--item-->
<?php
        if ( $counter % 6 == 1 || $counter % 6 == 3 || $counter % 6 == 5 || $counter % 6 == 0 ) { // use this line everytime you close a subblock
            echo '</div>';
        }
    if ( $counter++ % 3 == 0 ) { // use this line for the third and the sixth iteration
        echo '</div>';
    }
?>

Method 2

I think this would work:

<?php 
$counter = 1;
if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>

<div class="layer">

    <?php if ($counter < 3) { ?>
        <div class="large left">
            <div class="item">
                <?php the_title(); ?>
                <?php the_content(); ?>
            </div><!--item-->
        </div>
        <div class="small left">
            <div class="item">
            <?php the_title(); ?>
            <?php the_content(); ?>
            </div><!--item-->

            <div class="item">
            <?php the_title(); ?>
            <?php the_content(); ?>
            </div><!--item-->
        </div>
    <?php
            $counter++;
        } elseif ($counter < 6) { ?>
            <div class="small left">
                <div class="item">
                <?php the_title(); ?>
                <?php the_content(); ?>
                </div><!--item-->

                <div class="item">
                <?php the_title(); ?>
                <?php the_content(); ?>
                </div><!--item-->
            </div>

            <div class="large right">
                <div class="item">
                <?php the_title(); ?>
                <?php the_content(); ?>
                </div><!--item-->
            </div>
    <?php
            $counter++;
        } else { 
            $counter = 0;
        }
    ?>
</div><!--layer-->
?>

Set a counter, if the loop is less than 3, do the first option, elseif the loop is less than 6 do the second option, else, reset the counter

Method 3

I think this may work, might need some refinement:

<?php if ($counter == 1){ ?>
    <div class="layer">
        <div class="large left">
            <div class="item">
            <?php the_title(); ?>
            <?php the_content(); ?>
            </div><!--item-->
        </div>
<?php } elseif ($counter == 2){ ?>}
        <div class="small left">
            <div class="item">
                <?php the_title(); ?>
                <?php the_content(); ?>
            </div><!--item-->

<?php } elseif ($counter == 3){ ?>}
            <div class="item">
                <?php the_title(); ?>
                <?php the_content(); ?>
            </div><!--item-->
        </div><!--end small left-->
    </div><!--end layer-->
<?php } elseif ($counter == 4){ ?>}
    <div class="layer">
        <div class="small left">
            <div class="item">
                <?php the_title(); ?>
                <?php the_content(); ?>
            </div><!--end item-->
<?php } elseif ($counter == 5){ ?>}
            <div class="item">
                <?php the_title(); ?>
                <?php the_content(); ?>
            </div><!--item-->
        </div><!--end small left-->
<?php } elseif ($counter == 6){ ?>}
        <div class="large right">
            <div class="item">
                <?php the_title(); ?>
                <?php the_content(); ?>
            </div><!--item-->
        </div>
    </div><!--layer-->
<?php }
    $counter++;
    if (($wp_query->current_post + 1) == ($wp_query->post_count)) {
        switch($counter){
            case 1:
                echo '</div><!--end layer-->';
                break;
            case 2:
                echo '</div><!--end small left-->
                        </div><!--end layer-->';
                break;
            case 3:
                break;
            case 4:
                echo '</div><!--end small left-->
    </div><!--end layer-->';
                break;
            case 5:
                echo '</div><!--end layer-->';
                break;
            case 6:
                break;
            default:
                break;
        }
    }
endwhile;?>

Method 4

For reference, someone on another forum achieved the same correct output slightly differently (although using the same principles…). Thanks to both!

<?php 
while( have_posts() ) : the_post();

$position = $wp_query->current_post;
$p3 = $position%3;
$p6 = $position%6;
$number_posts = $wp_query->post_count-1;

if( $p3 == 0 ) echo '<div class="layer">';
if( $p6 == 0 ) echo '<div class="large left">';
elseif( $p6 == 1 || $p6 == 3) echo '<div class="small left">';
elseif( $p6 == 5 ) echo '<div class="large right">'; ?>

    <div class="item">
    <?php the_title(); ?>
    <?php the_content(); ?>
    </div><!--item-->

<?php if( $position == $number_posts || in_array($p6, array(0, 2, 4, 5)) ) echo '</div>';
if( $p3 == 2 || $position == $number_posts ) echo '</div><!--layer-->'; 

endwhile; ?>


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment