Meta query con valore booleano true/false
Sto cercando di mostrare tutte le proprietà in affitto, prima quelle che non sono state affittate e poi quelle attualmente affittate. C'è un custom post type 'rent' con un custom post meta per il prezzo affittato (_price_rented) che è una checkbox (restituisce true o false... true se È stata affittata). Ho bisogno di modificare la query per mostrare tutte le proprietà con quelle disponibili (non affittate) che appaiono prima e poi quelle affittate.
Ecco la mia query:
$ts_properties = new WP_Query(
array(
'post_type' => 'rent',
'paged' => $paged,
'posts_per_page' => -1,
'meta_key' => '_price_rented',
'orderby' => 'meta_value',
'order' => 'DESC',
'meta_query' => array(
array(
'key' => '_price_rented',
'value' => false,
'type' => 'BOOLEAN',
),
)
)
);
Per qualche motivo questa query mostra tutte le proprietà che SONO state affittate. Quando cambio il valore da 'false' a 'true' nella meta_query non mostra alcuna proprietà.
Quindi, ho pensato che il valore restituito sia false (per le proprietà che SONO affittate) o NULL (per le proprietà che NON sono affittate), ma non sono sicuro di come fare una query per un risultato NULL (non false). Ho aggiunto un argomento 'compare' alla meta_query e impostato il valore su '!=' ma non ha funzionato neanche questo.
MODIFICA: var_dump restituisce quanto segue per un appartamento disponibile, non affittato: string(0) ""
e per un appartamento non disponibile, affittato: string(1) "1"

TL;DR: Questo problema probabilmente si verifica soprattutto quando un campo booleano viene creato come opzionale. Puoi risolverlo rendendolo obbligatorio, oppure usando una query più complessa per recuperare il caso predefinito.
Maggiori dettagli:
Ci sono due problemi di rappresentazione dei dati qui: uno riguarda quali valori di dati vengono utilizzati per rappresentare vero/falso e l'altro riguarda se il campo viene memorizzato o meno se è il valore predefinito (solitamente falso).
Parte 1: Ho esaminato l'SQL generato da WP_Meta_Query
per i confronti con vero e falso, e ho scoperto che per vero sostituisce '1' e per falso '' (stringa vuota). Quindi qualsiasi cosa tu scriva nel database deve concordare con questo se intendi eseguire query che confrontano con valori veri e falsi effettivi. In particolare, non vuoi scrivere '0' per falso. Potrebbe essere più sicuro scrivere e testare 0 e 1 invece (e molti costruttori di form lo fanno). Ma controlla cosa viene scritto nel database e tienilo a mente quando costruisci la tua query.
Parte 2: Assumendo che falso sia il valore predefinito, trovare record il cui valore è vero è semplice:
... 'meta_key' => 'my_key', 'meta_value' => 1
(o true)
Ma l'altro lato è più complesso: potrebbe esserci un valore falso, o potrebbe non esserci alcun valore. Questo può accadere se il valore era elencato come opzionale in un form - finché l'utente non lo imposta o modifica esplicitamente, non verrà aggiunto al database. Nota che se usi solo get_post_meta
funzionerà bene così: restituire un valore falso e non restituire alcun valore darà lo stesso risultato.
Ma quando usi WP_Query
, non è così semplice. (O se lo è, non ho ancora capito come).
Hai due (o forse tre) opzioni:
Assicurati che il campo sia sempre inizializzato esplicitamente a un valore reale. In alcuni costruttori di form, lo fai rendendo il campo obbligatorio e dandogli un valore predefinito. Quindi puoi testare
...'meta_value' => 0
in modo affidabile.Esegui due query, la prima che testa per un valore falso e la seconda che testa per nessun valore. Queste possono essere combinate in una singola WP_Query così:
meta_query => array( 'relation' => 'OR', array( 'key' => 'my_key', 'value' => 0, 'compare' => '=' ), array( 'key' => 'my_key', 'compare' => 'NOT EXISTS', ), )
Questa probabilmente non è una query efficiente. A seconda di molti fattori, potrebbe essere meglio restituire tutti gli oggetti e filtrarli nel tuo codice.
- È possibile utilizzare 'nessun valore' per indicare falso. Per farlo, ogni volta che il valore dovrebbe essere impostato su falso, devi eliminare il meta valore invece di aggiornarlo.
In quel caso, una singola query 'NOT EXISTS'
restituirà in modo affidabile gli oggetti corretti. (Non penso che molti costruttori di form o plugin supportino questo comportamento, quindi lo userei solo in codice puramente personalizzato).

WP_Meta_Query
è una parte del core di WordPress che può essere "non molto stabile" e, se non si presta molta attenzione, può facilmente confondersi e rompersi.
Quando esegui un new WP_Query()
e hai argomenti come meta_query => array()
o le loro controparti a coppia chiave/valore singola, allora entra in gioco new WP_Meta_Query()
, seguito immediatamente dal parsing.
$this->meta_query = new WP_Meta_Query();
$this->meta_query->parse_query_vars( $q );
Valori consentiti
Quando interroghi i metadati, c'è un'opzione bool
. Se la usassi, questa ricadrebbe su CHAR
, che è il valore predefinito in quanto l'array di valori consentiti è:
'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'
dove NUMERIC
verrà reimpostato su SIGNED
.
Debugging
Ci sono numerosi filtri che possono influenzare il processo di salvataggio dei post, quindi la prima cosa da fare è controllare i diversi valori all'interno di un ciclo:
var_dump( get_post_meta( get_the_ID(), '_price_rented', true ) );
Poi, a seconda del valore restituito, dovrai usare SIGNED
se il risultato è 0
o 1
, oppure "true"
o "false"
se il risultato è una stringa. Se è davvero booleano, suggerirei comunque di usare string
solo per assicurarsi che passi attraverso $GLOBALS['wpdb']
, che può passare solo %s
per le stringhe e %d
per i numeri.
Note aggiuntive
Mentre aggiornavo oggi la voce del Codex per WP_Meta_Query
, ho notato che ci sono molti output diversi (che aggiungono numerose quantità di JOIN
non necessari, discussi su Trac qui e qui consenza una singola patch integrata nel core). (Ticket di follow-up per le parti AND
qui) Il punto è che è possibile usare una combinazione di argomenti meta_*
insieme all'array meta_query
e ai suoi sottoarray. Il risultato è piuttosto sconosciuto a meno che non lo si esamini con un dump, quindi secondo me è meglio usare o un metodo o l'altro per aggiungere input. Soprattutto quando si usa solo meta_key
, poiché in alcuni casi questo risulta in una "query solo per chiave".
Soluzione
Come sottolineato nei commenti:
(...)
var_dump
restituisce quanto segue per un appartamento disponibile, non affittato:string(0) ""
e per un appartamento non disponibile, affittato:string(1) "1"
Ora il meta_query
deve usare
'meta_query' => array( 'relation' => 'OR', array(
'meta_key' => '_price_rented',
'meta_value' => '1',
'meta_compare' => '='
) );
Se vuoi ottenere gli "appartamenti non disponibili, affittati" oppure usa '!='
per recuperare gli appartamenti "non affittati".
Nota: I valori possibili per meta_compare
sono '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'NOT EXISTS', 'REGEXP', 'NOT REGEXP'
o 'RLIKE'
. Il valore predefinito è '='
.

Ho affrontato lo stesso problema e dopo un'ora di ricerca ho trovato i valori "NOT EXISTS"
e "EXISTS"
(solo in WP >= 3.5)
.
Quindi non c'è bisogno di richiedere un meta valore, basta verificare se il meta_key esiste:
'meta_key' => '_price_rented' ,
'meta_compare' => 'NOT EXISTS' ,
Funziona perfettamente nel mio caso.

return false viene registrato come 0, return true viene registrato come 1
Quindi, basta aggiungere value="1" al tuo input type checkbox, così può inviare il valore "1" se selezionato e non "on" come default
Nella tua meta query, fai come al solito:
array(
'key' => 'your_key',
'value' => 'your_value',
'compare' => '='
)
