Event and Location Grouping and Ordering
As of version 5.8, it is possible to easily group up events and locations by specific values using the groupby, groupby_orderby and groupby_order search attributes, and display only one item per group in a list along with other ungrouped items.
This is a complex feature because of the many possible applications for it, but when applied to a specific situation it becomes easier to understand.
The term 'Grouping' in this context is not to be confused with grouping events via categories/tags, BuddyPress Groups (i.e. the group attribute) or the events_list_grouped shortcode which outputs event lists grouped by day, week, month or year.
What is grouping?
We should start with a commonly used example. In a scenario where you have various daily recurring events, and a few one-off events, your list will look very repetitive if you showed every upcoming daily recurrence, and it'd be hard for people to see the important one-off events you may have within that list. If you would like to display all your upcoming events, but only display the first recurrence for each recurring event set, Grouping is what you're after.
By using these grouping attributes, you can display the first item of each group, which can be useful in many circumstances such as if you wanted to display a list of:
- All upcoming events, but showing only the first recurrence of an event in each set of recurring events.
- Locations showing the first location within each state of a specific country.
- The next upcoming event in each city, state or country.
- Locations where the next upcoming event will occur for each blog you have in a MultiSite environment (with our Global Tables feature enabled)
The possibilities of grouping are endless, but we'll give you a few shortcode examples of the above further down to show you the possibilities.
Working example
Whilst we explain each attribute, we'll work off the example below where we're trying to show the next upcoming event at each location, as well as any other upcoming events without locations. However, we'll display our final list of events in alphabetical order (just to highlight the different attributes and how they affect the final result):
[events_list groupby="location_id" orderby="event_name" order="ASC" groupby_orderby="event_start_date, event_start_time" groupby_order="DESC" scope="future"]
In PHP it'd look like this:
echo EM\_Events::output('groupby'=>'location\_id', 'orderby'=>'event\_name', 'order'=>'ASC'...);
Here's a diagram we hope will help clarify how the final result is obtained:
Notice how the final result (the purple box) has a list of events in alphabetical order and non-sequential dates, containing only one event per location as well as events without locations. This is because order is set to event_name which is what determines the order of the final list.
In the diagram, the shortcode doesn't include scope="future" and order="ASC" as these two arguments are the default values in Events Manager (unless changed in our settings page).
Understanding each grouping attribute and how to use it
Let's go through each attribute and break down the meaning and use:
groupby - What to group by
groupby is the main argument and is required for the other two to take effect. This attribute defines what fields you want to group your results by, and accepts any field name from the wp_em_events and wp_em_locations tables (just like orderby).
In our working example, we have set groupby to location_id which allows you to group events by location, and display one event from each location.
Note, that in situations where an event or location does not have a value for what is being grouped by, those items are not grouped and shown separately. In our example above, you'll see two events without locations showed up in the final list.
You can use other attributes provided by EM to filter your results further. If we wanted to only show events with locations, we'd also add the has_locations="1" attribute to the shortcode above.
groupby_orderby - What is used to choose each result in each group
groupby_orderby defines on what basis we decide to choose the event/location that ends up on our final list. This also accepts a comma-separated list of event or location table field names, just like groupby and orderby.
In our shortcode example above, we have chosen the event based on when it begins. You should use 'event_start_date, event_start_time' to order by the start date and then the time, we chose 'event_start_date' in our example just to shorten the shortcode length for display purposes.
groupby_order - How to sort what you're using to choose in each result in each group
groupby_order will sort the list within each group of events/locations in ASCending or DESCending order, and accepts either ASC or DESC as a value (or lowercase asc/desc).
Since the first item is what is chosen to be used in the final list of events/locations, the order of sorting will determine whether you will obtain the first or last item within each group as sorted by group_orderby.
In our example, you'll be getting the latest event starting at each location, because groupby_order value is DESCending order for a list sorted by start date in group_orderby. If it was ASCending, you'd get the earliest event. Also, note that here, we're not choosing the next upcoming event here, we're getting the earliest or latest event within the scope we've chosen, which in this case is future events.
Further considerations
Now that you have an understanding of how grouping works, it's important to note that grouping simply defines what you're grouping by, and which item to choose within each group.
order and orderby, whilst similar in terms of accepted values, will order the final list of events and has no impact on what happens within the list of items within each group.
Grouping can (and should) be paired with your usual attributes to limit the what's chosen within each group, and in the final result. For example, scope will let you choose the time span from which to choose your events, has_location allows you to only show events that have a location, or eventful will let you only show a list of locations that have an event associated with it.
Another situation where people may get confused is grouping by location, categories and tags. If you would like to show a list of upcoming events, but grouped by location, but show more than one event per location, this isn't the right solution for you. In that sort of situation, you're actually displaying a list of locations, and within each location you would want to display upcoming events by using #_LOCATIONNEXTEVENTS. The resulting shortcode may look like this:
[locations_list scope="future" eventful="1"]
#_LOCATIONNAME
#_LOCATIONNEXTEVENTS[/locations_list]
However, here's a great example of how you can still use grouping show a list of upcoming events at one location (the first location alphabetically) per country for example!
[locations_list scope="future" eventful="1" groupby="location_country" groupby_orderby="location_name"]
#_LOCATIONNAME
#_LOCATIONNEXTEVENTS[/locations_list]
As you can see, the combinations are endless!
More real-world examples
We hope this article has given you a better understanding of how to leverage this powerful new feature. We'll finish off by providing an example shortcode for each of the initial scenarios we presented at the beginning.
We'll make some assumptions here, to keep the shortcodes shorter. The default scope and ordering would look like this in each shortcode:
scope="future" orderby="event_start_date, event_start_time" order="asc" groupby_order="asc"
Depending on your settings, you may need to add one or more of these to produce the right results.
All upcoming events, but showing only the first recurrence of an event in each set of recurring events.
[events_list groupby="recurrence_id" groupby_orderby="event_start_date,event_start_time"]
Locations showing the first location alphabetically within each state of a specific country.
[locations_list groupby="location_country" groupby_orderby="location_name" orderby="location"]
The next upcoming event in each city.
[events_list groupby="location_city" groupby_orderby="event_start_date, event_start_time"]
Locations where the next upcoming event will occur for each blog you have in a MultiSite environment (with our Global Tables feature enabled)
[events_list has_location="1" groupby="blog_id" groupby_orderby="event_start_date, event_start_time"]#_LOCATIONNAME
[/events_list]In this last example, we use events_list rather locations_list because we're looking for locations based on upcoming events, which we can obtain from the event via placeholders as well as information about the specific event if needed.