query_posts -> folosind meta_compare / unde valoarea meta este mai mică, mai mare sau egală
Folosesc query_posts( $args )
pentru a filtra Loop-ul.
Vreau să filtrez postările bazate pe meta_value
"vote", uneori mai mic decât, alteori egal și așa mai departe....
Vreau neapărat să folosesc funcția query_posts()
și să transmit filtrul meu prin $args
!
Nu vreau să folosesc add_filter('posts_where', 'filter_where');
și apoi să adaug o instrucțiune AND
la query.
Vreau să folosesc funcționalitatea oferită de WordPress pentru a filtra postările cu meta_key
, meta_value
și meta_compare
astfel:
$args = array( 'meta_key'=>'vote', 'meta_compare'=>'>=', 'meta_value'=>5, 'posts_per_page'=>100 ) )
query_posts( $args );
Rezultatul acestuia este:
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
Problema este:
wp_postmeta.meta_value >= '5'
Ar trebui să fie:
wp_postmeta.meta_value >= 5
Atunci ar funcționa bine.
Nu înțeleg de ce WordPress adaugă ghilimele.
Folosesc parametrul predefinit din WordPress (<
, >
, <=
, >=
) și este evident că acesta va funcționa doar cu numere și nu cu șiruri care ar trebui să fie între ghilimele.
Documentația spune:
Returnează postări cu cheia câmpului personalizat 'miles' cu o valoare a câmpului personalizat care este MAI MICĂ SAU EGALĂ CU 22
query_posts('meta_key=miles&meta_compare=<=&meta_value=22');

Începând cu WP 3.1, puteți converti valoarea meta în orice doriți folosind argumentul 'type' în 'meta_query':
$args = array(
'meta_query'=> array(
array(
'key' => 'vote',
'compare' => '>=',
'value' => 5,
'type' => 'numeric',
)
)
'posts_per_page' => 100
) );
query_posts( $args );

După o scurtă privire peste documentație, se pare că meta_value
este destinat pentru șiruri de caractere, iar pentru valori numerice există meta_value_num
.
Vezi Parametrii Orderby
Actualizare
Am investigat mai detaliat.
meta_value_num
este într-adevăr ignorat în scopul filtrării. Cred că pur și simplu au uitat să adauge acea parte. :)
Problema este că WP_Query
primește corect numărul ca int
(transmiterea ca array nu contează), dar trece condiția generată meta_compare
prin $wpdb->prepare()
și marchează explicit valoarea ca șir %s
. În acest caz, prepare
o pune între ghilimele simple.
Deci se pare că va trebui să filtrezi posts_where
până la urmă. Poți încerca să elimini ghilimelele din acel șir specific, în loc să generezi condiția manual.

Vă recomand să analizați array-ul $args
și să îl convertiți într-un șir înainte de a-l transmite în query_posts
. Când creați array-ul $args
, sistemul va converti automat numărul 5 în șirul "5" atunci când array-ul este transformat înapoi într-un șir.
Deci, folosiți această variantă:
query_posts('meta_key=vote&meta_compare=>=&meta_value=5&posts_per_page=100');
Aceasta transmite aceleași informații către query_posts, dar ar trebui să transmită numărul 5 în loc de șirul "5".
Actualizare
Deoarece am descoperit acum că meta_value stochează șiruri în loc de numere și nu puteți efectua în mod eficient o comparație de tip mai mare/mai mic cu șiruri. Cu toate acestea, după câteva cercetări suplimentare, am dat peste flag-ul de interogare meta_value_num
.
Dacă executați următorul apel query_posts
:
query_posts('meta_key=vote&meta_compare=>=&meta_value=5&posts_per_page=100&orderby=meta_value_num');
Atunci ar trebui să obțineți comportamentul dorit. meta_value_num
instruiește WordPress să evalueze valorile meta_value
ca numere în loc de șiruri.

Am încercat și produce exact același lucru. De fapt, am urmărit calea de la funcție la funcție în WordPress-Core și șirul este separat la & și transformat într-un array înainte de a fi procesat....

Conform Codex: Notă: valoarea 99 va fi considerată mai mare decât 100, deoarece datele sunt stocate ca șiruri de caractere, nu ca numere.
Deci meta_value
este stocat ca șir de caractere... motiv pentru care WordPress adaugă ghilimele. Următoarea mea întrebare ar fi, poți descrie cum "nu funcționează"? Returnează vreun date deloc?

Da, ai dreptate! Cum am spus mai sus, indiferent ce fac, este încapsulat în '5'. MySQL nu poate compara ceva la nivel numeric dacă este încapsulat în '', așa că mă întreb de ce WordPress a implementat această funcție dacă nu funcționează. Nu, returnează rezultate, dar nu cele dorite.

Vezi actualizarea mea de mai sus. Adăugarea orderby=meta_value_num
ar trebui să rezolve problema dacă folosești WP 2.8.4 sau o versiune mai recentă.

Mulțumesc pentru toate eforturile. Dar nici asta nu funcționează. Am cercetat temă în profunzime și pur și simplu nu este suportat de WP. Voi crea un ticket pentru această problemă pentru că este foarte ușor de rezolvat și ar face multe lucruri posibile!

@Joakim Da, această funcționalitate este suportată de WP. Citește ticket-ul pe care l-am menționat mai sus unde a fost adăugată această caracteristică. Poate ne poți oferi un exemplu mai mare de cod pentru ceea ce încerci să faci... ar putea fi o altă problemă.

WordPress tratează toate valorile 'value' ca șiruri de caractere și le adaugă ghilimele simple în interogarea finală, așa că SQL este forțat să le considere ca șiruri și nu ca numere. Puteți elimina aceste ghilimele cu un filtru:
add_filter('get_meta_sql', function($data) {
$regex = "/'(-?\d+)'/";
$data['where'] = preg_replace($regex, "$1", $data['where']);
return $data;
});
Și asigurați-vă că aveți 'type' => 'NUMERIC'
sau similar
