3

I am attempting to create an 'a to z' listing on a site with 1000+ entries of people. The catch is that it needs to be indexed by surname unless that person doesn't have a surname, in which case it will use their forename.

I know what I need to end up with — an array of 'a' to 'z' as keys, with the value another array of people, indexed by their name with the entry id as the value. I can then iterate over this and create the relevant sections for styling.

Is this even possible in Twig? If so, how?

5

I base my example on the assumption that all people are Users (Element type User). If users are entries, you'd have to replace users by entries ;)

I don't think there's a way to do this without iterating through all users first, creating some sort of ordering attribute (if lastName != '' ? lastName : firstName). Then, you'd be able to group your array by your ordering attribute:

{# create a variable to hold all user data you need #}
{% set allUsers = [] %}

{# loop through users ... #}
{% for user in craft.users.find() %}
    {# 
        ... and set variable for each user, containing the info you need
        and an 'orderMeBy' attribute, set to the uppercased first character of lastName or firstName
    #}
    {% set thisUser = [{
        fullName : user.fullName,
        orderMeBy : user.lastName != '' ? user.lastName | slice(0,1) | upper : user.firstName | slice(0,1) | upper
    }] %}

    {# merge this user's info with your allUsers variable #}
    {% set allUsers = allUsers | merge (thisUser) %}
{% endfor %}

{# group 'allUsers' variable by 'orderMeBy' attribute #}
{% set groupedUsers = allUsers | group('orderMeBy') %}

{# create an array of all numbers and letters #}
{% set numbers = 0..9 %}
{% set letters = 'A'..'Z' %}
{% set allChars = numbers | merge(letters) %}

{# loop to chars and, if users in groupedUsers[char], display those users #}
{% for char in allChars %}
    {% if groupedUsers[char] is defined %}
    <h2>{{ char }}</h2>
    <ul>
        {% for user in groupedUsers[char] %}
            <li>{{ user.fullName }}</li>
        {% endfor %}
    </ul>
    {% endif %}
{% endfor %}

If anyone knows a quicker and/or easier way, tell me :)

1

Paul's answer is good, but I suspect it would end up being a bit easier and cleaner if you just it from a plugin so you could do all of your logic from PHP.

The just return your sorted, assembled array back to the template to loop through.

  • I responded to the Is this even possible in Twig? If so, how? part of the question ;) Wanted to show that nearly everything is possible in Twig ... This is for the poor souls not able or willing to create plugins :) – Paul Nov 24 '14 at 18:48
  • 1
    Of course. At some point the programmer in me starts to cringe seeing so much logic in a template is all. :) – Brad Bell Nov 24 '14 at 18:49
  • Always ignore the programmer in you, it makes life so much easier ... – Paul Nov 24 '14 at 18:50
  • I agree with Brad, I think I'll be writing my first plugin here. – hamishtaplin Nov 25 '14 at 8:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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