| | 103 | $upload_ref = $request->get_header( 'X-WP-UploadRef' ); |
| | 104 | $post_process = $request->get_header( 'X-WP-UploadPostProcess' ); |
| | 105 | |
| | 106 | if ( $upload_ref && $post_process ) { |
| | 107 | // Include upload ref functions. |
| | 108 | require_once ABSPATH . 'wp-admin/includes/file.php'; |
| | 109 | |
| | 110 | $attachment_id = _wp_get_upload_ref_attachment_id( $upload_ref ); |
| | 111 | |
| | 112 | if ( ! $attachment_id ) { |
| | 113 | // The upload has failed before an attachment post was created. |
| | 114 | return new WP_Error( 'upload_reference_not_found', __( 'Upload failed. Please try again.' ), array( 'status' => 404 ) ); |
| | 115 | } |
| | 116 | |
| | 117 | if ( 'create-image-subsizes' === $post_process ) { |
| | 118 | // Try to create image sub-sizes again. |
| | 119 | // This can still be pretty slow and cause timeout or out of memory errors. |
| | 120 | // The client would need to also handle HTTP 500 responses. |
| | 121 | require_once ABSPATH . 'wp-admin/includes/image.php'; |
| | 122 | wp_update_image_subsizes( $attachment_id ); |
| | 123 | |
| | 124 | // If this completed successfully the upload ref is no longer needed. |
| | 125 | _wp_clear_upload_ref( $upload_ref ); |
| | 126 | } elseif ( 'upload-failed-cleanup' === $post_process ) { |
| | 127 | // The upload failed. Cleanup. |
| | 128 | if ( wp_attachment_is_image( $attachment_id ) ) { |
| | 129 | $attachment = get_post( $attachment_id ); |
| | 130 | |
| | 131 | // Posted at most 10 min ago. |
| | 132 | if ( $attachment && ( time() - strtotime( $attachment->post_date_gmt ) < 600 ) ) { |
| | 133 | /** |
| | 134 | * Runs when an image upload fails during the post-processing phase, |
| | 135 | * and the newly created attachment post is about to be deleted. |
| | 136 | * |
| | 137 | * @since 5.3.0 |
| | 138 | * |
| | 139 | * @param int $attachment_id The attachment post ID. |
| | 140 | */ |
| | 141 | do_action( 'wp_upload_failed_cleanup', $attachment_id ); |
| | 142 | |
| | 143 | wp_delete_attachment( $attachment_id, true ); |
| | 144 | _wp_clear_upload_ref( $upload_ref ); |
| | 145 | |
| | 146 | // Error message is the same as in script-loader.php |
| | 147 | $message = __( 'Post-processing of the image failed. If this is a photo or a large image, please scale it down to 2500 pixels and upload it again.' ); |
| | 148 | return new WP_Error( 'upload_failed_post_processing', $message ); |
| | 149 | } |
| | 150 | } |
| | 151 | |
| | 152 | return new WP_Error( 'upload_reference_not_found', __( 'Upload failed. Please try again.' ), array( 'status' => 404 ) ); |
| | 153 | } |
| | 154 | } else { |
| | 155 | // Initial upload request. |
| | 156 | $insert = $this->insert_attachment( $request ); |
| | 157 | $set_ref = null; |
| | 158 | |
| | 159 | if ( is_wp_error( $insert ) ) { |
| | 160 | return $insert; |
| | 161 | } |
| | 162 | |
| | 163 | // Extract by name. |
| | 164 | $attachment_id = $insert['attachment_id']; |
| | 165 | $file = $insert['file']; |
| | 166 | |
| | 167 | if ( isset( $request['alt_text'] ) ) { |
| | 168 | update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) ); |
| | 169 | } |
| | 170 | |
| | 171 | $attachment = get_post( $attachment_id ); |
| | 172 | $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); |
| | 173 | |
| | 174 | if ( is_wp_error( $fields_update ) ) { |
| | 175 | return $fields_update; |
| | 176 | } |
| | 177 | |
| | 178 | // When uploading images store the unique upload ref. |
| | 179 | if ( $upload_ref && wp_attachment_is_image( $attachment_id ) ) { |
| | 180 | // Include upload ref functions. |
| | 181 | require_once ABSPATH . 'wp-admin/includes/file.php'; |
| | 182 | $set_ref = _wp_set_upload_ref( $upload_ref, $attachment_id ); |
| | 183 | } |
| | 184 | |
| | 185 | // Include admin function to get access to wp_generate_attachment_metadata(). |
| | 186 | require_once ABSPATH . 'wp-admin/includes/media.php'; |
| | 187 | |
| | 188 | // Post-process the upload (create image sub-sizes, make PDF thumbnalis, etc.) and insert attachment meta. |
| | 189 | // At this point the server may run out of resources and post-processing of uploaded images may fail. |
| | 190 | wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) ); |
| | 191 | |
| | 192 | // At this point the file has been uploaded successfully. The upload ref is no longer needed. |
| | 193 | if ( $set_ref ) { |
| | 194 | _wp_clear_upload_ref( $upload_ref ); |
| | 195 | } |
| | 196 | } |
| | 197 | |
| | 198 | // The following runs on initial upload requests and after successfully re-trying to create image sub-sizes. |
| | 199 | // At this point the file has been uploaded and post-processed successfully. |
| | 200 | if ( empty( $attachment ) ) { |
| | 201 | $attachment = get_post( $attachment_id ); |
| | 202 | } |
| | 203 | |
| | 204 | $request->set_param( 'context', 'edit' ); |
| | 205 | |
| | 206 | /** |
| | 207 | * Fires after a single attachment is completely created or updated via the REST API. |
| | 208 | * |
| | 209 | * @since 5.0.0 |
| | 210 | * |
| | 211 | * @param WP_Post $attachment Inserted or updated attachment object. |
| | 212 | * @param WP_REST_Request $request Request object. |
| | 213 | * @param bool $creating True when creating an attachment, false when updating. |
| | 214 | */ |
| | 215 | do_action( 'rest_after_insert_attachment', $attachment, $request, true ); |
| | 216 | |
| | 217 | $response = $this->prepare_item_for_response( $attachment, $request ); |
| | 218 | $response = rest_ensure_response( $response ); |
| | 219 | $response->set_status( 201 ); |
| | 220 | $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $attachment_id ) ) ); |
| | 221 | |
| | 222 | return $response; |
| | 223 | } |
| | 224 | |
| | 225 | /** |
| | 226 | * Inserts the attachment post in the database. Does not update the attachment meta. |
| | 227 | * |
| | 228 | * @since 5.3.0 |
| | 229 | * |
| | 230 | * @param WP_REST_Request $request |
| | 231 | * |
| | 232 | * @return array|WP_Error |
| | 233 | */ |
| | 234 | protected function insert_attachment( $request ) { |
| 175 | | // Include admin function to get access to wp_generate_attachment_metadata(). |
| 176 | | require_once ABSPATH . 'wp-admin/includes/media.php'; |
| 177 | | |
| 178 | | wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) ); |
| 179 | | |
| 180 | | if ( isset( $request['alt_text'] ) ) { |
| 181 | | update_post_meta( $id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) ); |
| 182 | | } |
| 183 | | |
| 184 | | $fields_update = $this->update_additional_fields_for_object( $attachment, $request ); |
| 185 | | |
| 186 | | if ( is_wp_error( $fields_update ) ) { |
| 187 | | return $fields_update; |
| 188 | | } |
| 189 | | |
| 190 | | $request->set_param( 'context', 'edit' ); |
| 191 | | |
| 192 | | /** |
| 193 | | * Fires after a single attachment is completely created or updated via the REST API. |
| 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 | | |
| 203 | | $response = $this->prepare_item_for_response( $attachment, $request ); |
| 204 | | $response = rest_ensure_response( $response ); |
| 205 | | $response->set_status( 201 ); |
| 206 | | $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $id ) ) ); |
| 207 | | |
| 208 | | return $response; |
| | 309 | return array( |
| | 310 | 'attachment_id' => $id, |
| | 311 | 'file' => $file, |
| | 312 | ); |