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

Commit 924c823

Browse files
authored
Product Query: Add product visibility query support (#7951)
1 parent a4e6854 commit 924c823

File tree

2 files changed

+160
-13
lines changed

2 files changed

+160
-13
lines changed

src/BlockTypes/ProductQuery.php

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,9 @@ public function update_rest_query( $args, $request ) {
127127
$orderby_query = isset( $orderby ) ? $this->get_custom_orderby_query( $orderby ) : array();
128128
$attributes_query = is_array( $woo_attributes ) ? $this->get_product_attributes_query( $woo_attributes ) : array();
129129
$stock_query = is_array( $woo_stock_status ) ? $this->get_stock_status_query( $woo_stock_status ) : array();
130+
$visibility_query = $this->get_product_visibility_query( $stock_query );
130131

131-
return array_merge( $args, $on_sale_query, $orderby_query, $attributes_query, $stock_query );
132+
return array_merge( $args, $on_sale_query, $orderby_query, $attributes_query, $stock_query, $visibility_query );
132133
}
133134

134135
/**
@@ -325,6 +326,34 @@ function ( $carry, $item ) {
325326
* @return array
326327
*/
327328
private function get_stock_status_query( $stock_statii ) {
329+
if ( ! is_array( $stock_statii ) ) {
330+
return array();
331+
}
332+
333+
$stock_status_options = array_keys( wc_get_product_stock_status_options() );
334+
335+
/**
336+
* If all available stock status are selected, we don't need to add the
337+
* meta query for stock status.
338+
*/
339+
if (
340+
count( $stock_statii ) === count( $stock_status_options ) &&
341+
array_diff( $stock_statii, $stock_status_options ) === array_diff( $stock_status_options, $stock_statii )
342+
) {
343+
return array();
344+
}
345+
346+
/**
347+
* If all stock statuses are selected except 'outofstock', we use the
348+
* product visibility query to filter out out of stock products.
349+
*
350+
* @see get_product_visibility_query()
351+
*/
352+
$diff = array_diff( $stock_status_options, $stock_statii );
353+
if ( count( $diff ) === 1 && in_array( 'outofstock', $diff, true ) ) {
354+
return array();
355+
}
356+
328357
return array(
329358
'meta_query' => array(
330359
array(
@@ -336,6 +365,34 @@ private function get_stock_status_query( $stock_statii ) {
336365
);
337366
}
338367

368+
/**
369+
* Return a query for product visibility depending on their stock status.
370+
*
371+
* @param array $stock_query Stock status query.
372+
*
373+
* @return array Tax query for product visibility.
374+
*/
375+
private function get_product_visibility_query( $stock_query ) {
376+
$product_visibility_terms = wc_get_product_visibility_term_ids();
377+
$product_visibility_not_in = array( is_search() ? $product_visibility_terms['exclude-from-search'] : $product_visibility_terms['exclude-from-catalog'] );
378+
379+
// Hide out of stock products.
380+
if ( empty( $stock_query ) && 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
381+
$product_visibility_not_in[] = $product_visibility_terms['outofstock'];
382+
}
383+
384+
return array(
385+
'tax_query' => array(
386+
array(
387+
'taxonomy' => 'product_visibility',
388+
'field' => 'term_taxonomy_id',
389+
'terms' => $product_visibility_not_in,
390+
'operator' => 'NOT IN',
391+
),
392+
),
393+
);
394+
}
395+
339396
/**
340397
* Set the query vars that are used by filter blocks.
341398
*
@@ -439,11 +496,13 @@ private function get_queries_by_attributes( $parsed_block ) {
439496
$on_sale_enabled = isset( $query['__woocommerceOnSale'] ) && true === $query['__woocommerceOnSale'];
440497
$attributes_query = isset( $query['__woocommerceAttributes'] ) ? $this->get_product_attributes_query( $query['__woocommerceAttributes'] ) : array();
441498
$stock_query = isset( $query['__woocommerceStockStatus'] ) ? $this->get_stock_status_query( $query['__woocommerceStockStatus'] ) : array();
499+
$visibility_query = $this->get_product_visibility_query( $stock_query );
442500

443501
return array(
444502
'on_sale' => ( $on_sale_enabled ? $this->get_on_sale_products_query() : array() ),
445503
'attributes' => $attributes_query,
446504
'stock_status' => $stock_query,
505+
'visibility' => $visibility_query,
447506
);
448507
}
449508

tests/php/BlockTypes/ProductQuery.php

Lines changed: 100 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,10 @@ public function test_merging_on_sale_queries() {
8989
foreach ( $on_sale_product_ids as $id ) {
9090
$this->assertContainsEquals( $id, $merged_query['post__in'] );
9191
}
92+
9293
$this->assertCount( 4, $merged_query['post__in'] );
94+
95+
delete_transient( 'wc_products_onsale' );
9396
}
9497

9598
/**
@@ -112,24 +115,34 @@ public function test_merging_stock_status_queries() {
112115
),
113116
$merged_query['meta_query']
114117
);
118+
}
115119

120+
/**
121+
* Test merging default stock queries that should use product visibility
122+
* queries instead of meta query for stock status.
123+
*/
124+
public function test_merging_default_stock_queries() {
116125
$parsed_block = $this->get_base_parsed_block();
117126
$parsed_block['attrs']['query']['__woocommerceStockStatus'] = array(
118127
'instock',
128+
'outofstock',
119129
'onbackorder',
120130
);
121-
$this->block_instance->set_parsed_block( $parsed_block );
122131

123-
$merged_query = $this->block_instance->build_query( $parsed_block['attrs']['query'] );
132+
$merged_query = $this->initialize_merged_query( $parsed_block );
124133

125-
$this->assertContainsEquals(
126-
array(
127-
'compare' => 'IN',
128-
'key' => '_stock_status',
129-
'value' => array( 'instock', 'onbackorder' ),
130-
),
131-
$merged_query['meta_query']
134+
$this->assertEmpty( $merged_query['meta_query'] );
135+
136+
// Test with hide out of stock items option enabled.
137+
$parsed_block = $this->get_base_parsed_block();
138+
$parsed_block['attrs']['query']['__woocommerceStockStatus'] = array(
139+
'instock',
140+
'onbackorder',
132141
);
142+
143+
$merged_query = $this->initialize_merged_query( $parsed_block );
144+
145+
$this->assertEmpty( $merged_query['meta_query'] );
133146
}
134147

135148
/**
@@ -201,6 +214,57 @@ public function test_merging_order_by_popularity_queries() {
201214
$this->assertEquals( 'total_sales', $merged_query['meta_key'] );
202215
}
203216

217+
/**
218+
* Test product visibility query exist in merged query.
219+
*/
220+
public function test_product_visibility_query_exist_in_merged_query() {
221+
$product_visibility_terms = wc_get_product_visibility_term_ids();
222+
$product_visibility_not_in = array( is_search() ? $product_visibility_terms['exclude-from-search'] : $product_visibility_terms['exclude-from-catalog'] );
223+
224+
$parsed_block = $this->get_base_parsed_block();
225+
226+
$merged_query = $this->initialize_merged_query( $parsed_block );
227+
228+
$this->assertContainsEquals(
229+
array(
230+
'taxonomy' => 'product_visibility',
231+
'field' => 'term_taxonomy_id',
232+
'terms' => $product_visibility_not_in,
233+
'operator' => 'NOT IN',
234+
),
235+
$merged_query['tax_query']
236+
);
237+
238+
$fn = function() {
239+
return 'yes';
240+
};
241+
242+
// Test with hide out of stock items option enabled.
243+
add_filter(
244+
'pre_option_woocommerce_hide_out_of_stock_items',
245+
$fn
246+
);
247+
$product_visibility_not_in[] = $product_visibility_terms['outofstock'];
248+
249+
$parsed_block = $this->get_base_parsed_block();
250+
251+
$merged_query = $this->initialize_merged_query( $parsed_block );
252+
253+
$this->assertContainsEquals(
254+
array(
255+
'taxonomy' => 'product_visibility',
256+
'field' => 'term_taxonomy_id',
257+
'terms' => $product_visibility_not_in,
258+
'operator' => 'NOT IN',
259+
),
260+
$merged_query['tax_query']
261+
);
262+
remove_filter(
263+
'pre_option_woocommerce_hide_out_of_stock_items',
264+
$fn
265+
);
266+
}
267+
204268
/**
205269
* Test merging multiple queries.
206270
*/
@@ -209,7 +273,7 @@ public function test_merging_multiple_queries() {
209273
$parsed_block['attrs']['query']['orderBy'] = 'rating';
210274
$parsed_block['attrs']['query']['__woocommerceStockStatus'] = array(
211275
'instock',
212-
'onbackorder',
276+
'outofstock',
213277
);
214278
$parsed_block['attrs']['query']['__woocommerceAttributes'] = array(
215279
array(
@@ -230,7 +294,7 @@ public function test_merging_multiple_queries() {
230294
array(
231295
'compare' => 'IN',
232296
'key' => '_stock_status',
233-
'value' => array( 'instock', 'onbackorder' ),
297+
'value' => array( 'instock', 'outofstock' ),
234298
),
235299
$merged_query['meta_query']
236300
);
@@ -266,6 +330,7 @@ public function test_merging_filter_by_max_price_queries() {
266330
),
267331
$merged_query['meta_query']
268332
);
333+
set_query_var( 'max_price', '' );
269334
}
270335

271336
/**
@@ -289,6 +354,7 @@ public function test_merging_filter_by_min_price_queries() {
289354
),
290355
$merged_query['meta_query']
291356
);
357+
set_query_var( 'min_price', '' );
292358
}
293359

294360
/**
@@ -318,6 +384,9 @@ public function test_merging_filter_by_min_and_max_price_queries() {
318384
),
319385
$merged_query['meta_query']
320386
);
387+
388+
set_query_var( 'max_price', '' );
389+
set_query_var( 'min_price', '' );
321390
}
322391

323392
/**
@@ -336,6 +405,8 @@ public function test_merging_filter_by_stock_status_queries() {
336405
),
337406
$merged_query['meta_query']
338407
);
408+
409+
set_query_var( 'filter_stock_status', '' );
339410
}
340411

341412
/**
@@ -363,8 +434,16 @@ public function test_merging_filter_by_attribute_queries() {
363434

364435
$merged_query = $this->initialize_merged_query();
365436

366-
$attribute_tax_query = $merged_query['tax_query'][0];
437+
$attribute_tax_query = array();
438+
439+
foreach ( $merged_query['tax_query'] as $tax_query ) {
440+
if ( isset( $tax_query['relation'] ) ) {
441+
$attribute_tax_query = $tax_query;
442+
}
443+
}
444+
367445
$attribute_tax_query_queries = $attribute_tax_query[0];
446+
368447
$this->assertEquals( 'AND', $attribute_tax_query['relation'] );
369448

370449
$this->assertContainsEquals(
@@ -385,6 +464,11 @@ public function test_merging_filter_by_attribute_queries() {
385464
),
386465
$attribute_tax_query_queries
387466
);
467+
468+
set_query_var( 'filter_color', '' );
469+
set_query_var( 'query_type_color', '' );
470+
set_query_var( 'filter_size', '' );
471+
set_query_var( 'query_type_size', '' );
388472
}
389473

390474
/**
@@ -424,6 +508,10 @@ public function test_merging_multiple_filter_queries() {
424508
),
425509
$merged_query['meta_query']
426510
);
511+
512+
set_query_var( 'max_price', '' );
513+
set_query_var( 'min_price', '' );
514+
set_query_var( 'filter_stock_status', '' );
427515
}
428516
}
429517

0 commit comments

Comments
 (0)