Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Fix Product categories, Product Tags & Keyword filter not working in Products block #8377

Merged
merged 12 commits into from
Feb 21, 2023
Merged
89 changes: 74 additions & 15 deletions src/BlockTypes/ProductQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,10 @@ public function build_query( $query ) {
$common_query_values,
$this->get_global_query( $parsed_block ),
$this->get_custom_orderby_query( $query['orderby'] ),
$this->get_queries_by_attributes( $parsed_block ),
$this->get_queries_by_applied_filters()
$this->get_queries_by_custom_attributes( $parsed_block ),
$this->get_queries_by_applied_filters(),
$this->get_filter_by_taxonomies_query( $query['tax_query'] ),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$this->get_filter_by_taxonomies_query( $query['tax_query'] ),
$this->get_filter_by_taxonomies_query( isset($query['tax_query'] ? $query['tax_query']: array()),

Now, if the Products block doesn't have any filter defined, tax_query doesn't exist, and WP returns an error.

$this->get_filter_by_keyword_query( $query )
);
}

Expand All @@ -182,7 +184,7 @@ private function get_products_ids_by_attributes( $parsed_block ) {
'meta_query' => array(),
'tax_query' => array(),
),
$this->get_queries_by_attributes( $parsed_block ),
$this->get_queries_by_custom_attributes( $parsed_block ),
$this->get_global_query( $parsed_block )
);

Expand Down Expand Up @@ -220,8 +222,8 @@ function( $acc, $query ) {
* duplicated items.
*/
if (
! empty( $merged_query['post__in'] ) &&
count( $merged_query['post__in'] ) > count( array_unique( $merged_query['post__in'] ) )
! empty( $merged_query['post__in'] ) &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, but I guess that we should revert this formatting change.

count( $merged_query['post__in'] ) > count( array_unique( $merged_query['post__in'] ) )
) {
$merged_query['post__in'] = array_unique(
array_diff(
Expand Down Expand Up @@ -337,8 +339,8 @@ private function get_stock_status_query( $stock_statii ) {
* meta query for stock status.
*/
if (
count( $stock_statii ) === count( $stock_status_options ) &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, but I guess that we should revert this formatting change.

array_diff( $stock_statii, $stock_status_options ) === array_diff( $stock_status_options, $stock_statii )
count( $stock_statii ) === count( $stock_status_options ) &&
array_diff( $stock_statii, $stock_status_options ) === array_diff( $stock_status_options, $stock_statii )
) {
return array();
}
Expand Down Expand Up @@ -491,7 +493,7 @@ private function get_queries_by_applied_filters() {
* @param array $parsed_block The Product Query that being rendered.
* @return array
*/
private function get_queries_by_attributes( $parsed_block ) {
private function get_queries_by_custom_attributes( $parsed_block ) {
$query = $parsed_block['attrs']['query'];
$on_sale_enabled = isset( $query['__woocommerceOnSale'] ) && true === $query['__woocommerceOnSale'];
$attributes_query = isset( $query['__woocommerceAttributes'] ) ? $this->get_product_attributes_query( $query['__woocommerceAttributes'] ) : array();
Expand Down Expand Up @@ -619,15 +621,15 @@ function( $stock_status ) {

return array(
// Ignoring the warning of not using meta queries.
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
'meta_query' => array(
array(
'key' => '_stock_status',
'value' => $filtered_stock_status_values,
'operator' => 'IN',
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
'meta_query' => array(
array(
'key' => '_stock_status',
'value' => $filtered_stock_status_values,
'operator' => 'IN',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, but I guess that we should revert this formatting change.


),
),
),
);
}

Expand Down Expand Up @@ -814,4 +816,61 @@ function( $rating ) use ( $product_visibility_terms ) {
);
}


/**
* Return a query to filter products by taxonomies (product categories, product tags, etc.)
*
* For example:
* User could provide "Product Categories" using "Filters" ToolsPanel available in Inspector Controls.
* We use this function to extract it's query from $tax_query.
*
* For example, this is how the query for product categories will look like in $tax_query array:
* Array
* (
* [taxonomy] => product_cat
* [terms] => Array
* (
* [0] => 36
* )
* )
*
* For product categories, taxonomy would be "product_tag"
*
* @param array $tax_query taxonomy query.
* @return array Query to filter products by taxonomies.
*/
private function get_filter_by_taxonomies_query( $tax_query ): array {
if ( ! is_array( $tax_query ) ) {
return [];
}

/**
* Get an array of taxonomy names associated with the "product" post type because
* we also want to include custom taxonomies associated with the "product" post type.
*/
$product_taxonomies = get_taxonomies( array( 'object_type' => array( 'product' ) ), 'names' );
$result = array_filter(
$tax_query,
function( $item ) use ( $product_taxonomies ) {
return isset( $item['taxonomy'] ) && in_array( $item['taxonomy'], $product_taxonomies, true );
}
);

return ! empty( $result ) ? [ 'tax_query' => $result ] : [];
}

/**
* Returns the keyword filter from the given query.
*
* @param WP_Query $query The query to extract the keyword filter from.
* @return array The keyword filter, or an empty array if none is found.
* @throws InvalidArgumentException If $query is not an array.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thank that we should do this check, in this way, we will not throw any errors. Now we don't catch the error.

*/
private function get_filter_by_keyword_query( $query ): array {
if ( isset( $query['s'] ) ) {
return [ 's' => $query['s'] ];
}

return [];
}
}