WP_Query con meta_query usando relation OR e orderby meta_value non funziona
Sto combattendo con un bug da diverse ore e non riesco a trovare l'errore. Potrebbe esserci un bug con il tipo di relazione 'OR' in 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' => '>=',
),
),
));
La cosa strana è che se imposto la relazione a 'AND', funziona come previsto. Se entrambe le condizioni sono vere, il post viene visualizzato. Se imposto la relazione a 'OR', tutti i post vengono visualizzati e per qualche motivo anche l'ordinamento non funziona correttamente. Anche cambiando 'order' da 'ASC' a 'DESC' non cambia l'ordine dei risultati.
Per capire la query, ecco nel dettaglio cosa sto cercando di fare:
Voglio mostrare gli eventi che sono in corso o nel futuro. I due metadati sono la data di inizio dell'evento (startDate) e la data di fine dell'evento (endDate).
Quindi se la data di inizio è maggiore o uguale (per includere gli eventi di oggi) a oggi OPPURE la data di fine è maggiore o uguale a oggi, mostra il post.
La seconda parte (con la data di fine) serve per mostrare un evento in corso, e non posso rimuovere la prima parte (con la data di inizio) perché se l'evento dura solo un giorno, il cliente inserirà solo il metadato startDate.
Ho escluso che il bug derivi dai plugin poiché ho disattivato tutti i plugin e il bug era ancora presente.
Ecco cosa ottengo se eseguo 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

Il problema è che WordPress sta recuperando tutti i post che hanno una meta chiave 'startDate', indipendentemente dal valore del meta.
Puoi capirlo da questa parte della richiesta:
...
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' )
)
...
Quindi, se un post ha la meta_key 'startDate' verrà restituito.
La causa di questo comportamento è l'argomento 'meta_key'
...
new WP_Query( array(
'post_type' => 'evenements',
'orderby' => 'meta_value',
'meta_key' => 'startDate', // <-- questo è il problema
...
Tuttavia, se lo rimuovi non potrai ordinare per un meta valore, perché, a volte WordPress è... (non conosco il termine inglese, completa tu la frase).
La soluzione è (dovrebbe essere) mettere la prima parte della tua meta query (riguardante la data di inizio) come argomenti semplici (non parte di meta_query
), e la seconda parte (riguardante la data di fine) dentro l'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'
)
)
));
La tua configurazione è troppo complessa per permettermi di testarla accuratamente, quindi prova tu stesso e fammi sapere.
