Sort & filter entries from a structure field

Hi again,

I’m trying to filter and sort entries by date, from a structure field.
I tried to piece together solutions I found in related K2 threads but without success…

Here’s the structure field in my blueprint:

  shows:      
    type: structure
    fields:
      show_date:
        label: Date
        type: date

I’d like to display only entries whose date in the show_date field are in the future and in ascending chronological order.

My template:

 <?php foreach ($page->shows()->toStructure() as $show): ?>

  <?php if ($show->show_date()->filterBy('show_date', '>', time())): ?>
  <li>
     The <?php echo $show->show_date() ?> show is in the future.
  </li>
  <?php endif ?>

  <?php endforeach ?>

So far, all entries are displayed, both ones with dates in the future and dates in the past.
I haven’t included the sorting yet, because I first need to get the filtering part to work.

I’m pretty sure it’s a simple problem is in the <?php if… line…
Can somebody see it?

The problem is that you are trying to filter a single entry which will not work. You have to use the filter() method on the structure collection:

$shows = $page->shows()->toStructure()->filterBy('show_date', '>', time());
foreach ($shows as $show) {
  echo $show->show_date()->toDate('Y-m-d');
}

We have a wonderful recipe all about filtering: https://getkirby.com/docs/cookbook/content/filtering :yum:

1 Like

Aaahh thank you! And I hadn’t seen the Filtering compendium until now. Very helpful!

I’m experiencing a funny problem when using toStructure() coupled with a callback filter() function.

My data structure is as follows:

Title: Forum Users

----

Users: 

- 
  user: user1
  key: >

  3e0c7b3706538eb211e40c04xlemfeflf1r3errgrgrgglrmeglregmrlgmgldgmdglkmd
- 
  user: guest
  key: >
      xlemfeflf1r3errgrgrgglrmeglregmrlgmgldgmdglkmde503c3bc806e3

If I try a code like this:

$usr_key = page('forum-users')->users()->toStructure()->filter(function ($usr) {
  return $usr->user() == 'guest'; 
});

echo $usr_key;

I get back 1. I can’t do $usr_key->key() as there is only 1 as a string value.

If I do it “manually” like this

$usr_key = '';
        foreach(page('forum-users')->users()->toStructure() as $usr) {
          if ($usr->user() == 'guest') {
            $usr_key = $usr->key()->value();
          };
        };

echo $usr_key;

I get back the actual value (xlemfeflf1r3errgrgrgglrmeglregmrlgmgldgmdglkmde503c3bc806e3).

I haven’t been writing Kirby code in a while and can’t figure what I am missing out.

I tried first with a simple

page('forum-users')->users()->toStructure()->filterBy('user', 'guest');

and also get back 1.

Any help highly appreciated! (:

You have to loop through the collection:

$filteredUsers = page('forum-users')->users()->toStructure()->filter(function ($usr) {
  return $usr->user() == 'guest'; 
});
foreach ($filteredUsers as $user) {
  echo $user->key();
}

argh, thanks!

it’s about the same amount of code, compared to the other function i used, so i’ll stick with that (:

i was hoping to get a more “functional / one liner” code eheh.

EDIT

actually this makes it!

$filteredUsers = page('forum-users')->users()->toStructure()->filter(function ($usr) {
  return $usr->user() == 'guest'; 
});
echo $filteredUsers->first()->key();

Oh, ok, if you just want one, you might as well use findByinstead of filtering

<?= page('forum-users')->users()->toStructure()->findBy('user', 'guest')->key() ?>

But with an if-statement to make sure the entry exists.

1 Like

Hello texnixe, could you please help me to understand how you quote (I don’t know php, I try to make sense and copy/paste bits for trial/error…). when you answer

$shows = $page->shows()->toStructure()->filterBy…

which part does it corrects in

<?php foreach ($page->shows()->toStructure() as $show): ?>

 <?php if ($show->show_date()->filterBy('show_date', '>', time())): ?>
 <li>
    The <?php echo $show->show_date() ?> show is in the future.
 </li>
 <?php endif ?>

 <?php endforeach ?>

Thank you for your help

You can only filter a collection, not the individual fields in the structure, so the code would have to look like this:

<?php
$shows = $page->shows()->toStructure()->filterBy('show_date', '>', time());
foreach ($shows as $show): ?>
<li>
    The <?= $show->show_date()->toDate('Y-m-d') ?> show is in the future.
 </li>
 <?php endif ?>
 <?php endforeach ?>

While you don’t have to define the variable first, it’s a bit cleaner that putting everything into the foreach loop. You could do it like this as well if you absolutely want:

<?php foreach ($page->shows()->toStructure()->filterBy('show_date', '>', time()) as $show): ?>
1 Like

Hello texnixe, I try to do my best to learn Kirby (I appreciate its beautiful approach and lightness), but I’m lacking a lot (I’m just a designer).
I want to show only the coming dates from a structure. I copy and use the example codes. But as I enter a date on the panel, I get a error message on the page. I did try with the 2 codes you provided without any luck.
Can you point me in a direction, thank you

  right:
    width: 1/2
    sections:
      content:
        type: fields
        fields:
          shows:
            type: structure
            fields:
              show_date:
                label: Date
                type: date

The problem is time() here, we have to change this:

$shows = $page->shows()->toStructure()->filterBy('show_date', '>', date('Y-m-d'));
1 Like

Thank you, but with this code I still have the error message…

   <?php
    $shows = $page->shows()->toStructure()->filterBy('show_date', '>', date('Y-m-d'));
    foreach ($shows as $show): ?>
    <li>
    <?= $show->show_date()->toDate('Y-m-d') ?>
    </li>
    <?php endif ?>
    <?php endforeach ?>

This does not help, what is the error message?

Why is there an “endif” within the “foreach” loop?

Ok, the endif is a leftover from the original code.

   <?php
    $shows = $page->shows()->toStructure()->filterBy('show_date', '>', date('Y-m-d'));
    foreach ($shows as $show): ?>
    <li>
    <?= $show->show_date()->toDate('Y-m-d') ?>
    </li>

    <?php endforeach ?>

@KrsBee In the future, please post any error messages you get, that makes it a lot easier to help. Thanks.

2 Likes

This page is currently offline due to an unexpected error. We are very sorry for the inconvenience and will fix it as soon as possible.

Ah, then debugging is not enabled. In your /site/config/config.php please add

'debug' => true

within the return array so that it looks like this. If the file does not exists, please create it.

<?php
 
return [

// other options...
'debug' => true
];
2 Likes

Thank you so very much, it’s working now.
I will buy me an introduction book on php tomorrow.

There are quite good online resources available, unless you are a fan of books. But usually in the coding area, books are often not up to date (but can still do their stuff for the basics).

1 Like

You can find some suggestions here:

3 Likes