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

Product Query - add support for the global query #7382

Merged
merged 63 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
16ea028
Product Query: Fix pagination issue
gigitux Sep 12, 2022
f19fd99
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Sep 14, 2022
816ffe9
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Sep 15, 2022
6e93dd0
Product Query - Add support for the Filter By Price Block #6790
gigitux Sep 15, 2022
b243528
fix query relation
gigitux Sep 16, 2022
e55a41d
fix on sale query
gigitux Sep 16, 2022
341d47b
Merge branch 'trunk' into add/price_filter_support
gigitux Sep 16, 2022
1fd15a8
Merge branch 'trunk' into add/price_filter_support
gigitux Sep 20, 2022
926f62c
Product Query - Add support for the Filter By Attributes block #6790
gigitux Sep 20, 2022
3176679
Merge branch 'trunk' into add/attribute_filter_support
gigitux Sep 21, 2022
1d56a2e
fix bugged pagination and on-sale filter after refactor
gigitux Sep 21, 2022
c9839f2
Merge branch 'add/price_filter_support' of https://github.com/woocomm…
gigitux Sep 21, 2022
9065ab3
Merge branch 'add/price_filter_support' of https://github.com/woocomm…
gigitux Sep 21, 2022
0be510e
Merge branch 'add/attribute_filter_support' of https://github.com/woo…
gigitux Sep 21, 2022
6f326eb
Merge ranch 'trunk' of https://github.com/woocommerce/woocommerce-blo…
gigitux Sep 22, 2022
5622639
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Sep 28, 2022
c22d149
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Sep 28, 2022
80a0dbf
address feedback
gigitux Sep 28, 2022
5be22b9
Product Query - Add support for the Filter By Stock Block #6790
gigitux Sep 29, 2022
b8bf17e
Fix filter blocks: the data (e.g: max price or stock-status) match th…
gigitux Sep 29, 2022
1bef270
Merge branch 'trunk' into fix/filter_display_data
gigitux Sep 29, 2022
c7e9773
Merge branch 'trunk' into fix/filter_display_data
gigitux Oct 7, 2022
b1b05f6
Merge branch 'trunk' into fix/filter_display_data
gigitux Oct 10, 2022
f20d7da
Merge branch 'trunk' into fix/filter_display_data
gigitux Oct 11, 2022
0ce3e42
rename allowControls to allowedControls
gigitux Oct 11, 2022
3d18a8e
Merge branch 'fix/allowed-controls-product-query' of https://github.c…
gigitux Oct 11, 2022
c34cae7
add support to the global query
gigitux Oct 12, 2022
327919a
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Oct 12, 2022
93a9df7
Merge branch 'trunk' into fix/product-query-global-query
gigitux Oct 12, 2022
fd187b0
fix eslint error
gigitux Oct 12, 2022
1d6993f
Merge branch 'fix/product-query-global-query' of https://github.com/w…
gigitux Oct 12, 2022
b5d401d
Merge branch 'trunk' into fix/product-query-global-query
gigitux Oct 13, 2022
202d587
Merge branch 'trunk' into fix/product-query-global-query
gigitux Oct 23, 2022
8718ab5
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Nov 2, 2022
322e3f8
Merge branch 'fix/product-query-global-query' of https://github.com/w…
gigitux Nov 2, 2022
2367c4c
Merge branch 'trunk' into fix/product-query-global-query
gigitux Nov 7, 2022
da7578b
bot: update checkstyle.xml
github-actions[bot] Nov 7, 2022
d8e43b7
Update src/BlockTypes/ProductQuery.php
gigitux Nov 7, 2022
6abaaaf
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Nov 7, 2022
6886d1b
fix global query generation
gigitux Nov 7, 2022
8982a87
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Nov 7, 2022
2c72ca0
Merge branch 'trunk' into fix/product-query-global-query
gigitux Nov 8, 2022
c650f59
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Nov 9, 2022
b722cb1
Merge branch 'trunk' into fix/product-query-global-query
gigitux Nov 14, 2022
3cdba16
bot: update checkstyle.xml
github-actions[bot] Nov 14, 2022
91f8a65
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Nov 14, 2022
780e5c0
Merge branch 'fix/product-query-global-query' of https://github.com/w…
gigitux Nov 14, 2022
a73a130
try: refactor merge_queries
dinhtungdu Nov 17, 2022
7c6a9a6
remove debug code
dinhtungdu Nov 17, 2022
679aa5d
Merge branch 'trunk' into refactor/merge_queries
dinhtungdu Nov 18, 2022
ba47bf6
Merge branch 'trunk' into refactor/merge_queries
dinhtungdu Nov 21, 2022
cd908d5
Merge branch 'trunk' into refactor/merge_queries
dinhtungdu Nov 24, 2022
0f37868
fix: unpack assoc array php 7.4
dinhtungdu Nov 24, 2022
c492ce6
try: refactor merge_queries to take any form of input without unpacking
dinhtungdu Nov 24, 2022
c8e315c
add missing query vars
dinhtungdu Nov 24, 2022
6905099
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Nov 24, 2022
dac0895
Merge branch 'refactor/merge_queries' of https://github.com/woocommer…
gigitux Nov 24, 2022
a1a6eb2
Merge branch 'trunk' into fix/product-query-global-query
gigitux Nov 25, 2022
bc3abe7
add feature flag
gigitux Nov 25, 2022
939faac
Merge branch 'trunk' into fix/product-query-global-query
gigitux Nov 28, 2022
90e224c
Merge branch 'trunk' of https://github.com/woocommerce/woocommerce-bl…
gigitux Nov 28, 2022
a5e4ea2
updates comment
gigitux Nov 28, 2022
b538fa9
Merge branch 'fix/product-query-global-query' of https://github.com/w…
gigitux Nov 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions assets/js/blocks/product-query/inspector-controls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
1 change: 1 addition & 0 deletions assets/js/blocks/product-query/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface ProductQueryArguments {
* ```
*/
__woocommerceOnSale?: boolean;
__woocommerceInherit?: boolean;
/**
* Filter products by their stock status.
*
Expand Down
9 changes: 8 additions & 1 deletion assets/js/blocks/product-query/variations/product-query.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ 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.
// https://github.com/woocommerce/woocommerce-blocks/pull/7382
const isCustomInheritGlobalQueryImplementationEnabled = false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about using an experimental flag here instead? I think we just need to limit the global query support to experimental/development build only. 🤔

Copy link
Contributor Author

@gigitux gigitux Nov 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we just need to limit the global query support to experimental/development build only.

At least for now, we want to show the option inherited query from the template from Gutenberg. The Product Query is a foundation for other blocks, too (for example, Buy it again), and having two inherit query from template options can be confusing for the developers that check the block for the first time.

Also, this is a super WIP code because there is still a discussion about how we should approach the problem: this is why I used this approach.

For me, It is fine to change it, but I think it could not be very clear.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Product Query is a foundation for other blocks, too (for example, Buy it again), and having two inherit query from template options can be confusing for the developers that check the block for the first time.

Make senses!

Can you explain how can we use this flag for development later? I mean what do we need to do to enable the flag? At glance, we have to temporarily change the flag in the source code, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain how can we use this flag for development later? I mean what do we need to do to enable the flag? At glance, we have to temporarily change the flag in the source code, right?

Yes! Just set isCustomInheritGlobalQueryImplementationEnabled and is_custom_inherit_global_query_implementation_enabled to true.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe adding a note here to update the PHP flag too? (and vice-versa)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense! I updated the comments!


if ( isExperimentalBuild() ) {
registerBlockVariation( QUERY_LOOP_ID, {
name: VARIATION_NAME,
Expand All @@ -41,7 +46,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' ],
} );
Expand Down
2 changes: 1 addition & 1 deletion checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
167 changes: 118 additions & 49 deletions src/BlockTypes/ProductQuery.php
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -37,6 +39,14 @@ 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.
* https://github.com/woocommerce/woocommerce-blocks/pull/7382
*
* @var boolean
*/
protected $is_custom_inherit_global_query_implementation_enabled = false;

/**
* Initialize this block type.
*
Expand Down Expand Up @@ -132,49 +142,34 @@ public function build_query( $query ) {
'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(),
'post_status' => 'publish',
'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 );
Expand All @@ -186,16 +181,68 @@ function( $acc, $query ) {
/**
* 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',
)
);

$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 $a;
return $merged_query;
}

/**
Expand Down Expand Up @@ -258,9 +305,11 @@ private function get_custom_orderby_query( $orderby ) {
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',
),
),
);
}
Expand Down Expand Up @@ -493,22 +542,42 @@ function( $stock_status ) {
}

/**
* 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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should also check if we're on a WooCommerce page before processing. For Product Query, we care about the Product Catalog (is_shop()) and product taxonomy archive pages (is_product_taxonomy()).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmm, not sure about this check. We want to use the Product Query for the Product Search template too.

In any case, I would say not to add any particular check here. In this way, 3rd developers could use the Product Query everywhere. The important thing is that they update the 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;
}

}