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....
User
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?
EAMann
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.
User
Vedi il mio aggiornamento sopra. Aggiungere orderby=meta_value_num dovrebbe risolvere il problema se stai utilizzando WP 2.8.4 o versioni successive.
EAMann
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!
User
@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.
EAMann
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