wp/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 19 3d72ae0968f4
equal deleted inserted replaced
17:34716fd837a4 18:be944660c56a
    32 				'methods'             => WP_REST_Server::CREATABLE,
    32 				'methods'             => WP_REST_Server::CREATABLE,
    33 				'callback'            => array( $this, 'post_process_item' ),
    33 				'callback'            => array( $this, 'post_process_item' ),
    34 				'permission_callback' => array( $this, 'post_process_item_permissions_check' ),
    34 				'permission_callback' => array( $this, 'post_process_item_permissions_check' ),
    35 				'args'                => array(
    35 				'args'                => array(
    36 					'id'     => array(
    36 					'id'     => array(
    37 						'description' => __( 'Unique identifier for the object.' ),
    37 						'description' => __( 'Unique identifier for the attachment.' ),
    38 						'type'        => 'integer',
    38 						'type'        => 'integer',
    39 					),
    39 					),
    40 					'action' => array(
    40 					'action' => array(
    41 						'type'     => 'string',
    41 						'type'     => 'string',
    42 						'enum'     => array( 'create-image-subsizes' ),
    42 						'enum'     => array( 'create-image-subsizes' ),
   189 		 * @param WP_REST_Request $request    Request object.
   189 		 * @param WP_REST_Request $request    Request object.
   190 		 * @param bool            $creating   True when creating an attachment, false when updating.
   190 		 * @param bool            $creating   True when creating an attachment, false when updating.
   191 		 */
   191 		 */
   192 		do_action( 'rest_after_insert_attachment', $attachment, $request, true );
   192 		do_action( 'rest_after_insert_attachment', $attachment, $request, true );
   193 
   193 
       
   194 		wp_after_insert_post( $attachment, false, null );
       
   195 
   194 		if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
   196 		if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
   195 			// Set a custom header with the attachment_id.
   197 			// Set a custom header with the attachment_id.
   196 			// Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
   198 			// Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
   197 			header( 'X-WP-Upload-Attachment-ID: ' . $attachment_id );
   199 			header( 'X-WP-Upload-Attachment-ID: ' . $attachment_id );
   198 		}
   200 		}
   268 		if ( empty( $attachment->post_title ) ) {
   270 		if ( empty( $attachment->post_title ) ) {
   269 			$attachment->post_title = preg_replace( '/\.[^.]+$/', '', wp_basename( $file ) );
   271 			$attachment->post_title = preg_replace( '/\.[^.]+$/', '', wp_basename( $file ) );
   270 		}
   272 		}
   271 
   273 
   272 		// $post_parent is inherited from $attachment['post_parent'].
   274 		// $post_parent is inherited from $attachment['post_parent'].
   273 		$id = wp_insert_attachment( wp_slash( (array) $attachment ), $file, 0, true );
   275 		$id = wp_insert_attachment( wp_slash( (array) $attachment ), $file, 0, true, false );
   274 
   276 
   275 		if ( is_wp_error( $id ) ) {
   277 		if ( is_wp_error( $id ) ) {
   276 			if ( 'db_update_error' === $id->get_error_code() ) {
   278 			if ( 'db_update_error' === $id->get_error_code() ) {
   277 				$id->add_data( array( 'status' => 500 ) );
   279 				$id->add_data( array( 'status' => 500 ) );
   278 			} else {
   280 			} else {
   317 				__( 'Invalid parent type.' ),
   319 				__( 'Invalid parent type.' ),
   318 				array( 'status' => 400 )
   320 				array( 'status' => 400 )
   319 			);
   321 			);
   320 		}
   322 		}
   321 
   323 
   322 		$response = parent::update_item( $request );
   324 		$attachment_before = get_post( $request['id'] );
       
   325 		$response          = parent::update_item( $request );
   323 
   326 
   324 		if ( is_wp_error( $response ) ) {
   327 		if ( is_wp_error( $response ) ) {
   325 			return $response;
   328 			return $response;
   326 		}
   329 		}
   327 
   330 
   342 
   345 
   343 		$request->set_param( 'context', 'edit' );
   346 		$request->set_param( 'context', 'edit' );
   344 
   347 
   345 		/** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */
   348 		/** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */
   346 		do_action( 'rest_after_insert_attachment', $attachment, $request, false );
   349 		do_action( 'rest_after_insert_attachment', $attachment, $request, false );
       
   350 
       
   351 		wp_after_insert_post( $attachment, true, $attachment_before );
   347 
   352 
   348 		$response = $this->prepare_item_for_response( $attachment, $request );
   353 		$response = $this->prepare_item_for_response( $attachment, $request );
   349 		$response = rest_ensure_response( $response );
   354 		$response = rest_ensure_response( $response );
   350 
   355 
   351 		return $response;
   356 		return $response;
   431 				__( 'Unable to get meta information for file.' ),
   436 				__( 'Unable to get meta information for file.' ),
   432 				array( 'status' => 404 )
   437 				array( 'status' => 404 )
   433 			);
   438 			);
   434 		}
   439 		}
   435 
   440 
   436 		$supported_types = array( 'image/jpeg', 'image/png', 'image/gif' );
   441 		$supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp' );
   437 		$mime_type       = get_post_mime_type( $attachment_id );
   442 		$mime_type       = get_post_mime_type( $attachment_id );
   438 		if ( ! in_array( $mime_type, $supported_types, true ) ) {
   443 		if ( ! in_array( $mime_type, $supported_types, true ) ) {
   439 			return new WP_Error(
   444 			return new WP_Error(
   440 				'rest_cannot_edit_file_type',
   445 				'rest_cannot_edit_file_type',
   441 				__( 'This type of file cannot be edited.' ),
   446 				__( 'This type of file cannot be edited.' ),
   442 				array( 'status' => 400 )
   447 				array( 'status' => 400 )
   443 			);
   448 			);
   444 		}
   449 		}
   445 
   450 
   446 		// Check if we need to do anything.
   451 		// The `modifiers` param takes precedence over the older format.
   447 		$rotate = 0;
   452 		if ( isset( $request['modifiers'] ) ) {
   448 		$crop   = false;
   453 			$modifiers = $request['modifiers'];
   449 
   454 		} else {
   450 		if ( ! empty( $request['rotation'] ) ) {
   455 			$modifiers = array();
   451 			// Rotation direction: clockwise vs. counter clockwise.
   456 
   452 			$rotate = 0 - (int) $request['rotation'];
   457 			if ( ! empty( $request['rotation'] ) ) {
   453 		}
   458 				$modifiers[] = array(
   454 
   459 					'type' => 'rotate',
   455 		if ( isset( $request['x'], $request['y'], $request['width'], $request['height'] ) ) {
   460 					'args' => array(
   456 			$crop = true;
   461 						'angle' => $request['rotation'],
   457 		}
   462 					),
   458 
   463 				);
   459 		if ( ! $rotate && ! $crop ) {
   464 			}
   460 			return new WP_Error(
   465 
   461 				'rest_image_not_edited',
   466 			if ( isset( $request['x'], $request['y'], $request['width'], $request['height'] ) ) {
   462 				__( 'The image was not edited. Edit the image before applying the changes.' ),
   467 				$modifiers[] = array(
   463 				array( 'status' => 400 )
   468 					'type' => 'crop',
   464 			);
   469 					'args' => array(
       
   470 						'left'   => $request['x'],
       
   471 						'top'    => $request['y'],
       
   472 						'width'  => $request['width'],
       
   473 						'height' => $request['height'],
       
   474 					),
       
   475 				);
       
   476 			}
       
   477 
       
   478 			if ( 0 === count( $modifiers ) ) {
       
   479 				return new WP_Error(
       
   480 					'rest_image_not_edited',
       
   481 					__( 'The image was not edited. Edit the image before applying the changes.' ),
       
   482 					array( 'status' => 400 )
       
   483 				);
       
   484 			}
   465 		}
   485 		}
   466 
   486 
   467 		/*
   487 		/*
   468 		 * If the file doesn't exist, attempt a URL fopen on the src link.
   488 		 * If the file doesn't exist, attempt a URL fopen on the src link.
   469 		 * This can occur with certain file replication plugins.
   489 		 * This can occur with certain file replication plugins.
   482 				__( 'Unable to edit this image.' ),
   502 				__( 'Unable to edit this image.' ),
   483 				array( 'status' => 500 )
   503 				array( 'status' => 500 )
   484 			);
   504 			);
   485 		}
   505 		}
   486 
   506 
   487 		if ( 0 !== $rotate ) {
   507 		foreach ( $modifiers as $modifier ) {
   488 			$result = $image_editor->rotate( $rotate );
   508 			$args = $modifier['args'];
   489 
   509 			switch ( $modifier['type'] ) {
   490 			if ( is_wp_error( $result ) ) {
   510 				case 'rotate':
   491 				return new WP_Error(
   511 					// Rotation direction: clockwise vs. counter clockwise.
   492 					'rest_image_rotation_failed',
   512 					$rotate = 0 - $args['angle'];
   493 					__( 'Unable to rotate this image.' ),
   513 
   494 					array( 'status' => 500 )
   514 					if ( 0 !== $rotate ) {
   495 				);
   515 						$result = $image_editor->rotate( $rotate );
   496 			}
   516 
   497 		}
   517 						if ( is_wp_error( $result ) ) {
   498 
   518 							return new WP_Error(
   499 		if ( $crop ) {
   519 								'rest_image_rotation_failed',
   500 			$size = $image_editor->get_size();
   520 								__( 'Unable to rotate this image.' ),
   501 
   521 								array( 'status' => 500 )
   502 			$crop_x = round( ( $size['width'] * floatval( $request['x'] ) ) / 100.0 );
   522 							);
   503 			$crop_y = round( ( $size['height'] * floatval( $request['y'] ) ) / 100.0 );
   523 						}
   504 			$width  = round( ( $size['width'] * floatval( $request['width'] ) ) / 100.0 );
   524 					}
   505 			$height = round( ( $size['height'] * floatval( $request['height'] ) ) / 100.0 );
   525 
   506 
   526 					break;
   507 			$result = $image_editor->crop( $crop_x, $crop_y, $width, $height );
   527 
   508 
   528 				case 'crop':
   509 			if ( is_wp_error( $result ) ) {
   529 					$size = $image_editor->get_size();
   510 				return new WP_Error(
   530 
   511 					'rest_image_crop_failed',
   531 					$crop_x = round( ( $size['width'] * $args['left'] ) / 100.0 );
   512 					__( 'Unable to crop this image.' ),
   532 					$crop_y = round( ( $size['height'] * $args['top'] ) / 100.0 );
   513 					array( 'status' => 500 )
   533 					$width  = round( ( $size['width'] * $args['width'] ) / 100.0 );
   514 				);
   534 					$height = round( ( $size['height'] * $args['height'] ) / 100.0 );
       
   535 
       
   536 					if ( $size['width'] !== $width && $size['height'] !== $height ) {
       
   537 						$result = $image_editor->crop( $crop_x, $crop_y, $width, $height );
       
   538 
       
   539 						if ( is_wp_error( $result ) ) {
       
   540 							return new WP_Error(
       
   541 								'rest_image_crop_failed',
       
   542 								__( 'Unable to crop this image.' ),
       
   543 								array( 'status' => 500 )
       
   544 							);
       
   545 						}
       
   546 					}
       
   547 
       
   548 					break;
       
   549 
   515 			}
   550 			}
   516 		}
   551 		}
   517 
   552 
   518 		// Calculate the file name.
   553 		// Calculate the file name.
   519 		$image_ext  = pathinfo( $image_file, PATHINFO_EXTENSION );
   554 		$image_ext  = pathinfo( $image_file, PATHINFO_EXTENSION );
   851 				'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database().
   886 				'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database().
   852 				'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database().
   887 				'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database().
   853 			),
   888 			),
   854 			'properties'  => array(
   889 			'properties'  => array(
   855 				'raw'      => array(
   890 				'raw'      => array(
   856 					'description' => __( 'Description for the object, as it exists in the database.' ),
   891 					'description' => __( 'Description for the attachment, as it exists in the database.' ),
   857 					'type'        => 'string',
   892 					'type'        => 'string',
   858 					'context'     => array( 'edit' ),
   893 					'context'     => array( 'edit' ),
   859 				),
   894 				),
   860 				'rendered' => array(
   895 				'rendered' => array(
   861 					'description' => __( 'HTML description for the object, transformed for display.' ),
   896 					'description' => __( 'HTML description for the attachment, transformed for display.' ),
   862 					'type'        => 'string',
   897 					'type'        => 'string',
   863 					'context'     => array( 'view', 'edit' ),
   898 					'context'     => array( 'view', 'edit' ),
   864 					'readonly'    => true,
   899 					'readonly'    => true,
   865 				),
   900 				),
   866 			),
   901 			),
  1279 	 *
  1314 	 *
  1280 	 * @return array
  1315 	 * @return array
  1281 	 */
  1316 	 */
  1282 	protected function get_edit_media_item_args() {
  1317 	protected function get_edit_media_item_args() {
  1283 		return array(
  1318 		return array(
  1284 			'rotation' => array(
  1319 			'src'       => array(
  1285 				'description'      => __( 'The amount to rotate the image clockwise in degrees.' ),
  1320 				'description' => __( 'URL to the edited image file.' ),
       
  1321 				'type'        => 'string',
       
  1322 				'format'      => 'uri',
       
  1323 				'required'    => true,
       
  1324 			),
       
  1325 			'modifiers' => array(
       
  1326 				'description' => __( 'Array of image edits.' ),
       
  1327 				'type'        => 'array',
       
  1328 				'minItems'    => 1,
       
  1329 				'items'       => array(
       
  1330 					'description' => __( 'Image edit.' ),
       
  1331 					'type'        => 'object',
       
  1332 					'required'    => array(
       
  1333 						'type',
       
  1334 						'args',
       
  1335 					),
       
  1336 					'oneOf'       => array(
       
  1337 						array(
       
  1338 							'title'      => __( 'Rotation' ),
       
  1339 							'properties' => array(
       
  1340 								'type' => array(
       
  1341 									'description' => __( 'Rotation type.' ),
       
  1342 									'type'        => 'string',
       
  1343 									'enum'        => array( 'rotate' ),
       
  1344 								),
       
  1345 								'args' => array(
       
  1346 									'description' => __( 'Rotation arguments.' ),
       
  1347 									'type'        => 'object',
       
  1348 									'required'    => array(
       
  1349 										'angle',
       
  1350 									),
       
  1351 									'properties'  => array(
       
  1352 										'angle' => array(
       
  1353 											'description' => __( 'Angle to rotate clockwise in degrees.' ),
       
  1354 											'type'        => 'number',
       
  1355 										),
       
  1356 									),
       
  1357 								),
       
  1358 							),
       
  1359 						),
       
  1360 						array(
       
  1361 							'title'      => __( 'Crop' ),
       
  1362 							'properties' => array(
       
  1363 								'type' => array(
       
  1364 									'description' => __( 'Crop type.' ),
       
  1365 									'type'        => 'string',
       
  1366 									'enum'        => array( 'crop' ),
       
  1367 								),
       
  1368 								'args' => array(
       
  1369 									'description' => __( 'Crop arguments.' ),
       
  1370 									'type'        => 'object',
       
  1371 									'required'    => array(
       
  1372 										'left',
       
  1373 										'top',
       
  1374 										'width',
       
  1375 										'height',
       
  1376 									),
       
  1377 									'properties'  => array(
       
  1378 										'left'   => array(
       
  1379 											'description' => __( 'Horizontal position from the left to begin the crop as a percentage of the image width.' ),
       
  1380 											'type'        => 'number',
       
  1381 										),
       
  1382 										'top'    => array(
       
  1383 											'description' => __( 'Vertical position from the top to begin the crop as a percentage of the image height.' ),
       
  1384 											'type'        => 'number',
       
  1385 										),
       
  1386 										'width'  => array(
       
  1387 											'description' => __( 'Width of the crop as a percentage of the image width.' ),
       
  1388 											'type'        => 'number',
       
  1389 										),
       
  1390 										'height' => array(
       
  1391 											'description' => __( 'Height of the crop as a percentage of the image height.' ),
       
  1392 											'type'        => 'number',
       
  1393 										),
       
  1394 									),
       
  1395 								),
       
  1396 							),
       
  1397 						),
       
  1398 					),
       
  1399 				),
       
  1400 			),
       
  1401 			'rotation'  => array(
       
  1402 				'description'      => __( 'The amount to rotate the image clockwise in degrees. DEPRECATED: Use `modifiers` instead.' ),
  1286 				'type'             => 'integer',
  1403 				'type'             => 'integer',
  1287 				'minimum'          => 0,
  1404 				'minimum'          => 0,
  1288 				'exclusiveMinimum' => true,
  1405 				'exclusiveMinimum' => true,
  1289 				'maximum'          => 360,
  1406 				'maximum'          => 360,
  1290 				'exclusiveMaximum' => true,
  1407 				'exclusiveMaximum' => true,
  1291 			),
  1408 			),
  1292 			'x'        => array(
  1409 			'x'         => array(
  1293 				'description' => __( 'As a percentage of the image, the x position to start the crop from.' ),
  1410 				'description' => __( 'As a percentage of the image, the x position to start the crop from. DEPRECATED: Use `modifiers` instead.' ),
  1294 				'type'        => 'number',
  1411 				'type'        => 'number',
  1295 				'minimum'     => 0,
  1412 				'minimum'     => 0,
  1296 				'maximum'     => 100,
  1413 				'maximum'     => 100,
  1297 			),
  1414 			),
  1298 			'y'        => array(
  1415 			'y'         => array(
  1299 				'description' => __( 'As a percentage of the image, the y position to start the crop from.' ),
  1416 				'description' => __( 'As a percentage of the image, the y position to start the crop from. DEPRECATED: Use `modifiers` instead.' ),
  1300 				'type'        => 'number',
  1417 				'type'        => 'number',
  1301 				'minimum'     => 0,
  1418 				'minimum'     => 0,
  1302 				'maximum'     => 100,
  1419 				'maximum'     => 100,
  1303 			),
  1420 			),
  1304 			'width'    => array(
  1421 			'width'     => array(
  1305 				'description' => __( 'As a percentage of the image, the width to crop the image to.' ),
  1422 				'description' => __( 'As a percentage of the image, the width to crop the image to. DEPRECATED: Use `modifiers` instead.' ),
  1306 				'type'        => 'number',
  1423 				'type'        => 'number',
  1307 				'minimum'     => 0,
  1424 				'minimum'     => 0,
  1308 				'maximum'     => 100,
  1425 				'maximum'     => 100,
  1309 			),
  1426 			),
  1310 			'height'   => array(
  1427 			'height'    => array(
  1311 				'description' => __( 'As a percentage of the image, the height to crop the image to.' ),
  1428 				'description' => __( 'As a percentage of the image, the height to crop the image to. DEPRECATED: Use `modifiers` instead.' ),
  1312 				'type'        => 'number',
  1429 				'type'        => 'number',
  1313 				'minimum'     => 0,
  1430 				'minimum'     => 0,
  1314 				'maximum'     => 100,
  1431 				'maximum'     => 100,
  1315 			),
  1432 			),
  1316 			'src'      => array(
       
  1317 				'description' => __( 'URL to the edited image file.' ),
       
  1318 				'type'        => 'string',
       
  1319 				'format'      => 'uri',
       
  1320 				'required'    => true,
       
  1321 			),
       
  1322 		);
  1433 		);
  1323 	}
  1434 	}
  1324 
  1435 
  1325 }
  1436 }