Image Grid: Fetch 6 Last Projects with Bootstrap

Hi.

I have following problem:

I want to display on my index-site my last 6 projects.
They are shown in 2 rows and 3 columns within a bootstrap grid.

Without bootstrap i would solve this problem with list items.
But how can I solve this within the bootstrap grid?

Does somebody has any idea?

Thanks
Daniel

With bootstrap you would use div elements. You have to create a new row after every three projects.

okay. Thank you.

How can I say Kirby to create a new row?

You need a helper variable within a foreach loop:

<?php 
// grab your projects
$projects = page('projects')->children()->visible()->limit(6);

// helper variable
$count = 0;

// loop through projects
foreach($projects as $project):
  
// if the result of the modulo operation is 0, open new row
  if($count % 3 == 0): ?>
    <div class="row">
  <?php endif ?>
    <div class="col-3">
       <!-- here goes your content -->
    </div>

 <?php
 // if the result of the modulo operation is 2, close row
 if($count % 3 == 2): ?>
    </div>
  <?php endif ?>
<?php $count++; endforeach ?>
2 Likes

Great! Thank you. I’ll try that.

I was testing this way of creating new rows and I noticed that the code as posted above does not create a closing </div> for the last row as soon as the last project is a first in a row. So if I have 1, 4, 7, 10 projects, and so on, this code doesn’t validate any more. Can anybody please give me a hint to solve this?

Edit:

Something like

<?php if($count % 3 == 2) || something ->last() : ?>

How do I express this in a correct way?

Exactly, check if it is the last project:

<?php if($count % 3 == 2) || $projects->last()->bool() : ?>

Or if this does not work, then try:

<?php if($count % 3 == 2) || $project->is($projects->last()) : ?>

An alternative would be to change the number of cols in the last row depending on how many items are left.

So I found it myself:

<?php if(($count % 3 == 2) || $project == $projects->last()) : ?>

Sorry, I got no notification sign! Thanks @texnixe!

if you use different grid sizes for different viewports you can also add clear fixes with the visible-* classes provided by bootstrap instead of creating multiple rows :slight_smile:

Hi.

I’ve tried that. But there is one problem:
The latest six projects are displayed. But six times instead of one.
It seems that the rows are rotated by 90 degrees.

That’s my code:

<?php 
// grab your projects
$projects = page('projekte')->children()->visible()->limit(6);

// helper variable
$count = 0;

// loop through projects
foreach($projects as $project):
  
// if the result of the modulo operation is 0, open new row
  if($count % 3 == 0): ?>
    <div class="row">
        <?php endif ?>
            <!-- here goes your content -->


            <div class="col-md-4 col-sm-6">

                <?php foreach(page('projekte')->children()->children()->visible()->flip()->limit(6) as $project): ?>
                    <?php if($image = $project->images()->sortBy('sort', 'asc')->first()): ?>
                        <a href="<?php echo $project->url() ?>">
                            <div class="box">
                                <img class="img-responsive" src="<?php echo $image->url() ?>" alt="<?php echo $project->title()->html() ?>">
                                <div class="overbox">
                                    <div class="title overtext">
                                        <?php echo $project->title()->html() ?>
                                    </div>
                                    <div class="tagline overtext">
                                        <?php echo $project->tag()->html() ?>
                                    </div>
                                </div>
                            </div>
                        </a>
                        <?php endif ?>
                            <?php endforeach ?>

            </div>



            <!-- the content ends there. -->
            <?php
 // if the result of the modulo operation is 2, close row
 if($count % 3 == 2): ?>
    </div>
    <?php endif ?>
        <?php $count++; endforeach ?>

Does anyone have a clue to solve that?

Hey there!
You’re redefining a foreach loop without taking into account the active project in your first foreach.
Remove the second foreach and you should be good to go!

Note: there’s also a flip in your second loop you may want to apply to your first loop.

Argh! Thanks for your hint.

1 Like

I would also recommend one more thing. You’re checking if your project has an image too late in the process to make sure there’ll be 6 projects.

EDIT: hasImages() only works on a page not on a collection.
Try replacing your first foreach loop with:
$projects = page('projekte')->children()->visible()->hasImages()->limit(6);

Cleaning up, this will give you:

<?php 
// grab your projects
$projects = page('projekte')->children()->visible()->hasImages()->limit(6);

// helper variable
$count = 0;

// loop through projects
foreach($projects as $project):
  
// if the result of the modulo operation is 0, open new row
  if($count % 3 == 0): ?>
    <div class="row">
        <?php endif ?>
            <div class="col-md-4 col-sm-6">
                <?php $image = $project->images()->sortBy('sort', 'asc')->first() ?>
                <a href="<?php echo $project->url() ?>">
                    <div class="box">
                        <img class="img-responsive" src="<?php echo $image->url() ?>" alt="<?php echo $project->title()->html() ?>">
                        <div class="overbox">
                            <div class="title overtext">
                                <?php echo $project->title()->html() ?>
                            </div>
                            <div class="tagline overtext">
                                <?php echo $project->tag()->html() ?>
                            </div>
                        </div>
                    </div>
                </a>
            </div>
            
 <?php if($count % 3 == 2):  // if the result of the modulo operation is 2, close row ?>
    </div>
<?php endif ?>
<?php $count++; endforeach ?>

If I do this, all snippets after the latest projects (and them itself) are no longer displayed.

I’m not sure I understand your reply. Do you mean that setting hasImages() results in no projets?

Yes. I have some snippets at the template I’m working on. For example:

  • Header
  • Navigation
  • Latest Projects
  • About us
  • Footer

When I add the line hasImages, then everything from Latest Project and below is not dispalyed anymore at the frontend.

hasImages() is a $page method, so it only works with a single page, not with a collection.

https://getkirby.com/docs/cheatsheet/page/has-images

1 Like

@herr.grab: Do you only want to get projects which have images? Or only 6 projects no matter if they have images or not?

If you want to fetch only projects with images, you can use a filter with a callback:

$projects= page('projekte')->children()->filter(function($child) {
  return $child->images()->count() > 0;
})->limit(6);

Only a side question: In your code above you posted:

foreach(page('projekte')->children()->children()...

children()->children(): what is this about? Doesn’t sound correct. Do still have it there?

Thanks for pointing out that hasImages only works on a page, I hadn’t realized that! Would it work in your code then ?

$projects= page('projekte')->children()->filter(function($child) {
  return $child->hasImages();
})->limit(6);