Event query recipes
How to query events correctly, reproducing what the plugin's own listings do.
The rule
Query on event_start_date and event_end_date. They are normalized Y-m-d values written on save, precisely so they can be compared and sorted.
The datetime values are for display. Comparing them in a query gives unreliable results.
Upcoming events, in order
This is what the search form does:
$query = new WP_Query( array(
'post_type' => 'event',
'post_status' => 'publish',
'posts_per_page' => 12,
'orderby' => 'event_start_date',
'order' => 'ASC',
'meta_query' => array(
array(
'key' => 'event_end_date',
'value' => date( 'Y-m-d' ),
'compare' => '>=',
'type' => 'DATE',
),
),
) );
Note the comparison is on the end date: an event that has started but not finished is still upcoming.
Past events
'meta_query' => array(
array(
'key' => 'event_end_date',
'value' => date( 'Y-m-d' ),
'compare' => '<',
'type' => 'DATE',
),
),
'orderby' => 'event_start_date',
'order' => 'DESC',
Most recent first, which is what a past-events listing wants.
Events running on a specific date
The date picker's logic — events that started on or before the date and end on or after it, so a multi-day event is found on every one of its days:
'meta_query' => array(
array(
'key' => 'event_start_date',
'value' => $date,
'compare' => '<=',
'type' => 'DATE',
),
array(
'key' => 'event_end_date',
'value' => $date,
'compare' => '>=',
'type' => 'DATE',
),
),
Events in a month
'meta_query' => array(
array(
'key' => 'event_start_date',
'value' => "$year-$month-01",
'compare' => '>=',
'type' => 'DATE',
),
array(
'key' => 'event_end_date',
'value' => date( 'Y-m-t', strtotime( "$year-$month-01" ) ),
'compare' => '<=',
'type' => 'DATE',
),
),
Filtering by taxonomy
'tax_query' => array(
array(
'taxonomy' => 'event_category',
'field' => 'slug',
'terms' => array( 'concerts' ),
'include_children' => true,
),
),
Both event taxonomies are hierarchical, so include children unless you deliberately want the parent alone.
Events with places remaining
There is no stored "remaining" value; it is derived from the capacity and the registrations. Compute it:
$meta = get_post_meta( $event_id, 'pom', true );
$capacity = (int) ( $meta['available_space'] ?? 0 );
$assistants = get_post_meta( $event_id, 'event_assistants', true ) ?: array();
$unlimited = 0 === $capacity;
$remaining = $unlimited ? null : max( 0, $capacity - count( $assistants ) );
A capacity of zero means unlimited. Do not try to express "has places" as a meta query.
Events a user is registered for
$events = get_user_meta( $user_id, 'attended_events', true ) ?: array();
Or, from the event's side, inspect its event_assistants map, which is keyed by user ID.
Performance
- Do not use
posts_per_page => -1on a public page. Both listings paginate for a reason. - Date meta queries are string comparisons on normalized values, which is why the derived keys exist.
- Counting registrations means loading the map. For a listing showing availability across many events, expect one meta read per event and cache the result.
Always guard the post type
if ( ! post_type_exists( 'event' ) ) {
return; // Not the POM theme, or too early.
}