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

Commit

Permalink
Refactor ProductQuery::merge_queries to accept multiple queries (#7697
Browse files Browse the repository at this point in the history
)
  • Loading branch information
dinhtungdu authored Nov 29, 2022
1 parent bbee496 commit 1f587b6
Showing 1 changed file with 127 additions and 34 deletions.
161 changes: 127 additions & 34 deletions src/BlockTypes/ProductQuery.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ class ProductQuery extends AbstractBlock {
*/
protected $is_custom_inherit_global_query_implementation_enabled = false;

/**
* All query args from WP_Query.
*
* @var array
*/
protected $valid_query_vars;

/**
* Initialize this block type.
*
Expand Down Expand Up @@ -186,42 +193,17 @@ private function get_products_ids_by_attributes( $parsed_block ) {
* @return array
*/
private function merge_queries( ...$queries ) {
$valid_query_vars = array_keys( ( new WP_Query() )->fill_query_vars( array() ) );
$valid_query_vars = array_merge(
$valid_query_vars,
// fill_query_vars doesn't include these vars so we need to add them manually.
array(
'date_query',
'exact',
'ignore_sticky_posts',
'lazy_load_term_meta',
'meta_compare_key',
'meta_compare',
'meta_query',
'meta_type_key',
'meta_type',
'nopaging',
'offset',
'order',
'orderby',
'page',
'post_type',
'posts_per_page',
'suppress_filters',
'tax_query',
)
);

$merged_query = array_reduce(
$queries,
function( $acc, $query ) use ( $valid_query_vars ) {
function( $acc, $query ) {
if ( ! is_array( $query ) ) {
return $acc;
}
if ( empty( array_intersect( $valid_query_vars, array_keys( $query ) ) ) ) {
// If the $query doesn't contain any valid query keys, we unpack/spread it then merge.
if ( empty( array_intersect( $this->get_valid_query_vars(), array_keys( $query ) ) ) ) {
return $this->merge_queries( $acc, ...array_values( $query ) );
}
return array_merge_recursive( $acc, $query );
return $this->array_merge_recursive_replace_non_array_properties( $acc, $query );
},
array()
);
Expand Down Expand Up @@ -450,9 +432,11 @@ private function get_filter_by_price_query() {

return array(
'meta_query' => array(
'relation' => 'AND',
$max_price_query,
$min_price_query,
array(
'relation' => 'AND',
$max_price_query,
$min_price_query,
),
),
);
}
Expand Down Expand Up @@ -499,8 +483,10 @@ function( $acc, $query_args ) {

return array(
'tax_query' => array(
'relation' => 'AND',
$queries,
array(
'relation' => 'AND',
$queries,
),
),
);
}
Expand Down Expand Up @@ -542,6 +528,112 @@ function( $stock_status ) {
);
}

/**
* Return or initialize $valid_query_vars.
*
* @return array
*/
private function get_valid_query_vars() {
if ( ! empty( $this->valid_query_vars ) ) {
return $this->valid_query_vars;
}

$valid_query_vars = array_keys( ( new WP_Query() )->fill_query_vars( array() ) );
$this->valid_query_vars = array_merge(
$valid_query_vars,
// fill_query_vars doesn't include these vars so we need to add them manually.
array(
'date_query',
'exact',
'ignore_sticky_posts',
'lazy_load_term_meta',
'meta_compare_key',
'meta_compare',
'meta_query',
'meta_type_key',
'meta_type',
'nopaging',
'offset',
'order',
'orderby',
'page',
'post_type',
'posts_per_page',
'suppress_filters',
'tax_query',
)
);

return $this->valid_query_vars;
}

/**
* Merge two array recursively but replace the non-array values instead of
* merging them. The merging strategy:
*
* - If keys from merge array doesn't exist in the base array, create them.
* - For array items with numeric keys, we merge them as normal.
* - For array items with string keys:
*
* - If the value isn't array, we'll use the value comming from the merge array.
* $base = ['orderby' => 'date']
* $new = ['orderby' => 'meta_value_num']
* Result: ['orderby' => 'meta_value_num']
*
* - If the value is array, we'll use recursion to merge each key.
* $base = ['meta_query' => [
* [
* 'key' => '_stock_status',
* 'compare' => 'IN'
* 'value' => ['instock', 'onbackorder']
* ]
* ]]
* $new = ['meta_query' => [
* [
* 'relation' => 'AND',
* [...<max_price_query>],
* [...<min_price_query>],
* ]
* ]]
* Result: ['meta_query' => [
* [
* 'key' => '_stock_status',
* 'compare' => 'IN'
* 'value' => ['instock', 'onbackorder']
* ],
* [
* 'relation' => 'AND',
* [...<max_price_query>],
* [...<min_price_query>],
* ]
* ]]
*
* $base = ['post__in' => [1, 2, 3, 4, 5]]
* $new = ['post__in' => [3, 4, 5, 6, 7]]
* Result: ['post__in' => [1, 2, 3, 4, 5, 3, 4, 5, 6, 7]]
*
* @param array $base First array.
* @param array $new Second array.
*/
private function array_merge_recursive_replace_non_array_properties( $base, $new ) {
foreach ( $new as $key => $value ) {
if ( is_numeric( $key ) ) {
$base[] = $value;
} else {
if ( is_array( $value ) ) {
if ( ! isset( $base[ $key ] ) ) {
$base[ $key ] = array();
}
$base[ $key ] = $this->array_merge_recursive_replace_non_array_properties( $base[ $key ], $value );
} else {
$base[ $key ] = $value;
}
}
}

return $base;
}

/**
* Get product-related query variables from the global query.
*
Expand Down Expand Up @@ -582,3 +674,4 @@ private function get_global_query( $parsed_block ) {
}

}

0 comments on commit 1f587b6

Please sign in to comment.