diff --git a/api/class-wc-rest-dev-product-variations-controller.php b/api/class-wc-rest-dev-product-variations-controller.php index 92cc71b..8a192bd 100644 --- a/api/class-wc-rest-dev-product-variations-controller.php +++ b/api/class-wc-rest-dev-product-variations-controller.php @@ -130,8 +130,7 @@ protected function prepare_object_for_database( $request, $creating = false ) { // Thumbnail. if ( isset( $request['image'] ) ) { if ( is_array( $request['image'] ) ) { - $image = $request['image']; - $variation = $this->set_product_images( $variation, array( $image ) ); + $variation = $this->set_variation_image( $variation, $request['image'] ); } else { $variation->set_image_id( '' ); } @@ -339,6 +338,48 @@ protected function get_image( $variation ) { return; } + /** + * Set variation image. + * + * @throws WC_REST_Exception REST API exceptions. + * @param WC_Product_Variation $variation Variation instance. + * @param array $image Image data. + * @return WC_Product_Variation + */ + protected function set_variation_image( $variation, $image ) { + $attachment_id = isset( $image['id'] ) ? absint( $image['id'] ) : 0; + + if ( 0 === $attachment_id && isset( $image['src'] ) ) { + $upload = wc_rest_upload_image_from_url( esc_url_raw( $image['src'] ) ); + + if ( is_wp_error( $upload ) ) { + if ( ! apply_filters( 'woocommerce_rest_suppress_image_upload_error', false, $upload, $variation->get_id(), array( $image ) ) ) { + throw new WC_REST_Exception( 'woocommerce_variation_image_upload_error', $upload->get_error_message(), 400 ); + } + } + + $attachment_id = wc_rest_set_uploaded_image_as_attachment( $upload, $variation->get_id() ); + } + + if ( ! wp_attachment_is_image( $attachment_id ) ) { + throw new WC_REST_Exception( 'woocommerce_variation_invalid_image_id', sprintf( __( '#%s is an invalid image ID.', 'woocommerce' ), $attachment_id ), 400 ); + } + + $variation->set_image_id( $attachment_id ); + + // Set the image alt if present. + if ( ! empty( $image['alt'] ) ) { + update_post_meta( $attachment_id, '_wp_attachment_image_alt', wc_clean( $image['alt'] ) ); + } + + // Set the image name if present. + if ( ! empty( $image['name'] ) ) { + wp_update_post( array( 'ID' => $attachment_id, 'post_title' => $image['name'] ) ); + } + + return $variation; + } + /** * Get the Variation's schema, conforming to JSON Schema. * diff --git a/tests/unit-tests/product-variations.php b/tests/unit-tests/product-variations.php index d4b1efa..3b3208b 100644 --- a/tests/unit-tests/product-variations.php +++ b/tests/unit-tests/product-variations.php @@ -195,6 +195,43 @@ public function test_update_variation() { $product->delete( true ); } + /** + * Test setting variation image from ID. (src is tested in `test_update_variation`) + */ + public function test_set_variation_image_from_id() { + wp_set_current_user( $this->user ); + + $orig_file = dirname( __FILE__ ) . '/../../assets/icon-128x128.png'; + $this->test_file = '/tmp/icon.png'; + copy( $orig_file, $this->test_file ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + $request->set_header( 'Content-Type', 'image/png' ); + $request->set_header( 'Content-Disposition', 'attachment; filename=icon.png' ); + $request->set_body( file_get_contents( $this->test_file ) ); + $response = $this->server->dispatch( $request ); + $image = $response->get_data(); + + $product = WC_Helper_Product::create_variation_product(); + $children = $product->get_children(); + $variation_id = $children[0]; + + $request = new WP_REST_Request( 'PUT', '/wc/v3/products/' . $product->get_id() . '/variations/' . $variation_id ); + $request->set_body_params( array( + 'image' => array( 'id' => $image['id'] ), + ) ); + $response = $this->server->dispatch( $request ); + $variation = $response->get_data(); + + $this->assertNotEmpty( $variation['image'] ); + $this->assertEquals( $image['id'], $variation['image']['id'] ); + + $product->delete( true ); + if ( file_exists( $this->test_file ) ) { + unlink( $this->test_file ); + } + } + /** * Test updating a single variation without permission. *