Orderby by multipe fields?

I don’t think this is possible by i’m trying to sort upcoming events using a CPT and ACF. The following snippet works but what if two events happen on the same day? I’d like for the events to first be ordered by the _StartEventDate then by _StartEventTime.

<Loop type=events orderby_field=_StartEventDate>
  <h2><Field title /></h2>
  <div><Field acf_date=_StartEventDate /></div>
  <p><Field acf_time=_StartEventTime format="g:i a"/> - <Field acf_time=_EndEventTime format="g:i a"/></p>   
</Loop>

Output would be similar to the following:

Event Title (Venue A)
06-29-2022
9:00 am - 11:00 am

Event Title (Venue B)
06-29-2022
10:00 am - 11:00 am

Event Title (Venue C)
06-30-2022
9:00 am - 11:30 am

Thanks!

That’s a great question, not really one that I’ve put thought into yet myself! There doesn’t seem to be a built-in way to sort by multiple fields at the moment, so maybe it would be worth a feature request to see whether it’s possible.

After giving it some thought, maybe a way to achieve this could involve a nested loop where the outside loop is basically just grabbing all the date fields from posts and then the inside loop is re-grabbing all the event posts that have the same date field and sorting by the time field. The issue with that though would be that the inner loop would run once for every post, so if multiple posts share the same date, the inner loop would display the same group of same-day events as many times as there are events in that group. You could probably use some conditional logic to get around that.

I haven’t tested this to see if it actually works so you’ll probably want to test and troubleshoot this, but here’s sorta what I’m thinking:

<Loop type=events orderby_field=_StartEventDate>
  <If check="{_StartEventDate}" is_not value="{Get last_event_date}">
    <Loop type=events custom_field=_StartEventDate custom_field_value="{Field _StartEventDate}" orderby_field=_StartEventTime>
      <h2><Field title /></h2>
      <div><Field acf_date=_StartEventDate /></div>
      <p><Field acf_time=_StartEventTime format="g:i a"/> - <Field acf_time=_EndEventTime format="g:i a"/></p>
      <If count more_than value=1><Set last_event_date><Field _StartEventDate /></Set></If>
    </Loop>
  </If>
</Loop>

This markup has two loops, two conditional logic statements, and a variable that gets set just about every loop so this seems super inefficient and could almost definitely be improved with some rewriting. Someone with more experience could probably suggest something better, but I figured this might give you a way to get started in thinking about this. If the markup didn’t have to run the inner loop for events that were on a unique date, that might improve things, but it would probably involve using the Template tag to avoid writing your display markup (the h2s and divs) multiple times.

Hope this is helpful!

Very helpful!

I thought about this exact method as well but didn’t think about using conditions / variable to fix the inner loop. Rolling my own event “calendar” is going to be a chore!

EDIT: @benjamin looks like there is a request that’s in progress “Add orderby_field_date as loop query parameter” @eliot would / could this solve my issue? I don’t want to double post a feature request.

1 Like

I just had a crazy idea but I haven’t tested it yet. As far as I understand from Eliot’s post here, orderby is a query parameter, which would mean that it’s actually reordering items on the query-level, whereas sort_field is a loop filter, meaning that it just reorders the output of a query. If my understanding is correct, sort_field would run after orderby, which might mean that if you had a loop like this, it would start by ordering your events by their start time on the query level and would then sort those posts by their start date, which could give you the two-level post sorting you’re looking for.

<Loop type=events orderby_field=_StartEventTime sort_field=_StartEventDate>

I haven’t tested this so do report back if this works! There are reasons why you’d generally want to use a query parameter instead of a loop filter (as explained in Eliot’s comment that I linked to above) so even if this does work it might not be the best solution in all instances, but I assume it would be more effective than my messy solution above.

Edit: finally got around to testing this, it seems to work as I was expecting, which would make this a much more efficient solution compared to what I suggested above.