I have a channel of Musical Compositions:

enter image description here

Now all these Compositions have a Composer. All the composers are stored in a separate channel and then linked with their respective compositions trough a entries field

Now I like to order the compositions by the last name of the composer and group them together alphabetically.

I managed them to be grouped but not by the composer name, just by the composition title which is not helpful.

{% set allEntries = craft.entries.section('komposition').limit(null) %}
{% set allEntriesByPrename = allEntries | group('title|upper|slice(0, 1)') %}

{% for letter, allEntriesSorted in allEntriesByPrename %} 
 {# stuff #}
{% endfor %}

Now the catch here is the group filter I guess but when I use the handle of the entries field it doesn't work:

| group('composerRelated.lastName|upper|slice(0, 1)')

If I write it like this, the group filter simply is ignored. Since the entries field returns an array I have no idea how to write this. And I think at the time of the group filter the entries field is not available yet.

I also tried to grab all composers from the section and put it into the group filter:

{% set allEntries = craft.entries.section('komposition').limit(null) %}
{% set composerName = craft.entries.section('komponist').limit(null) %}

{% set allEntriesByPrename = allEntries | group('composerName.lastName|upper|slice(0, 1)') %} 

This is too much inception for me. How do I have to write this?

2 Answers 2


I think you're nearly there! Give this a shot:

{% set allEntriesByPrename = allEntries | group('{{ (object.composerName | first).lastName | upper | slice(0, 1) }}') %}

I believe the issue is that relations always come back as an array, and you were trying to immediately access a property of the Element at index 0 in that array, rather than de-referencing it, then accessing the property.

Be aware that this may generate some deprecation errors, as using the first filter will attempt to use the relational field as an array. Instead, I'd recommend eager-loading your Composers along with the Compositions--in addition to being safer, moving forward, it avoids an N+1 problem, and will dramatically reduce the number of queries on your page:

{# See: `with`, including the `composerName` field handle: #}
{% set allEntries = craft.entries({
  section: 'komposition',
  limit: null,
  with: [

{# Grouping by a relation will no longer trigger another query per Composition: #}
{% set allEntriesByPrename = allEntries | group('{{ (object.composerName | first).lastName | upper | slice(0, 1) }}') %}

Note: I had to use the expanded syntax for the group filter ({{ ... }}) in order to enforce the proper order of operations. In that context, object is a reference to the Composition.

  • If I wrap the group filter into {{}} I get A hash key must be followed by a colon (:). Unexpected token "punctuation" of value "}" ("punctuation" expected with value ":")
    – KSPR
    Jan 10, 2020 at 11:47
  • Is it still surrounded with single quotes, or did you remove those in the process? Jan 10, 2020 at 12:08
  • yes is use single quotes: {% set allEntriesByPrename = allEntries | group('{{object.composerName | first .lastName|upper|slice(0, 1)}}') %}
    – KSPR
    Jan 10, 2020 at 12:10
  • Same like this: {% set allEntriesByPrename = allEntries | group('{{ (object.komponistRelated | first).nachname | upper | slice(0, 1) }}') %}
    – KSPR
    Jan 10, 2020 at 12:12

A little late to the party here, but in case anyone else comes across this post.

The suggestion that August was making here was very close, but when I tried something similar, I was running into the same error as @KSPR

A hash key must be followed by a colon (:). Unexpected token "punctuation" of value "}" ("punctuation" expected with value ":")

According to the docs for Crafts twig group filter what you actually need is something like this:

{% set allEntriesByPrename = allEntries | group( e => (e.composerName| first).lastName | upper | slice(0, 1) ) %}

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.