Product Query: Add product visibility query support (https://github.com/woocommerce/woocommerce-blocks/pull/7951)

This commit is contained in:
Tung Du 2022-12-19 21:05:16 +07:00 committed by GitHub
parent e22d6e7fcf
commit b02b7f9348
2 changed files with 161 additions and 14 deletions

View File

@ -127,8 +127,9 @@ class ProductQuery extends AbstractBlock {
$orderby_query = isset( $orderby ) ? $this->get_custom_orderby_query( $orderby ) : array(); $orderby_query = isset( $orderby ) ? $this->get_custom_orderby_query( $orderby ) : array();
$attributes_query = is_array( $woo_attributes ) ? $this->get_product_attributes_query( $woo_attributes ) : array(); $attributes_query = is_array( $woo_attributes ) ? $this->get_product_attributes_query( $woo_attributes ) : array();
$stock_query = is_array( $woo_stock_status ) ? $this->get_stock_status_query( $woo_stock_status ) : array(); $stock_query = is_array( $woo_stock_status ) ? $this->get_stock_status_query( $woo_stock_status ) : array();
$visibility_query = $this->get_product_visibility_query( $stock_query );
return array_merge( $args, $on_sale_query, $orderby_query, $attributes_query, $stock_query ); return array_merge( $args, $on_sale_query, $orderby_query, $attributes_query, $stock_query, $visibility_query );
} }
/** /**
@ -325,6 +326,34 @@ class ProductQuery extends AbstractBlock {
* @return array * @return array
*/ */
private function get_stock_status_query( $stock_statii ) { private function get_stock_status_query( $stock_statii ) {
if ( ! is_array( $stock_statii ) ) {
return array();
}
$stock_status_options = array_keys( wc_get_product_stock_status_options() );
/**
* If all available stock status are selected, we don't need to add the
* meta query for stock status.
*/
if (
count( $stock_statii ) === count( $stock_status_options ) &&
array_diff( $stock_statii, $stock_status_options ) === array_diff( $stock_status_options, $stock_statii )
) {
return array();
}
/**
* If all stock statuses are selected except 'outofstock', we use the
* product visibility query to filter out out of stock products.
*
* @see get_product_visibility_query()
*/
$diff = array_diff( $stock_status_options, $stock_statii );
if ( count( $diff ) === 1 && in_array( 'outofstock', $diff, true ) ) {
return array();
}
return array( return array(
'meta_query' => array( 'meta_query' => array(
array( array(
@ -336,6 +365,34 @@ class ProductQuery extends AbstractBlock {
); );
} }
/**
* Return a query for product visibility depending on their stock status.
*
* @param array $stock_query Stock status query.
*
* @return array Tax query for product visibility.
*/
private function get_product_visibility_query( $stock_query ) {
$product_visibility_terms = wc_get_product_visibility_term_ids();
$product_visibility_not_in = array( is_search() ? $product_visibility_terms['exclude-from-search'] : $product_visibility_terms['exclude-from-catalog'] );
// Hide out of stock products.
if ( empty( $stock_query ) && 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
$product_visibility_not_in[] = $product_visibility_terms['outofstock'];
}
return array(
'tax_query' => array(
array(
'taxonomy' => 'product_visibility',
'field' => 'term_taxonomy_id',
'terms' => $product_visibility_not_in,
'operator' => 'NOT IN',
),
),
);
}
/** /**
* Set the query vars that are used by filter blocks. * Set the query vars that are used by filter blocks.
* *
@ -439,11 +496,13 @@ class ProductQuery extends AbstractBlock {
$on_sale_enabled = isset( $query['__woocommerceOnSale'] ) && true === $query['__woocommerceOnSale']; $on_sale_enabled = isset( $query['__woocommerceOnSale'] ) && true === $query['__woocommerceOnSale'];
$attributes_query = isset( $query['__woocommerceAttributes'] ) ? $this->get_product_attributes_query( $query['__woocommerceAttributes'] ) : array(); $attributes_query = isset( $query['__woocommerceAttributes'] ) ? $this->get_product_attributes_query( $query['__woocommerceAttributes'] ) : array();
$stock_query = isset( $query['__woocommerceStockStatus'] ) ? $this->get_stock_status_query( $query['__woocommerceStockStatus'] ) : array(); $stock_query = isset( $query['__woocommerceStockStatus'] ) ? $this->get_stock_status_query( $query['__woocommerceStockStatus'] ) : array();
$visibility_query = $this->get_product_visibility_query( $stock_query );
return array( return array(
'on_sale' => ( $on_sale_enabled ? $this->get_on_sale_products_query() : array() ), 'on_sale' => ( $on_sale_enabled ? $this->get_on_sale_products_query() : array() ),
'attributes' => $attributes_query, 'attributes' => $attributes_query,
'stock_status' => $stock_query, 'stock_status' => $stock_query,
'visibility' => $visibility_query,
); );
} }

View File

@ -89,7 +89,10 @@ class ProductQuery extends \WP_UnitTestCase {
foreach ( $on_sale_product_ids as $id ) { foreach ( $on_sale_product_ids as $id ) {
$this->assertContainsEquals( $id, $merged_query['post__in'] ); $this->assertContainsEquals( $id, $merged_query['post__in'] );
} }
$this->assertCount( 4, $merged_query['post__in'] ); $this->assertCount( 4, $merged_query['post__in'] );
delete_transient( 'wc_products_onsale' );
} }
/** /**
@ -112,24 +115,34 @@ class ProductQuery extends \WP_UnitTestCase {
), ),
$merged_query['meta_query'] $merged_query['meta_query']
); );
}
/**
* Test merging default stock queries that should use product visibility
* queries instead of meta query for stock status.
*/
public function test_merging_default_stock_queries() {
$parsed_block = $this->get_base_parsed_block();
$parsed_block['attrs']['query']['__woocommerceStockStatus'] = array(
'instock',
'outofstock',
'onbackorder',
);
$merged_query = $this->initialize_merged_query( $parsed_block );
$this->assertEmpty( $merged_query['meta_query'] );
// Test with hide out of stock items option enabled.
$parsed_block = $this->get_base_parsed_block(); $parsed_block = $this->get_base_parsed_block();
$parsed_block['attrs']['query']['__woocommerceStockStatus'] = array( $parsed_block['attrs']['query']['__woocommerceStockStatus'] = array(
'instock', 'instock',
'onbackorder', 'onbackorder',
); );
$this->block_instance->set_parsed_block( $parsed_block );
$merged_query = $this->block_instance->build_query( $parsed_block['attrs']['query'] ); $merged_query = $this->initialize_merged_query( $parsed_block );
$this->assertContainsEquals( $this->assertEmpty( $merged_query['meta_query'] );
array(
'compare' => 'IN',
'key' => '_stock_status',
'value' => array( 'instock', 'onbackorder' ),
),
$merged_query['meta_query']
);
} }
/** /**
@ -201,6 +214,57 @@ class ProductQuery extends \WP_UnitTestCase {
$this->assertEquals( 'total_sales', $merged_query['meta_key'] ); $this->assertEquals( 'total_sales', $merged_query['meta_key'] );
} }
/**
* Test product visibility query exist in merged query.
*/
public function test_product_visibility_query_exist_in_merged_query() {
$product_visibility_terms = wc_get_product_visibility_term_ids();
$product_visibility_not_in = array( is_search() ? $product_visibility_terms['exclude-from-search'] : $product_visibility_terms['exclude-from-catalog'] );
$parsed_block = $this->get_base_parsed_block();
$merged_query = $this->initialize_merged_query( $parsed_block );
$this->assertContainsEquals(
array(
'taxonomy' => 'product_visibility',
'field' => 'term_taxonomy_id',
'terms' => $product_visibility_not_in,
'operator' => 'NOT IN',
),
$merged_query['tax_query']
);
$fn = function() {
return 'yes';
};
// Test with hide out of stock items option enabled.
add_filter(
'pre_option_woocommerce_hide_out_of_stock_items',
$fn
);
$product_visibility_not_in[] = $product_visibility_terms['outofstock'];
$parsed_block = $this->get_base_parsed_block();
$merged_query = $this->initialize_merged_query( $parsed_block );
$this->assertContainsEquals(
array(
'taxonomy' => 'product_visibility',
'field' => 'term_taxonomy_id',
'terms' => $product_visibility_not_in,
'operator' => 'NOT IN',
),
$merged_query['tax_query']
);
remove_filter(
'pre_option_woocommerce_hide_out_of_stock_items',
$fn
);
}
/** /**
* Test merging multiple queries. * Test merging multiple queries.
*/ */
@ -209,7 +273,7 @@ class ProductQuery extends \WP_UnitTestCase {
$parsed_block['attrs']['query']['orderBy'] = 'rating'; $parsed_block['attrs']['query']['orderBy'] = 'rating';
$parsed_block['attrs']['query']['__woocommerceStockStatus'] = array( $parsed_block['attrs']['query']['__woocommerceStockStatus'] = array(
'instock', 'instock',
'onbackorder', 'outofstock',
); );
$parsed_block['attrs']['query']['__woocommerceAttributes'] = array( $parsed_block['attrs']['query']['__woocommerceAttributes'] = array(
array( array(
@ -230,7 +294,7 @@ class ProductQuery extends \WP_UnitTestCase {
array( array(
'compare' => 'IN', 'compare' => 'IN',
'key' => '_stock_status', 'key' => '_stock_status',
'value' => array( 'instock', 'onbackorder' ), 'value' => array( 'instock', 'outofstock' ),
), ),
$merged_query['meta_query'] $merged_query['meta_query']
); );
@ -266,6 +330,7 @@ class ProductQuery extends \WP_UnitTestCase {
), ),
$merged_query['meta_query'] $merged_query['meta_query']
); );
set_query_var( 'max_price', '' );
} }
/** /**
@ -289,6 +354,7 @@ class ProductQuery extends \WP_UnitTestCase {
), ),
$merged_query['meta_query'] $merged_query['meta_query']
); );
set_query_var( 'min_price', '' );
} }
/** /**
@ -318,6 +384,9 @@ class ProductQuery extends \WP_UnitTestCase {
), ),
$merged_query['meta_query'] $merged_query['meta_query']
); );
set_query_var( 'max_price', '' );
set_query_var( 'min_price', '' );
} }
/** /**
@ -336,6 +405,8 @@ class ProductQuery extends \WP_UnitTestCase {
), ),
$merged_query['meta_query'] $merged_query['meta_query']
); );
set_query_var( 'filter_stock_status', '' );
} }
/** /**
@ -363,8 +434,16 @@ class ProductQuery extends \WP_UnitTestCase {
$merged_query = $this->initialize_merged_query(); $merged_query = $this->initialize_merged_query();
$attribute_tax_query = $merged_query['tax_query'][0]; $attribute_tax_query = array();
foreach ( $merged_query['tax_query'] as $tax_query ) {
if ( isset( $tax_query['relation'] ) ) {
$attribute_tax_query = $tax_query;
}
}
$attribute_tax_query_queries = $attribute_tax_query[0]; $attribute_tax_query_queries = $attribute_tax_query[0];
$this->assertEquals( 'AND', $attribute_tax_query['relation'] ); $this->assertEquals( 'AND', $attribute_tax_query['relation'] );
$this->assertContainsEquals( $this->assertContainsEquals(
@ -385,6 +464,11 @@ class ProductQuery extends \WP_UnitTestCase {
), ),
$attribute_tax_query_queries $attribute_tax_query_queries
); );
set_query_var( 'filter_color', '' );
set_query_var( 'query_type_color', '' );
set_query_var( 'filter_size', '' );
set_query_var( 'query_type_size', '' );
} }
/** /**
@ -424,6 +508,10 @@ class ProductQuery extends \WP_UnitTestCase {
), ),
$merged_query['meta_query'] $merged_query['meta_query']
); );
set_query_var( 'max_price', '' );
set_query_var( 'min_price', '' );
set_query_var( 'filter_stock_status', '' );
} }
} }