Automattic\WooCommerce\Internal\ProductAttributesLookup
Filterer::filter_by_attribute_post_clauses
Adds post clauses for filtering via lookup table. This method should be invoked within a posts_clauses
Method of the class: Filterer{}
Hooks from the method
Returns
Array. The updated product query clauses.
Usage
$Filterer = new Filterer(); $Filterer->filter_by_attribute_post_clauses( $args, $wp_query, $attributes_to_filter_by );
- $args(array) (required)
- Product query clauses as supplied to the posts_clauses
- $wp_query(WP_Query) (required)
- Current product query as supplied to the posts_clauses
- $attributes_to_filter_by(array) (required)
- Attribute filtering data as generated by WC_Query::get_layered_nav_chosen_attributes.
Filterer::filter_by_attribute_post_clauses() Filterer::filter by attribute post clauses code WC 10.3.3
public function filter_by_attribute_post_clauses( array $args, \WP_Query $wp_query, array $attributes_to_filter_by ) {
global $wpdb;
/**
* Filter whether to add the filter post clauses
*
* @param bool $is_main_query Whether the current query is 'is_main_query'.
* @param WP_Query $wp_query The current WP_Query object.
*
* @since 9.9.0
*/
$enable_filtering = apply_filters( 'woocommerce_enable_post_clause_filtering', $wp_query->is_main_query(), $wp_query );
if ( ! $enable_filtering || ! $this->filtering_via_lookup_table_is_active() ) {
return $args;
}
// 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 (";
/**
* Filters the woocommerce_hide_out_of_stock_items option to override the default behavior in product filtering by attribute.
*
* @param bool $option_value The behavior configured in WooCommerce settings.
* @return bool The behavior to use in the catalog when product filtering by attribute.
*
* @since 9.8.0.
*/
$hide_out_of_stock = apply_filters( 'woocommerce_product_attributes_filterer_hide_out_of_stock', 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) );
if ( $hide_out_of_stock ) {
$in_stock_clause = ' AND in_stock = 1';
} else {
$in_stock_clause = '';
}
$attribute_ids_for_and_filtering = array();
$clauses = array();
foreach ( $attributes_to_filter_by as $taxonomy => $data ) {
$all_terms = get_terms( $taxonomy, array( 'hide_empty' => false ) );
$term_ids_by_slug = wp_list_pluck( $all_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' === $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->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->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->lookup_table_name} lt
WHERE is_variation_attribute=1
{$in_stock_clause}
AND term_id in {$term_ids_to_filter_by_list}
GROUP BY product_or_parent_id
HAVING COUNT(DISTINCT term_id)={$count}
)";
}
if ( ! empty( $clauses ) ) {
// "temp" is needed because the extra derived tables require an alias.
$args['where'] .= ' AND (' . join( ' temp ) AND ', $clauses ) . ' temp ))';
} elseif ( ! empty( $attributes_to_filter_by ) ) {
$args['where'] .= ' AND 1=0';
}
return $args;
}