Product Query - add support for the global query (https://github.com/woocommerce/woocommerce-blocks/pull/7382)

* 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

* Product Query - Add support for the Filter By Attributes block woocommerce/woocommerce-blocks#6790

Product Query - Add support for the Filter By Attributes block

* fix bugged pagination and on-sale filter after refactor

* address feedback

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

Product Query - Add support for the Filter By Stock Block

* Fix filter blocks: the data (e.g: max price or stock-status) match the variation woocommerce/woocommerce-blocks#7245

fix filter blocks: the data (e.g: max price or stock-status) match the variation

* rename allowControls to allowedControls

* add support to the global query

* fix eslint error

* bot: update checkstyle.xml

* Update src/BlockTypes/ProductQuery.php

Co-authored-by: Tung Du <dinhtungdu@gmail.com>

* fix global query generation

* bot: update checkstyle.xml

* try: refactor merge_queries

* remove debug code

* fix: unpack assoc array php 7.4

* try: refactor merge_queries to take any form of input without unpacking
and preparing the input arrays

* add missing query vars

* add feature flag

* updates comment

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Tung Du <dinhtungdu@gmail.com>
This commit is contained in:
Luigi Teschio 2022-11-28 15:31:31 +01:00 committed by GitHub
parent c7bfa1d89c
commit 58423a2025
5 changed files with 142 additions and 51 deletions

View File

@ -143,6 +143,18 @@ export const TOOLS_PANEL_CONTROLS = {
</ToolsPanelItem>
);
},
wooInherit: ( props: ProductQueryBlock ) => (
<ToggleControl
label={ __(
'Woo Inherit query from template',
'woo-gutenberg-products-block'
) }
checked={ props.attributes.query.__woocommerceInherit || false }
onChange={ ( __woocommerceInherit ) => {
setQueryAttribute( props, { __woocommerceInherit } );
} }
/>
),
};
export const withProductQueryControls =

View File

@ -40,6 +40,7 @@ export interface ProductQueryArguments {
* ```
*/
__woocommerceOnSale?: boolean;
__woocommerceInherit?: boolean;
/**
* Filter products by their stock status.
*

View File

@ -19,6 +19,12 @@ import {
const VARIATION_NAME = 'woocommerce/product-query';
// This is a feature flag to enable the custom inherit Global Query implementation.
// This is not intended to be a permanent feature flag, but rather a temporary.
// It is also necessary to enable this feature flag on the PHP side: `src/BlockTypes/ProductQuery.php:49`.
// https://github.com/woocommerce/woocommerce-blocks/pull/7382
const isCustomInheritGlobalQueryImplementationEnabled = false;
if ( isExperimentalBuild() ) {
registerBlockVariation( QUERY_LOOP_ID, {
name: VARIATION_NAME,
@ -41,7 +47,9 @@ if ( isExperimentalBuild() ) {
// https://github.com/WordPress/gutenberg/pull/43632
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
allowedControls: DEFAULT_ALLOWED_CONTROLS,
allowedControls: isCustomInheritGlobalQueryImplementationEnabled
? [ ...DEFAULT_ALLOWED_CONTROLS, 'wooInherit' ]
: DEFAULT_ALLOWED_CONTROLS,
innerBlocks: INNER_BLOCKS_TEMPLATE,
scope: [ 'block', 'inserter' ],
} );

View File

@ -3420,7 +3420,7 @@
<error line="14" column="2" severity="error" message="Module &apos;&quot;@wordpress/components&quot;&apos; has no exported member &apos;__experimentalToolsPanel&apos;." source="TS2305" />
<error line="16" column="2" severity="error" message="Module &apos;&quot;@wordpress/components&quot;&apos; has no exported member &apos;__experimentalToolsPanelItem&apos;." source="TS2305" />
<error line="51" column="6" severity="error" message="Property &apos;getBlockVariations&apos; does not exist on type &apos;typeof import(&quot;/home/runner/work/woocommerce-blocks/woocommerce-blocks/node_modules/@types/wordpress__blocks/store/selectors&quot;)&apos;." source="TS2339" />
<error line="118" column="6" severity="error" message="Type &apos;{ label: string; onChange: (statusLabels: readonly Value[]) =&gt; void; suggestions: string[]; validateInput: (value: string) =&gt; boolean; value: string[]; __experimentalExpandOnFocus: boolean; }&apos; is not assignable to type &apos;IntrinsicAttributes &amp; Props &amp; { children?: ReactNode; }&apos;.
<error line="130" column="6" severity="error" message="Type &apos;{ label: string; onChange: (statusLabels: readonly Value[]) =&gt; void; suggestions: string[]; validateInput: (value: string) =&gt; boolean; value: string[]; __experimentalExpandOnFocus: boolean; }&apos; is not assignable to type &apos;IntrinsicAttributes &amp; Props &amp; { children?: ReactNode; }&apos;.
Property &apos;label&apos; does not exist on type &apos;IntrinsicAttributes &amp; Props &amp; { children?: ReactNode; }&apos;." source="TS2322" />
</file>
<file name="assets/js/blocks/product-search/block.js">

View File

@ -1,6 +1,8 @@
<?php
namespace Automattic\WooCommerce\Blocks\BlockTypes;
use WP_Query;
// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_tax_query
// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_query
// phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key
@ -37,6 +39,15 @@ class ProductQuery extends AbstractBlock {
*/
protected $attributes_filter_query_args = array();
/** This is a feature flag to enable the custom inherit Global Query implementation.
* This is not intended to be a permanent feature flag, but rather a temporary.
* It is also necessary to enable this feature flag on the PHP side: `assets/js/blocks/product-query/variations/product-query.tsx:26`.
* https://github.com/woocommerce/woocommerce-blocks/pull/7382
*
* @var boolean
*/
protected $is_custom_inherit_global_query_implementation_enabled = false;
/**
* Initialize this block type.
*
@ -132,41 +143,24 @@ class ProductQuery extends AbstractBlock {
'tax_query' => array(),
);
$queries_by_attributes = $this->get_queries_by_attributes( $parsed_block );
$queries_by_filters = $this->get_queries_by_applied_filters();
$orderby_query = $this->get_custom_orderby_query( $query['orderby'] );
$base_query = array_merge(
return $this->merge_queries(
$common_query_values,
$orderby_query
);
return array_reduce(
array_merge(
$queries_by_attributes,
$queries_by_filters
),
function( $acc, $query ) {
return $this->merge_queries( $acc, $query );
},
$base_query
$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()
);
}
/**
* Return the product ids based on the attributes.
* Return the product ids based on the attributes and global query.
* This is used to allow the filter blocks to render data that matches with variations. More details here: https://github.com/woocommerce/woocommerce-blocks/issues/7245
*
* @param array $parsed_block The block being rendered.
* @return array
*/
private function get_products_ids_by_attributes( $parsed_block ) {
$queries_by_attributes = $this->get_queries_by_attributes( $parsed_block );
$query = array_reduce(
$queries_by_attributes,
function( $acc, $query ) {
return $this->merge_queries( $acc, $query );
},
$query = $this->merge_queries(
array(
'post_type' => 'product',
'post__in' => array(),
@ -174,7 +168,9 @@ class ProductQuery extends AbstractBlock {
'posts_per_page' => -1,
'meta_query' => array(),
'tax_query' => array(),
)
),
$this->get_queries_by_attributes( $parsed_block ),
$this->get_global_query( $parsed_block )
);
$products = new \WP_Query( $query );
@ -186,16 +182,68 @@ class ProductQuery extends AbstractBlock {
/**
* Merge in the first parameter the keys "post_in", "meta_query" and "tax_query" of the second parameter.
*
* @param array $a The first query.
* @param array $b The second query.
* @param array[] ...$queries Query arrays to be merged.
* @return array
*/
private function merge_queries( $a, $b ) {
$a['post__in'] = ( isset( $b['post__in'] ) && ! empty( $b['post__in'] ) ) ? $this->intersect_arrays_when_not_empty( $a['post__in'], $b['post__in'] ) : $a['post__in'];
$a['meta_query'] = ( isset( $b['meta_query'] ) && ! empty( $b['meta_query'] ) ) ? array_merge( $a['meta_query'], array( $b['meta_query'] ) ) : $a['meta_query'];
$a['tax_query'] = ( isset( $b['tax_query'] ) && ! empty( $b['tax_query'] ) ) ? array_merge( $a['tax_query'], array( $b['tax_query'] ) ) : $a['tax_query'];
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',
)
);
return $a;
$merged_query = array_reduce(
$queries,
function( $acc, $query ) use ( $valid_query_vars ) {
if ( ! is_array( $query ) ) {
return $acc;
}
if ( empty( array_intersect( $valid_query_vars, array_keys( $query ) ) ) ) {
return $this->merge_queries( $acc, ...array_values( $query ) );
}
return array_merge_recursive( $acc, $query );
},
array()
);
/**
* If there are duplicated items in post__in, it means that we need to
* use the intersection of the results, which in this case, are the
* duplicated items.
*/
if (
! empty( $merged_query['post__in'] ) &&
count( $merged_query['post__in'] ) > count( array_unique( $merged_query['post__in'] ) )
) {
$merged_query['post__in'] = array_unique(
array_diff(
$merged_query['post__in'],
array_unique( $merged_query['post__in'] )
)
);
}
return $merged_query;
}
/**
@ -258,9 +306,11 @@ class ProductQuery extends AbstractBlock {
private function get_stock_status_query( $stock_statii ) {
return array(
'meta_query' => array(
'key' => '_stock_status',
'value' => (array) $stock_statii,
'compare' => 'IN',
array(
'key' => '_stock_status',
'value' => (array) $stock_statii,
'compare' => 'IN',
),
),
);
}
@ -493,22 +543,42 @@ class ProductQuery extends AbstractBlock {
}
/**
* Intersect arrays neither of them are empty, otherwise merge them.
* Get product-related query variables from the global query.
*
* @param array $parsed_block The Product Query that being rendered.
*
* @param array ...$arrays Arrays.
* @return array
*/
private function intersect_arrays_when_not_empty( ...$arrays ) {
return array_reduce(
$arrays,
function( $acc, $array ) {
if ( ! empty( $array ) && ! empty( $acc ) ) {
return array_intersect( $acc, $array );
}
return array_merge( $acc, $array );
},
array()
);
private function get_global_query( $parsed_block ) {
if ( ! $this->is_custom_inherit_global_query_implementation_enabled ) {
return array();
}
global $wp_query;
$inherit_enabled = isset( $parsed_block['attrs']['query']['__woocommerceInherit'] ) && true === $parsed_block['attrs']['query']['__woocommerceInherit'];
if ( ! $inherit_enabled ) {
return array();
}
$query = array();
if ( isset( $wp_query->query_vars['taxonomy'] ) && isset( $wp_query->query_vars['term'] ) ) {
$query['tax_query'] = array(
array(
'taxonomy' => $wp_query->query_vars['taxonomy'],
'field' => 'slug',
'terms' => $wp_query->query_vars['term'],
),
);
}
if ( isset( $wp_query->query_vars['s'] ) ) {
$query['s'] = $wp_query->query_vars['s'];
}
return $query;
}
}