Dates in structure field from child pages

hopefully someone could help me with that – I’ve read several threads here and tried many versions, but nothing really worked as I want … I am pretty new to php, so maybe it’s a silly question …

I have a page (produktionen) with some children (project); each child (project) has a structured field (termine):

project.yml:


sections:
          daten:
            type: fields
            fields:
              obertitel:
                label: Obertitel
                type: text
              untertitel:
                label: Untertitel
                type: text
              untertitel2:
                label: Untertitel 2
                type: text  
              inhalt:
                extends: fields/blockEditor
                help: Inhalt und Mitwirkende
              presse:
                extends: fields/blockEditor
                help: Pressestimmen
sections:
          termindaten:
            type: fields
            fields:
              termine:
                label: Termine
                type: structure
                fields:
                  datum: 
                    label: Datum
                    type: date
                  zeit:
                    label: Uhrzeit
                    type: text
                  zusatz:
                    label: Text
                    type: text

my goal is to get something like a lineup from listed children of which i can post on a new page like lineup.php

date / title / untertitel … sorted by date asc
for example:
Apr 23 2022 - Project A
Project B

May 4 2022 - Project A

and so on …

my lineup.php:

<?php $projects = page('produktionen')->children(); ?>

<?php foreach ($projects->listed() as $items): ?>
  <?= $items as $item->termine()->toStructure(); ?>
    <?php foreach ($item->termine()->datum()->toDate()); ?>
    <? $item->datum()->toDate(); ?>  
    <?php endforeach ?>
  <?= $item->title() ?>
  <?= $item->untertitel() ?>
<?php endforeach ?>

unfortunately this isn’t working … thx for any help!

Something went a bit wrong in your code. I renamed your variables a bit to make the structure a bit clearer:

<?php $projects = page('produktionen')->children()->listed(); ?>

<?php foreach ($projects as $project): ?>
  <?php $data = $project->termine()->toStructure();  /* fetch the structure items into $data variable */?>
    <?php foreach ($data as $dataItem): ?>
    <?= $dataItem->datum()->toDate(); ?>  
    <?php endforeach ?>
  <?= $project->title() ?>
  <?= $project->untertitel() ?>
<?php endforeach ?>

thx a lot!!! that works!
there was a “-” missing in your code

<?= $project->title() ?>

just to help others with that stuff :wink:
perfect, thx @texnixe !!!

another question:
how can I achieve to group the dates and sort them ascending?
i’m not sure if I have to ->group or ->groupBy …?

if possible I’d like to get an output like:
Apr 23 2022 - Project A, Project B, …
May 4 2022 - Project C …

thx in advance!

You would use group and then a day based format, see first example in this section: Grouping collections | Kirby CMS

While the example uses a page, this works just as well for structure items.

thx for your hint with grouping collections - my code works, but still not grouping per date …?
any help is much appreciated!

<?php $projects = page('produktionen')->children()->listed(); ?>

<?php foreach ($projects as $project): ?>
  <?php $data = $project->termine()->toStructure(); /* fetch the structure items into $data variable */?>
    
      <?php
      // function that returns the formatted date
      $callback = function($data) {
      return $data->datum()->toDate('EE, dd. MMM YYYY');
      };
      // group items using $callback
      $groupedItems = $data->group($callback);

      // output items by date
      foreach ($groupedItems as $datum => $itemsPerDatum): ?>
        <h2><?= $datum ?></h2>
        <?php foreach ($itemsPerDatum as $dataItem) : ?>
        <?= $project->title() ?>
        <?= $project->untertitel() ?>
        <?= $dataItem->zeit() ?> Uhr 
        <?= $dataItem->zusatz() ?></br>
        <?php endforeach ?>
      <?php endforeach ?>
    
<?php endforeach ?>

Sorry, my suggestion didn’t make sense, because that only groups the structure items. But you want to group the projects by the data in the structure items…

The easiest approach would probably be to collect all dates from all project into an array.

Then loop through that array and filter out the projects that have this date in their structure field.

ah, I understand!

well, that sounds a bit complex for a noob like me :wink:

any advice where to start?
thank you very much!

Another option would be virtual pages collection, where each project appears multiple times with a new slug:

// This code should go into a controller or maybe better collection
$projects = page('produktionen')->children()->listed()
$collection = [];

foreach ($projects as $project) {
  foreach ($project->termine()->toStructure() as $item)
  {
    $collection[] = [
      'slug' => $project->slug() . '-' . $item->date()->toDate(),
      'template' => $project->intendedTemplate()->name(),
      'content' => array_merge(
        $project->content()->toArray(), 
        ['date' => $item->date()->date('Y-m-d')]
      ),
    ];
  }
}
$projectPages = Pages::factory($collection)->sortBy('date')->groupBy('date');

?>

This would then be the template part

<?php foreach ($projectPages as $date => $items): ?>
        <h2><?= $date ?></h2>
        <?php foreach ($items as $project) : ?>
        <?= $project->title() ?>
        <?= $project->untertitel() ?>
        <?= $project->zeit() ?> Uhr 
        <?= $project->zusatz() ?></br>
        <?php endforeach ?>
<?php endforeach ?>

sorry for bothering …
I put the first part of your code in a collection (site/collections/lineup.php)

this is the code of my template (also called lineup.php):

<?php $kirby->collection("lineup"); ?>    
  
<?php foreach ($projectPages as $date => $items): ?>
        <h2><?= $date ?></h2>
        <?php foreach ($items as $project) : ?>
        <?= $project->title() ?>
        <?= $project->untertitel() ?>
        <?= $project->zeit() ?> Uhr 
        <?= $project->zusatz() ?></br>
        <?php endforeach ?>
<?php endforeach ?>

now i got the following error:


ParseError thrown with message "syntax error, unexpected variable "$collection""

do I have to put something in there [ ]?

$collection = [];

You have to replace this with

<?php foreach ($kirby->collection('lineup') as $date => $items): ?>

Or assign the collection to $projectPages variable.

In your collection, I don’t know what’s wrong, because you didn’t post the code.

ok, I replaced the line in my template now;

this is my collection file: (lineup.php)



<?php 
  // This code should go into a controller or maybe better collection
$projects = page('produktionen')->children()->listed()
$collection = [];

foreach ($projects as $project) {
  foreach ($project->termine()->toStructure() as $item)
  {
    $collection[] = [
      'slug' => $project->slug() . '-' . $item->date()->toDate(),
      'template' => $project->intendedTemplate()->name(),
      'content' => array_merge(
        $project->content()->toArray(), 
        ['date' => $item->date()->date('Y-m-d')]
      ),
    ];
  }
}
$projectPages = Pages::factory($collection)->sortBy('date')->groupBy('date');

I get a parse error
syntax error, unexpected variable “$collection”
in line 4 site/theme/collections/lineup.php

I am not sure if I have to put something in the brackets in the collection-file?
$collection = [];

thx for your patience!

Missing semicolon at the end

Also, please check out the docs how a collection file has to look like: Collections | Kirby CMS

ok … I read the docs, watched the video about collections but I have no idea :frowning:

when I attach the missing semicolon as you mentioned above, now I get the error:
“The collection cannot be found” …?
I did nothing more, just added the semicolon …

but it is found without the semicolon and then there comes the error which I mentioned before …

this is strange :-/

I don’t know what you are doing, but this is what your collection should look like

<?php

return function ($site) {
    $projects = $site->find('produktionen')->children()->listed();
    $collection = [];

    foreach ($projects as $project) {
        foreach ($project->termine()->toStructure() as $item) {
            $collection[] = [
                'slug'     => $project->slug() . '-' . $item->date()->toDate(),
                'template' => $project->intendedTemplate()->name(),
                'content'  => array_merge(
                    $project->content()->toArray(),
                    ['date' => $item->date()->date('Y-m-d')]
                ),
            ];
        }
    }

    return Pages::factory($collection)->sortBy('date')->groupBy('date');

finally :grinning: it works :wink:

this is my collection-file:

<?php

return function ($site) {
    $projects = $site->find('produktionen')->children()->listed();
    $collection = [];

    foreach ($projects as $project) {
        foreach ($project->termine()->toStructure() as $item) {
            $collection[] = [
                'slug'     => $project->slug() . '-' . $item->datum()->toDate('EE, dd. MMM YYYY'),
                'template' => $project->intendedTemplate()->name(),
                'content'  => array_merge(
                    $project->content()->toArray(),
                    ['datum' => $item->datum()->toDate('EE, dd. MMM YYYY'),
                     'zeit' => $item->zeit(),
                     'zusatz' => $item->zusatz()]
                ),
            ];
        }
    }
  

  return Pages::factory($collection)->sortBy('datum', 'asc')->groupBy('datum', 'asc');
  };

and this ist my template-file:

<?php $kirby->collection('lineup'); ?>    
  
<?php foreach ($kirby->collection('lineup') as $date => $items): ?>
    <h2><?= $date ?></h2>
        <?php foreach ($items as $project): ?>
          <?= $project->title() ?>
          <?= $project->untertitel(); ?>
          <?= $project->zeit() ?> Uhr 
          <?= $project->zusatz() ?></br>
        <?php endforeach ?>   
<?php endforeach ?>

the only thing left is: the sorting by date …
for now it seems the dates are sorted kind of weired … I tried to add ‘asc’ as you can see in the collection-file - but that has no effect … maybe you have an idea?

many many many thanks so far!!! :wink:

Don’t know why you are formatting the date here like that, that doesn’t make sense. Keep it at (‘Y-m-d’) or equivalent with the intl formatter.

Then format your date as desired when rendering in the frontend.

interesting … I used the date handler ‘intl’ in my config.php and sorting went wrong,
when I use ‘date’ sorting works perfect!

maybe this is because I use kirby 3.7.3 … I think I have read something about an issue with date handlers in kirby 3.7.x?

anyway, now it works :+1:
thk u very much!