WP_Query usando meta_query con relación OR y orderby meta_value no funciona
He estado luchando contra un error durante varias horas y no logro encontrar mi error. ¿Podría haber un error con el tipo de relación 'OR' en WordPress?
$evenements = new WP_Query(array(
'post_type' => 'evenements',
'orderby' => 'meta_value',
'meta_key' => 'startDate',
'order' => 'ASC',
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'startDate',
'value' => date('Ymd'),
'compare' => '>=',
),
array(
'key' => 'endDate',
'value' => date('Ymd'),
'compare' => '>=',
),
),
));
Lo extraño es que si pongo la relación como 'AND', funciona como se espera. Si ambas condiciones son verdaderas, el post aparecerá. Si pongo la relación como 'OR', todos los posts aparecen, y por alguna razón incluso el orden no funciona correctamente. Incluso cambiar 'order' de 'ASC' a 'DESC' no cambia el orden en que llegan los resultados.
Para entender la consulta, aquí está el detalle de lo que exactamente estoy tratando de hacer:
Quiero mostrar eventos que están en progreso o en el futuro. Los dos meta son la fecha en que comienza el evento (startDate) y la fecha cuando termina el evento (endDate).
Entonces, si la fecha de inicio es mayor o igual (para obtener si un evento está ocurriendo hoy) a hoy o la fecha de finalización es mayor o igual a hoy, mostrar el post.
La segunda parte (con la fecha de finalización) está hecha para que un evento en progreso se muestre, y no puedo eliminar la primera parte (con la fecha de inicio) porque si el evento solo dura un día, el cliente solo ingresará el meta startDate.
Descarté que el error viniera de plugins ya que desactivé todos los plugins y el error seguía ahí.
Aquí está lo que obtengo si echo $evenements->request
.
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
INNER JOIN wp_postmeta ON wp_posts.ID = wp_postmeta.post_id
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
JOIN wp_icl_translations t
ON wp_posts.ID = t.element_id AND t.element_type = 'post_evenements'
JOIN wp_icl_languages l ON t.language_code=l.code AND l.active=1
WHERE 1=1
AND wp_posts.post_type = 'evenements'
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
AND (
wp_postmeta.meta_key = 'startDate'
OR ( mt1.meta_key = 'startDate' AND CAST(mt1.meta_value AS CHAR) >= '20140305' )
OR ( mt2.meta_key = 'endDate' AND CAST(mt2.meta_value AS CHAR) >= '20140305' )
)
AND t.language_code='fr'
GROUP BY wp_posts.ID
ORDER BY wp_postmeta.meta_value ASC
LIMIT 0, 10

El problema es que WordPress está obteniendo todas las publicaciones que tienen una meta clave 'startDate', sin importar el valor del meta.
Puedes entenderlo a partir de esta parte de la solicitud:
...
AND (
wp_postmeta.meta_key = 'startDate'
OR ( mt1.meta_key = 'startDate' AND CAST(mt1.meta_value AS CHAR) >= '20140305' )
OR ( mt2.meta_key = 'endDate' AND CAST(mt2.meta_value AS CHAR) >= '20140305' )
)
...
así que si una publicación tiene la meta clave 'startDate', será devuelta.
El responsable de este comportamiento es el argumento 'meta_key'
...
new WP_Query( array(
'post_type' => 'evenements',
'orderby' => 'meta_value',
'meta_key' => 'startDate', // <-- este es el culpable
...
Sin embargo, si lo eliminas, no podrás ordenar por un valor meta, porque, a veces WordPress es... (no sé el término en inglés, completa la frase tú mismo).
La solución es (debería ser) colocar la primera parte de tu consulta meta (relacionada con la fecha de inicio), como argumentos simples (no parte de meta_query
), y la segunda parte (relacionada con la fecha de finalización) dentro del array meta_query
:
$evenements = new WP_Query(array(
'post_type' => 'evenements',
'meta_key' => 'startDate',
'meta_value' => date('Ymd'),
'meta_type' => 'NUMERIC',
'meta_compare' => '>=',
'orderby' => 'meta_value',
'order' => 'ASC',
'meta_query' => array(
'relation' => 'OR',
array (
'key' => 'endDate',
'value' => date('Ymd'),
'compare' => '>=',
'type' => 'NUMERIC'
)
)
));
Tu configuración es demasiado compleja para que pueda probarla con precisión, así que pruébalo tú mismo y házmelo saber.
