[Product Query] Add support for the Filter By Price Block (https://github.com/woocommerce/woocommerce-blocks/pull/7162)

* Product Query: Fix pagination issue

* Product Query - Add support for the Filter By Price Block woocommerce/woocommerce-blocks#6790

Product Query - Add support for the Filter By Price Block

* fix query relation

* fix on sale query

* fix bugged pagination and on-sale filter after refactor

* fix reload page when the Filter By Price block is used with All Products block

* use array_intersect instead of array_merge
This commit is contained in:
Luigi Teschio 2022-09-28 15:44:20 +02:00 committed by GitHub
parent a97cd87ba1
commit 222407cb93
2 changed files with 101 additions and 24 deletions

View File

@ -11,5 +11,7 @@ class PriceFilter extends AbstractBlock {
*
* @var string
*/
protected $block_name = 'price-filter';
protected $block_name = 'price-filter';
const MIN_PRICE_QUERY_VAR = 'min_price';
const MAX_PRICE_QUERY_VAR = 'max_price';
}

View File

@ -27,6 +27,7 @@ class ProductQuery extends AbstractBlock {
* - Hook into pre_render_block to update the query.
*/
protected function initialize() {
add_filter( 'query_vars', array( $this, 'set_query_vars' ) );
parent::initialize();
add_filter(
'pre_render_block',
@ -63,9 +64,12 @@ class ProductQuery extends AbstractBlock {
$this->parsed_block = $parsed_block;
if ( $this->is_woocommerce_variation( $parsed_block ) ) {
// Set this so that our product filters can detect if it's a PHP template.
$this->asset_data_registry->add( 'has_filterable_products', true, true );
$this->asset_data_registry->add( 'is_rendering_php_template', true, true );
add_filter(
'query_loop_block_query_vars',
array( $this, 'get_query_by_attributes' ),
array( $this, 'build_query' ),
10,
1
);
@ -73,12 +77,12 @@ class ProductQuery extends AbstractBlock {
}
/**
* Return a custom query based on the attributes.
* Return a custom query based on attributes, filters and global WP_Query.
*
* @param WP_Query $query The WordPress Query.
* @return array
*/
public function get_query_by_attributes( $query ) {
public function build_query( $query ) {
$parsed_block = $this->parsed_block;
if ( ! $this->is_woocommerce_variation( $parsed_block ) ) {
return $query;
@ -90,40 +94,111 @@ class ProductQuery extends AbstractBlock {
'posts_per_page' => $query['posts_per_page'],
'orderby' => $query['orderby'],
'order' => $query['order'],
'offset' => $query['offset'],
// Ignoring the warning of not using meta queries.
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
'meta_query' => array(),
);
do_action( 'qm/debug', $parsed_block );
$queries_attributes = $this->get_queries_by_attributes( $parsed_block );
$queries_filters = $this->get_queries_by_applied_filters();
return array_reduce(
array_merge(
$queries_attributes,
$queries_filters
),
function( $acc, $query ) {
if ( isset( $query['post__in'] ) ) {
$acc['post__in'] = isset( $acc['post__in'] ) ? array_intersect( $acc['post__in'], $query['post__in'] ) : $query['post__in'];
}
// Ignoring the warning of not using meta queries.
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
$acc['meta_query'] = isset( $query['meta_query'] ) ? array_merge( $acc['meta_query'], array( $query['meta_query'] ) ) : $acc['meta_query'];
return $acc;
},
$common_query_values
);
$on_sale_query = $this->get_on_sale_products_query( $parsed_block['attrs']['query'] );
return array_merge( $query, $common_query_values, $on_sale_query );
}
/**
* Return a query for on sale products.
*
* @param array $query_params Block query parameters.
* @return array
*/
private function get_on_sale_products_query( $query_params ) {
if ( ! isset( $query_params['__woocommerceOnSale'] ) || true !== $query_params['__woocommerceOnSale'] ) {
return array();
}
private function get_on_sale_products_query() {
return array(
'post__in' => wc_get_product_ids_on_sale(),
);
}
/**
* Set the query vars that are used by filter blocks.
*
* @param array $qvars Public query vars.
* @return array
*/
public function set_query_vars( $qvars ) {
$filter_query_args = array( PriceFilter::MIN_PRICE_QUERY_VAR, PriceFilter::MAX_PRICE_QUERY_VAR );
return array_merge( $qvars, $filter_query_args );
}
/**
* Return queries that are generated by query args
*
* @return array
*/
private function get_queries_by_applied_filters() {
return array( 'price_filter' => $this->get_filter_by_price_query() );
}
/**
* Return queries that are generated by attributes
*
* @param array $parsed_block The Product Query that being rendered.
* @return array
*/
private function get_queries_by_attributes( $parsed_block ) {
$on_sale_enabled = isset( $parsed_block['attrs']['query']['__woocommerceOnSale'] ) && true === $parsed_block['attrs']['query']['__woocommerceOnSale'];
return array(
'on_sale' => ( $on_sale_enabled ? $this->get_on_sale_products_query() : array() ),
);
}
/**
* Return a query that filters products by price.
*
* @return array
*/
private function get_filter_by_price_query() {
$min_price = get_query_var( PriceFilter::MIN_PRICE_QUERY_VAR );
$max_price = get_query_var( PriceFilter::MAX_PRICE_QUERY_VAR );
$max_price_query = empty( $max_price ) ? array() : [
'key' => '_price',
'value' => $max_price,
'compare' => '<=',
'type' => 'numeric',
];
$min_price_query = empty( $min_price ) ? array() : [
'key' => '_price',
'value' => $min_price,
'compare' => '>=',
'type' => 'numeric',
];
return array(
// Ignoring the warning of not using meta queries.
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
'meta_query' => array(
'relation' => 'OR',
array(
'key' => '_sale_price',
'value' => 0,
'compare' => '>',
'type' => 'numeric',
),
array(
'key' => '_min_variation_sale_price',
'value' => 0,
'compare' => '>',
'type' => 'numeric',
),
'relation' => 'AND',
$max_price_query,
$min_price_query,
),
);
}