Structured data input field: optimise code

Two questions:

  1. Imagine you have a structured data input field with 4 rows. Is it possible to define in the foreach loop of the template to only show the data of row 1 and 2? And on another place in the template to show the data of row 3 and 4.

Right now i use two different structured data fields but it would look more clean to combine it.

  1. I have a structured data input field with 3 rows:

I have a data field for the number in my blueprint but i wonder if it is possible to use the automatic generated #1 #2 #3 order number in my template for the “steps” heading?

I can’t answer your first question but, about the numbers, you could simpy use a variable and increment it.

<?php $i = 0 ?>
<?php foreach($items as $item): ?>
	<h2><?= $i ?></h2>
	<strong><?= $item->title() ?></strong>
	<?= $item->description()->kt() ?>
	<?php $i++ ?>
<?php endforeach ?>

Then, if you want to add zeros to your numbers, you can use sprintf:
https://www.php.net/manual/en/function.sprintf.php

Regarding your first question you could try to split your collection and create two arrays.

$benefits = $page->benefits()->yaml(); // or whatever your structure field is called
$total = count($benefits);
$benefitsA = array_slice($benefits, 0, $total / 2);
$benefitsB = array_slice($benefits, $total / 2);
?>

<?php foreach($benefitsA as $benefit):?>
    <h2><?= $benefit['heading']?></h2>
    <p><?= $benefit['subheading']?></p>
    <p><?= $benefit['text']?></p>
<?php endforeach ?>

<?php foreach($benefitsB as $benefit):?>
    <h2><?= $benefit['heading']?></h2>
    <p><?= $benefit['subheading']?></p>
    <p><?= $benefit['text']?></p>
<?php endforeach ?>

You could go crazy and refactor this to a snippet:

// /snippets/benefit-list.php
<?php foreach($benefits as $benefit):?>
    <li>
        <h2><?= $benefit['heading']; ?></h2>
        <p><?= $benefit['subheading']; ?></p>
        <p><?= $benefit['text']; ?></p>
    </li>
<?php endforeach; ?>
// pages/template.php
$benefits = $page->benefits()->yaml(); // or whatever your structure field is called
$total = count($benefits);
$benefitsA = array_slice($benefits, 0, $total / 2);
$benefitsB = array_slice($benefits, $total / 2);
?>

<h2>My Benefits</h2>
<?php snippet('benefit-list', ['benefits' => $benefitsA]); ?></li>

<!-- more markup -->

<h2>More Benefits</h2>
<?php snippet('benefit-list', ['benefits' => $benefitsB]); ?></li>

A structure field can be converted into a structure object, which is a collection. IMHO, that’s easier to deal with than the yaml array solution suggested by @gearsdigital. You can use all collection methods, in this case, using limit() and offset() are useful:

$benefitsA = $page->benefits()->toStructure()->limit(2);
$benefitsB = $page->benefits()->toStructure()->offset(2)->limit(2);

// then loop through them:

foreach ($benefitsA as $item) {
  echo $item->heading(); // etc. for the other fields
} 

// then the same for $benefitsB

As regards the numbering, you can either use the counter as suggested above by @sara, or:

<?php foreach($items as $item): ?>
	<h2><?= $items->indexOf($item) + 1 ?></h2>
	<strong><?= $item->heading() ?></strong>
	<?= $item->text()->kt() ?>
<?php endforeach ?>
2 Likes

@texnixe Thats true, toStructure() is more handy! But your example works for a known amount of entries. If entries are added or removed this wouldn’t work without adapting the template, right?

Nonetheless that might fit OPs needs :slight_smile:

@gearsdigital You could also set the limit and offset dynamically.

$benefits   = $page->benefits()->toStructure();
$count      = $benefits->count();
$limit      = ceil($count/2);

$benefitsA  = $benefits->limit($limit);
$benefitsB  = $page->benefits()->toStructure()->offset($limit)->limit($limit); // or remove the limit or $count - $limit ...
1 Like

For sure! I know… but not sure about OP :smiley: Anyhow your code looks very much more readable!

And while we are at it: The chunk() method creates equally sized chunks:

$chunks = $page->benefits()->toStructure()->chunk(2); // this creates chunks of 2, again, it would be possible to create this number depending on total number of elements to get two more or less equally sized chunks.

// first chunk
if ($chunk = $chunks->first()) {
  foreach ($chunk as $benefit) {
    echo $benefit->heading();
  }
}
// second chunk
if ($chunk = $chunks->nth(2)) {
  foreach ($chunk as $benefit) {
    echo $benefit->heading();
  }
}

Thanks for the help! I learned something new again :smiley:

I went for the chunk() method.