2

I have an event calendar of sorts for music gigs. The back-end has sections for Artists and Venues, where I enter appropriate info, and another section, Shows, which I choose an artist, a venue, and enter the event date (in a custom field).

The template that pulls everything together grabs all future show dates, groups the dates by the artist, then checks each entry for fields before displaying it in the HTML, like so:

{#-- grab all current shows and order by date --#}
{% set all_shows = craft.entries.section('shows').gig_date('>=' ~ (now.date)).order('gig_date asc') %}

{#-- group shows by artist --#}
{% set artist_shows = all_shows|group('gig_artist.first()') %}

{% for artist, shows in artist_shows %}

    {#-- artist title --#}
    <h3>{% if shows[0].gig_artist[0].artist_url|length %}<a href="{{ shows[0].gig_artist[0].artist_url }}">{{ artist }}</a>{% else %}{{ artist }}{% endif %}</h3>

    <table>
        <tbody>

            {#-- shows list --#}
            {% for show in shows %}

                <tr>
                    <td class="gig_date">

                        {#-- date --#}
                        <time title="{{ show.gig_date.w3c }}">{{ show.gig_date|date('F j') }}</time>
                    </td>
                    <td class="gig_venue">

                        {#-- venue name and website--#}
                        {% if show.gig_venue[0].venue_url|length %}<a href="{{ show.gig_venue[0].venue_url }}">{{ show.gig_venue[0].title }}</a>{% else %}{{ show.gig_venue[0].title }}{% endif %}

                        {#-- city --#}  
                        {% if show.gig_venue[0].venue_city|length %}, {{ show.gig_venue[0].venue_city }}{% endif %}

                        {#-- state --#}
                        {% if show.gig_venue[0].venue_state|length %} {{ show.gig_venue[0].venue_state }}{% endif %}

                        {#-- notes --#}
                        {% if show.gig_notes|length %}<div class="gig_notes">{{ show.gig_notes }}</div>{% endif %}
                    </td>

                </tr>

            {% endfor %}
        </tbody>    
    </table>

{% endfor %}

This page takes several seconds to render on my site versus the other pages. I've tried this without the |group filtering, and without the date comparison, and it's still equally slow, which leads me to believe it's the pinging the multiple entry fields that's slowing things down.

I have a hunch eager loading will be helpful, but unfortunately I can't wrap my brain around it at this level. Any ideas?

2 Answers 2

4

Caching will improve performance, but the actual issue is that your code is generating a lot of queries. You should look into eager loading:

https://craftcms.com/docs/templating/eager-loading-elements

The basic idea is that you predefine what sub-elements you're going to need (in your case gig_artist and gig_venue), so that Craft can preload them instead of loading them when Craft encounters them in your code (and do less efficient queries).

2
  • I have to admit I feel like a dummy—I read through the eager-loading docs before posting this and thought that technique wouldn't apply. But you made it clearer to me how Craft performs its queries. Eager-loading in my initial query (and changing my group filter from all_shows|group('gig_artist.first() to all_shows|group('gig_artist[0]) has got me back in a reasonable time frame. Commented Aug 15, 2017 at 3:37
  • Yeah, I had the same experience a while ago. I thought it was something like lazy loading, before I really had a good look at it.
    – Youniteus
    Commented Aug 15, 2017 at 7:22
4

Have you considered to cache the whole output? https://craftcms.com/docs/templating/cache

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.