0

I need to be able to group dates by their month but then order them by month too because the order they're inserted into the database in na super field table isn't always in date order.

So far, I have this:

{% set today = now|date('U') %}
{% set dates = [] %}
{% for date in entry.dates %}
    {% if date.start|date('U') >= today %}
    {% set dates = dates|merge([date]) %}
    {% endif %}
{% endfor %}

{% set datesByMonth = dates|group('start|date("F Y")') %}
{% for month, dates in datesByMonth %}
    {{ month }}
    dates stuff
{% endfor %}

which works fine except for the ordering.

I thought for the ordering, I might be able to do this:

{% for month, dates in datesByMonth|multisort(['start|date("c")']) %}
…
{% endfor %}

but that doesn't change the order. Am I doing that wrong or is there another way?

4
  • What's in your dates variable - entries, DateTime values?
    – MoritzLost
    Commented Sep 27, 2023 at 5:47
  • If it's entries, please post the entry query as well, might be possible to order the results right in the query.
    – MoritzLost
    Commented Sep 27, 2023 at 5:48
  • @MoritzLost it's an array from a super table field which contains datetime start and end columns.
    – Tyssen
    Commented Sep 27, 2023 at 5:51
  • @MoritzLost I've edited the question to include more of the code prior to what I originally posted.
    – Tyssen
    Commented Sep 27, 2023 at 5:54

1 Answer 1

1

You could order the dates inside the for-loop, but I would order the dates before they're grouped, much simpler. You can do this in one clean pipeline, much easier to reason about and understand:

{% set datesByMonth = entry.dates
    |filter(date => date.start >= now)
    |sort((a, b) => a.start <=> b.start)
    |group(date => date.start | date('F Y'))
%}

First, the filter removes all dates before today, this means you can get rid of the first for-loop. Then, the array is sorted using the sort filter. Finally, the sorted array is grouped using the group filter. Since the array was already sorted, the grouped items will be sorted as well.

This assumes that entry.dates returns an array of DateTime objects. You can compare DateTime objects directly (both in PHP and Twig), so you don't need the date filter. If entry.dates is an array of something else (like dates string in a specific format), you can first map that to an array of DateTime objects using the map filter and the date function:

{% set datesByMonth = entry.dates
    |map(dateString => date(dateString))
    |filter(date => date.start >= now)
    |sort((a, b) => a.start <=> b.start)
    |group(date => date.start | date('F Y'))
%}
3
  • That's nearly there except that on the page I'm testing, there are events in September, October, November, but the first heading that appears on the page is October 2023.
    – Tyssen
    Commented Sep 27, 2023 at 23:36
  • 1
    Actually, not looking at the dates closely enough, there are dates in September, but none after today, so all good, thanks. :)
    – Tyssen
    Commented Sep 27, 2023 at 23:54
  • @Tyssen If the order is really inverted, just switch the a and b, I always get the order wrong the first time :-)
    – MoritzLost
    Commented Sep 28, 2023 at 11:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.