Automattic\WooCommerce\Internal\ProductFilters
QueryClauses::add_attribute_clauses
Add query clauses for filtering products by attributes.
Method of the class: QueryClauses{}
No Hooks.
Returns
Array.
Usage
$QueryClauses = new QueryClauses(); $QueryClauses->add_attribute_clauses( $args, $chosen_attributes ): array;
- $args(array) (required)
- Query args.
- $chosen_attributes(array) (required)
Chosen attributes array.
- {$taxonomy:(array)
Attribute taxonomy name} {@type string[] $terms Chosen terms' slug. @type string $query_type Query type. Accepts 'and' or 'or'.
- {$taxonomy:(array)
QueryClauses::add_attribute_clauses() QueryClauses::add attribute clauses code WC 10.3.3
public function add_attribute_clauses( array $args, array $chosen_attributes ): array {
if ( empty( $chosen_attributes ) ) {
return $args;
}
global $wpdb;
// The extra derived table ("SELECT product_or_parent_id FROM") is needed for performance
// (causes the filtering subquery to be executed only once).
$clause_root = " {$wpdb->posts}.ID IN ( SELECT product_or_parent_id FROM (";
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
$in_stock_clause = ' AND in_stock = 1';
} else {
$in_stock_clause = '';
}
$attribute_ids_for_and_filtering = array();
$clauses = array();
// Get all terms for all attribute taxonomies in one query for better performance.
$all_terms_slugs = array();
foreach ( $chosen_attributes as $data ) {
if ( ! empty( $data['terms'] ) && is_array( $data['terms'] ) ) {
$all_terms_slugs = array_merge( $all_terms_slugs, $data['terms'] );
}
}
$all_terms = get_terms(
array(
'taxonomy' => array_keys( $chosen_attributes ),
'slug' => $all_terms_slugs,
'hide_empty' => false,
)
);
if ( is_wp_error( $all_terms ) ) {
return $args;
}
// Group terms by taxonomy for easier processing.
$terms_by_taxonomy = array();
foreach ( $all_terms as $term ) {
$terms_by_taxonomy[ $term->taxonomy ][] = $term;
}
foreach ( $chosen_attributes as $taxonomy => $data ) {
$current_attribute_terms = $terms_by_taxonomy[ $taxonomy ] ?? array();
$term_ids_by_slug = wp_list_pluck( $current_attribute_terms, 'term_id', 'slug' );
$term_ids_to_filter_by = array_values( array_intersect_key( $term_ids_by_slug, array_flip( $data['terms'] ) ) );
$term_ids_to_filter_by = array_map( 'absint', $term_ids_to_filter_by );
$term_ids_to_filter_by_list = '(' . join( ',', $term_ids_to_filter_by ) . ')';
$is_and_query = 'and' === strtolower( $data['query_type'] );
$count = count( $term_ids_to_filter_by );
if ( 0 !== $count ) {
if ( $is_and_query && $count > 1 ) {
$attribute_ids_for_and_filtering = array_merge( $attribute_ids_for_and_filtering, $term_ids_to_filter_by );
} else {
$clauses[] = "
{$clause_root}
SELECT product_or_parent_id
FROM {$this->get_lookup_table_name()} lt
WHERE term_id in {$term_ids_to_filter_by_list}
{$in_stock_clause}
)";
}
}
}
if ( ! empty( $attribute_ids_for_and_filtering ) ) {
$count = count( $attribute_ids_for_and_filtering );
$term_ids_to_filter_by_list = '(' . join( ',', $attribute_ids_for_and_filtering ) . ')';
$clauses[] = "
{$clause_root}
SELECT product_or_parent_id
FROM {$this->get_lookup_table_name()} lt
WHERE is_variation_attribute=0
{$in_stock_clause}
AND term_id in {$term_ids_to_filter_by_list}
GROUP BY product_id
HAVING COUNT(product_id)={$count}
UNION
SELECT product_or_parent_id
FROM {$this->get_lookup_table_name()} lt
WHERE is_variation_attribute=1
{$in_stock_clause}
AND term_id in {$term_ids_to_filter_by_list}
)";
}
if ( ! empty( $clauses ) ) {
// "temp" is needed because the extra derived tables require an alias.
$args['where'] .= ' AND (' . join( ' temp ) AND ', $clauses ) . ' temp ))';
} elseif ( ! empty( $chosen_attributes ) ) {
$args['where'] .= ' AND 1=0';
}
return $args;
}