5

I am looking for a way to show posts that belongs to a specific category or if they have a custom field. If I specify both parameter 'cat' => '9' and 'meta_key' => 'featured' in query arguments then WP_Query returns posts which satisfy both conditions simultaneously.

That I do not want. What I need is to show posts if they have category 9 or if they have custom field featured.

Let me know if it does not make sense. I will post an example to explain.

  • I don't think it's possible to use OR relationship except in meta queries in WP_Query. You need to use custom sql query. – sakibmoon May 31 '15 at 14:40
6

You can try the custom _meta_or_tax argument in WP_Query (PHP 5.4+):

$args = [
    'post_type'    => 'post',
    '_meta_or_tax' => true,        // <-- our new custom parameter
    'tax_query'    => [...],       // <-- our tax query
    'meta_query'   => [...],       // <-- our meta query
];

$query = new WP_Query( $args );

where we use the following plugin to support this custom argument:

/**
 * Modify WP_Query to support 'meta_or_tax' argument
 * to use OR between meta- and taxonomy query parts.
 */
add_filter( 'posts_where', function( $where, \WP_Query $q )
{
   // Get query vars
   $tax_args    = isset( $q->query_vars['tax_query'] ) 
       ? $q->query_vars['tax_query'] 
       : null;
   $meta_args   = isset( $q->query_vars['meta_query'] ) 
       ? $q->query_vars['meta_query'] 
       : null;
   $meta_or_tax = isset( $q->query_vars['_meta_or_tax'] ) 
       ? wp_validate_boolean( $q->query_vars['_meta_or_tax'] )
       : false;

   // Construct the "tax OR meta" query
   if( $meta_or_tax && is_array( $tax_args ) &&  is_array( $meta_args )  )
   {
       global $wpdb;

       // Primary id column
       $field = 'ID';

       // Tax query
       $sql_tax  = get_tax_sql(  $tax_args,  $wpdb->posts, $field );

       // Meta query
       $sql_meta = get_meta_sql( $meta_args, 'post', $wpdb->posts, $field );

       // Modify the 'where' part
       if( isset( $sql_meta['where'] ) && isset( $sql_tax['where'] ) )
       {
           $where  = str_replace( 
               [ $sql_meta['where'], $sql_tax['where'] ], 
               '', 
               $where 
           );
           $where .= sprintf( 
               ' AND ( %s OR  %s ) ', 
                substr( trim( $sql_meta['where'] ), 4 ), 
                substr( trim( $sql_tax['where']  ), 4 )
           );
        }
    }
    return $where;
}, PHP_INT_MAX, 2 );

This is an untested simplification of my answers here.

  • WOW thanks. And I was thinking it might not even be possible. Thanks for the solution. Works like charm. – Robert hue Jun 1 '15 at 4:58
  • glad to hear it worked for you @Roberthue – birgire Jun 1 '15 at 7:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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