Add API Rest endpoint to duplicate product (#46141)
* Add API Rest endpoint to duplicate product * Add update functionality * update duplicate_product * Fix function comment * Add unit tests * Add changelog * Add missing variable * Improve tests * Fix tests and lint * Add comment explaining process
This commit is contained in:
parent
c34399b28c
commit
46b07c040f
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: dev
|
||||
|
||||
Add API Rest endpoint to duplicate product #46141
|
|
@ -62,6 +62,58 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
|
|||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/(?P<id>[\d]+)/duplicate',
|
||||
array(
|
||||
'args' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'duplicate_product' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate a product and returns the duplicated product.
|
||||
* The product status is set to "draft" and the name includes a "(copy)" at the end by default.
|
||||
*
|
||||
* @param WP_REST_Request $request Request data.
|
||||
* @return WP_REST_Response|WP_Error
|
||||
*/
|
||||
public function duplicate_product( $request ) {
|
||||
$product_id = $request->get_param( 'id' );
|
||||
$product = wc_get_product( $product_id );
|
||||
|
||||
if ( ! $product ) {
|
||||
return new WP_Error( 'woocommerce_rest_product_invalid_id', __( 'Invalid product ID.', 'woocommerce' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
if ( 'simple' !== $product->get_type() ) {
|
||||
$request['type'] = $product->get_type();
|
||||
}
|
||||
|
||||
// Creating product object from request data in preparation for copying.
|
||||
$updated_product = $this->prepare_object_for_database( $request );
|
||||
$duplicated_product = ( new WC_Admin_Duplicate_Product() )->product_duplicate( $updated_product );
|
||||
|
||||
if ( is_wp_error( $duplicated_product ) ) {
|
||||
return new WP_Error( 'woocommerce_rest_product_duplicate_error', $duplicated_product->get_error_message(), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
$response_data = $duplicated_product->get_data();
|
||||
|
||||
return new WP_REST_Response( $response_data, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -325,7 +377,7 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
|
|||
global $wpdb;
|
||||
if ( ! empty( $this->search_sku_in_product_lookup_table ) ) {
|
||||
$like_search = '%' . $wpdb->esc_like( $this->search_sku_in_product_lookup_table ) . '%';
|
||||
$where .= ' AND ' . $wpdb->prepare( '(wc_product_meta_lookup.sku LIKE %s)', $like_search );
|
||||
$where .= ' AND ' . $wpdb->prepare( '(wc_product_meta_lookup.sku LIKE %s)', $like_search );
|
||||
}
|
||||
return $where;
|
||||
}
|
||||
|
@ -1112,7 +1164,7 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
|
|||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'low_stock_amount' => array(
|
||||
'low_stock_amount' => array(
|
||||
'description' => __( 'Low Stock amount for the product.', 'woocommerce' ),
|
||||
'type' => array( 'integer', 'null' ),
|
||||
'context' => array( 'view', 'edit' ),
|
||||
|
@ -1344,7 +1396,7 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
|
|||
),
|
||||
),
|
||||
),
|
||||
'has_options' => array(
|
||||
'has_options' => array(
|
||||
'description' => __( 'Shows if the product needs to be configured before it can be bought.', 'woocommerce' ),
|
||||
'type' => 'boolean',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
|
|
|
@ -160,7 +160,7 @@ class WC_REST_Products_Controller_Tests extends WC_REST_Unit_Test_Case {
|
|||
public function test_product_api_get_all_fields() {
|
||||
$expected_response_fields = $this->get_expected_response_fields();
|
||||
|
||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_simple_product();
|
||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_simple_product();
|
||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/products/' . $product->get_id() ) );
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
|
@ -183,7 +183,7 @@ class WC_REST_Products_Controller_Tests extends WC_REST_Unit_Test_Case {
|
|||
$call_product_data_wrapper = function () use ( $product ) {
|
||||
return $this->get_product_data( $product );
|
||||
};
|
||||
$response = $call_product_data_wrapper->call( new WC_REST_Products_Controller() );
|
||||
$response = $call_product_data_wrapper->call( new WC_REST_Products_Controller() );
|
||||
$this->assertArrayHasKey( 'id', $response );
|
||||
}
|
||||
|
||||
|
@ -192,7 +192,7 @@ class WC_REST_Products_Controller_Tests extends WC_REST_Unit_Test_Case {
|
|||
*/
|
||||
public function test_products_get_each_field_one_by_one() {
|
||||
$expected_response_fields = $this->get_expected_response_fields();
|
||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_simple_product();
|
||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_simple_product();
|
||||
|
||||
foreach ( $expected_response_fields as $field ) {
|
||||
$request = new WP_REST_Request( 'GET', '/wc/v3/products/' . $product->get_id() );
|
||||
|
@ -325,7 +325,7 @@ class WC_REST_Products_Controller_Tests extends WC_REST_Unit_Test_Case {
|
|||
$this->assertArrayHasKey( 'meta_data', $order );
|
||||
$this->assertEquals( 1, count( $order['meta_data'] ) );
|
||||
$meta_keys = array_map(
|
||||
function( $meta_item ) {
|
||||
function ( $meta_item ) {
|
||||
return $meta_item->get_data()['key'];
|
||||
},
|
||||
$order['meta_data']
|
||||
|
@ -349,7 +349,7 @@ class WC_REST_Products_Controller_Tests extends WC_REST_Unit_Test_Case {
|
|||
foreach ( $response_data as $order ) {
|
||||
$this->assertArrayHasKey( 'meta_data', $order );
|
||||
$meta_keys = array_map(
|
||||
function( $meta_item ) {
|
||||
function ( $meta_item ) {
|
||||
return $meta_item->get_data()['key'];
|
||||
},
|
||||
$order['meta_data']
|
||||
|
@ -374,7 +374,7 @@ class WC_REST_Products_Controller_Tests extends WC_REST_Unit_Test_Case {
|
|||
foreach ( $response_data as $order ) {
|
||||
$this->assertArrayHasKey( 'meta_data', $order );
|
||||
$meta_keys = array_map(
|
||||
function( $meta_item ) {
|
||||
function ( $meta_item ) {
|
||||
return $meta_item->get_data()['key'];
|
||||
},
|
||||
$order['meta_data']
|
||||
|
@ -401,7 +401,7 @@ class WC_REST_Products_Controller_Tests extends WC_REST_Unit_Test_Case {
|
|||
$this->assertArrayHasKey( 'meta_data', $order );
|
||||
$this->assertEquals( 1, count( $order['meta_data'] ) );
|
||||
$meta_keys = array_map(
|
||||
function( $meta_item ) {
|
||||
function ( $meta_item ) {
|
||||
return $meta_item->get_data()['key'];
|
||||
},
|
||||
$order['meta_data']
|
||||
|
@ -425,4 +425,86 @@ class WC_REST_Products_Controller_Tests extends WC_REST_Unit_Test_Case {
|
|||
|
||||
$this->assertIsArray( $decoded_data_object[0]->meta_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the duplicate product endpoint with simple products.
|
||||
*/
|
||||
public function test_duplicate_simple_product() {
|
||||
$product = WC_Helper_Product::create_simple_product(
|
||||
true,
|
||||
array(
|
||||
'name' => 'Carrot Cake',
|
||||
'sku' => 'carrot-cake-1',
|
||||
)
|
||||
);
|
||||
$product_id = $product->get_id();
|
||||
|
||||
$request = new WP_REST_Request( 'POST', '/wc/v3/products/' . $product_id . '/duplicate' );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
|
||||
$response_data = $response->get_data();
|
||||
$this->assertArrayHasKey( 'id', $response_data );
|
||||
$this->assertNotEquals( $product, $response_data['id'] );
|
||||
|
||||
$duplicated_product = wc_get_product( $response_data['id'] );
|
||||
$this->assertEquals( $product->get_name() . ' (Copy)', $duplicated_product->get_name() );
|
||||
$this->assertEquals( 'draft', $duplicated_product->get_status() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the duplicate product endpoint with variable products.
|
||||
*/
|
||||
public function test_duplicate_variable_product() {
|
||||
$variable_product = WC_Helper_Product::create_variation_product();
|
||||
$product_id = $variable_product->get_id();
|
||||
|
||||
$request = new WP_REST_Request( 'POST', '/wc/v3/products/' . $product_id . '/duplicate' );
|
||||
$response = $this->server->dispatch( $request );
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
|
||||
$response_data = $response->get_data();
|
||||
$this->assertArrayHasKey( 'id', $response_data );
|
||||
$this->assertNotEquals( $product_id, $response_data['id'] );
|
||||
|
||||
$duplicated_product = wc_get_product( $response_data['id'] );
|
||||
$this->assertEquals( $variable_product->get_name() . ' (Copy)', $duplicated_product->get_name() );
|
||||
$this->assertTrue( $duplicated_product->is_type( 'variable' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the duplicate product endpoint with extra args to also update the product.
|
||||
*/
|
||||
public function test_duplicate_product_with_extra_args() {
|
||||
$product = WC_Helper_Product::create_simple_product(
|
||||
true,
|
||||
array(
|
||||
'name' => 'Tiramisu Cake',
|
||||
'sku' => 'tiramisu-cake-1',
|
||||
)
|
||||
);
|
||||
$product_id = $product->get_id();
|
||||
|
||||
$request = new WP_REST_Request( 'POST', '/wc/v3/products/' . $product_id . '/duplicate' );
|
||||
$request->set_param( 'sku', 'new-sku' );
|
||||
$request->set_param(
|
||||
'meta_data',
|
||||
array(
|
||||
array(
|
||||
'key' => 'test',
|
||||
'value' => 'test',
|
||||
),
|
||||
)
|
||||
);
|
||||
$response = $this->server->dispatch( $request );
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
|
||||
$response_data = $response->get_data();
|
||||
$this->assertArrayHasKey( 'id', $response_data );
|
||||
$this->assertNotEquals( $product_id, $response_data['id'] );
|
||||
|
||||
$duplicated_product = wc_get_product( $response_data['id'] );
|
||||
$this->assertEquals( 'new-sku', $duplicated_product->get_sku() );
|
||||
$this->assertEquals( 'test', $duplicated_product->get_meta( 'test', true ) );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue