Question

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.

Was it helpful?

Solution

What 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. :)

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top