diff --git a/src/BlockTypes/ProductQuery.php b/src/BlockTypes/ProductQuery.php index 6b63c16d489..85805715cfd 100644 --- a/src/BlockTypes/ProductQuery.php +++ b/src/BlockTypes/ProductQuery.php @@ -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 ), + $this->get_filter_by_keyword_query( $query ) ); } @@ -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 ) ); @@ -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(); @@ -625,7 +627,6 @@ function( $stock_status ) { 'key' => '_stock_status', 'value' => $filtered_stock_status_values, 'operator' => 'IN', - ), ), ); @@ -814,4 +815,65 @@ 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 $query WP_Query. + * @return array Query to filter products by taxonomies. + */ + private function get_filter_by_taxonomies_query( $query ): array { + if ( ! isset( $query['tax_query'] ) || ! is_array( $query['tax_query'] ) ) { + return []; + } + + $tax_query = $query['tax_query']; + /** + * 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. + */ + private function get_filter_by_keyword_query( $query ): array { + if ( ! is_array( $query ) ) { + return []; + } + + if ( isset( $query['s'] ) ) { + return [ 's' => $query['s'] ]; + } + + return []; + } }