query_posts -> utilizzare meta_compare / dove il valore meta è minore, maggiore o uguale
Sto usando query_posts( $args )
per filtrare il Loop.
Voglio filtrare i post in base al loro meta_value
"vote", a volte minore di, a volte uguale e così via...
Voglio assolutamente utilizzare la funzione query_posts()
e passare il mio filtro attraverso $args
!
Non voglio usare add_filter('posts_where', 'filter_where');
e poi aggiungere un'istruzione AND
alla query.
Voglio utilizzare la funzionalità predefinita di WordPress per filtrare i post con meta_key
, meta_value
e meta_compare
in questo modo:
$args = array( 'meta_key'=>'vote', 'meta_compare'=>'>=', 'meta_value'=>5, 'posts_per_page'=>100 ) )
query_posts( $args );
Il risultato di questo è:
SELECT SQL_CALC_FOUND_ROWS wp_posts.* FROM wp_posts JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) WHERE 1=1 AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') AND wp_postmeta.meta_key = 'vote' AND wp_postmeta.meta_value >= '5' GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 100
Il problema è questo:
wp_postmeta.meta_value >= '5'
Dovrebbe essere:
wp_postmeta.meta_value >= 5
A questo punto funzionerebbe correttamente.
Non capisco perché WordPress aggiunge le virgolette.
Sto usando i parametri predefiniti di WordPress (<
, >
, <=
, >=
) ed è ovvio che questo funzionerà solo con i numeri e non con le stringhe che avrebbero bisogno delle virgolette.
La documentazione dice:
Restituisce i post con chiave del campo personalizzato 'miles' con un valore del campo personalizzato che è MINORE O UGUALE A 22
query_posts('meta_key=miles&meta_compare=<=&meta_value=22');

Da WP 3.1, puoi convertire il valore meta in qualsiasi cosa desideri utilizzando l'argomento 'type' in 'meta_query':
$args = array(
'meta_query'=> array(
array(
'key' => 'vote',
'compare' => '>=',
'value' => 5,
'type' => 'numeric',
)
)
'posts_per_page' => 100
) );
query_posts( $args );

Dando un'occhiata veloce alla documentazione, sembra che meta_value
sia destinato alle stringhe e per i valori numerici c'è meta_value_num
.
Vedi Parametri Orderby
Aggiornamento
Ho fatto alcune ricerche.
meta_value_num
viene effettivamente ignorato per il filtraggio. Penso che si siano semplicemente dimenticati di aggiungere quella parte. :)
Il problema è che WP_Query
riceve correttamente il numero come int
(passarlo come array non cambia), ma passa la condizione generata meta_compare
attraverso $wpdb->prepare()
e contrassegna esplicitamente il valore come stringa %s
. In questo caso prepare
lo racchiude forzatamente tra apici singoli.
Quindi sembra che dovrai filtrare posts_where
dopo tutto. Puoi provare a rimuovere gli apici da quella specifica stringa invece di generare manualmente la condizione.

Consiglio di analizzare il tuo array $args
e convertirlo in una stringa prima di passarlo a query_posts
. Quando crei l'array $args
, il sistema convertirà automaticamente il numero 5 nella stringa "5" quando l'array viene riconvertito in stringa.
Quindi usa invece questo:
query_posts('meta_key=vote&meta_compare=>=&meta_value=5&posts_per_page=100');
In questo modo stai passando le stesse informazioni a query_posts, ma dovrebbe passare il numero 5 anziché la stringa "5".
Aggiornamento
Dato che ora abbiamo scoperto che meta_value memorizza stringhe anziché numeri, e non puoi effettivamente fare un confronto maggiore/minore con le stringhe. Tuttavia, dopo alcune ricerche aggiuntive mi sono imbattuto nel flag di query meta_value_num
.
Se esegui la seguente chiamata query_posts
:
query_posts('meta_key=vote&meta_compare=>=&meta_value=5&posts_per_page=100&orderby=meta_value_num');
Dovresti ottenere il comportamento desiderato. meta_value_num
dice a WordPress di valutare i tuoi meta_value
come numeri anziché come stringhe.

Ho provato e produce esattamente lo stesso risultato. In effetti ho persino seguito il percorso da funzione a funzione nel WordPress-Core e la stringa viene suddivisa su & e trasformata in un array prima di essere elaborata....

Secondo il Codex: Nota che il valore 99 sarà considerato maggiore di 100 poiché i dati sono memorizzati come stringhe, non come numeri.
Quindi meta_value
viene memorizzato come stringa... ecco perché WordPress aggiunge gli apici. La mia prossima domanda sarebbe: puoi descrivere come "non funziona"? Restituisce comunque dei dati?

Sì, hai ragione! Come ho detto sopra, non importa cosa faccia viene racchiuso in '5'. MySQL non può confrontare qualcosa a livello numerico se è racchiuso tra '', quindi mi chiedo perché WordPress abbia implementato questa funzione se non funziona. No, restituisce risultati ma semplicemente non quelli desiderati.

Vedi il mio aggiornamento sopra. Aggiungere orderby=meta_value_num
dovrebbe risolvere il problema se stai utilizzando WP 2.8.4 o versioni successive.

Grazie per tutti gli sforzi. Ma anche questo non funziona. Ho approfondito molto questo argomento e semplicemente non è supportato da WP. Creerò un ticket per questo problema perché è davvero facile da risolvere e renderebbe possibili così tante cose!

@Joakim Sì, questa funzionalità è supportata da WP. Leggi il ticket che ho citato sopra dove è stata aggiunta la funzionalità. Forse puoi fornirci un esempio di codice più ampio di ciò che stai cercando di fare... potrebbe esserci un problema diverso.

WordPress tratta tutti i 'valori' come stringhe e aggiunge apici singoli attorno ad essi nella query finale, quindi anche SQL è costretto a trattarli come stringhe e non come numeri. Puoi rimuovere questi apici con un filtro:
add_filter('get_meta_sql', function($data) {
$regex = "/'(-?\d+)'/";
$data['where'] = preg_replace($regex, "$1", $data['where']);
return $data;
});
E assicurati di avere 'type' => 'NUMERIC'
o simile
