Recetas de consultas de eventos

Cómo consultar eventos correctamente, reproduciendo lo que hacen los propios listados del plugin.

La regla

Consulta sobre event_start_date y event_end_date. Son valores Y-m-d normalizados que se escriben al guardar, precisamente para que puedan compararse y ordenarse.

Los valores de fecha y hora son para mostrar. Compararlos en una consulta da resultados poco fiables.

Próximos eventos, en orden

Esto es lo que hace el formulario de búsqueda:

$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',
        ),
    ),
) );

Ten en cuenta que la comparación se hace sobre la fecha de fin: un evento que ha empezado pero no ha terminado sigue contando como próximo.

Eventos pasados

'meta_query' => array(
    array(
        'key'     => 'event_end_date',
        'value'   => date( 'Y-m-d' ),
        'compare' => '<',
        'type'    => 'DATE',
    ),
),
'orderby' => 'event_start_date',
'order'   => 'DESC',

Los más recientes primero, que es lo que conviene en un listado de eventos pasados.

Eventos que se celebran en una fecha concreta

La lógica del selector de fechas — eventos que empezaron en la fecha o antes y terminan en ella o después, de modo que un evento de varios días se encuentra en cada uno de sus días:

'meta_query' => array(
    array(
        'key'     => 'event_start_date',
        'value'   => $date,
        'compare' => '<=',
        'type'    => 'DATE',
    ),
    array(
        'key'     => 'event_end_date',
        'value'   => $date,
        'compare' => '>=',
        'type'    => 'DATE',
    ),
),

Eventos de un mes

'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',
    ),
),

Filtrar por taxonomía

'tax_query' => array(
    array(
        'taxonomy'         => 'event_category',
        'field'            => 'slug',
        'terms'            => array( 'concerts' ),
        'include_children' => true,
    ),
),

Ambas taxonomías de eventos son jerárquicas, así que incluye las subcategorías a menos que quieras deliberadamente solo la categoría principal.

Eventos con plazas disponibles

No existe un valor «restante» almacenado; se deriva del aforo y de las inscripciones. Calcúlalo:

$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 ) );

Un aforo de cero significa ilimitado. No intentes expresar «tiene plazas» como una consulta de metadatos.

Eventos en los que está inscrito un usuario

$events = get_user_meta( $user_id, 'attended_events', true ) ?: array();

O, desde el lado del evento, inspecciona su mapa event_assistants, que está indexado por el ID de usuario.

Rendimiento

  • No uses posts_per_page => -1 en una página pública. Ambos listados paginan por un motivo.
  • Las consultas de fechas por metadatos son comparaciones de cadenas sobre valores normalizados, y por eso existen las claves derivadas.
  • Contar las inscripciones implica cargar el mapa. Para un listado que muestra la disponibilidad en muchos eventos, espera una lectura de metadatos por evento y guarda el resultado en caché.

Protege siempre el tipo de contenido

if ( ! post_type_exists( 'event' ) ) {
    return; // Not the POM theme, or too early.
}