Use custom code to exclude the products on your choice depending on users search query terms.
This is an outdated version of this article. Find a new article that explains how to filter search results based on your current search query using the built-in filters.
In this article we will describe one specific problem and its solution, namely, how to exclude certain products from search depending on search words.
For example - we have products called Phone
and Phone case
. By default when a user searches for phone
he will see both products in the plugin search results. But we want to show only the product Phone
when users only use the search term phone
. This is possible to achieve by using code snippets that we provide below.
For example we have product Phone
with ID 1 and product Phone case
with ID 2.
When a user searches for phone
we want to exclude the product Phone case
.
When a user searches for phone case
we want to exclude the product Phone
.
To get such behaviour we can use the following code snippet:
class AWS_Exclude_By_terms { public $terms = ''; public function __construct() { add_filter( 'aws_search_terms', array( $this, 'aws_search_terms' ) ); add_filter( 'aws_search_query_array', array( $this, 'aws_search_query_array' ) ); } function aws_search_terms( $terms ) { $this->terms = $terms; return $terms; } function aws_search_query_array( $query ) { $exclude_array = array( 'phone' => array( 2 ), 'phone case' => array( 1 ) ); $exclude_ids_array = array(); if ( $this->terms ) { foreach ( $exclude_array as $term => $ids ) { $term_arr = explode(' ', $term ); $exclude = false; if ( $term_arr && count($term_arr) === count( $this->terms ) ) { foreach ( $term_arr as $term_i ) { if ( array_search( $term_i, $this->terms ) !== false ) { $exclude = true; } else { $exclude = false; } } } if ( $exclude ) { $exclude_ids_array = array_merge($exclude_ids_array, $ids); } } } if ( ! empty( $exclude_ids_array ) ) { $ids = implode( ',', $exclude_ids_array ); $query['exclude_products'] = " AND ( id NOT IN ( {$ids} ))"; } return $query; } } new AWS_Exclude_By_terms();
edit lines
$exclude_array = array( 'phone' => array( 2 ), 'phone case' => array( 1 ) );
to exclude more products based on search terms.
Let's update our example and now exclude not single products, but all products from certain categories.
For example we have product category Phone
with ID 1 and product category Phone case
with ID 2.
When a user searches for phone
we want to exclude all products with category Phone case
.
When a user searches for phone case
we want to exclude all products with category Phone
.
In such case code snippet can looks like that:
class AWS_Exclude_By_terms { public $terms = ''; public function __construct() { add_filter( 'aws_search_terms', array( $this, 'aws_search_terms' ) ); add_filter( 'aws_search_query_array', array( $this, 'aws_search_query_array' ) ); } function aws_search_terms( $terms ) { $this->terms = $terms; return $terms; } function aws_search_query_array( $query ) { $exclude_array = array( 'phone' => array( 2 ), 'phone case' => array( 1 ) ); $exclude_ids_array = array(); if ( $this->terms ) { foreach ( $exclude_array as $term => $ids ) { $term_arr = explode(' ', $term ); $exclude = false; if ( $term_arr && count($term_arr) === count( $this->terms ) ) { foreach ( $term_arr as $term_i ) { if ( array_search( $term_i, $this->terms ) !== false ) { $exclude = true; } else { $exclude = false; } } } if ( $exclude ) { $exclude_ids_array = array_merge($exclude_ids_array, $ids); } } } if ( ! empty( $exclude_ids_array ) ) { global $wpdb; $taxonomies = implode( ',', $exclude_ids_array ); $query['exclude_products'] = " AND ( id NOT IN ( SELECT $wpdb->posts.ID FROM $wpdb->term_relationships JOIN $wpdb->posts ON ( $wpdb->term_relationships.object_id = $wpdb->posts.post_parent OR $wpdb->term_relationships.object_id = $wpdb->posts.ID ) WHERE $wpdb->term_relationships.term_taxonomy_id IN ( select term_taxonomy_id from $wpdb->term_taxonomy WHERE term_id IN ({$taxonomies}) ) ))"; } return $query; } } new AWS_Exclude_By_terms();
As and in previous example edit line
$exclude_array = array( 'phone' => array( 2 ), 'phone case' => array( 1 ) );
to set your own rules based on different search terms.
Now lets create a bit different exclude logic and filter not products but archive pages.
For example we have product category Phone
with ID 1 and product category Phone case
with ID 2.
When a user searches for phone
we want to exclude product category Phone case
from search results.
When a user searches for phone case
we want to exclude product category Phone
from search results.
To create such logic you just need to use the following code snippet:
class AWS_Exclude_By_terms { public $terms = ''; public function __construct() { add_filter( 'aws_search_terms', array( $this, 'aws_search_terms' ) ); add_filter( 'aws_terms_search_query', array( $this, 'aws_terms_search_query' ), 10, 2 ); } function aws_search_terms( $terms ) { $this->terms = $terms; return $terms; } function aws_terms_search_query( $sql, $taxonomy ) { $filter_taxonomy = 'product_cat'; if ( array_search( $filter_taxonomy, $taxonomy ) === false ) { return $sql; } $exclude_array = array( 'phone' => array( 2 ), 'phone case' => array( 1 ) ); $exclude_ids_array = array(); if ( $this->terms ) { foreach ( $exclude_array as $term => $ids ) { $term_arr = explode(' ', $term ); $exclude = false; if ( $term_arr && count($term_arr) === count( $this->terms ) ) { foreach ( $term_arr as $term_i ) { if ( array_search( $term_i, $this->terms ) !== false ) { $exclude = true; } else { $exclude = false; } } } if ( $exclude ) { $exclude_ids_array = array_merge($exclude_ids_array, $ids); } } } if ( ! empty( $exclude_ids_array ) ) { global $wpdb; $ids = implode( ',', $exclude_ids_array ); $query = " AND ( " . $wpdb->terms . ".term_id NOT IN ( {$ids} ))"; $sql = str_replace( 'WHERE 1 = 1', 'WHERE 1 = 1' . $query, $sql ); } return $sql; } } new AWS_Exclude_By_terms();
As always, edit the following line to adjust that filtering logic.
$exclude_array = array( 'phone' => array( 2 ), 'phone case' => array( 1 ) );