Using PHP loop to add Bootstrap rows and proper column numbers to elements

I’m trying to create the following front-end using a PHP loop and Twitter Bootstrap’s 12 column grid system:

enter image description here

Read More

The HTML output is:

<div class="row">
    <div class="col-lg-4">
        Content...
    </div>
    <div class="col-lg-4">
        Content...
    </div>
    <div class="col-lg-4">
        Content...
    </div>
</div>

<div class="row">
    <div class="col-lg-4">
        Content...
    </div>
    <div class="col-lg-4">
        Content...
    </div>
    <div class="col-lg-4">
        Content...
    </div>
</div>

<div class="row">
    <div class="col-lg-6">
        Content...
    </div>
    <div class="col-lg-6">
        Content...
    </div>
</div>

In PHP (WordPress) I’m wrapping every 3 items in a .row div:

<?php $i=0; // counter ?>

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

    <?php if ($i%3==0) { // if counter is multiple of 3 ?>
    <div class="row">
    <?php } ?>

    <div class="col-md-4">
        Content...
    </div>        

    <?php $i++; ?>

    <?php if($i%3==0) { // if counter is multiple of 3 ?>
    </div>
    <?php } ?>

<?php endwhile; ?>

<?php if($i%3!=0) { // put closing div if loop is not exactly a multiple of 3 ?>
</div>
<?php } ?>

The Problem:

I don’t know how to add the appropriate column number to the items in the last row so that they fill the 12 column grid.

For example, in my illustration above each item in the last row has col-6 (expands 6 columns) filling the 12 grid system. As another example, if there was 1 item in the last row it should have col-12.

Note: each row has 3 items at most as shown in the illustration and in PHP.

I know the following:

  • Total number of items $loop->post_count

  • Item number $i

  • Number of remainder items in the last row $loop->post_count%3 (I think)

  • Total number of columns 12 (12 could be divided by the number of remainder items to figure out the column number to give them)

Question:

How can I use that data in the PHP above to change the column number of the items in the last row so that they will fill the 12 grid (making them them centered)?

Related posts

7 comments

  1. I liked your question because I’m working on a very similar situation. Since other answers are a bit longer, I decided to leave mine here for your consideration. For me, the less variables you use, the best the solution is.

    BootstrapContentArranger.php

    <?php
    function BootstrapContentArrange($i) {
        $items = $i;                // qnt of items
        $rows = ceil($items/3);     // rows to fill
        $lr = $items%3;             // last row items
        $lrc = $lr;                 // counter to last row
    
        while ($items > 0) {        // while still have items
            $cell = 0;
            if ($rows > 1) {        // if not last row...
                echo '<div class="row">'.PHP_EOL;
                while ($cell < 3) {     // iterate with 3x4 cols
                    echo '<div class="col-md-4">Content</div>'.PHP_EOL;
                    $cell++;
                }
                echo "</div>".PHP_EOL;
            $rows--;        // end a row
            } elseif ($rows == 1 && $lr > 0) {      // if last row and still has items
                echo '<div class="row">'.PHP_EOL;
                while ($lrc > 0) {      // iterate over qnt of remaining items
                    $lr == 2 ?      // is it two?
                        print('<div class="col-md-6">Content</div>'.PHP_EOL) :  // makes 2x6 row
                        print('<div class="col-md-12">Content</div>'.PHP_EOL); // makes 1x12 row
                    $lrc--;
                } 
                echo "</div>".PHP_EOL;
                break;
            } else {        // if round qnt of items (exact multiple of 3)
                echo '<div class="row">'.PHP_EOL;
                while ($cell < 3) {     // iterate as usual
                    echo '<div class="col-md-4">Content</div>'.PHP_EOL;
                    $cell++;
                }
                echo "</div>".PHP_EOL;
                break;
            }
            $items--;       // decrement items until it's over or it breaks
        }
    }
    

    Test Cases

    BootstrapContentArrange(3);
    BootstrapContentArrange(11);
    BootstrapContentArrange(1);
    
    1. 3 items, outputs:
    <div class="row">
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    </div>
    1. 11 items, outputs:
    <div class="row">
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    </div>
    <div class="row">
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    </div>
    <div class="row">
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    <div class="col-md-4">Content</div>
    </div>
    <div class="row">
    <div class="col-md-6">Content</div>
    <div class="col-md-6">Content</div>
    </div>
    1. A single item, outputs:
    <div class="row">
    <div class="col-md-12">Content</div>
    </div>

    Note: you can remove the PHP_EOL, I used it to read the source better.

  2. Everytime I need to to this, I just use array_chunk to build a proper array chunk for my rows and columns.

    For example You have:

    $posts = [['id' => 1], ['id' => 2] ...]

    Instead of looping and calculating whether to add row, make chunks of your posts:

    $posts = [['id' => 1], ['id' => 2] ...]
    
    $postChunks = array_chunk($posts, 4); // 4 is used to have 4 items in a row
    foreach ($postChunks as $posts) {
        <div class="row">
            foreach ($posts as $post) {
                <div class="col-md-3">
                    <?=$post['id'];?>
                </div>     
            }
        </div>
    }
    
  3. I think I found the solution by first finding at which item the last row starts and applying the appropriate column number to all the items in that row:

    <?php
    $max_columns = 3; //columns will arrange to any number (as long as it is evenly divisible by 12)
    $column = 12/$max_columns; //column number
    $total_items = $loop->post_count;
    $remainder = $loop->post_count%$max_columns; //how many items are in the last row
    $first_row_item = ($total_items - $remainder); //first item in the last row
    ?>
    
    <?php $i=0; // counter ?>
    
    <?php while ( have_posts() ) : the_post(); ?> 
    
        <?php if ($i%$max_columns==0) { // if counter is multiple of 3 ?>
        <div class="row">
        <?php } ?>
    
        <?php if ($i >= $first_row_item) { //if in last row ?>   
        <div class="col-md-<?php echo 12/$remainder; ?>">
        <?php } else { ?>
        <div class="col-md-<?php echo $column; ?>">
        <?php } ?>
            Content...
        </div>        
    
        <?php $i++; ?>
    
        <?php if($i%$max_columns==0) { // if counter is multiple of 3 ?>
        </div>
        <?php } ?>
    
    <?php endwhile; ?>
    
    <?php if($i%$max_columns!=0) { // put closing div if loop is not exactly a multiple of 3 ?>
    </div>
    <?php } ?>
    

    The advantage is that any number (evenly divisible by 12) can be added to $max_columns and it will apply the proper columns.

  4. Why don’t you evaluate your modulo?

    $two = false; 
    if($i%3 == 2)
    {
          <div class="col-md-6">
             Content...
          </div>
          $two = true;  
    }
    
    if($i%3 == 1)
    {
          if($two)
          {
              <div class="col-md-6">
                  Content...
              </div>
          }
          else
          {
              <div class="col-md-12">
                  Content...
              </div>              
          }          
    }
    
  5. Print a row at a time determining html class for each element depending on how full the row is; for 0 col-md-4, for 1 col-md-12… You would need some helper structures. Finally print the final row if there’s something in the buffer.

    /**
     * Prints the row in a grid
     * @param array $posts
     * @param string $class
     */
    function printRow($posts, $class) {
        echo '<div class="row">';
    
        foreach ($posts as $post) {
            echo '<div class="' . $class . '">' . $post . '</div>';
        }
    
        echo '</div>';
    }
    
    $i = 0;
    $htmlClasses = ['col-md-4', 'col-md-12', 'col-md-6']; //helper for setting html classes
    $buffer = []; //helper array to hold row elements
    
    while (have_posts()) {
        the_post();
        $i++;
    
        $mod = $i % 3;
    
        //determine html class
        $htmlClass = $htmlClasses[$mod];
    
        if ($mod > 0) {
            $buffer[] = $currentPost; //this is the post content
        } else {
            printRow($buffer, $htmlClass);
            $buffer = [];
        }
    }
    
    //printing final row if there are elements
    if (!empty($buffer)) {
        printRow($buffer, $htmlClass);
    }
    
  6.         <?php
                //total products or items you have
                $total_pr = count($products);
    
                //grid of columns you want 
                $grid = 3;
                $tol_raw = ceil($total_pr / $grid);
                $count =0;
            ?>
    
    
            <?php for($i=0;$i<$tol_raw;$i++): ?>
                <?php
    
                $repeat = $grid;
                if($total_pr<$grid)$repeat = $total_pr;
                $total_pr -= $repeat;
    
                ?>
                <div class="row">
                    <?php for($pr=0;$pr<$repeat;$pr++):?>
                        <?php $product = $products[$count]; ?>
                         <!-- column selection is based onn your grid -->
                        <div class="col-md-4">
                             //do whatever you want to do here
                        </div>
                        <?php $count++; ?>
                    <?php endfor; ?>
                </div>
            <?php endfor; ?>
    
  7. For someone who don’t want the elements to span all the columns but just a simple grid…. Here’s how to do it in .

            <?php
            $users = $db->run('SELECT * FROM users');
            $counter = 0;
    
            foreach ($users as $row) {
              if ($counter % 3 == 0 && $printed) {
                echo '</div>';
              }
              if ($counter % 3 == 0) {
                $printed = true;
                echo '<div class="row pb-4">';
              }
            ?>
            <!-- print your data start -->
              <div class="col-md-4">
                <div class="shadow-sm p-3  rounded m-1">
                  <h5>Hello Header</h5>
                  <div>Hello Body</div>
                </div>
              </div>
            <!-- print your data end -->
            <?php
              $counter += 1;
            }
            ?>
    

    The result
    enter image description here

Comments are closed.