1

Seems like a simple problem but I'm having issues dealing with it.

Here's the layout I need

loop one

Feature

loop two

Secondary

tert - tert - tert

Secondary

tert - tert - tert

Secondary

etc

Easy enough to do feature as a separate loop. But I want to repeat the 1 col (secondary) 3 (tert) col layout. The problem is the container(s) around the tert elements, and closing them at the right stage as the loop could feasibly end at a single or two terts or after a Secondary. Here's what I have so far.

<?php 

$args = array(
'post_type' => 'advice',
'offset'=>1
);
$counter = 0;
$offset = 2;
// the query
$the_query = new WP_Query( $args ); ?>

<?php if ( $the_query->have_posts() ) : ?>
  <?php echo '<div class="clearfix">'; ?>
    <?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
      <?php 

      if ($counter % 4 == 0) {


        get_template_part('templates/content', 'advice-secondary');
        $offset++;
        $counter++;

      } else {
            if ( $offset % 3 == 0 ){
               echo '</div>';
               echo '<div class="three-split-bg bg-light">';
               echo '<div class="container wrap">';

             }
             get_template_part('templates/content', 'advice-tert');
               $offset++;
               $counter++;

      }?>


  <?php endwhile; ?>
  <?php echo '</div>'; ?>
  <?php else : ?>

  <p><?php _e( 'Sorry, no posts matched your criteria.' ); ?></p>

  <?php endif; ?>

3 Answers 3

3

You could use 3 separate loops, and break out of each loop early once you've got enough posts.

For example, here is a 2 column grid with a single query:

$q = new WP_Query( ... );

if ( $q->have_posts() ) {
    ?>
    <div class="columns">
        <div>
            <?php
            $counter = 0;
            while( $q->have_posts() ) {
                $q->the_post();
                the_title();
                $counter++;
                if ( $counter === $q->post_count/2 ) {
                    break;
                }
            }
            ?>
        </div>
        <div>
            <?php
            $counter = 0;
            while( $q->have_posts() ) {
                $q->the_post();
                the_title();
                $counter++;
                if ( $counter === $q->post_count/2 ) {
                    break;
                }
            }
            ?>
        </div>
    </div>
    <?php
} else {
    echo 'No posts found';
}

Notice how I counted each post as it was displayed, then exited the loop early when the counter was halfway through?

Arbitrary Columns

Note that here the columns are all of the same design, and the conditional check has been changed.

$q = new WP_Query( ... );

if ( $q->have_posts() ) {
    ?>
    <div class="columns">
        <?php
        $columns = 2;
        for ( $i = 1; $i < $columns; $i++ ) {
            echo '<div>';
            $counter = 0;
            while ( $q->have_posts() ) {
                $q->the_post();
                get_template_part( 'column','post' );
                $counter++;
                if ( $counter > $q->post_count/$columns ) {
                    break;
                }
            }
            echo '</div>';
        }
        ?>
    </div>
    <?php
} else {
    echo 'No posts found';
}

Note the get_template_part call, simplifying the template.

With these 2 examples, and some basic math you can turn these into any combination of columns

Alternatively, have rows of posts floated to the left and make each post 50% width or fixed width, using CSS to avoid PHP entirely

5
  • As it stands all the loop does is run through all posts twice then end. The issue is that $q->post_count / 3 does not equal a whole number (currently 1.66 recurring). Apr 24, 2017 at 9:03
  • Congrats you now have a pure math problem, pure PHP will help you there, no more WP knowledge necessary. My answer demonstrates the basic design pattern of using multiple loops and exiting them early for individual columns, the rest is out of scope. Rounding the value up before comparing or changing the comparison will do the trick, the round function in PHP will be very helpful here. Also consider testing if the counter is > rather than ===. If this answers the basic design of how to do multiple columns please mark as accepted
    – Tom J Nowell
    Apr 24, 2017 at 11:57
  • I've updated the answer with an example that'll handle arbitrary columns in a nested loop. It has advantages and disadvantages over the previous example, but the rest is just adjusting the if statement to do what you want
    – Tom J Nowell
    Apr 24, 2017 at 12:06
  • Hi Tom, thanks for your help. My issue isn't necessarily with the 3 column solution (which works great) it's going from the 3 col (with parent divs) to a one col and then back to a 3 col (rinse and repeat). Any thoughts? Apr 27, 2017 at 7:50
  • I'm not sure what you mean by going to a 3 then back to a 1. You already have all the necessary parts in the answer above, aka just change the markup to match, aka pretend it's 4 columns or more, and close off the 3rd column row at the end. You already know how to break out of the loop early to output markup as demonstrated above. At this point we've moved far away from WordPress into the realm of basic HTML and simple logic ( and I outright refuse to just write it out as copypasta for you )
    – Tom J Nowell
    Apr 27, 2017 at 14:12
0

OK I found a solution. It is far from an elegant one though, I feel like my conditional statements could be improved greatly if anyone could help me with that:

....
while ( $the_query->have_posts() ) : $the_query->the_post();
if($counter == 0):
        get_template_part('templates/content', 'advice-secondary');
        $counter++;


    else:
            if($counter == 1){
              echo '<div class="three-split-bg bg-light">
                      <div class="container wrap">
                        <div class="row">';
            };

            echo '<div class="text-left col-xs-6 col-md-4 content">';
              get_template_part('templates/content', 'advice-tert');
            echo '</div>';
            $counter++;

            if ($the_query->current_post +1 == $the_query->found_posts || $counter % 4 == 0) {
               $counter = 0;

              echo      '</div>
                      </div>
                  </div>';
            };

    endif;
endwhile;
...
0

Do you really need multiple loops? Are you getting different content for each section? If not you can manage with one single loop and display differently with flexbox.

.parent {
   display: flex;
   flex-direction; row;
   flex-wrap: wrap;
}

.children {
   flex: 1 1 33,33%;
}

.children:nth-child(1),
.children:nth-child(5) {
   flex-basis: 100%;
}

Something like that would help. You can create more complex child selectors for more repetition.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.