WP_Query OR clause for tax_query and keywords

Is it possible to make an OR clause between tax_query and keywords? I'd like WP_Query to return posts if there is a tax_query match or a s keyword match.

Answers 1

  • Here's a little experiment:

    You can try the following setup:

    $args = array(
        'wpse_search_or_tax_query'      => true,    // <-- New parameter!
        's'                             => 'some search text',
        'tax_query'                     => array(
            array(
                'taxonomy' => 'category',
                'field'    => 'slug',
                'terms'    => array( 'some-category-slug' ),
                'operator' => 'IN',
            ),
        ),      
    );
    $query = new WP_Query( $args );
    

    where we introduce the custom wpse_search_or_tax_query parameter to activate the query modifications.

    This is supported by the following demo plugin:

    <?php
    /**
     * Plugin Name: Modify the WP_Query to use OR between the search and tax query parts.
     * Description: Activation through the boolean 'wpse_search_or_tax_query' parameter.
     * Plugin URI:  http://wordpress.stackexchange.com/a/174221/26350
     * Author:      Birgir Erlendsson (birgire)
     * Version:     0.0.2
     */
    
    add_action( 'init', function()
    {   
        if( ! is_admin() && class_exists( 'WPSE_Modify_Query' ) )
        {
            $o = new WPSE_Modify_Query;
            $o->activate();
        }
    });
    
    
    class WPSE_Modify_Query
    {
        private $search    = '';
    
        public function activate()
        {
            add_action( 'pre_get_posts', array( $this, 'pre_get_posts' ) );
        }
    
        public function pre_get_posts( WP_Query $q )
        {
            if( filter_var( 
                    $q->get( 'wpse_search_or_tax_query' ), 
                    FILTER_VALIDATE_BOOLEAN 
                 ) 
                 && $q->get( 'tax_query' ) 
                 && $q->get( 's' )
            )
            {                                                           
                add_filter( 'posts_clauses', array( $this, 'posts_clauses' ), 10, 2 );
                add_filter( 'posts_search', array( $this, 'posts_search' ), 10, 2 );
            }
        }
    
        public function posts_clauses( $clauses, \WP_Query $q )
        {
            remove_filter( current_filter(), array( $this, __FUNCTION__ ) );
    
            // Generate the tax query:
            $tq = new WP_Tax_Query( $q->query_vars['tax_query'] );
    
            // Get the generated taxonomy clauses:
            global $wpdb;
            $tc = $tq->get_sql( $wpdb->posts, 'ID' );
    
            // Remove the search part:
            $clauses['where'] = str_ireplace( 
                $this->search, 
                ' ', 
                $clauses['where'] 
            );
    
            // Remove the taxonomy part:
            $clauses['where'] = str_ireplace( 
                $tc['where'], 
                ' ', 
                $clauses['where'] 
            );
    
            // Add the search OR taxonomy part:
            $clauses['where'] .= sprintf( 
                " AND ( ( 1=1 %s ) OR ( 1=1 %s ) ) ", 
                $tc['where'],
                $this->search
            );
    
            return $clauses;
        }
    
        public function posts_search( $search, \WP_Query $q )
        {
            remove_filter( current_filter(), array( $this, __FUNCTION__ ) );
            $this->search = $search;
            return $search;
        }
    
    } // end class
    

    Hopefully you can adjust this further to your needs.


Related Questions