1

I have a section for addresses which has fields for address, state, suburb and postcode. On the front end, I want to display them like this:

State 1
- Suburb 1
-- Address 1
-- Address 2
- Suburb 2
-- Address 1
-- Address 2

so in other words, they'd be grouped by their state and then by their suburb. How would I go about doing that?

2 Answers 2

2

Assuming you can't change your data model easily to use relationships pointing to a 2-level Structure for State > Suburb (which would be a more robust approach), you can use the group filter to create 2-dimensional arrays like this:

{% set buildings = craft.entries.section('buildings').authorId(currentUser.id).all() %}
{% set buildingsByState = buildings|group(building => building.state) %}
<ul>
    {% for state, buildingsInState in buildingsByState %}
        <li>
            <h3>{{ state }}</h3>
            {% for suburb, buildingsInSuburb in buildingsInState|group(building => building.suburb) %}
                <h4>{{ suburb }}</h4>
                <ul>
                    {% for building in buildingsInSuburb %}
                        <li>{{ building.title }}</li>
                    {% endfor %}
                </ul>
            {% endfor %}
        </li>
    {% endfor %}
</ul>
1

Wasn't that hard actually, just needed to stop and think about it for a bit.

{% set buildings = craft.entries.authorId(currentUser.id) %}
{% set states = [] %}
{% set suburbs = [] %}
{% for building in buildings %}
    {% set states = states|merge([building.state])|unique %}
    {% set suburbs = suburbs|merge([building.suburb])|unique %}
{% endfor %}

<ul>
    {% for state in states %}
    <li>
        <div>{{ state }}</div>
        <ul>
            {% for suburb in suburbs %}
            <li>
               {{ suburb }}
                <ul>
                    {% set addresses = craft.entries.authorId(currentUser.id).suburb(suburb) %}
                    {% for address in addresses %}
                    <li>{{ address.title }}</li>
                    {% endfor %}
                </ul>
            </li>
            {% endfor %}
        </ul>
    </li>
    {% endfor %}
</ul>
3
  • 1
    Be careful with this solution - you've created an N+1 problem here by having a query inside a loop - and a nested loop at that, which will compound the problem. Every entry that gets added will progressively degrade the performance of this. Turn on your template debugger and keep an eye on the DB query count and timing. Are your states and suburbs relationship fields (entries/categories) or plain text/dropdowns? Aug 18, 2023 at 8:43
  • @JamesSmith Plain text fields
    – Tyssen
    Aug 21, 2023 at 0:09
  • You also seem to be looping through all suburbs here, not just the ones that belong to the current state. If it's not too late I'd recommend you refine your content model so that states and suburbs are a 2-level Structure (a suburb can never be a child of more than one state, so this is a suitable setup). It'll also improve your data quality by avoiding typos or alternate spellings. Even someone putting a space or capital letter in the wrong place could spoil your output. Aug 21, 2023 at 10:53

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.