0

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.

1 Answer 1

0

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

8
  • Really!? Is there really no way to specify OR between the elements of my search? I assumed it was just syntactic nuance I hadn't yet understood. Commented Oct 14, 2020 at 2:10
  • Unfortunately, none as far as I know for the time being - and that top-level 'relation' => 'OR' you've attempted won't work because that relation isn't part of the main parameters.
    – Sally CJ
    Commented Oct 14, 2020 at 2:16
  • Remember, you're trying to use the OR relation between the tax_query and meta_query - and not between clauses inside those parameters, and that is not supported by default, so your option for now would be using a hook like in my example. But of course, the other (better) option would be to turn that metadata into a custom taxonomy or just use an existing taxonomy.
    – Sally CJ
    Commented Oct 14, 2020 at 2:29
  • 1
    A taxonomy is to group a collection into one, so whether the term's value is a boolean or string, a simple 1 or 0 number, or a category name like 'Movies', 'Web Design', etc. they'd eventually still form a collection - and for example in your case, you're using the metadata to mark posts that are "available" and not, so you could create a taxonomy playlist_available with just two terms 1 and 0, then use them in your tax_query and you'd notice the query runs faster than with the meta query - which could end up with various JOIN clauses.
    – Sally CJ
    Commented Oct 14, 2020 at 3:02
  • 1
    Definitely, and thanks for all your excellent help. I'm climbing a steep curve in using Wordpress properly. Better use of taxonomies is on the menu, and this has definitely helped. Commented Oct 14, 2020 at 21:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.