Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

WordPress

Devin Gray
Devin Gray
39,261 Points

How can I have my rows of blogs display a 3 column layout using bootstrap for the home.php page?

        <div class                                        ="container">
            <div class                            ="row">
                <!--right-->
                <div class                        ="col-md-9">

                    <?php if (have_posts()) : while (have_posts()) : the_post(); ?>
                    <article class                    ="post blog-post">

                        <h3>
                            <a href               ="<?php the_permalink(); ?>"><?php the_title(''); ?></a>
                        </h3>
                        <div class                ="post-info">
                            <em>
                                <p><em  class     ="comment-author">By <?php the_author(); ?></em><em class="post-date date"> on <?php echo the_time('l, F jS, Y'); ?></em><em> in <?php the_category(', '); ?>.</em>
                                    <a href       ="<?php comments_link(); ?>"> <?php comments_number(); ?></a>
                                </p>
                            </em>
                            <p class              ="post-summary"><?php the_excerpt(); ?></p>
                        </div>
                    </article>
                    <?php endwhile; else: ?>
                    <div class                        ="page-header"><h1>Uh Oh!</h1></div>
                    <p>Sorry, for some reason the contents of this page isn't displaying.</p>
                    <?php endif; ?>
                </div><!--/right-->
                <!--left--><?php get_sidebar('blog'); ?><!--/left-->
            </div><!--/row-->
        </div><!--/container-->

I want the listing for each post to display 3 columns, end the row, and then start another row for the next 3 items. Like this, except my container is only 9 columns wide

<div class="row">
  <div class="col-sm-3">content</div>
  <div class="col-sm-3">content</div>
  <div class="col-sm-3">content</div>
</div>

I noticed that Zac did something similar with his page-portfolio.php file and I tried to do something similar to that, but I can't find any solutions that work and display properly.

Any suggestions? Thanks.

7 Answers

Hello Devin--

So, I did make some syntax errors. I tested the following with default bootstrap and it is working. I also inlined some comments so that you can see what is happening at each point.

<div class="container">
      <div class="row">
                <!--right-->
        <div class="col-md-9">
          <?php 
          /*
            Start with variables to help with row creation;
          */
            $startRow = true;
            $postCounter = 0;
          ?>
          <?php
          /*
            Start the loop
          */
            if (have_posts()) : while (have_posts()) : the_post();  
          ?>

            <?php
            /*
              Check whether we need to add the start of a new row.
              If true, echo a div with the "row" class and set the startRow variable to false 
              If false, do nothing. 
            */
            if ($startRow) {
              echo '<!-- START OF INTERNAL ROW --><div class="row">';
              $startRow = false;
            }  
            ?>
            <?php
            /* Add one to the counter because a new post is being added to your page.  */ 
              $postCounter += 1; 
            ?>
            <!-- This div serves as the template for each post returned within the loop -->
            <div class="col-sm-4">
              <article class="post blog-post">
                <h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
                <div class="post-info">
                  <em>
                    <p>
                      <em class="comment-author">By <?php the_author(); ?></em><em class="post-date date"> on <?php echo the_time('l, F jS, Y'); ?></em><em> in <?php the_category(', '); ?></em><a href="<?php comments_link(); ?>"><?php comments_number(); ?></a>
                    </p>
                  </em>
                  <p>Post Counter: <?php echo $postCounter; ?></p>
                  <p class="post-summary"><?php the_excerpt(); ?></p>
                </div>
              </article>
            </div>
            <?php 
            /*
            Check whether the counter has hit 3 posts.  
            If true, close the "row" div.  Also reset the $startRow variable so that before the next post, a new "row" div is being created. Finally, reset the counter to track the next set of three posts.
            If false, do nothing. 
            */
            if ( 3 === $postCounter ) {
                echo '</div><!-- END OF INTERNAL ROW -->';
                $startRow = true;
                $postCounter = 0;
            }
            ?>
            <?php 
            /* END THE WHILE LOOP*/
            endwhile;
            ?>
            <?php 
            /* If you are returning an odd number of posts (i.e., anything other than a multiple of 3), we will need to close the row div.*/
            if ($postCounter !== 0 ) {
              echo '</div><!-- END OF INTERNAL ROW -->';
            }
            ?>
            <?php else:  ?>
              <div class="page-header"><h1>Uh Oh!</h1></div>
              <p>Sorry, for some reason the contents of this page isn't displaying.</p>
            <?php endif; ?>

        </div><!-- END OF COL-MD-9  -->
        <div class="col-md-3">
          <?php get_sidebar('blog'); ?>
        </div><!-- END OF COL-MD-3 -->
      </div><!-- END OF ROW -->
    </div><!-- END OF CONTAINER -->

Hopefully this makes sense.

Devin Gray
Devin Gray
39,261 Points

Yes I just tested it and it worked perfectly. Thanks.

Hello Devin--

One way to do this is to use a counter within your loop to know how many posts have been created and then add the appropriate row div markup when you need to. I'm sure someone else may have a more elegant way to do this, but here is at least an idea to help you get started:

<?php
<div class="container">
            <div class="row">
                <!--right-->
                <div class="col-md-9">
                    <?php 
                        $counter = 0; 
                        $startRow = true; 
                    ?>
                    <?php if (have_posts()) : while (have_posts()) : the_post(); ?>
                        <?php 
                            if ($startRow) { 
                                echo '<div class="row">';
                                $startRow = false; 
                            }
                        ?>              
                            <div class="col-sm-4">
                                <article class="post blog-post">
                                    <h3>
                                        <a href="<?php the_permalink(); ?>"><?php the_title(''); ?></a>
                                    </h3>
                                    <div class="post-info">
                                        <em>
                                            <p><em  class="comment-author">By <?php the_author(); ?></em><em class="post-date date"> on <?php echo the_time('l, F jS, Y'); ?></em><em> in <?php the_category(', '); ?>.</em>
                                                <a href="<?php comments_link(); ?>"> <?php comments_number(); ?></a>
                                            </p>
                                        </em>
                                        <p class="post-summary"><?php the_excerpt(); ?></p>
                                    </div>
                                </article>
                            </div>

                        <?php $counter += 1; ?>

                        <?php 
                            if ($counter == 3 ) {
                                echo '</div';
                                $startRow = true;
                                $counter = 0;
                            }
                        ?>                    
                    <?php endwhile; ?>
                    if ($counter != 3) {
                        echo '</div';
                      }

<?php else: ?>
                    <div class="page-header"><h1>Uh Oh!</h1></div>
                    <p>Sorry, for some reason the contents of this page isn't displaying.</p>
                    <?php endif; ?>
                </div><!--/right-->
                <!--left-->
                <div class="col-md-3">
                <?php get_sidebar('blog'); ?><!--/left-->
                </div>
            </div><!--/row-->
        </div><!--/container-->

To explain, there are two points you would need to track within the loop: when to add the opening row div markup and then when to close the row.

To address the opening row div, I just added a $startRow variable and initially set it to true. In the loop, you have an if statement that checks that variable. If true, it will output the opening row div markup. It will then set the $startRow variable to false so that it doesn't output another "row" element on your second or third post.

To address the closing div, I added a counter set initially to 0. Once you add a post, you update the counter by 1. Then there is a second conditional statement at the end of the loop to check whether the counter variable is equal to 3. If it is, it outputs the closing div, resets the counter and sets $startRow to true so that on the next post it would again recreate the opening row div markup.

If your loop ends without any even number of posts, we do a final check of the counter outside of the while loop so that we can properly close the row. Hope that makes sense.

One additional change I made was to switch your individual post containers from col-sm-3 to col-sm-4. Within each row you create, there is another 12 columns for you to work with--regardless of how many columns a parent container may be using in a parent row.

I haven't had a chance to test this, so I apologize for any syntax errors that may found in the example above..

Devin Gray
Devin Gray
39,261 Points

I've been looking online for something like this and I've tried some different counter examples, but they all seem to either cause a syntax error or they display a row but it's so unorganized and the styling gets completely disrupted that I don't know if I can pull off this 3 column layout. I was hoping for a simple fix but that doesn't seem possible for some reason :(

Devin Gray
Devin Gray
39,261 Points

Okay so the styling works, this is the best example of what I've found so far to work, but it still doesn't display 3 columns to a row "consistently", do you think there's some css or js I need to add to make this display properly?

Hey devin-- glad we are getting closer.

Can you confirm that the html is outputting properly? If so, then we can look at the css you have on your elements.

Devin Gray
Devin Gray
39,261 Points

Well when I checked the Chrome Dev tools, it is outputting properly. I'm not at the computer with all my files on it right now, but the output is correct, but the first 3 or 6 columns display wonky, then the ones after that seem to work fine. I'll check in with more when I get a break. I'm at work now, the life of a full-timer with a secret identity of a web developer on the side.

Devin Gray
Devin Gray
39,261 Points

Okay I'm back on my computer and now that I'm inspecting the elements they aren't all ordered properly

Devin Gray
Devin Gray
39,261 Points

I finally figured it out! Thanks for your help Christopher Rebacz you set the foundation for this, and your counter was the only one I could get to work. Here is my final code:

<?php
$counter = 0;
$startRow = true;
?>
                    <?php if (have_posts()) : while (have_posts()) : the_post(); ?>
                        <?php
                            if ($startRow) {
                                echo '<div class="row">';
                                $startRow = false;
                            }
                        ?>
<div class="col-sm-3">

                    <article class                    ="post blog-post leftCol">
                    <?php
                        $thumbnail_id = get_post_thumbnail_id();
                        $thumbnail_url= wp_get_attachment_image_src($thumbnail_id, 'thumbnail-size', true);
                        $thumbnail_meta = get_post_meta($thumbnail_id, '_wp_attachment_image_alt', true);
                    ?>
                    <p class="featured-image single-post-image">
                        <img src="<?php echo $thumbnail_url[0]; ?>" alt="<?php echo $thumbnail_meta; ?> featured-image project">
                    </p>
                        <h3>
                            <a href               ="<?php the_permalink(); ?>"><?php the_title(''); ?></a>
                        </h3>
                        <div class                ="post-info">
                            <em>
                                <p><em  class     ="comment-author">By <?php the_author(); ?></em><em class="post-date date"> on <?php echo the_time('l, F jS, Y'); ?></em><em> in <?php the_category(', '); ?>.</em>
                                    <a href       ="<?php comments_link(); ?>"> <?php comments_number(); ?></a>
                                </p>
                            </em>
                            <p class              ="post-summary"><?php the_excerpt(); ?></p>
                        </div>
                    </article>

</div>
                    <?php $counter ++; ?>
                    <?php if ($counter == 3) {
                            echo '</div>';
                            $startRow = true;
                            $counter = 0;
                        }
?>
                    <?php if ($counter != 3 && $counter < 0) {
                            echo '</div>';
                        }
?>
                    <?php endwhile; else: ?>

So basically I added some code so that the featured image for my blogs displays in each column, but I found the problem that was making my rows break I had to change this line

                    <?php if ($counter != 3) {
                            echo '</div>';
                        }
?>

To this:

                    <?php if ($counter != 3 && $counter < 0) {
                            echo '</div>';
                        }
?>

It was sporadically adding closing divs so that rows were just constantly getting nested inside each other until it got a condition where $counter = 3. By adding that condition, it only adds a div to the last row that just happens to not =3, instead of closing every row because every single column can never equal 3. I hope my explanation made sense, I couldn't have done it without you!.

Great job figuring it out!

Devin Gray
Devin Gray
39,261 Points

Well I had lots of help, and once you refactored the code I decided on using yours, it works just as well and is a lot easier to read, besides, how I got it to work by making $counter < 0 was pure fluke, I couldn't explain how that actually was supposed to happen.

Thank you, I just showed my client my page last night with your help and he loved it, it was an internship and now I'm finally about to get paid!

Devin Gray
Devin Gray
39,261 Points

Well I had lots of help, and once you refactored the code I decided on using yours, it works just as well and is a lot easier to read, besides, how I got it to work by making $counter < 0 was pure fluke, I couldn't explain how that actually was supposed to happen.

Thank you, I just showed my client my page last night with your help and he loved it, it was an internship and now I'm finally about to get paid!

I'm glad it finally works and that I was able to help. Congrats on getting paid!

And I learned here as ell. Just to explain, there are two things I did wrong in the initial counter code:

  1. As you also saw, the initial code never properly closed the divs.
    I couldn't understand why $counter == 3 wasn't working right. I went to the PHP manual and looked at comparison operators, and saw the triple equals operator. Their description was to use '===' when you want to be sure that the values are identical (in both value and type), rather than equal in value. Since we want the $counter variable to be both a number and equal to the number 3, I used the triple equals so that 'only' in the instance when the counter is equal to 3 should we close the row. Otherwise, there may be some false positives included along the way. I used the 'yoda syntax' -- ( 3 === $postCounter) to help during testing and making sure the variable and constant were in fact equal.

I'm still unclear when in the counter the double equals would evaluate to true, but I guess this is why the triple equals is considered best practice (i.e., to make sure you are evaluating exactly what you want to evaluate).

  1. There was also a mistake, which you also spotted, in the conditional after the endwhile statement. This was just a basic mistake. Since we reset the counter to 0 whenever we close a row, there would never be an instance when the counter would be 3. The only options are 0, 1, and 2. So, in that final conditional, we would only need to add an additional closing div if the counter was anything but 0.

Cheers, Chris

Devin Gray
Devin Gray
39,261 Points

Well I had lots of help, and once you refactored the code I decided on using yours, it works just as well and is a lot easier to read, besides, how I got it to work by making $counter < 0 was pure fluke, I couldn't explain how that actually was supposed to happen.

Thank you, I just showed my client my page last night with your help and he loved it, it was an internship and now I'm finally about to get paid!