90 * Creates a single attachment. |
134 * Creates a single attachment. |
91 * |
135 * |
92 * @since 4.7.0 |
136 * @since 4.7.0 |
93 * |
137 * |
94 * @param WP_REST_Request $request Full details about the request. |
138 * @param WP_REST_Request $request Full details about the request. |
95 * @return WP_Error|WP_REST_Response Response object on success, WP_Error object on failure. |
139 * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. |
96 */ |
140 */ |
97 public function create_item( $request ) { |
141 public function create_item( $request ) { |
98 |
|
99 if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ), true ) ) { |
142 if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ), true ) ) { |
100 return new WP_Error( 'rest_invalid_param', __( 'Invalid parent type.' ), array( 'status' => 400 ) ); |
143 return new WP_Error( |
101 } |
144 'rest_invalid_param', |
102 |
145 __( 'Invalid parent type.' ), |
|
146 array( 'status' => 400 ) |
|
147 ); |
|
148 } |
|
149 |
|
150 $insert = $this->insert_attachment( $request ); |
|
151 |
|
152 if ( is_wp_error( $insert ) ) { |
|
153 return $insert; |
|
154 } |
|
155 |
|
156 $schema = $this->get_item_schema(); |
|
157 |
|
158 // Extract by name. |
|
159 $attachment_id = $insert['attachment_id']; |
|
160 $file = $insert['file']; |
|
161 |
|
162 if ( isset( $request['alt_text'] ) ) { |
|
163 update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) ); |
|
164 } |
|
165 |
|
166 if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) { |
|
167 $meta_update = $this->meta->update_value( $request['meta'], $attachment_id ); |
|
168 |
|
169 if ( is_wp_error( $meta_update ) ) { |
|
170 return $meta_update; |
|
171 } |
|
172 } |
|
173 |
|
174 $attachment = get_post( $attachment_id ); |
|
175 $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); |
|
176 |
|
177 if ( is_wp_error( $fields_update ) ) { |
|
178 return $fields_update; |
|
179 } |
|
180 |
|
181 $request->set_param( 'context', 'edit' ); |
|
182 |
|
183 /** |
|
184 * Fires after a single attachment is completely created or updated via the REST API. |
|
185 * |
|
186 * @since 5.0.0 |
|
187 * |
|
188 * @param WP_Post $attachment Inserted or updated attachment object. |
|
189 * @param WP_REST_Request $request Request object. |
|
190 * @param bool $creating True when creating an attachment, false when updating. |
|
191 */ |
|
192 do_action( 'rest_after_insert_attachment', $attachment, $request, true ); |
|
193 |
|
194 if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { |
|
195 // 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. |
|
197 header( 'X-WP-Upload-Attachment-ID: ' . $attachment_id ); |
|
198 } |
|
199 |
|
200 // Include media and image functions to get access to wp_generate_attachment_metadata(). |
|
201 require_once ABSPATH . 'wp-admin/includes/media.php'; |
|
202 require_once ABSPATH . 'wp-admin/includes/image.php'; |
|
203 |
|
204 // Post-process the upload (create image sub-sizes, make PDF thumbnails, etc.) and insert attachment meta. |
|
205 // At this point the server may run out of resources and post-processing of uploaded images may fail. |
|
206 wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) ); |
|
207 |
|
208 $response = $this->prepare_item_for_response( $attachment, $request ); |
|
209 $response = rest_ensure_response( $response ); |
|
210 $response->set_status( 201 ); |
|
211 $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $attachment_id ) ) ); |
|
212 |
|
213 return $response; |
|
214 } |
|
215 |
|
216 /** |
|
217 * Inserts the attachment post in the database. Does not update the attachment meta. |
|
218 * |
|
219 * @since 5.3.0 |
|
220 * |
|
221 * @param WP_REST_Request $request |
|
222 * @return array|WP_Error |
|
223 */ |
|
224 protected function insert_attachment( $request ) { |
103 // Get the file via $_FILES or raw data. |
225 // Get the file via $_FILES or raw data. |
104 $files = $request->get_file_params(); |
226 $files = $request->get_file_params(); |
105 $headers = $request->get_headers(); |
227 $headers = $request->get_headers(); |
106 |
228 |
107 if ( ! empty( $files ) ) { |
229 if ( ! empty( $files ) ) { |
170 * @param WP_REST_Request $request The request sent to the API. |
294 * @param WP_REST_Request $request The request sent to the API. |
171 * @param bool $creating True when creating an attachment, false when updating. |
295 * @param bool $creating True when creating an attachment, false when updating. |
172 */ |
296 */ |
173 do_action( 'rest_insert_attachment', $attachment, $request, true ); |
297 do_action( 'rest_insert_attachment', $attachment, $request, true ); |
174 |
298 |
175 // Include admin function to get access to wp_generate_attachment_metadata(). |
299 return array( |
176 require_once ABSPATH . 'wp-admin/includes/media.php'; |
300 'attachment_id' => $id, |
177 |
301 'file' => $file, |
178 wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) ); |
302 ); |
|
303 } |
|
304 |
|
305 /** |
|
306 * Updates a single attachment. |
|
307 * |
|
308 * @since 4.7.0 |
|
309 * |
|
310 * @param WP_REST_Request $request Full details about the request. |
|
311 * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. |
|
312 */ |
|
313 public function update_item( $request ) { |
|
314 if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ), true ) ) { |
|
315 return new WP_Error( |
|
316 'rest_invalid_param', |
|
317 __( 'Invalid parent type.' ), |
|
318 array( 'status' => 400 ) |
|
319 ); |
|
320 } |
|
321 |
|
322 $response = parent::update_item( $request ); |
|
323 |
|
324 if ( is_wp_error( $response ) ) { |
|
325 return $response; |
|
326 } |
|
327 |
|
328 $response = rest_ensure_response( $response ); |
|
329 $data = $response->get_data(); |
179 |
330 |
180 if ( isset( $request['alt_text'] ) ) { |
331 if ( isset( $request['alt_text'] ) ) { |
181 update_post_meta( $id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) ); |
332 update_post_meta( $data['id'], '_wp_attachment_image_alt', $request['alt_text'] ); |
182 } |
333 } |
|
334 |
|
335 $attachment = get_post( $request['id'] ); |
183 |
336 |
184 $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); |
337 $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); |
185 |
338 |
186 if ( is_wp_error( $fields_update ) ) { |
339 if ( is_wp_error( $fields_update ) ) { |
187 return $fields_update; |
340 return $fields_update; |
188 } |
341 } |
189 |
342 |
190 $request->set_param( 'context', 'edit' ); |
343 $request->set_param( 'context', 'edit' ); |
191 |
344 |
192 /** |
345 /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */ |
193 * Fires after a single attachment is completely created or updated via the REST API. |
346 do_action( 'rest_after_insert_attachment', $attachment, $request, false ); |
194 * |
|
195 * @since 5.0.0 |
|
196 * |
|
197 * @param WP_Post $attachment Inserted or updated attachment object. |
|
198 * @param WP_REST_Request $request Request object. |
|
199 * @param bool $creating True when creating an attachment, false when updating. |
|
200 */ |
|
201 do_action( 'rest_after_insert_attachment', $attachment, $request, true ); |
|
202 |
347 |
203 $response = $this->prepare_item_for_response( $attachment, $request ); |
348 $response = $this->prepare_item_for_response( $attachment, $request ); |
204 $response = rest_ensure_response( $response ); |
349 $response = rest_ensure_response( $response ); |
|
350 |
|
351 return $response; |
|
352 } |
|
353 |
|
354 /** |
|
355 * Performs post processing on an attachment. |
|
356 * |
|
357 * @since 5.3.0 |
|
358 * |
|
359 * @param WP_REST_Request $request Full details about the request. |
|
360 * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. |
|
361 */ |
|
362 public function post_process_item( $request ) { |
|
363 switch ( $request['action'] ) { |
|
364 case 'create-image-subsizes': |
|
365 require_once ABSPATH . 'wp-admin/includes/image.php'; |
|
366 wp_update_image_subsizes( $request['id'] ); |
|
367 break; |
|
368 } |
|
369 |
|
370 $request['context'] = 'edit'; |
|
371 |
|
372 return $this->prepare_item_for_response( get_post( $request['id'] ), $request ); |
|
373 } |
|
374 |
|
375 /** |
|
376 * Checks if a given request can perform post processing on an attachment. |
|
377 * |
|
378 * @since 5.3.0 |
|
379 * |
|
380 * @param WP_REST_Request $request Full details about the request. |
|
381 * @return true|WP_Error True if the request has access to update the item, WP_Error object otherwise. |
|
382 */ |
|
383 public function post_process_item_permissions_check( $request ) { |
|
384 return $this->update_item_permissions_check( $request ); |
|
385 } |
|
386 |
|
387 /** |
|
388 * Checks if a given request has access to editing media. |
|
389 * |
|
390 * @since 5.5.0 |
|
391 * |
|
392 * @param WP_REST_Request $request Full details about the request. |
|
393 * @return true|WP_Error True if the request has read access, WP_Error object otherwise. |
|
394 */ |
|
395 public function edit_media_item_permissions_check( $request ) { |
|
396 if ( ! current_user_can( 'upload_files' ) ) { |
|
397 return new WP_Error( |
|
398 'rest_cannot_edit_image', |
|
399 __( 'Sorry, you are not allowed to upload media on this site.' ), |
|
400 array( 'status' => rest_authorization_required_code() ) |
|
401 ); |
|
402 } |
|
403 |
|
404 return $this->update_item_permissions_check( $request ); |
|
405 } |
|
406 |
|
407 /** |
|
408 * Applies edits to a media item and creates a new attachment record. |
|
409 * |
|
410 * @since 5.5.0 |
|
411 * |
|
412 * @param WP_REST_Request $request Full details about the request. |
|
413 * @return WP_REST_Response|WP_Error Response object on success, WP_Error object on failure. |
|
414 */ |
|
415 public function edit_media_item( $request ) { |
|
416 require_once ABSPATH . 'wp-admin/includes/image.php'; |
|
417 |
|
418 $attachment_id = $request['id']; |
|
419 |
|
420 // This also confirms the attachment is an image. |
|
421 $image_file = wp_get_original_image_path( $attachment_id ); |
|
422 $image_meta = wp_get_attachment_metadata( $attachment_id ); |
|
423 |
|
424 if ( |
|
425 ! $image_meta || |
|
426 ! $image_file || |
|
427 ! wp_image_file_matches_image_meta( $request['src'], $image_meta, $attachment_id ) |
|
428 ) { |
|
429 return new WP_Error( |
|
430 'rest_unknown_attachment', |
|
431 __( 'Unable to get meta information for file.' ), |
|
432 array( 'status' => 404 ) |
|
433 ); |
|
434 } |
|
435 |
|
436 $supported_types = array( 'image/jpeg', 'image/png', 'image/gif' ); |
|
437 $mime_type = get_post_mime_type( $attachment_id ); |
|
438 if ( ! in_array( $mime_type, $supported_types, true ) ) { |
|
439 return new WP_Error( |
|
440 'rest_cannot_edit_file_type', |
|
441 __( 'This type of file cannot be edited.' ), |
|
442 array( 'status' => 400 ) |
|
443 ); |
|
444 } |
|
445 |
|
446 // Check if we need to do anything. |
|
447 $rotate = 0; |
|
448 $crop = false; |
|
449 |
|
450 if ( ! empty( $request['rotation'] ) ) { |
|
451 // Rotation direction: clockwise vs. counter clockwise. |
|
452 $rotate = 0 - (int) $request['rotation']; |
|
453 } |
|
454 |
|
455 if ( isset( $request['x'], $request['y'], $request['width'], $request['height'] ) ) { |
|
456 $crop = true; |
|
457 } |
|
458 |
|
459 if ( ! $rotate && ! $crop ) { |
|
460 return new WP_Error( |
|
461 'rest_image_not_edited', |
|
462 __( 'The image was not edited. Edit the image before applying the changes.' ), |
|
463 array( 'status' => 400 ) |
|
464 ); |
|
465 } |
|
466 |
|
467 /* |
|
468 * If the file doesn't exist, attempt a URL fopen on the src link. |
|
469 * This can occur with certain file replication plugins. |
|
470 * Keep the original file path to get a modified name later. |
|
471 */ |
|
472 $image_file_to_edit = $image_file; |
|
473 if ( ! file_exists( $image_file_to_edit ) ) { |
|
474 $image_file_to_edit = _load_image_to_edit_path( $attachment_id ); |
|
475 } |
|
476 |
|
477 $image_editor = wp_get_image_editor( $image_file_to_edit ); |
|
478 |
|
479 if ( is_wp_error( $image_editor ) ) { |
|
480 return new WP_Error( |
|
481 'rest_unknown_image_file_type', |
|
482 __( 'Unable to edit this image.' ), |
|
483 array( 'status' => 500 ) |
|
484 ); |
|
485 } |
|
486 |
|
487 if ( 0 !== $rotate ) { |
|
488 $result = $image_editor->rotate( $rotate ); |
|
489 |
|
490 if ( is_wp_error( $result ) ) { |
|
491 return new WP_Error( |
|
492 'rest_image_rotation_failed', |
|
493 __( 'Unable to rotate this image.' ), |
|
494 array( 'status' => 500 ) |
|
495 ); |
|
496 } |
|
497 } |
|
498 |
|
499 if ( $crop ) { |
|
500 $size = $image_editor->get_size(); |
|
501 |
|
502 $crop_x = round( ( $size['width'] * floatval( $request['x'] ) ) / 100.0 ); |
|
503 $crop_y = round( ( $size['height'] * floatval( $request['y'] ) ) / 100.0 ); |
|
504 $width = round( ( $size['width'] * floatval( $request['width'] ) ) / 100.0 ); |
|
505 $height = round( ( $size['height'] * floatval( $request['height'] ) ) / 100.0 ); |
|
506 |
|
507 $result = $image_editor->crop( $crop_x, $crop_y, $width, $height ); |
|
508 |
|
509 if ( is_wp_error( $result ) ) { |
|
510 return new WP_Error( |
|
511 'rest_image_crop_failed', |
|
512 __( 'Unable to crop this image.' ), |
|
513 array( 'status' => 500 ) |
|
514 ); |
|
515 } |
|
516 } |
|
517 |
|
518 // Calculate the file name. |
|
519 $image_ext = pathinfo( $image_file, PATHINFO_EXTENSION ); |
|
520 $image_name = wp_basename( $image_file, ".{$image_ext}" ); |
|
521 |
|
522 // Do not append multiple `-edited` to the file name. |
|
523 // The user may be editing a previously edited image. |
|
524 if ( preg_match( '/-edited(-\d+)?$/', $image_name ) ) { |
|
525 // Remove any `-1`, `-2`, etc. `wp_unique_filename()` will add the proper number. |
|
526 $image_name = preg_replace( '/-edited(-\d+)?$/', '-edited', $image_name ); |
|
527 } else { |
|
528 // Append `-edited` before the extension. |
|
529 $image_name .= '-edited'; |
|
530 } |
|
531 |
|
532 $filename = "{$image_name}.{$image_ext}"; |
|
533 |
|
534 // Create the uploads sub-directory if needed. |
|
535 $uploads = wp_upload_dir(); |
|
536 |
|
537 // Make the file name unique in the (new) upload directory. |
|
538 $filename = wp_unique_filename( $uploads['path'], $filename ); |
|
539 |
|
540 // Save to disk. |
|
541 $saved = $image_editor->save( $uploads['path'] . "/$filename" ); |
|
542 |
|
543 if ( is_wp_error( $saved ) ) { |
|
544 return $saved; |
|
545 } |
|
546 |
|
547 // Create new attachment post. |
|
548 $new_attachment_post = array( |
|
549 'post_mime_type' => $saved['mime-type'], |
|
550 'guid' => $uploads['url'] . "/$filename", |
|
551 'post_title' => $image_name, |
|
552 'post_content' => '', |
|
553 ); |
|
554 |
|
555 // Copy post_content, post_excerpt, and post_title from the edited image's attachment post. |
|
556 $attachment_post = get_post( $attachment_id ); |
|
557 |
|
558 if ( $attachment_post ) { |
|
559 $new_attachment_post['post_content'] = $attachment_post->post_content; |
|
560 $new_attachment_post['post_excerpt'] = $attachment_post->post_excerpt; |
|
561 $new_attachment_post['post_title'] = $attachment_post->post_title; |
|
562 } |
|
563 |
|
564 $new_attachment_id = wp_insert_attachment( wp_slash( $new_attachment_post ), $saved['path'], 0, true ); |
|
565 |
|
566 if ( is_wp_error( $new_attachment_id ) ) { |
|
567 if ( 'db_update_error' === $new_attachment_id->get_error_code() ) { |
|
568 $new_attachment_id->add_data( array( 'status' => 500 ) ); |
|
569 } else { |
|
570 $new_attachment_id->add_data( array( 'status' => 400 ) ); |
|
571 } |
|
572 |
|
573 return $new_attachment_id; |
|
574 } |
|
575 |
|
576 // Copy the image alt text from the edited image. |
|
577 $image_alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ); |
|
578 |
|
579 if ( ! empty( $image_alt ) ) { |
|
580 // update_post_meta() expects slashed. |
|
581 update_post_meta( $new_attachment_id, '_wp_attachment_image_alt', wp_slash( $image_alt ) ); |
|
582 } |
|
583 |
|
584 if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { |
|
585 // Set a custom header with the attachment_id. |
|
586 // Used by the browser/client to resume creating image sub-sizes after a PHP fatal error. |
|
587 header( 'X-WP-Upload-Attachment-ID: ' . $new_attachment_id ); |
|
588 } |
|
589 |
|
590 // Generate image sub-sizes and meta. |
|
591 $new_image_meta = wp_generate_attachment_metadata( $new_attachment_id, $saved['path'] ); |
|
592 |
|
593 // Copy the EXIF metadata from the original attachment if not generated for the edited image. |
|
594 if ( isset( $image_meta['image_meta'] ) && isset( $new_image_meta['image_meta'] ) && is_array( $new_image_meta['image_meta'] ) ) { |
|
595 // Merge but skip empty values. |
|
596 foreach ( (array) $image_meta['image_meta'] as $key => $value ) { |
|
597 if ( empty( $new_image_meta['image_meta'][ $key ] ) && ! empty( $value ) ) { |
|
598 $new_image_meta['image_meta'][ $key ] = $value; |
|
599 } |
|
600 } |
|
601 } |
|
602 |
|
603 // Reset orientation. At this point the image is edited and orientation is correct. |
|
604 if ( ! empty( $new_image_meta['image_meta']['orientation'] ) ) { |
|
605 $new_image_meta['image_meta']['orientation'] = 1; |
|
606 } |
|
607 |
|
608 // The attachment_id may change if the site is exported and imported. |
|
609 $new_image_meta['parent_image'] = array( |
|
610 'attachment_id' => $attachment_id, |
|
611 // Path to the originally uploaded image file relative to the uploads directory. |
|
612 'file' => _wp_relative_upload_path( $image_file ), |
|
613 ); |
|
614 |
|
615 /** |
|
616 * Filters the meta data for the new image created by editing an existing image. |
|
617 * |
|
618 * @since 5.5.0 |
|
619 * |
|
620 * @param array $new_image_meta Meta data for the new image. |
|
621 * @param int $new_attachment_id Attachment post ID for the new image. |
|
622 * @param int $attachment_id Attachment post ID for the edited (parent) image. |
|
623 */ |
|
624 $new_image_meta = apply_filters( 'wp_edited_image_metadata', $new_image_meta, $new_attachment_id, $attachment_id ); |
|
625 |
|
626 wp_update_attachment_metadata( $new_attachment_id, $new_image_meta ); |
|
627 |
|
628 $response = $this->prepare_item_for_response( get_post( $new_attachment_id ), $request ); |
205 $response->set_status( 201 ); |
629 $response->set_status( 201 ); |
206 $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $id ) ) ); |
630 $response->header( 'Location', rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $new_attachment_id ) ) ); |
207 |
631 |
208 return $response; |
632 return $response; |
209 } |
633 } |
210 |
634 |
211 /** |
635 /** |
212 * Updates a single attachment. |
636 * Prepares a single attachment for create or update. |
213 * |
637 * |
214 * @since 4.7.0 |
638 * @since 4.7.0 |
215 * |
639 * |
216 * @param WP_REST_Request $request Full details about the request. |
|
217 * @return WP_Error|WP_REST_Response Response object on success, WP_Error object on failure. |
|
218 */ |
|
219 public function update_item( $request ) { |
|
220 if ( ! empty( $request['post'] ) && in_array( get_post_type( $request['post'] ), array( 'revision', 'attachment' ), true ) ) { |
|
221 return new WP_Error( 'rest_invalid_param', __( 'Invalid parent type.' ), array( 'status' => 400 ) ); |
|
222 } |
|
223 |
|
224 $response = parent::update_item( $request ); |
|
225 |
|
226 if ( is_wp_error( $response ) ) { |
|
227 return $response; |
|
228 } |
|
229 |
|
230 $response = rest_ensure_response( $response ); |
|
231 $data = $response->get_data(); |
|
232 |
|
233 if ( isset( $request['alt_text'] ) ) { |
|
234 update_post_meta( $data['id'], '_wp_attachment_image_alt', $request['alt_text'] ); |
|
235 } |
|
236 |
|
237 $attachment = get_post( $request['id'] ); |
|
238 |
|
239 $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); |
|
240 |
|
241 if ( is_wp_error( $fields_update ) ) { |
|
242 return $fields_update; |
|
243 } |
|
244 |
|
245 $request->set_param( 'context', 'edit' ); |
|
246 |
|
247 /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php */ |
|
248 do_action( 'rest_after_insert_attachment', $attachment, $request, false ); |
|
249 |
|
250 $response = $this->prepare_item_for_response( $attachment, $request ); |
|
251 $response = rest_ensure_response( $response ); |
|
252 |
|
253 return $response; |
|
254 } |
|
255 |
|
256 /** |
|
257 * Prepares a single attachment for create or update. |
|
258 * |
|
259 * @since 4.7.0 |
|
260 * |
|
261 * @param WP_REST_Request $request Request object. |
640 * @param WP_REST_Request $request Request object. |
262 * @return WP_Error|stdClass $prepared_attachment Post object. |
641 * @return stdClass|WP_Error Post object. |
263 */ |
642 */ |
264 protected function prepare_item_for_database( $request ) { |
643 protected function prepare_item_for_database( $request ) { |
265 $prepared_attachment = parent::prepare_item_for_database( $request ); |
644 $prepared_attachment = parent::prepare_item_for_database( $request ); |
266 |
645 |
267 // Attachment caption (post_excerpt internally) |
646 // Attachment caption (post_excerpt internally). |
268 if ( isset( $request['caption'] ) ) { |
647 if ( isset( $request['caption'] ) ) { |
269 if ( is_string( $request['caption'] ) ) { |
648 if ( is_string( $request['caption'] ) ) { |
270 $prepared_attachment->post_excerpt = $request['caption']; |
649 $prepared_attachment->post_excerpt = $request['caption']; |
271 } elseif ( isset( $request['caption']['raw'] ) ) { |
650 } elseif ( isset( $request['caption']['raw'] ) ) { |
272 $prepared_attachment->post_excerpt = $request['caption']['raw']; |
651 $prepared_attachment->post_excerpt = $request['caption']['raw']; |
273 } |
652 } |
274 } |
653 } |
275 |
654 |
276 // Attachment description (post_content internally) |
655 // Attachment description (post_content internally). |
277 if ( isset( $request['description'] ) ) { |
656 if ( isset( $request['description'] ) ) { |
278 if ( is_string( $request['description'] ) ) { |
657 if ( is_string( $request['description'] ) ) { |
279 $prepared_attachment->post_content = $request['description']; |
658 $prepared_attachment->post_content = $request['description']; |
280 } elseif ( isset( $request['description']['raw'] ) ) { |
659 } elseif ( isset( $request['description']['raw'] ) ) { |
281 $prepared_attachment->post_content = $request['description']['raw']; |
660 $prepared_attachment->post_content = $request['description']['raw']; |
525 * @param array $headers HTTP headers from the request. |
926 * @param array $headers HTTP headers from the request. |
526 * @return array|WP_Error Data from wp_handle_sideload(). |
927 * @return array|WP_Error Data from wp_handle_sideload(). |
527 */ |
928 */ |
528 protected function upload_from_data( $data, $headers ) { |
929 protected function upload_from_data( $data, $headers ) { |
529 if ( empty( $data ) ) { |
930 if ( empty( $data ) ) { |
530 return new WP_Error( 'rest_upload_no_data', __( 'No data supplied.' ), array( 'status' => 400 ) ); |
931 return new WP_Error( |
|
932 'rest_upload_no_data', |
|
933 __( 'No data supplied.' ), |
|
934 array( 'status' => 400 ) |
|
935 ); |
531 } |
936 } |
532 |
937 |
533 if ( empty( $headers['content_type'] ) ) { |
938 if ( empty( $headers['content_type'] ) ) { |
534 return new WP_Error( 'rest_upload_no_content_type', __( 'No Content-Type supplied.' ), array( 'status' => 400 ) ); |
939 return new WP_Error( |
|
940 'rest_upload_no_content_type', |
|
941 __( 'No Content-Type supplied.' ), |
|
942 array( 'status' => 400 ) |
|
943 ); |
535 } |
944 } |
536 |
945 |
537 if ( empty( $headers['content_disposition'] ) ) { |
946 if ( empty( $headers['content_disposition'] ) ) { |
538 return new WP_Error( 'rest_upload_no_content_disposition', __( 'No Content-Disposition supplied.' ), array( 'status' => 400 ) ); |
947 return new WP_Error( |
|
948 'rest_upload_no_content_disposition', |
|
949 __( 'No Content-Disposition supplied.' ), |
|
950 array( 'status' => 400 ) |
|
951 ); |
539 } |
952 } |
540 |
953 |
541 $filename = self::get_filename_from_disposition( $headers['content_disposition'] ); |
954 $filename = self::get_filename_from_disposition( $headers['content_disposition'] ); |
542 |
955 |
543 if ( empty( $filename ) ) { |
956 if ( empty( $filename ) ) { |
544 return new WP_Error( 'rest_upload_invalid_disposition', __( 'Invalid Content-Disposition supplied. Content-Disposition needs to be formatted as `attachment; filename="image.png"` or similar.' ), array( 'status' => 400 ) ); |
957 return new WP_Error( |
|
958 'rest_upload_invalid_disposition', |
|
959 __( 'Invalid Content-Disposition supplied. Content-Disposition needs to be formatted as `attachment; filename="image.png"` or similar.' ), |
|
960 array( 'status' => 400 ) |
|
961 ); |
545 } |
962 } |
546 |
963 |
547 if ( ! empty( $headers['content_md5'] ) ) { |
964 if ( ! empty( $headers['content_md5'] ) ) { |
548 $content_md5 = array_shift( $headers['content_md5'] ); |
965 $content_md5 = array_shift( $headers['content_md5'] ); |
549 $expected = trim( $content_md5 ); |
966 $expected = trim( $content_md5 ); |
550 $actual = md5( $data ); |
967 $actual = md5( $data ); |
551 |
968 |
552 if ( $expected !== $actual ) { |
969 if ( $expected !== $actual ) { |
553 return new WP_Error( 'rest_upload_hash_mismatch', __( 'Content hash did not match expected.' ), array( 'status' => 412 ) ); |
970 return new WP_Error( |
|
971 'rest_upload_hash_mismatch', |
|
972 __( 'Content hash did not match expected.' ), |
|
973 array( 'status' => 412 ) |
|
974 ); |
554 } |
975 } |
555 } |
976 } |
556 |
977 |
557 // Get the content-type. |
978 // Get the content-type. |
558 $type = array_shift( $headers['content_type'] ); |
979 $type = array_shift( $headers['content_type'] ); |
559 |
980 |
560 /** Include admin functions to get access to wp_tempnam() and wp_handle_sideload(). */ |
981 // Include filesystem functions to get access to wp_tempnam() and wp_handle_sideload(). |
561 require_once ABSPATH . 'wp-admin/includes/file.php'; |
982 require_once ABSPATH . 'wp-admin/includes/file.php'; |
562 |
983 |
563 // Save the file. |
984 // Save the file. |
564 $tmpfname = wp_tempnam( $filename ); |
985 $tmpfname = wp_tempnam( $filename ); |
565 |
986 |
566 $fp = fopen( $tmpfname, 'w+' ); |
987 $fp = fopen( $tmpfname, 'w+' ); |
567 |
988 |
568 if ( ! $fp ) { |
989 if ( ! $fp ) { |
569 return new WP_Error( 'rest_upload_file_error', __( 'Could not open file handle.' ), array( 'status' => 500 ) ); |
990 return new WP_Error( |
|
991 'rest_upload_file_error', |
|
992 __( 'Could not open file handle.' ), |
|
993 array( 'status' => 500 ) |
|
994 ); |
570 } |
995 } |
571 |
996 |
572 fwrite( $fp, $data ); |
997 fwrite( $fp, $data ); |
573 fclose( $fp ); |
998 fclose( $fp ); |
574 |
999 |