I have a custom post type 'csl_playlist_manager', and one of its meta-fields is 'available_to_all'. I also have a custom hierarchical taxonomy, 'csl_source', which identifies the owner of each playlist. I need a query that allows me to find all suitable playlists for a particular source, where "suitable" means the playlist is either available_to_all OR a match for source or the children of source.
I've successfully created a list of ids for the source and its children, which deals with the taxonomy hierarchy issue. My query currently looks like this:
$args = array (
'post_type' => 'csl_playlist_manager',
'post_status' => 'publish',
'relation' => 'OR',
'tax_query' => array(
array(
'taxonomy' => 'csl_source',
'field' => 'term_id',
'terms' => $strTax,
'operator' => 'IN',
),
),
'meta_query' => array(
array(
'key' => '_csl_playlist_available_to_all',
'value' => 1,
'compare' => '=',
),
),
'nopaging' => 'true',
);
var_dump reveals the resulting query is:
["request"]=>
string(531) "SELECT wp_posts.* FROM wp_posts LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND (
wp_term_relationships.term_taxonomy_id IN (26,34,35,36,37,38,39,40,41,42,43,44)
) AND (
( wp_postmeta.meta_key = '_csl_playlist_available_to_all' AND wp_postmeta.meta_value = '1' )
) AND wp_posts.post_type = 'csl_playlist_manager' AND ((wp_posts.post_status = 'publish')) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC "
'AND' appears as the logical operator when I need it to be 'OR'. I have searched widely but found no example of how to achieve the simple thing I'm trying to achieve. Wisdom appreciated.
I have a custom post type 'csl_playlist_manager', and one of its meta-fields is 'available_to_all'. I also have a custom hierarchical taxonomy, 'csl_source', which identifies the owner of each playlist. I need a query that allows me to find all suitable playlists for a particular source, where "suitable" means the playlist is either available_to_all OR a match for source or the children of source.
I've successfully created a list of ids for the source and its children, which deals with the taxonomy hierarchy issue. My query currently looks like this:
$args = array (
'post_type' => 'csl_playlist_manager',
'post_status' => 'publish',
'relation' => 'OR',
'tax_query' => array(
array(
'taxonomy' => 'csl_source',
'field' => 'term_id',
'terms' => $strTax,
'operator' => 'IN',
),
),
'meta_query' => array(
array(
'key' => '_csl_playlist_available_to_all',
'value' => 1,
'compare' => '=',
),
),
'nopaging' => 'true',
);
var_dump reveals the resulting query is:
["request"]=>
string(531) "SELECT wp_posts.* FROM wp_posts LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND (
wp_term_relationships.term_taxonomy_id IN (26,34,35,36,37,38,39,40,41,42,43,44)
) AND (
( wp_postmeta.meta_key = '_csl_playlist_available_to_all' AND wp_postmeta.meta_value = '1' )
) AND wp_posts.post_type = 'csl_playlist_manager' AND ((wp_posts.post_status = 'publish')) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC "
'AND' appears as the logical operator when I need it to be 'OR'. I have searched widely but found no example of how to achieve the simple thing I'm trying to achieve. Wisdom appreciated.
Share Improve this question asked Oct 13, 2020 at 23:37 Wayne McHughWayne McHugh 31 silver badge2 bronze badges1 Answer
Reset to default 0What you're trying to do — using the OR
relation with the tax_query
and meta_query
parameters, i.e. to have a <tax queries> OR <meta queries>
instead of <tax queries> AND <meta queries>
command in SQL, unfortunately (without custom and possibly complex queries) is not possible in WP_Query
for now, therefore that 'relation' => 'OR'
in your query args (the $args
array) is not going to work or even do anything.
However, what you can (and I would) do, is: Turn that metadata into a custom taxonomy which is better suited for grouping a collection of posts together just like in your case where you used the metadata to group posts that are "playlist-available" (?), and moreover, taxonomy terms can also be as simple as 1
and 0
, and not necessarily need to be titles like Movies
and Web Design
. You could even create a custom metabox with a "Yes-or-No" checkbox which then updates the taxonomy terms for the post. (I mean, if you don't like the default taxonomy UI/selector..)
So for example, register a taxonomy named playlist_available
, and then add these terms to that taxonomy: 1
("Playlist available") and 0
("Playlist not available") — although I think you may not need the latter..?
And then for all existing posts that had the metadata _csl_playlist_available_to_all
set to 1
, remove that metadata from the post and then assign the post to the 1
term in the playlist_available
taxonomy.
Then when you make your WP_Query
, there's no need for the meta_query
and just add another clause to the tax_query
parameter/array:
$args = array(
'post_type' => 'csl_playlist_manager',
'tax_query' => array(
'relation' => 'OR',
array( // selects posts that are in this taxonomy
'taxonomy' => 'csl_source',
'field' => 'term_id',
'terms' => $strTax,
),
array( // OR the ones with the playlist available
'taxonomy' => 'playlist_available',
'field' => 'slug',
'terms' => '1', // or whatever the slug is
),
),
// ... your other args.
);
And now that should give you the results you expected, and the query would also run faster than with the meta_query
which could end up with various JOIN clauses — on small sites, you may not notice an obvious performance boost; but you would when your site gets larger (many posts, options, plugin data, traffic/users, etc.). But a bit of disclaimer, I'm far from being a performance expert. :)