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:
parent
c7bfa1d89c
commit
58423a2025
|
@ -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 =
|
||||
|
|
|
@ -40,6 +40,7 @@ export interface ProductQueryArguments {
|
|||
* ```
|
||||
*/
|
||||
__woocommerceOnSale?: boolean;
|
||||
__woocommerceInherit?: boolean;
|
||||
/**
|
||||
* Filter products by their stock status.
|
||||
*
|
||||
|
|
|
@ -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' ],
|
||||
} );
|
||||
|
|
|
@ -3420,7 +3420,7 @@
|
|||
<error line="14" column="2" severity="error" message="Module '"@wordpress/components"' has no exported member '__experimentalToolsPanel'." source="TS2305" />
|
||||
<error line="16" column="2" severity="error" message="Module '"@wordpress/components"' has no exported member '__experimentalToolsPanelItem'." source="TS2305" />
|
||||
<error line="51" column="6" severity="error" message="Property 'getBlockVariations' does not exist on type 'typeof import("/home/runner/work/woocommerce-blocks/woocommerce-blocks/node_modules/@types/wordpress__blocks/store/selectors")'." source="TS2339" />
|
||||
<error line="118" column="6" severity="error" message="Type '{ label: string; onChange: (statusLabels: readonly Value[]) => void; suggestions: string[]; validateInput: (value: string) => boolean; value: string[]; __experimentalExpandOnFocus: boolean; }' is not assignable to type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.
|
||||
<error line="130" column="6" severity="error" message="Type '{ label: string; onChange: (statusLabels: readonly Value[]) => void; suggestions: string[]; validateInput: (value: string) => boolean; value: string[]; __experimentalExpandOnFocus: boolean; }' is not assignable to type 'IntrinsicAttributes & Props & { children?: ReactNode; }'.
|
||||
Property 'label' does not exist on type 'IntrinsicAttributes & Props & { children?: ReactNode; }'." source="TS2322" />
|
||||
</file>
|
||||
<file name="assets/js/blocks/product-search/block.js">
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue