Exclude multiple custom taxonomies terms from Wordpress search - php

I am excluding from Wordpress search results any posts or custom posts with custom taxonomies set to specific terms. I want to be able to add more taxonomies and terms simply (like in an array) without having the duplicate the function, and ensure I'm doing it efficiently.
Can anyone suggest a cleaner function that accommodates this?
/* Exclude from WordPress Search using custom taxonomy */
add_action( 'pre_get_posts', function ( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
// Exclude Terms by ID from Search and Archive Listings
if ( is_search() || is_tax( 'marque' ) ) {
$tax_query = array([
'taxonomy' => 'site_search',
'field' => 'term_id',
'terms' => [ exclude_page ],
'operator' => 'NOT IN',
]);
$query->set( 'tax_query', $tax_query );
}
}, 11, 1 );
/* Exclude from WordPress Search using custom taxonomy */
add_action( 'pre_get_posts', function ( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
// Exclude Terms by ID from Search and Archive Listings
if ( is_search() || is_tax( 'marque' ) ) {
$tax_query = array([
'taxonomy' => 'job_status',
'field' => 'term_id',
'terms' => [ closed ],
'operator' => 'NOT IN',
]);
$query->set( 'tax_query', $tax_query );
}
}, 11, 1 );

You could try first to define all your data in an array first as taxonomies / terms pairs (I have embedded the array in an external function, but it can be added directly in the hooked function). This way you can add or remove data easily.
Then we use a foreach loop to read and set the data in the tax query. So your code will be something like:
// HERE set in the array your taxonomies / terms pairs
function get_custom_search_data(){
return [
'site_search' => [ 'exclude_page' ],
'job_status' => [ 'closed' ],
];
}
/* Exclude from WordPress Search using custom taxonomy */
add_action( 'pre_get_posts', 'multiple_taxonomy_search', 33, 1 );
function multiple_taxonomy_search( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
// Exclude Terms by ID from Search and Archive Listings
if ( is_search() || is_tax( 'marque' ) ) {
// Set the "relation" argument if the array has more than 1 custom taxonomy
if( sizeof( get_custom_search_data() ) > 1 ){
$tax_query['relation'] = 'AND'; // or 'OR'
}
// Loop through taxonomies / terms pairs and add the data in the tax query
foreach( get_custom_search_data() as $taxonomy => $terms ){
$tax_query[] = [
'taxonomy' => $taxonomy,
'field' => 'slug', // <== Terms slug seems to be used
'terms' => $terms,
'operator' => 'NOT IN',
];
}
// Set the defined tax query
$query->set( 'tax_query', $tax_query );
}
}
Code goes in function.php file of your active child theme (or active theme). Untested, it should work.

Related

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' );

Exclude a woocommerce product category from wordpress global search results

I'm using this code to exclude some post category from the wordpress search results :
function SearchFilter($query)
{
if ($query->is_search)
{
$query->set('cat', '-709,-710,-614');
}
return $query;
}
add_filter('pre_get_posts','SearchFilter');
My problem is that it doesn't work for woocommerce categories and products are not filtered.
How can I filter some woocommerce categories too ?
Can you replace your category. hope this help you.
function wpse188669_pre_get_posts( $query ) {
if (
! is_admin()
&& $query->is_main_query()
&& $query->is_search()
) {
$query->set( 'post_type', array( 'product' ) );
// set your parameters according to
// https://codex.wordpress.org/Class_Reference/WP_Query#Taxonomy_Parameters
$tax_query = array(
array(
// likely what you are after
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => 'category-2',
'operator' => 'NOT IN',
),
);
$query->set( 'tax_query', $tax_query );
}
}
add_action( 'pre_get_posts', 'wpse188669_pre_get_posts' );

How to show search results from specific category in the end in WordPress

I am trying to move the posts in specific category (uncategorized) in the end of the search results in WordPress frontend search page.
The approach which I have for now is:
Remove the posts from the selected category from the main query
Create a new query and get posts from that category only
Merge both query results, so now the results from the specified category are in the end
Have to maintain pagination too
The code I am using for step 1 is:
function wcs_exclude_category_search( $query ) {
if ( is_admin() || ! $query->is_main_query() )
return;
if ( $query->is_search ) {
$query->set( 'cat', '-11' );
}
}
add_action( 'pre_get_posts', 'wcs_exclude_category_search', 1 );
Any guidance for this approach or a better approach would be appreciated. Thanks.
Normally I would prefer the "tax_query" parameter, something like
// in case there are other tax_query clauses on the query
$tax_query = (array) $query->get( 'tax_query' );
$tax_query[] = [
'taxonomy' => 'category',
'terms' => 11,
'field' => 'term_id',
'operator' => 'NOT IN'
];
$query->set( 'tax_query', $tax_query );
On the other hand, if the query already has posts from the "uncategorized" category, you could sort the results just before display by hooking on the_posts, something like:
add_action( 'the_posts', function( $posts, $query ){
if ( ! $query->is_search() ) {
return $posts;
}
usort( $posts, function ( $a, $b ){
$a_in_uncategorized = has_term( 11, 'category', $a );
$b_in_uncategorized = has_term( 11, 'category', $b );
// if neither or both are on the "uncategorized" category
// sort by date or whatever
if ( $a_in_uncategorized === $b_in_uncategorized ) {
return $b->post_date <=> $a->post_date;
}
if ( $a_in_uncategorized && ! $b_in_uncategorized ) {
return 1;
}
if ( ! $a_in_uncategorized && $b_in_uncategorized ) {
return -1;
}
return 0;
} );
return $posts;
}, 10, 2 );
I hope that helps :-)

Hiding WooCommerce Categories that don't have any products in them?

I would like to disable categories that don't have any products in them. Here's the code that seems to not be working.
Placed in my functions.php
function woo_hide_product_categories_widget( $list_args ){
$list_args[ 'hide_empty' ] = 1;
return $list_args;
}
add_filter( 'woocommerce_product_categories_widget_args','woo_hide_product_categories_widget' );
add_filter( 'woocommerce_product_categories_widget_args', 'wpsites_exclude_product_cat_widget' );
function wpsites_exclude_product_cat_widget( $args ) {
$args['exclude'] = array('16','46');
return $args;
}
try this
you can hide specific categories by the following:
add_action( 'pre_get_posts', 'uw_remove_product_cats_shop_page' );
function uw_remove_product_cats_shop_page( $query ) {
// Comment out the line below to hide products in the admin as well
if ( is_admin() ) return;
if ( is_shop() && $query->is_main_query() ) {
$query->set( 'tax_query', array(
array(
'taxonomy' => 'product_cat',
'field' => 'ID',
'terms' => array( 200, 205, 210 ), //ID of categories here
'operator' => 'NOT IN'
)
) );
}
}

PHP how to use a variable in an array

I have an options page in my wordpress theme, it's to select a number of categories from a custom taxonomy.
$terms_obj = get_option('shop_features')
This returns an array with $key being the category-name and $value being either 1 or empty depending if the category was checked.
I need to grab a list of the checked categories to use in an array in another function:
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( 'knives' ), // 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' );
}
Where I need to insert my category-names contained in a variable $terms to replace the 'terms' => array('knives') with 'terms' => array ( $terms )
Except it doesn't work by just doing that!
Here is how I've tried to accomplish that:
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() ) {
$terms_obj = of_get_option( 'eco_shop_features', $default );
foreach ( $terms_obj as $slug => $checked ) { //$key ==> value
if ( $checked > 0 )
$terms .= '\'' . $slug . '\', ';
}
$terms = rtrim( $terms, ', ' );
$q->set( 'tax_query', array(array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => array( "$terms" ), // 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 stuck of how to insert just the list of category names in to the terms field so it works as an array.
The right way seems to be commented out by you, below should work
foreach ( $terms_obj as $slug => $checked ) { //$key ==> value
if ( $checked > 0 )
$terms[] = $slug;
}
$q->set( 'tax_query', array(array(
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => $terms,
'operator' => 'NOT IN'
)));
To get your array of category names you can do :
$terms_obj = get_option('shop_features');
$category_name_array = array_keys($terms_obj, 1);
The array_keys($terms_obj, 1) function will extract in an array all the keys of the $terms_obj for witch the value match 1.
More info : http://php.net/manual/en/function.array-keys.php
Just prepare an array in the loop
$terms[] = $slug
And assign to term
'terms' => $terms,

Categories