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 { |
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 } |