From 258e49a8de93e0f1ca8e0d7a4d584a41e2083547 Mon Sep 17 00:00:00 2001 From: Peter Fabian Date: Wed, 2 Oct 2019 14:58:40 +0200 Subject: [PATCH 1/5] Allow attribute value 0 to work correctly with variations (especially add to cart and select variation). --- includes/data-stores/class-wc-product-data-store-cpt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/data-stores/class-wc-product-data-store-cpt.php b/includes/data-stores/class-wc-product-data-store-cpt.php index a0ee3a32da1..3b538d7ea13 100644 --- a/includes/data-stores/class-wc-product-data-store-cpt.php +++ b/includes/data-stores/class-wc-product-data-store-cpt.php @@ -1112,7 +1112,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da // Loop over the variation meta keys and values i.e. what is saved to the products. Note: $attribute_value is empty when 'any' is in use. foreach ( $variation as $attribute_key => $attribute_value ) { - $match_any_value = empty( $attribute_value ); + $match_any_value = empty( $attribute_value ) && 0 != $attribute_value; if ( ! $match_any_value && ! array_key_exists( $attribute_key, $match_attributes ) ) { $match = false; // Requires a selection but no value was provide. From e45fe949c1b18169acbb931ea476ec97e84ff9e3 Mon Sep 17 00:00:00 2001 From: Peter Fabian Date: Wed, 2 Oct 2019 14:59:42 +0200 Subject: [PATCH 2/5] Added unit test & updated other affected tests. --- .../helpers/class-wc-helper-product.php | 46 ++++++++++++++++++- tests/unit-tests/product/data-store.php | 25 ++++++++-- tests/unit-tests/product/functions.php | 4 +- tests/unit-tests/templates/functions.php | 4 +- 4 files changed, 71 insertions(+), 8 deletions(-) diff --git a/tests/framework/helpers/class-wc-helper-product.php b/tests/framework/helpers/class-wc-helper-product.php index b8fc6da0435..3f9074fa88f 100644 --- a/tests/framework/helpers/class-wc-helper-product.php +++ b/tests/framework/helpers/class-wc-helper-product.php @@ -119,7 +119,7 @@ class WC_Helper_Product { $attributes = array(); $attribute = new WC_Product_Attribute(); - $attribute_data = self::create_attribute( 'size', array( 'small', 'large' ) ); + $attribute_data = self::create_attribute( 'size', array( 'small', 'large', 'huge' ) ); $attribute->set_id( $attribute_data['attribute_id'] ); $attribute->set_name( $attribute_data['attribute_taxonomy'] ); $attribute->set_options( $attribute_data['term_ids'] ); @@ -138,6 +138,16 @@ class WC_Helper_Product { $attribute->set_variation( true ); $attributes[] = $attribute; + $attribute = new WC_Product_Attribute(); + $attribute_data = self::create_attribute( 'number', array( '0', '1', '2' ) ); + $attribute->set_id( $attribute_data['attribute_id'] ); + $attribute->set_name( $attribute_data['attribute_taxonomy'] ); + $attribute->set_options( $attribute_data['term_ids'] ); + $attribute->set_position( 1 ); + $attribute->set_visible( true ); + $attribute->set_variation( true ); + $attributes[] = $attribute; + $product->set_attributes( $attributes ); $product->save(); @@ -163,6 +173,40 @@ class WC_Helper_Product { $variation_2->set_attributes( array( 'pa_size' => 'large' ) ); $variation_2->save(); + $variation_3 = new WC_Product_Variation(); + $variation_3->set_props( + array( + 'parent_id' => $product->get_id(), + 'sku' => 'DUMMY SKU VARIABLE HUGE RED 0', + 'regular_price' => 16, + ) + ); + $variation_3->set_attributes( + array( + 'pa_size' => 'huge', + 'pa_colour' => 'red', + 'pa_number' => '0', + ) + ); + $variation_3->save(); + + $variation_4 = new WC_Product_Variation(); + $variation_4->set_props( + array( + 'parent_id' => $product->get_id(), + 'sku' => 'DUMMY SKU VARIABLE HUGE RED 2', + 'regular_price' => 17, + ) + ); + $variation_4->set_attributes( + array( + 'pa_size' => 'huge', + 'pa_colour' => 'red', + 'pa_number' => '2', + ) + ); + $variation_4->save(); + return wc_get_product( $product->get_id() ); } diff --git a/tests/unit-tests/product/data-store.php b/tests/unit-tests/product/data-store.php index d6380fc8ac3..73c2c8febf7 100644 --- a/tests/unit-tests/product/data-store.php +++ b/tests/unit-tests/product/data-store.php @@ -216,22 +216,29 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case { $product = new WC_Product_Variable( $product->get_id() ); - $this->assertEquals( 2, count( $product->get_children() ) ); + $this->assertEquals( 4, count( $product->get_children() ) ); $expected_prices['price'][ $children[0] ] = 8.00; $expected_prices['price'][ $children[1] ] = 15.00; + $expected_prices['price'][ $children[2] ] = 16.00; + $expected_prices['price'][ $children[3] ] = 17.00; $expected_prices['regular_price'][ $children[0] ] = 10.00; $expected_prices['regular_price'][ $children[1] ] = 15.00; + $expected_prices['regular_price'][ $children[2] ] = 16.00; + $expected_prices['regular_price'][ $children[3] ] = 17.00; $expected_prices['sale_price'][ $children[0] ] = 8.00; $expected_prices['sale_price'][ $children[1] ] = 15.00; + $expected_prices['sale_price'][ $children[2] ] = 16.00; + $expected_prices['sale_price'][ $children[3] ] = 17.00; $this->assertEquals( $expected_prices, $product->get_variation_prices() ); $expected_attributes = array( - 'pa_size' => array( 'small', 'large' ), - 'pa_colour' => array( 'blue', 'red' ), + 'pa_size' => array( 'small', 'large', 'huge' ), + 'pa_colour' => array( 'red' ), + 'pa_number' => array( '0', '2' ), ); $this->assertEquals( $expected_attributes, $product->get_variation_attributes() ); } @@ -1035,5 +1042,17 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case { array() ); $this->assertEquals( 0, $match ); + + // Test numeric attribute values. + $match = $data_store->find_matching_product_variation( + $product, + array( + 'attribute_pa_size' => 'huge', + 'attribute_pa_colour' => 'red', + 'attribute_pa_number' => '2', + ) + ); + + $this->assertEquals( $children[3], $match ); } } diff --git a/tests/unit-tests/product/functions.php b/tests/unit-tests/product/functions.php index 1d9f2c70e1d..01ea4e0b40e 100644 --- a/tests/unit-tests/product/functions.php +++ b/tests/unit-tests/product/functions.php @@ -70,7 +70,7 @@ class WC_Tests_Product_Functions extends WC_Unit_Test_Case { 'type' => 'variation', ) ); - $this->assertCount( 2, $products ); + $this->assertCount( 4, $products ); // Test parent. $products = wc_get_products( @@ -80,7 +80,7 @@ class WC_Tests_Product_Functions extends WC_Unit_Test_Case { 'parent' => $variation->get_id(), ) ); - $this->assertCount( 2, $products ); + $this->assertCount( 4, $products ); // Test parent_exclude. $products = wc_get_products( diff --git a/tests/unit-tests/templates/functions.php b/tests/unit-tests/templates/functions.php index 48bafed9cb9..efc9d524bf4 100644 --- a/tests/unit-tests/templates/functions.php +++ b/tests/unit-tests/templates/functions.php @@ -87,7 +87,7 @@ class WC_Tests_Template_Functions extends WC_Unit_Test_Case { public function test_wc_dropdown_variation_attribute_options_should_return_attributes_list() { $product = WC_Helper_Product::create_variation_product(); - $this->expectOutputString( '' ); + $this->expectOutputString( '' ); wc_dropdown_variation_attribute_options( array( @@ -104,7 +104,7 @@ class WC_Tests_Template_Functions extends WC_Unit_Test_Case { $product = WC_Helper_Product::create_variation_product(); $_REQUEST['attribute_pa_size'] = 'large'; - $this->expectOutputString( '' ); + $this->expectOutputString( '' ); wc_dropdown_variation_attribute_options( array( From 7ea9fdec62101ebace376867e7f694f13f22280c Mon Sep 17 00:00:00 2001 From: Peter Fabian Date: Wed, 2 Oct 2019 15:06:22 +0200 Subject: [PATCH 3/5] Added unit test for special case of attribute value 0. --- tests/unit-tests/product/data-store.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/unit-tests/product/data-store.php b/tests/unit-tests/product/data-store.php index 73c2c8febf7..f39ca4db78d 100644 --- a/tests/unit-tests/product/data-store.php +++ b/tests/unit-tests/product/data-store.php @@ -1054,5 +1054,17 @@ class WC_Tests_Product_Data_Store extends WC_Unit_Test_Case { ); $this->assertEquals( $children[3], $match ); + + // Test numeric attribute value 0. + $match = $data_store->find_matching_product_variation( + $product, + array( + 'attribute_pa_size' => 'huge', + 'attribute_pa_colour' => 'red', + 'attribute_pa_number' => '0', + ) + ); + + $this->assertEquals( $children[2], $match ); } } From 4cfe22eef90d5bc441669a28e5d899062110353d Mon Sep 17 00:00:00 2001 From: Peter Fabian Date: Wed, 2 Oct 2019 16:05:44 +0200 Subject: [PATCH 4/5] Made the attribute value comparison strict. --- includes/data-stores/class-wc-product-data-store-cpt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/data-stores/class-wc-product-data-store-cpt.php b/includes/data-stores/class-wc-product-data-store-cpt.php index 3b538d7ea13..328ea09c858 100644 --- a/includes/data-stores/class-wc-product-data-store-cpt.php +++ b/includes/data-stores/class-wc-product-data-store-cpt.php @@ -1112,7 +1112,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da // Loop over the variation meta keys and values i.e. what is saved to the products. Note: $attribute_value is empty when 'any' is in use. foreach ( $variation as $attribute_key => $attribute_value ) { - $match_any_value = empty( $attribute_value ) && 0 != $attribute_value; + $match_any_value = empty( $attribute_value ) && 0.0 !== floatval( $attribute_value ); if ( ! $match_any_value && ! array_key_exists( $attribute_key, $match_attributes ) ) { $match = false; // Requires a selection but no value was provide. From 3cbea2a902603bffe3321687c2115c76467286b7 Mon Sep 17 00:00:00 2001 From: Peter Fabian Date: Wed, 2 Oct 2019 16:58:45 +0200 Subject: [PATCH 5/5] Simplify 'any-check' to only include empty string. --- includes/data-stores/class-wc-product-data-store-cpt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/data-stores/class-wc-product-data-store-cpt.php b/includes/data-stores/class-wc-product-data-store-cpt.php index 328ea09c858..e968a715785 100644 --- a/includes/data-stores/class-wc-product-data-store-cpt.php +++ b/includes/data-stores/class-wc-product-data-store-cpt.php @@ -1112,7 +1112,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da // Loop over the variation meta keys and values i.e. what is saved to the products. Note: $attribute_value is empty when 'any' is in use. foreach ( $variation as $attribute_key => $attribute_value ) { - $match_any_value = empty( $attribute_value ) && 0.0 !== floatval( $attribute_value ); + $match_any_value = '' === $attribute_value; if ( ! $match_any_value && ! array_key_exists( $attribute_key, $match_attributes ) ) { $match = false; // Requires a selection but no value was provide.