TL;DR: This problem probably mostly happens when a boolean field is created as optional. You can fix it either by making it required, or using a more complex query to retrieve the default case.
More details:
There are two data representation problems going on here: one is which data values are being used to represent true/false and the other is whether or not the field is being stored at all if it is the default (usually false) value.
Part 1: I looked at the SQL generated by WP_Meta_Query
for comparisons to true and false, and found that for true it substitutes ‘1’ and for false ” (the empty string). So whatever you write into the database needs to agree with that if you are going do queries comparing to actual true and false values. In particular, you don’t want to write ‘0’ for false. It might be more foolproof to write and test for 0 and 1 instead (and many form builders do that). But check to see what is being written to the database and keep that in mind when building your query.
Part 2: Assuming that false is the default value, finding records whose value
is true is easy:
... 'meta_key' => 'my_key', 'meta_value' => 1
(or true)
But the other side is challenging: there might be a false value, or there might not be any value at all. This can happen if the value was listed as optional in a form — then so long as the user does not explicitly set it or change it, it will not be added to the database. Note that if you are only using get_post_meta
it will work just fine this way: returning a false value and returning no value will accomplish the same thing.
But when you are using WP_Query
, it isn’t so easy. (Or if it is, I haven’t figured out how yet).
You have two (or maybe three) options:
-
Make sure that the field is always explicitly initialized to a real value. In some form builders, you do this by making the field required and giving it a default value. Then you can test
...'meta_value' => 0
reliably. -
Do two queries, the first which tests for a false value and the second which tests for no value. These can be combined into a single WP_Query like this:
meta_query => array( 'relation' => 'OR', array( 'key' => 'my_key', 'value' => 0, 'compare' => '=' ), array( 'key' => 'my_key', 'compare' => 'NOT EXISTS', ), )
This is probably not an efficient query. Depending on a lot of factors, it might be better to return all objects and filter them in your own code.
- It is possible to use ‘no value’ to mean false. To do this, whenever the value should be set to false, you have to delete the meta value instead of updating it.
In that case, a single 'NOT EXISTS'
query will reliably return the correct objects. (I don’t think many form builders or plugins support this behavior, so I’d only use it in purely custom code.)