Enable custom taxonomies in WooCommerce product search - php

What I want: modify the query of the WooCommerce search form (in frontend) to display the products by searching in the name, description and product_tag of the products.
What I have: I'm trying with this code inspired from this answer that return a result for the name and description of the product. But if i make a search with the tags names, no results. The search query don't search in tags of the product.
How to reproduce this issue (put the code below in functions.php file of your active theme):
function search_product_by_tag( $search, &$query_vars ) {
global $wpdb, $pagenow;
if ( 'edit.php' == $pagenow || empty($search) ) {
return $search;
}
$args = array(
'posts_per_page' => -1,
'post_type' => 'product',
'meta_query' => array(
array(
'key' => 'taxonomy',
'value' => 'product_tag',
'field' => 'name',
'terms' => array($query_vars->query['s']),
'compare' => 'LIKE',
)));
$posts = get_posts( $args );
if ( empty( $posts ) ) return $search;
$get_post_ids = array();
foreach($posts as $post){
$get_post_ids[] = $post->ID;
}
if ( sizeof( $get_post_ids ) > 0 ) {
$search = str_replace( 'AND (((', "AND ((({$wpdb->posts}.ID IN (" . implode( ',', $get_post_ids ) . ")) OR (", $search);
}
return $search;
}
add_filter( 'posts_search', 'search_product_by_tag', 999, 2 );
Example: I've one product : Black Chocolate with the product tag "confection". With this code, if i search "Chocolate" in the search form, the product will be returned. But if i search "confection" : no results.

There are a lot of mistakes and errors in your code (a tax query is required for example).
To include WooCommmerce product tag terms in WooCommerce product search only (front end) use the following:
add_filter( 'posts_search', 'woocommerce_search_product_tag_extended', 999, 2 );
function woocommerce_search_product_tag_extended( $search, $query ) {
global $wpdb, $wp;
$qvars = $wp->query_vars;
if ( is_admin() || empty($search) || ! ( isset($qvars['s'])
&& isset($qvars['post_type']) && ! empty($qvars['s'])
&& $qvars['post_type'] === 'product' ) ) {
return $search;
}
// Here set your custom taxonomy
$taxonomy = 'product_tag'; // WooCommerce product tag
// Get the product Ids
$ids = get_posts( array(
'posts_per_page' => -1,
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'tax_query' => array( array(
'taxonomy' => $taxonomy,
'field' => 'name',
'terms' => esc_attr($qvars['s']),
)),
));
if ( count( $ids ) > 0 ) {
$search = str_replace( 'AND (((', "AND ((({$wpdb->posts}.ID IN (" . implode( ',', $ids ) . ")) OR (", $search);
}
return $search;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
To make it work On WordPress search too replace:
if ( is_admin() || empty($search) || ! ( isset($qvars['s'])
&& isset($qvars['post_type']) && ! empty($qvars['s'])
&& $qvars['post_type'] === 'product' ) ) {
By the following:
if ( is_admin() || empty($search) || ! ( isset($qvars['s']) && ! empty($qvars['s']) ) ) {
For WooCommerce product category you will replace:
$taxonomy = 'product_tag'; // WooCommerce product tag
with:
$taxonomy = 'product_cat'; // WooCommerce product category
For WooCommerce product brands you will replace:
$taxonomy = 'product_tag'; // WooCommerce product tag
with:
$taxonomy = 'product_brand'; // WooCommerce product Brands
For multiple taxonomies.
To enable the search for both product category terms and product tag terms, you will use:
add_filter( 'posts_search', 'woocommerce_search_product_tag_extended', 999, 2 );
function woocommerce_search_product_tag_extended( $search, $query ) {
global $wpdb, $wp;
$qvars = $wp->query_vars;
if ( is_admin() || empty($search) || ! ( isset($qvars['s'])
&& isset($qvars['post_type']) && ! empty($qvars['s'])
&& $qvars['post_type'] === 'product' ) ) {
return $search;
}
// Here set your custom taxonomies in the array
$taxonomies = array('product_tag', 'product_cat');
$tax_query = array('relation' => 'OR'); // Initializing tax query
// Loop through taxonomies to set the tax query
foreach( $taxonomies as $taxonomy ) {
$tax_query[] = array(
'taxonomy' => $taxonomy,
'field' => 'name',
'terms' => esc_attr($qvars['s']),
);
}
// Get the product Ids
$ids = get_posts( array(
'posts_per_page' => -1,
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'tax_query' => $tax_query,
) );
if ( sizeof( $ids ) > 0 ) {
$search = str_replace( 'AND (((', "AND ((({$wpdb->posts}.ID IN (" . implode( ',', $ids ) . ")) OR (", $search);
}
return $search;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
To make it work On WordPress search too replace:
if ( is_admin() || empty($search) || ! ( isset($qvars['s'])
&& isset($qvars['post_type']) && ! empty($qvars['s'])
&& $qvars['post_type'] === 'product' ) ) {
By the following:
if ( is_admin() || empty($search) || ! ( isset($qvars['s']) && ! empty($qvars['s']) ) ) {
New Thread: Extend WooCommerce product search to custom taxonomies and custom fields

Related

Search multiple products by custom field in WooCommerce Admin

Using the answer from search multiple sku's on woocommerce admin side I adapted my code to replace $sku with the value of the custom field within my product, which is $winner.
When I search by separating product custom fields with a delimiter, it does not work. How can I edit my code so I can search products multiple by custom field?
function woo_multiple_title_search( $query_vars ) {
global $typenow;
global $wpdb;
global $pagenow;
if ( 'product' === $typenow && isset( $_GET['s'] ) && 'edit.php' === $pagenow ) {
$search_term = esc_sql( sanitize_text_field( $_GET['s'] ) );
if (strpos($search_term, '|') == false) return $query_vars;
$names = explode('|',$search_term);
$meta_query = array(
'relation' => 'OR'
);
if(is_array($winners) && $winners) {
foreach($winners as $winner) {
$meta_query[] = array(
'key' => '_winner',
'value' => $winner,
'compare' => '='
);
}
}
$args = array(
'posts_per_page' => -1,
'post_type' => 'product',
'meta_query' => $meta_query
);
$posts = get_posts( $args );
if ( ! $posts ) return $query_vars;
foreach($posts as $post){
$query_vars['post__in'][] = $post->ID;
}
}
return $query_vars;
}
add_filter( 'request', 'woo_multiple_title_search', 20 );

WooCommerce exclude products from child category in parent category

What I try to accomplish in WooCommerce:
I have many categories (e.g. shoes) with child categories (e.g. heels, mules, wedges). All standard shoes are only in the parent category and a few special shoes (like heels, mules and wedges) are only in child categories.
If a user opens the category "shoes", I want to display only the products in the current category (not these from the child categories).
What I've tried so far
I searches a lot and tried many different approaches, but no chance.
Approach #1: as seen here
function exclude_product_cat_children( $wp_query ) {
if ( isset( $wp_query->query_vars['product_cat'] ) && $wp_query->is_main_query() ) {
$wp_query->set(
'tax_query', array( array (
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => $wp_query->query_vars['product_cat'],
'include_children' => false
) )
);
}
}
add_filter('pre_get_posts', 'exclude_product_cat_children', 99);
Approach #2: as seen here
add_filter( 'parse_tax_query', 'cyb_do_not_include_children_in_company_category_archive' );
function cyb_do_not_include_children_in_company_category_archive( $query ) {
if (
! is_admin()
&& $query->is_main_query()
&& $query->is_tax( 'shoes' )
) {
$query->tax_query->queries[0]['include_children'] = 0;
}
}
I really don't know how to fix this issue. It seems like this two approaches are working for all - just not for me. Any ideas?
Thank you!
I finally found the solution myself. Hopefully I can help someone with the code below.
What is the code for?
I hide all products in child categories in the current (parent) category.
function change_parent_category_query($query) {
if( ! is_admin() && $query->query_vars['post_type'] == 'product') {
global $wpdb;
$parent_id = get_queried_object()->term_id;
if( isset($parent_id) && is_numeric($parent_id) ){
$all_subcategory_ids = $wpdb->get_results( $wpdb->prepare( "SELECT term_taxonomy_id FROM {$wpdb->prefix}term_taxonomy WHERE taxonomy = 'product_cat' AND parent = %d", $parent_id ) );
$list_ids = array();
foreach( $all_subcategory_ids as $asi ){
$list_ids[] = esc_attr( $asi->term_taxonomy_id );
}
$tax_query = $query->get( 'tax_query' );
$tax_query[] = array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'parent' => 0,
'terms' => $list_ids,
'operator' => 'NOT IN'
);
$query->set( 'tax_query', $tax_query );
}
}
}
add_action( 'pre_get_posts', 'change_parent_category_query' );

Extend WooCommerce product search to custom taxonomies and custom fields

I am creating advance woocommerce search and I want to add sku and product_tag and product_category in search query. Below I am using Enable custom taxonomies in WooCommerce product search answer code, that enable search for multiple taxonomies:
add_filter( 'posts_search', 'woocommerce_search_product_tag_extended', 999, 2 );
function woocommerce_search_product_tag_extended( $search, $query ) {
global $wpdb, $wp;
$qvars = $wp->query_vars;
if ( is_admin() || empty($search) || ! ( isset($qvars['s'])
&& isset($qvars['post_type']) && ! empty($qvars['s'])
&& $qvars['post_type'] === 'product' ) ) {
return $search;
}
// Here set your custom taxonomies in the array
$taxonomies = array('product_tag', 'product_cat');
$tax_query = array('relation' => 'OR'); // Initializing tax query
// Loop through taxonomies to set the tax query
foreach( $taxonomies as $taxonomy ) {
$tax_query[] = array(
'taxonomy' => $taxonomy,
'field' => 'name',
'terms' => esc_attr($qvars['s']),
);
}
// Get the product Ids
$ids = get_posts( array(
'posts_per_page' => -1,
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'tax_query' => $tax_query,
) );
if ( sizeof( $ids ) > 0 ) {
$search = str_replace( 'AND (((', "AND ((({$wpdb->posts}.ID IN (" . implode( ',', $ids ) . ")) OR (", $search);
}
return $search;
}
I want to add product sku too in search query, how to add it ?
The following will extend Product search to multiple taxonomies (Product Category and Product tag) and multiple custom fields (as SKU here):
add_filter( 'posts_search', 'woocommerce_search_product_mega_extended', 999, 2 );
function woocommerce_search_product_mega_extended( $search, $query ) {
global $wpdb, $wp;
$qvars = $wp->query_vars;
if ( is_admin() || empty($search) || ! ( isset($qvars['s'])
&& isset($qvars['post_type']) && ! empty($qvars['s'])
&& $qvars['post_type'] === 'product' ) ) {
return $search;
}
// SETTINGS:
$taxonomies = array('product_tag', 'product_cat'); // Here set your custom taxonomies in the array
$meta_keys = array('_sku'); // Here set your product meta key(s) in the array
// Initializing tax query
$tax_query = count($taxonomies) > 1 ? array('relation' => 'OR') : array();
// Loop through taxonomies to set the tax query
foreach( $taxonomies as $taxonomy ) {
$tax_query[] = array(
'taxonomy' => $taxonomy,
'field' => 'name',
'terms' => esc_attr($qvars['s']),
);
}
// Get the product Ids from taxonomy(ies)
$tax_query_ids = (array) get_posts( array(
'posts_per_page' => -1,
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'tax_query' => $tax_query,
) );
// Initializing meta query
$meta_query = count($meta_keys) > 1 ? array('relation' => 'OR') : array();
// Loop through taxonomies to set the tax query
foreach( $taxonomies as $taxonomy ) {
$meta_query[] = array(
'key' => '_sku',
'value' => esc_attr($qvars['s']),
);
}
// Get the product Ids from custom field(s)
$meta_query_ids = (array) get_posts( array(
'posts_per_page' => -1,
'post_type' => 'product',
'post_status' => 'publish',
'fields' => 'ids',
'meta_query' => $meta_query,
) );
$product_ids = array_unique( array_merge( $tax_query_ids, $meta_query_ids ) ); // Merge Ids in one array with unique Ids
if ( sizeof( $product_ids ) > 0 ) {
$search = str_replace( 'AND (((', "AND ((({$wpdb->posts}.ID IN (" . implode( ',', $product_ids ) . ")) OR (", $search);
}
return $search;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Related: Enable custom taxonomies in WooCommerce product search

Show product variations on WooCommerce archive pages as shop

After a long search and a lot of trial and error I found the code below to display variable products in the shop and on the category page. After a small modification it works fine. But it also displays the variations in all categories, instead of only showing the variations of the current category.
add_action( 'pre_get_posts', 'custom_modify_query_get_posts_by_date' );
// Modify the current query
function custom_modify_query_get_posts_by_date( $query ) {
if ( ! is_admin() && $query->is_main_query() ) {
if ( is_post_type_archive( 'product' ) || is_product_category() || is_product_tag() ) {
$query->set( 'order', 'ASC' );
add_filter( 'posts_where', 'rc_filter_where' );
}
return $query;
}
}
// Add products variation post type to the loop
function rc_filter_where( $where = '' ) {
$type = 'product_variation';
$where .= " OR post_type = '$type'";
return $where;
}
I figured if I can limit the pre_get_posts to the current category that should work. Tried a lot of things, but I can't get it to work.
add_action( 'pre_get_posts', 'custom_modify_query_get_posts_by_date' );
// Modify the current query
function custom_modify_query_get_posts_by_date( $query ) {
if ( ! is_admin() && $query->is_main_query() ) {
if ( is_product_category() ) {
$cate = get_queried_object();
$cateID = $cate->term_id;
$query->set( 'order', 'ASC' );
$query->set('cat', $cateID);
add_filter( 'posts_where', 'rc_filter_where' );
} elseif ( is_post_type_archive( 'product' ) || is_product_tag() ) {
$query->set( 'order', 'ASC' );
add_filter( 'posts_where', 'rc_filter_where' );
}
return $query;
}
}
// Add products variation post type to the loop
function rc_filter_where( $where = '' ) {
$type = 'product_variation';
$where .= " OR post_type = '$type'";
return $where;
}
So I would like to know if it's possible to show all product variations in the shop and on the category view only show the variations that belong to that category.
Could you remove the posts_where's and try tax_query instead of $query->set('cat', $cateID);?
add_action( 'pre_get_posts', 'custom_modify_query_get_posts_by_date' );
// Modify the current query
function custom_modify_query_get_posts_by_date( $query ) {
if ( ! is_admin() && $query->is_main_query() && $query->is_tax('product_cat') ) {
if ( is_tax('product_cat') ) {
$cate = get_queried_object();
$cateID = $cate->term_id;
$cateslug = $cate->slug;
$catetax = $cate->taxonomy;
//$query->set('cat', $cateID);
$taxquery = array(
'tax_query' => array(
'taxonomy' => $catetax,
'terms' => $cateslug,
'field' => 'slug',
'include_children' => true,
'operator' => 'IN'
)
);
$query->set( 'tax_query', $taxquery );
$query->set( 'post_type', array('product', 'product_variation') );
$query->set( 'order', 'ASC' );
} elseif ( is_post_type_archive( 'product' ) || is_product_tag() ) {
$query->set( 'order', 'ASC' );
}
return $query;
}
}

Hide category in the WooCommerce shop page

I've been trying to hide a specific category from SHOP page. I found this code:
add_filter( 'pre_get_posts', 'custom_pre_get_posts_query' );
function custom_pre_get_posts_query( $q ) {
if ( ! $q->is_main_query() ) return;
if ( ! $q->is_post_type_archive() ) return;
$q->set( 'tax_query', array(array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => array( 'CATEGORY TO HIDE' ),
'operator' => 'NOT IN'
)));
remove_filter( 'pre_get_posts', 'custom_pre_get_posts_query' );
}
I've pasted this code in my theme function.php file but I'm not achieving the result...
Can anybody help me please?
I know this is a bit late, but had this problem myself and solved it with the following function:
add_filter( 'get_terms', 'get_subcategory_terms', 10, 3 );
function get_subcategory_terms( $terms, $taxonomies, $args ) {
$new_terms = array();
// if a product category and on the shop page
if ( in_array( 'product_cat', $taxonomies ) && ! is_admin() && is_shop() ) {
foreach ( $terms as $key => $term ) {
if ( ! in_array( $term->slug, array( '**CATEGORY-HERE**' ) ) ) {
$new_terms[] = $term;
}
}
$terms = $new_terms;
}
return $terms;
}
The following snippet it works fine for me:
add_action( 'pre_get_posts', 'custom_pre_get_posts_query' );
function custom_pre_get_posts_query( $q ) {
if ( ! $q->is_main_query() ) return;
if ( ! $q->is_post_type_archive() ) return;
if ( ! is_admin() && is_shop() ) {
$q->set( 'tax_query', array(array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => array( 'your category slug' ), // Don't display products in the knives category on the shop page
'operator' => 'NOT IN'
)));
}
remove_action( 'pre_get_posts', 'custom_pre_get_posts_query' );
}
I'm wondering how can I achieve the same for the products excluded within the category to be searchable via product search, while using the snippet those products gets totally hidden.
Simple way to hide a category from everything except the admin backend:
In functions.php:
add_filter( 'get_terms', 'hide_category', 10, 1 );
function hide_category( $terms ) {
$new_terms = array();
foreach ( $terms as $term ) {
if ( $term->slug !== 'secret_category' ) {
$new_terms[] = $term;
} else if ( $term->taxonomy !== 'product_cat' || is_admin() ) {
$new_terms[] = $term;
}
}
return $new_terms;
}
If you want to only hide it from the shop, add || !is_shop() to the else if condition.
If you want to hide some categories in your theme you can just pass exclude argument in the wp_list_categories function:
wp_list_categories( array(
'taxonomy' => 'product_cat',
'hide_empty' => 1,
'use_desc_for_title' => 0,
'title_li' => ' ',
'show_count' => 0,
'exclude' => '63' // <-- Hidden) );

Categories