wp/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 19 3d72ae0968f4
--- a/wp/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php	Tue Dec 15 15:52:01 2020 +0100
+++ b/wp/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php	Wed Sep 21 18:19:35 2022 +0200
@@ -34,7 +34,7 @@
 				'permission_callback' => array( $this, 'post_process_item_permissions_check' ),
 				'args'                => array(
 					'id'     => array(
-						'description' => __( 'Unique identifier for the object.' ),
+						'description' => __( 'Unique identifier for the attachment.' ),
 						'type'        => 'integer',
 					),
 					'action' => array(
@@ -191,6 +191,8 @@
 		 */
 		do_action( 'rest_after_insert_attachment', $attachment, $request, true );
 
+		wp_after_insert_post( $attachment, false, null );
+
 		if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
 			// Set a custom header with the attachment_id.
 			// Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
@@ -270,7 +272,7 @@
 		}
 
 		// $post_parent is inherited from $attachment['post_parent'].
-		$id = wp_insert_attachment( wp_slash( (array) $attachment ), $file, 0, true );
+		$id = wp_insert_attachment( wp_slash( (array) $attachment ), $file, 0, true, false );
 
 		if ( is_wp_error( $id ) ) {
 			if ( 'db_update_error' === $id->get_error_code() ) {
@@ -319,7 +321,8 @@
 			);
 		}
 
-		$response = parent::update_item( $request );
+		$attachment_before = get_post( $request['id'] );
+		$response          = parent::update_item( $request );
 
 		if ( is_wp_error( $response ) ) {
 			return $response;
@@ -345,6 +348,8 @@
 		/** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */
 		do_action( 'rest_after_insert_attachment', $attachment, $request, false );
 
+		wp_after_insert_post( $attachment, true, $attachment_before );
+
 		$response = $this->prepare_item_for_response( $attachment, $request );
 		$response = rest_ensure_response( $response );
 
@@ -433,7 +438,7 @@
 			);
 		}
 
-		$supported_types = array( 'image/jpeg', 'image/png', 'image/gif' );
+		$supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp' );
 		$mime_type       = get_post_mime_type( $attachment_id );
 		if ( ! in_array( $mime_type, $supported_types, true ) ) {
 			return new WP_Error(
@@ -443,25 +448,40 @@
 			);
 		}
 
-		// Check if we need to do anything.
-		$rotate = 0;
-		$crop   = false;
+		// The `modifiers` param takes precedence over the older format.
+		if ( isset( $request['modifiers'] ) ) {
+			$modifiers = $request['modifiers'];
+		} else {
+			$modifiers = array();
 
-		if ( ! empty( $request['rotation'] ) ) {
-			// Rotation direction: clockwise vs. counter clockwise.
-			$rotate = 0 - (int) $request['rotation'];
-		}
+			if ( ! empty( $request['rotation'] ) ) {
+				$modifiers[] = array(
+					'type' => 'rotate',
+					'args' => array(
+						'angle' => $request['rotation'],
+					),
+				);
+			}
 
-		if ( isset( $request['x'], $request['y'], $request['width'], $request['height'] ) ) {
-			$crop = true;
-		}
+			if ( isset( $request['x'], $request['y'], $request['width'], $request['height'] ) ) {
+				$modifiers[] = array(
+					'type' => 'crop',
+					'args' => array(
+						'left'   => $request['x'],
+						'top'    => $request['y'],
+						'width'  => $request['width'],
+						'height' => $request['height'],
+					),
+				);
+			}
 
-		if ( ! $rotate && ! $crop ) {
-			return new WP_Error(
-				'rest_image_not_edited',
-				__( 'The image was not edited. Edit the image before applying the changes.' ),
-				array( 'status' => 400 )
-			);
+			if ( 0 === count( $modifiers ) ) {
+				return new WP_Error(
+					'rest_image_not_edited',
+					__( 'The image was not edited. Edit the image before applying the changes.' ),
+					array( 'status' => 400 )
+				);
+			}
 		}
 
 		/*
@@ -484,34 +504,49 @@
 			);
 		}
 
-		if ( 0 !== $rotate ) {
-			$result = $image_editor->rotate( $rotate );
+		foreach ( $modifiers as $modifier ) {
+			$args = $modifier['args'];
+			switch ( $modifier['type'] ) {
+				case 'rotate':
+					// Rotation direction: clockwise vs. counter clockwise.
+					$rotate = 0 - $args['angle'];
+
+					if ( 0 !== $rotate ) {
+						$result = $image_editor->rotate( $rotate );
 
-			if ( is_wp_error( $result ) ) {
-				return new WP_Error(
-					'rest_image_rotation_failed',
-					__( 'Unable to rotate this image.' ),
-					array( 'status' => 500 )
-				);
-			}
-		}
+						if ( is_wp_error( $result ) ) {
+							return new WP_Error(
+								'rest_image_rotation_failed',
+								__( 'Unable to rotate this image.' ),
+								array( 'status' => 500 )
+							);
+						}
+					}
+
+					break;
 
-		if ( $crop ) {
-			$size = $image_editor->get_size();
+				case 'crop':
+					$size = $image_editor->get_size();
 
-			$crop_x = round( ( $size['width'] * floatval( $request['x'] ) ) / 100.0 );
-			$crop_y = round( ( $size['height'] * floatval( $request['y'] ) ) / 100.0 );
-			$width  = round( ( $size['width'] * floatval( $request['width'] ) ) / 100.0 );
-			$height = round( ( $size['height'] * floatval( $request['height'] ) ) / 100.0 );
+					$crop_x = round( ( $size['width'] * $args['left'] ) / 100.0 );
+					$crop_y = round( ( $size['height'] * $args['top'] ) / 100.0 );
+					$width  = round( ( $size['width'] * $args['width'] ) / 100.0 );
+					$height = round( ( $size['height'] * $args['height'] ) / 100.0 );
+
+					if ( $size['width'] !== $width && $size['height'] !== $height ) {
+						$result = $image_editor->crop( $crop_x, $crop_y, $width, $height );
 
-			$result = $image_editor->crop( $crop_x, $crop_y, $width, $height );
+						if ( is_wp_error( $result ) ) {
+							return new WP_Error(
+								'rest_image_crop_failed',
+								__( 'Unable to crop this image.' ),
+								array( 'status' => 500 )
+							);
+						}
+					}
 
-			if ( is_wp_error( $result ) ) {
-				return new WP_Error(
-					'rest_image_crop_failed',
-					__( 'Unable to crop this image.' ),
-					array( 'status' => 500 )
-				);
+					break;
+
 			}
 		}
 
@@ -853,12 +888,12 @@
 			),
 			'properties'  => array(
 				'raw'      => array(
-					'description' => __( 'Description for the object, as it exists in the database.' ),
+					'description' => __( 'Description for the attachment, as it exists in the database.' ),
 					'type'        => 'string',
 					'context'     => array( 'edit' ),
 				),
 				'rendered' => array(
-					'description' => __( 'HTML description for the object, transformed for display.' ),
+					'description' => __( 'HTML description for the attachment, transformed for display.' ),
 					'type'        => 'string',
 					'context'     => array( 'view', 'edit' ),
 					'readonly'    => true,
@@ -1281,44 +1316,120 @@
 	 */
 	protected function get_edit_media_item_args() {
 		return array(
-			'rotation' => array(
-				'description'      => __( 'The amount to rotate the image clockwise in degrees.' ),
+			'src'       => array(
+				'description' => __( 'URL to the edited image file.' ),
+				'type'        => 'string',
+				'format'      => 'uri',
+				'required'    => true,
+			),
+			'modifiers' => array(
+				'description' => __( 'Array of image edits.' ),
+				'type'        => 'array',
+				'minItems'    => 1,
+				'items'       => array(
+					'description' => __( 'Image edit.' ),
+					'type'        => 'object',
+					'required'    => array(
+						'type',
+						'args',
+					),
+					'oneOf'       => array(
+						array(
+							'title'      => __( 'Rotation' ),
+							'properties' => array(
+								'type' => array(
+									'description' => __( 'Rotation type.' ),
+									'type'        => 'string',
+									'enum'        => array( 'rotate' ),
+								),
+								'args' => array(
+									'description' => __( 'Rotation arguments.' ),
+									'type'        => 'object',
+									'required'    => array(
+										'angle',
+									),
+									'properties'  => array(
+										'angle' => array(
+											'description' => __( 'Angle to rotate clockwise in degrees.' ),
+											'type'        => 'number',
+										),
+									),
+								),
+							),
+						),
+						array(
+							'title'      => __( 'Crop' ),
+							'properties' => array(
+								'type' => array(
+									'description' => __( 'Crop type.' ),
+									'type'        => 'string',
+									'enum'        => array( 'crop' ),
+								),
+								'args' => array(
+									'description' => __( 'Crop arguments.' ),
+									'type'        => 'object',
+									'required'    => array(
+										'left',
+										'top',
+										'width',
+										'height',
+									),
+									'properties'  => array(
+										'left'   => array(
+											'description' => __( 'Horizontal position from the left to begin the crop as a percentage of the image width.' ),
+											'type'        => 'number',
+										),
+										'top'    => array(
+											'description' => __( 'Vertical position from the top to begin the crop as a percentage of the image height.' ),
+											'type'        => 'number',
+										),
+										'width'  => array(
+											'description' => __( 'Width of the crop as a percentage of the image width.' ),
+											'type'        => 'number',
+										),
+										'height' => array(
+											'description' => __( 'Height of the crop as a percentage of the image height.' ),
+											'type'        => 'number',
+										),
+									),
+								),
+							),
+						),
+					),
+				),
+			),
+			'rotation'  => array(
+				'description'      => __( 'The amount to rotate the image clockwise in degrees. DEPRECATED: Use `modifiers` instead.' ),
 				'type'             => 'integer',
 				'minimum'          => 0,
 				'exclusiveMinimum' => true,
 				'maximum'          => 360,
 				'exclusiveMaximum' => true,
 			),
-			'x'        => array(
-				'description' => __( 'As a percentage of the image, the x position to start the crop from.' ),
+			'x'         => array(
+				'description' => __( 'As a percentage of the image, the x position to start the crop from. DEPRECATED: Use `modifiers` instead.' ),
 				'type'        => 'number',
 				'minimum'     => 0,
 				'maximum'     => 100,
 			),
-			'y'        => array(
-				'description' => __( 'As a percentage of the image, the y position to start the crop from.' ),
+			'y'         => array(
+				'description' => __( 'As a percentage of the image, the y position to start the crop from. DEPRECATED: Use `modifiers` instead.' ),
 				'type'        => 'number',
 				'minimum'     => 0,
 				'maximum'     => 100,
 			),
-			'width'    => array(
-				'description' => __( 'As a percentage of the image, the width to crop the image to.' ),
+			'width'     => array(
+				'description' => __( 'As a percentage of the image, the width to crop the image to. DEPRECATED: Use `modifiers` instead.' ),
 				'type'        => 'number',
 				'minimum'     => 0,
 				'maximum'     => 100,
 			),
-			'height'   => array(
-				'description' => __( 'As a percentage of the image, the height to crop the image to.' ),
+			'height'    => array(
+				'description' => __( 'As a percentage of the image, the height to crop the image to. DEPRECATED: Use `modifiers` instead.' ),
 				'type'        => 'number',
 				'minimum'     => 0,
 				'maximum'     => 100,
 			),
-			'src'      => array(
-				'description' => __( 'URL to the edited image file.' ),
-				'type'        => 'string',
-				'format'      => 'uri',
-				'required'    => true,
-			),
 		);
 	}