How to loop all pages but wrap every 3 with a div?

I created a one page site according to the docs, and everything is working how it’s supposed to be, but I’m trying to find the best way to modify my menu template. I want to loop every page, it’s currently doing, but have every 3 pages wrapped in a div.

This is what is currently being output:

<div id="appetizers"></div>
<div id="soups"></div>
<div id="salads"></div>
<div id="entrees"></div>
<div id="desserts"></div>
<div id="beverages"></div>

But I desire this instead.

<div class="row">
	<div id="appetizers"></div>
	<div id="soups"></div>
	<div id="salads"></div>
</div>

<div class="row">
	<div id="entrees"></div>
	<div id="desserts"></div>
	<div id="beverages"></div>
</div>

This is the menu template code:

<?php
snippet('header');

foreach(page('menu')->children()->visible() as $section) {
  snippet($section->uid(), array('data' => $section));
}

snippet('footer');
?>

Any help would be much appreciated!

Check out this post: Image Grid: Fetch 6 Last Projects with Bootstrap

Thanks for your help, Texnixe! I’m making progress but my problem is that each column has a different number of items. For example the Appetizers section might have 10 items but the salad section might only have 5 items.

I found this thread: Creating a one-pager with subpages with your answer which helped, but I’m still having problems with the row looping. Heres my code:

<?php 
// grab your sections
$sections = page('menu')->children()->visible();

// helper variable
$count = 0;

// loop through sections
foreach($sections as $section):
  
//if the result of the modulo operation is 0, open new row
  if($count % 3 == 0): ?>
    <div class="row">
  <?php endif ?>

  <?php
  foreach(page('menu')->children()->visible() as $content):
	  snippet($content->intendedTemplate(), array('content' => $content));
  endforeach
  ?>

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

Each row has duplicates of all of the children, rather than only having 3 children per row.

Hi @Escendrix, the reason why this is happening is that you loop through the same collection a second time within the first loop:

  • the first loop:

$sections = page(‘menu’)->children()->visible();
foreach($sections as $section):


- the second loop: 

foreach(page(‘menu’)->children()->visible() as $content):


So your code should rather look like this:
<?php // grab your sections $sections = page('menu')->children()->visible(); // helper variable $count = 0; // loop through sections foreach($sections as $section): //if the result of the modulo operation is 0, open new row if($count % 3 == 0): ?>
<div class="row">
<?php endif ?> <?php snippet($section->intendedTemplate(), array('content' => $section)); ?> <?php // if the result of the modulo operation is 2, close row <?php if($count % 3 == 2) || $section->is($section->last()) : ?>
</div>
<?php endif ?> <?php $count++; endforeach ?>

Note that you need the `or` condition in the second if statement if the number of total items is not a multiple of 3.

I know this doesn’t answer your question, but this seems to be a problem that should be solved in CSS, not in the template.

CSS grid systems that require every row to be wrapped in a div should be a thing of the past by now. I know, that statement isn’t very helpful, but if you added some more information about your current CSS and design requirements, I’m sure we could suggest a more modern solution that doesn’t require the divs to be wrapped for purely visual reasons.

That’s true, however, if you use the Bootstrap grid systems, that unfortunately what you end up with … Even the next version 4 will stick to the same pattern, it seems (edit: not true, they offer an option to use flexbox instead).