From 04352adc48d9f069f305d97a4d17913f21b308dd Mon Sep 17 00:00:00 2001 From: Paul Kilmurray Date: Thu, 7 Mar 2024 21:52:39 +0100 Subject: [PATCH] Fix: remove POS Only products from frontend WC REST API response --- includes/Init.php | 2 - includes/WC_API.php | 70 +++++----------- tests/includes/Test_Products.php | 41 +-------- tests/includes/Test_WC_API.php | 107 ++++++++++++++++++++++++ tests/includes/Test_Wcpos_Functions.php | 9 +- 5 files changed, 139 insertions(+), 90 deletions(-) create mode 100644 tests/includes/Test_WC_API.php diff --git a/includes/Init.php b/includes/Init.php index b5ce9158..d9b0c4d8 100644 --- a/includes/Init.php +++ b/includes/Init.php @@ -39,8 +39,6 @@ public function __construct() { // Headers for API discoverability add_filter( 'rest_pre_serve_request', array( $this, 'rest_pre_serve_request' ), 5, 4 ); add_action( 'send_headers', array( $this, 'send_headers' ), 99, 1 ); - - // add_filter( 'woocommerce_rest_check_permissions', '__return_true' ); } /** diff --git a/includes/WC_API.php b/includes/WC_API.php index 5e0409df..de19077a 100644 --- a/includes/WC_API.php +++ b/includes/WC_API.php @@ -22,70 +22,44 @@ public function __construct() { $pos_only_products = woocommerce_pos_get_settings( 'general', 'pos_only_products' ); if ( $pos_only_products ) { - add_action( 'woocommerce_product_query', array( $this, 'hide_pos_only_products' ) ); - add_filter( 'woocommerce_variation_is_visible', array( $this, 'hide_pos_only_variations' ), 10, 4 ); + add_filter( 'woocommerce_rest_product_object_query', array( $this, 'hide_pos_only_products' ), 10, 2 ); + add_filter( 'woocommerce_rest_product_variation_object_query', array( $this, 'hide_pos_only_products' ), 10, 2 ); } } /** - * Hide POS Only products from the shop and category pages. + * Filter the query arguments for a request. * - * @TODO - this should be improved so that admin users can see the product, but get a message + * Enables adding extra arguments or setting defaults for a post + * collection request. * - * @param WP_Query $query Query instance. - * - * @return void + * @param array $args Key value array of query var to query value. + * @param WP_REST_Request $request The request used. */ - public function hide_pos_only_products( $query ) { - $meta_query = $query->get( 'meta_query' ); - - // Define your default meta query. - $default_meta_query = array( + public function hide_pos_only_products( $args, $request ) { + $meta_query = array( 'relation' => 'OR', array( - 'key' => '_pos_visibility', - 'value' => 'pos_only', - 'compare' => '!=', + 'key' => '_pos_visibility', + 'compare' => 'NOT EXISTS', ), array( - 'key' => '_pos_visibility', - 'compare' => 'NOT EXISTS', + 'key' => '_pos_visibility', + 'value' => 'pos_only', + 'compare' => '!=', ), ); - // Check if an existing meta query exists. - if ( is_array( $meta_query ) ) { - if ( ! isset( $meta_query ['relation'] ) ) { - $meta_query['relation'] = 'AND'; - } - $meta_query[] = $default_meta_query; + if ( empty( $args['meta_query'] ) ) { + $args['meta_query'] = $meta_query; } else { - $meta_query = $default_meta_query; - } - - // Set the updated meta query back to the query. - $query->set( 'meta_query', $meta_query ); - } - - /** - * Remove POS Only variations from the storefront. - * - * @param bool $visible Whether the variation is visible. - * @param int $variation_id The variation ID. - * @param int $product_id The product ID. - * @param \WC_Product_Variation $variation The variation object. - */ - public function hide_pos_only_variations( $visible, $variation_id, $product_id, $variation ) { - if ( \is_shop() || \is_product_category() || \is_product() ) { - // Get the _pos_visibility meta value for the variation. - $pos_visibility = get_post_meta( $variation_id, '_pos_visibility', true ); - - // Check if _pos_visibility is 'pos_only' for this variation. - if ( $pos_visibility === 'pos_only' ) { - return false; - } + $args['meta_query'] = array( + 'relation' => 'AND', + $args['meta_query'], + $meta_query, + ); } - return $visible; + return $args; } } diff --git a/tests/includes/Test_Products.php b/tests/includes/Test_Products.php index 5d3acf9e..acd3196f 100644 --- a/tests/includes/Test_Products.php +++ b/tests/includes/Test_Products.php @@ -3,9 +3,8 @@ namespace WCPOS\WooCommercePOS\Tests; use Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper; -use WC_REST_Unit_Test_Case; +use WP_UnitTestCase; use WP_Query; -use WC_Query; use WCPOS\WooCommercePOS\Products; use WC_Product_Variation; @@ -14,7 +13,7 @@ * * @coversNothing */ -class Test_Products extends WC_REST_Unit_Test_Case { +class Test_Products extends WP_UnitTestCase { public function setup(): void { parent::setup(); } @@ -118,40 +117,4 @@ function () { // Assert that the variation without '_pos_visibility' set is in the query $this->assertContains( $variation_ids[2], $queried_variation_ids ); } - - /** - * - */ - public function test_pos_only_products_via_store_api() { - add_filter( - 'woocommerce_pos_general_settings', - function () { - return array( - 'pos_only_products' => true, - ); - } - ); - new Products(); // reinstantiate the class to apply the filter - - // Create a visible product - $visible_product = ProductHelper::create_simple_product(); - - // Create a product with _pos_visibility set to 'pos_only' - $hidden_product = ProductHelper::create_simple_product(); - update_post_meta( $hidden_product->get_id(), '_pos_visibility', 'pos_only' ); - - // Verify that the meta value is set correctly - $pos_visibility = get_post_meta( $hidden_product->get_id(), '_pos_visibility', true ); - $this->assertEquals( 'pos_only', $pos_visibility, 'Meta value for _pos_visibility not set correctly' ); - - // Make WC REST request - add_filter( 'woocommerce_rest_check_permissions', '__return_true' ); - $request = new \WP_REST_Request( 'GET', '/wc/v3/products' ); - $response = $this->server->dispatch( $request ); - - $data = $response->get_data(); - $this->assertEquals( 200, $response->get_status() ); - $this->assertEquals( 1, \count( $data ) ); - $this->assertEquals( $visible_product->get_id(), $data[0]['id'] ); - } } diff --git a/tests/includes/Test_WC_API.php b/tests/includes/Test_WC_API.php new file mode 100644 index 00000000..a52bf9bb --- /dev/null +++ b/tests/includes/Test_WC_API.php @@ -0,0 +1,107 @@ + true, + ); + } + ); + new WC_API(); // reinstantiate the class to apply the filter + + // Create a visible product + $visible_product = ProductHelper::create_simple_product(); + + // Create a product with _pos_visibility set to 'pos_only' + $hidden_product = ProductHelper::create_simple_product(); + update_post_meta( $hidden_product->get_id(), '_pos_visibility', 'pos_only' ); + + // Verify that the meta value is set correctly + $pos_visibility = get_post_meta( $hidden_product->get_id(), '_pos_visibility', true ); + $this->assertEquals( 'pos_only', $pos_visibility, 'Meta value for _pos_visibility not set correctly' ); + + // Make WC REST request + add_filter( 'woocommerce_rest_check_permissions', '__return_true' ); + $request = new \WP_REST_Request( 'GET', '/wc/v3/products' ); + $response = $this->server->dispatch( $request ); + + $data = $response->get_data(); + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( 1, \count( $data ) ); + $this->assertEquals( $visible_product->get_id(), $data[0]['id'] ); + } + + /** + * + */ + public function test_pos_only_variations_via_store_api() { + add_filter( + 'woocommerce_pos_general_settings', + function () { + return array( + 'pos_only_products' => true, + ); + } + ); + new WC_API(); // reinstantiate the class to apply the filter + + // Create a variable product + $variable = ProductHelper::create_variation_product(); + $variation_ids = $variable->get_children(); + update_post_meta( $variation_ids[0], '_pos_visibility', 'pos_only' ); + + // Verify that the meta value is set correctly + $pos_visibility = get_post_meta( $variation_ids[0], '_pos_visibility', true ); + $this->assertEquals( 'pos_only', $pos_visibility, 'Meta value for _pos_visibility not set correctly' ); + + // Make WC REST request + add_filter( 'woocommerce_rest_check_permissions', '__return_true' ); + + $request = new \WP_REST_Request( 'GET', '/wc/v3/products/' . $variable->get_id() . '/variations' ); + $response = $this->server->dispatch( $request ); + + $data = $response->get_data(); + $this->assertEquals( 200, $response->get_status() ); + $this->assertEquals( 1, \count( $data ) ); + $this->assertEquals( $variation_ids[1], $data[0]['id'] ); + + /** + * @TODO should we remove the id from the parent response also? + * The WooCommerce code uses $object->get_children() to get the variation ids, NOT + * $object->get_visible_children() so it seems they return all variations ids regardless of visibility. + */ + // $request = new \WP_REST_Request( 'GET', '/wc/v3/products/' . $variable->get_id() ); + // $response = $this->server->dispatch( $request ); + + // $data = $response->get_data(); + // $this->assertEquals( 200, $response->get_status() ); + // $this->assertEquals( $variable->get_id(), $data['id'] ); + // $this->assertEquals( 1, \count( $data['variations'] ) ); + // $this->assertEquals( $variation_ids[1], $data['variations'][0] ); + } +} diff --git a/tests/includes/Test_Wcpos_Functions.php b/tests/includes/Test_Wcpos_Functions.php index 82dff0c4..f0697e51 100644 --- a/tests/includes/Test_Wcpos_Functions.php +++ b/tests/includes/Test_Wcpos_Functions.php @@ -58,7 +58,14 @@ public function test_woocommerce_pos_get_payment_gateways_settings(): void { $this->assertIsArray( $payment_gateways_settings ); $this->assertArrayHasKey( 'default_gateway', $payment_gateways_settings ); $this->assertArrayHasKey( 'gateways', $payment_gateways_settings ); - $this->assertEquals( count( $payment_gateways_settings['gateways'] ), 2 ); + + $active_gateways = array_filter( + $payment_gateways_settings['gateways'], + function ( $gateway ) { + return $gateway['enabled']; + } + ); + $this->assertEquals( count( $active_gateways ), 2 ); $payment_gateways_settings = woocommerce_pos_get_settings( 'payment_gateways', 'default_gateway' ); $this->assertEquals( 'pos_cash', $payment_gateways_settings );