How to sort by grouped field?

I want to show a list of articles, grouped by year, where year is a date in the festival, where festival is related field of article.

With this:

<?php

$callback = function($p) {
  return $p->festival()->toPage()->date()->toDate('Y');
};

$groupedItems = page('press')->children()->listed()->group($callback);


foreach($groupedItems as $year => $itemsPerYear): ?>
    <h2><?= $year ?></h2>
    <ul>
      <?php foreach($itemsPerYear->flip() as $item) : ?>
      <li><a href="<?= $item->sourceurl() ?>"><?= $item->title() ?></a>, <?= $item->source() ?>, <?= $item->date()->toDate('Y-m-d') ?></li>
      <?php endforeach; ?>
    </ul>
<?php endforeach ?>

I am getting this sort:

tried something like foreach($groupedItems->sortBy('$callback'), but no result, also in this case year are converted to numbers 0, 1, 2…

You have to sort the collection before grouping. You can use the same callback as for the grouping,

$groupedItems = page('press')->children()->listed()->sort($callback, 'desc')->group($callback);

Alright … this is just a wild untested guess :sweat_smile:

At first I would create a custom page method festivalYear() for the children of the press page.

// site/models/article.php – assuming the page type is "article"

class ArticlePage extends Page {
  public function festivalYear() {
    return $this->festival()->toPage()->date()->toDate('Y');
  }
}

Afterwards you should be able to sort and group by this custom method like this:

$groupedItems = page('press')->children()->listed()->sortBy('festivalYear', 'asc')->group(function($item) {
    return $item->festivalYear();
});

I didn’t know about the group() method so far. Great learning for me!

1 Like

What do you mean?

Thanks, tried it, but items are not grouped with this code.

I already updated my post…

1 Like

This should probably be (not tested)

$groupedItems = page('press')->children()->listed()->sortBy('festivalYear', 'asc')->groupBy('festivalYear');

Yes, great, thank you, it solved the problem :slight_smile:

@texnixe also one more question, can’t figure out how to pass the value of child pages radio field to $callback

A bit more details about the case:
There are festivals, each festival has performers as child pages. Each performer has category as radio value. So on festival page I need to show performers, grouped by their categories.

$performers = page('yourFestivalPage')->children()->listed()->groupBy('yourPerformerCategoryField');

Thank you, ok, clear, so turns out there is no need to get value of radio option :slight_smile:

In my example yourPerformerCategoryField would be the radio field

Yes, that’s clear, thanks. Only can’t understand how to print values of radio. As need to show titles of categories. Should be something like:

<?php
$field = $page->children()->blueprint()->field('performertype');
$value = $page->children()->performertype()->value();
?>

<?= $performertypeValue = $field['options'][$value][$kirby->language()->code()] ?? $value; ?>

But missing something.

I mean to show radio value here (now $performer shows machine names of radio):

<?php $groupedItems = $page->children()->listed()->groupBy('performertype'); ?>

  <?php foreach ($groupedItems as $performer => $itemsPerPerformer): ?>
  
    <h2 class="h1"><?= $performer ?></h2>
     ....

I this case it probably makes sense to set up a category map (i.e. array of key/ value pairs) in your config file or, since you seem to have a multilanguage site, in your translation files, otherwise you would have to get the blueprint of one specific page and get the text that matches the current value from that page’s blueprint.

Yes, that seems the easiest solution, tried and it works, thank you :slight_smile: