wp/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
    95 			}
    95 			}
    96 		}
    96 		}
    97 
    97 
    98 		// Filter query clauses to include filenames.
    98 		// Filter query clauses to include filenames.
    99 		if ( isset( $query_args['s'] ) ) {
    99 		if ( isset( $query_args['s'] ) ) {
   100 			add_filter( 'posts_clauses', '_filter_query_attachment_filenames' );
   100 			add_filter( 'wp_allow_query_attachment_by_filename', '__return_true' );
   101 		}
   101 		}
   102 
   102 
   103 		return $query_args;
   103 		return $query_args;
   104 	}
   104 	}
   105 
   105 
   169 
   169 
   170 		if ( isset( $request['alt_text'] ) ) {
   170 		if ( isset( $request['alt_text'] ) ) {
   171 			update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) );
   171 			update_post_meta( $attachment_id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) );
   172 		}
   172 		}
   173 
   173 
       
   174 		if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) {
       
   175 			$thumbnail_update = $this->handle_featured_media( $request['featured_media'], $attachment_id );
       
   176 
       
   177 			if ( is_wp_error( $thumbnail_update ) ) {
       
   178 				return $thumbnail_update;
       
   179 			}
       
   180 		}
       
   181 
   174 		if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
   182 		if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
   175 			$meta_update = $this->meta->update_value( $request['meta'], $attachment_id );
   183 			$meta_update = $this->meta->update_value( $request['meta'], $attachment_id );
   176 
   184 
   177 			if ( is_wp_error( $meta_update ) ) {
   185 			if ( is_wp_error( $meta_update ) ) {
   178 				return $meta_update;
   186 				return $meta_update;
   182 		$attachment    = get_post( $attachment_id );
   190 		$attachment    = get_post( $attachment_id );
   183 		$fields_update = $this->update_additional_fields_for_object( $attachment, $request );
   191 		$fields_update = $this->update_additional_fields_for_object( $attachment, $request );
   184 
   192 
   185 		if ( is_wp_error( $fields_update ) ) {
   193 		if ( is_wp_error( $fields_update ) ) {
   186 			return $fields_update;
   194 			return $fields_update;
       
   195 		}
       
   196 
       
   197 		$terms_update = $this->handle_terms( $attachment_id, $request );
       
   198 
       
   199 		if ( is_wp_error( $terms_update ) ) {
       
   200 			return $terms_update;
   187 		}
   201 		}
   188 
   202 
   189 		$request->set_param( 'context', 'edit' );
   203 		$request->set_param( 'context', 'edit' );
   190 
   204 
   191 		/**
   205 		/**
   199 		 */
   213 		 */
   200 		do_action( 'rest_after_insert_attachment', $attachment, $request, true );
   214 		do_action( 'rest_after_insert_attachment', $attachment, $request, true );
   201 
   215 
   202 		wp_after_insert_post( $attachment, false, null );
   216 		wp_after_insert_post( $attachment, false, null );
   203 
   217 
   204 		if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
   218 		if ( wp_is_serving_rest_request() ) {
   205 			// Set a custom header with the attachment_id.
   219 			/*
   206 			// Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
   220 			 * Set a custom header with the attachment_id.
       
   221 			 * Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
       
   222 			 */
   207 			header( 'X-WP-Upload-Attachment-ID: ' . $attachment_id );
   223 			header( 'X-WP-Upload-Attachment-ID: ' . $attachment_id );
   208 		}
   224 		}
   209 
   225 
   210 		// Include media and image functions to get access to wp_generate_attachment_metadata().
   226 		// Include media and image functions to get access to wp_generate_attachment_metadata().
   211 		require_once ABSPATH . 'wp-admin/includes/media.php';
   227 		require_once ABSPATH . 'wp-admin/includes/media.php';
   212 		require_once ABSPATH . 'wp-admin/includes/image.php';
   228 		require_once ABSPATH . 'wp-admin/includes/image.php';
   213 
   229 
   214 		// Post-process the upload (create image sub-sizes, make PDF thumbnails, etc.) and insert attachment meta.
   230 		/*
   215 		// At this point the server may run out of resources and post-processing of uploaded images may fail.
   231 		 * Post-process the upload (create image sub-sizes, make PDF thumbnails, etc.) and insert attachment meta.
       
   232 		 * At this point the server may run out of resources and post-processing of uploaded images may fail.
       
   233 		 */
   216 		wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
   234 		wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
   217 
   235 
   218 		$response = $this->prepare_item_for_response( $attachment, $request );
   236 		$response = $this->prepare_item_for_response( $attachment, $request );
   219 		$response = rest_ensure_response( $response );
   237 		$response = rest_ensure_response( $response );
   220 		$response->set_status( 201 );
   238 		$response->set_status( 201 );
   234 	protected function insert_attachment( $request ) {
   252 	protected function insert_attachment( $request ) {
   235 		// Get the file via $_FILES or raw data.
   253 		// Get the file via $_FILES or raw data.
   236 		$files   = $request->get_file_params();
   254 		$files   = $request->get_file_params();
   237 		$headers = $request->get_headers();
   255 		$headers = $request->get_headers();
   238 
   256 
       
   257 		$time = null;
       
   258 
       
   259 		// Matches logic in media_handle_upload().
       
   260 		if ( ! empty( $request['post'] ) ) {
       
   261 			$post = get_post( $request['post'] );
       
   262 			// The post date doesn't usually matter for pages, so don't backdate this upload.
       
   263 			if ( $post && 'page' !== $post->post_type && substr( $post->post_date, 0, 4 ) > 0 ) {
       
   264 				$time = $post->post_date;
       
   265 			}
       
   266 		}
       
   267 
   239 		if ( ! empty( $files ) ) {
   268 		if ( ! empty( $files ) ) {
   240 			$file = $this->upload_from_file( $files, $headers );
   269 			$file = $this->upload_from_file( $files, $headers, $time );
   241 		} else {
   270 		} else {
   242 			$file = $this->upload_from_data( $request->get_body(), $headers );
   271 			$file = $this->upload_from_data( $request->get_body(), $headers, $time );
   243 		}
   272 		}
   244 
   273 
   245 		if ( is_wp_error( $file ) ) {
   274 		if ( is_wp_error( $file ) ) {
   246 			return $file;
   275 			return $file;
   247 		}
   276 		}
   273 		$attachment = $this->prepare_item_for_database( $request );
   302 		$attachment = $this->prepare_item_for_database( $request );
   274 
   303 
   275 		$attachment->post_mime_type = $type;
   304 		$attachment->post_mime_type = $type;
   276 		$attachment->guid           = $url;
   305 		$attachment->guid           = $url;
   277 
   306 
       
   307 		// If the title was not set, use the original filename.
       
   308 		if ( empty( $attachment->post_title ) && ! empty( $files['file']['name'] ) ) {
       
   309 			// Remove the file extension (after the last `.`)
       
   310 			$tmp_title = substr( $files['file']['name'], 0, strrpos( $files['file']['name'], '.' ) );
       
   311 
       
   312 			if ( ! empty( $tmp_title ) ) {
       
   313 				$attachment->post_title = $tmp_title;
       
   314 			}
       
   315 		}
       
   316 
       
   317 		// Fall back to the original approach.
   278 		if ( empty( $attachment->post_title ) ) {
   318 		if ( empty( $attachment->post_title ) ) {
   279 			$attachment->post_title = preg_replace( '/\.[^.]+$/', '', wp_basename( $file ) );
   319 			$attachment->post_title = preg_replace( '/\.[^.]+$/', '', wp_basename( $file ) );
   280 		}
   320 		}
   281 
   321 
   282 		// $post_parent is inherited from $attachment['post_parent'].
   322 		// $post_parent is inherited from $attachment['post_parent'].
   311 			'file'          => $file,
   351 			'file'          => $file,
   312 		);
   352 		);
   313 	}
   353 	}
   314 
   354 
   315 	/**
   355 	/**
       
   356 	 * Determines the featured media based on a request param.
       
   357 	 *
       
   358 	 * @since 6.5.0
       
   359 	 *
       
   360 	 * @param int $featured_media Featured Media ID.
       
   361 	 * @param int $post_id        Post ID.
       
   362 	 * @return bool|WP_Error Whether the post thumbnail was successfully deleted, otherwise WP_Error.
       
   363 	 */
       
   364 	protected function handle_featured_media( $featured_media, $post_id ) {
       
   365 		$post_type         = get_post_type( $post_id );
       
   366 		$thumbnail_support = current_theme_supports( 'post-thumbnails', $post_type ) && post_type_supports( $post_type, 'thumbnail' );
       
   367 
       
   368 		// Similar check as in wp_insert_post().
       
   369 		if ( ! $thumbnail_support && get_post_mime_type( $post_id ) ) {
       
   370 			if ( wp_attachment_is( 'audio', $post_id ) ) {
       
   371 				$thumbnail_support = post_type_supports( 'attachment:audio', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:audio' );
       
   372 			} elseif ( wp_attachment_is( 'video', $post_id ) ) {
       
   373 				$thumbnail_support = post_type_supports( 'attachment:video', 'thumbnail' ) || current_theme_supports( 'post-thumbnails', 'attachment:video' );
       
   374 			}
       
   375 		}
       
   376 
       
   377 		if ( $thumbnail_support ) {
       
   378 			return parent::handle_featured_media( $featured_media, $post_id );
       
   379 		}
       
   380 
       
   381 		return new WP_Error(
       
   382 			'rest_no_featured_media',
       
   383 			sprintf(
       
   384 				/* translators: %s: attachment mime type */
       
   385 				__( 'This site does not support post thumbnails on attachments with MIME type %s.' ),
       
   386 				get_post_mime_type( $post_id )
       
   387 			),
       
   388 			array( 'status' => 400 )
       
   389 		);
       
   390 	}
       
   391 
       
   392 	/**
   316 	 * Updates a single attachment.
   393 	 * Updates a single attachment.
   317 	 *
   394 	 *
   318 	 * @since 4.7.0
   395 	 * @since 4.7.0
   319 	 *
   396 	 *
   320 	 * @param WP_REST_Request $request Full details about the request.
   397 	 * @param WP_REST_Request $request Full details about the request.
   342 		if ( isset( $request['alt_text'] ) ) {
   419 		if ( isset( $request['alt_text'] ) ) {
   343 			update_post_meta( $data['id'], '_wp_attachment_image_alt', $request['alt_text'] );
   420 			update_post_meta( $data['id'], '_wp_attachment_image_alt', $request['alt_text'] );
   344 		}
   421 		}
   345 
   422 
   346 		$attachment = get_post( $request['id'] );
   423 		$attachment = get_post( $request['id'] );
       
   424 
       
   425 		if ( ! empty( $schema['properties']['featured_media'] ) && isset( $request['featured_media'] ) ) {
       
   426 			$thumbnail_update = $this->handle_featured_media( $request['featured_media'], $attachment->ID );
       
   427 
       
   428 			if ( is_wp_error( $thumbnail_update ) ) {
       
   429 				return $thumbnail_update;
       
   430 			}
       
   431 		}
   347 
   432 
   348 		$fields_update = $this->update_additional_fields_for_object( $attachment, $request );
   433 		$fields_update = $this->update_additional_fields_for_object( $attachment, $request );
   349 
   434 
   350 		if ( is_wp_error( $fields_update ) ) {
   435 		if ( is_wp_error( $fields_update ) ) {
   351 			return $fields_update;
   436 			return $fields_update;
   444 				__( 'Unable to get meta information for file.' ),
   529 				__( 'Unable to get meta information for file.' ),
   445 				array( 'status' => 404 )
   530 				array( 'status' => 404 )
   446 			);
   531 			);
   447 		}
   532 		}
   448 
   533 
   449 		$supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp' );
   534 		$supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif' );
   450 		$mime_type       = get_post_mime_type( $attachment_id );
   535 		$mime_type       = get_post_mime_type( $attachment_id );
   451 		if ( ! in_array( $mime_type, $supported_types, true ) ) {
   536 		if ( ! in_array( $mime_type, $supported_types, true ) ) {
   452 			return new WP_Error(
   537 			return new WP_Error(
   453 				'rest_cannot_edit_file_type',
   538 				'rest_cannot_edit_file_type',
   454 				__( 'This type of file cannot be edited.' ),
   539 				__( 'This type of file cannot be edited.' ),
   534 					break;
   619 					break;
   535 
   620 
   536 				case 'crop':
   621 				case 'crop':
   537 					$size = $image_editor->get_size();
   622 					$size = $image_editor->get_size();
   538 
   623 
   539 					$crop_x = round( ( $size['width'] * $args['left'] ) / 100.0 );
   624 					$crop_x = (int) round( ( $size['width'] * $args['left'] ) / 100.0 );
   540 					$crop_y = round( ( $size['height'] * $args['top'] ) / 100.0 );
   625 					$crop_y = (int) round( ( $size['height'] * $args['top'] ) / 100.0 );
   541 					$width  = round( ( $size['width'] * $args['width'] ) / 100.0 );
   626 					$width  = (int) round( ( $size['width'] * $args['width'] ) / 100.0 );
   542 					$height = round( ( $size['height'] * $args['height'] ) / 100.0 );
   627 					$height = (int) round( ( $size['height'] * $args['height'] ) / 100.0 );
   543 
   628 
   544 					if ( $size['width'] !== $width && $size['height'] !== $height ) {
   629 					if ( $size['width'] !== $width || $size['height'] !== $height ) {
   545 						$result = $image_editor->crop( $crop_x, $crop_y, $width, $height );
   630 						$result = $image_editor->crop( $crop_x, $crop_y, $width, $height );
   546 
   631 
   547 						if ( is_wp_error( $result ) ) {
   632 						if ( is_wp_error( $result ) ) {
   548 							return new WP_Error(
   633 							return new WP_Error(
   549 								'rest_image_crop_failed',
   634 								'rest_image_crop_failed',
   560 
   645 
   561 		// Calculate the file name.
   646 		// Calculate the file name.
   562 		$image_ext  = pathinfo( $image_file, PATHINFO_EXTENSION );
   647 		$image_ext  = pathinfo( $image_file, PATHINFO_EXTENSION );
   563 		$image_name = wp_basename( $image_file, ".{$image_ext}" );
   648 		$image_name = wp_basename( $image_file, ".{$image_ext}" );
   564 
   649 
   565 		// Do not append multiple `-edited` to the file name.
   650 		/*
   566 		// The user may be editing a previously edited image.
   651 		 * Do not append multiple `-edited` to the file name.
       
   652 		 * The user may be editing a previously edited image.
       
   653 		 */
   567 		if ( preg_match( '/-edited(-\d+)?$/', $image_name ) ) {
   654 		if ( preg_match( '/-edited(-\d+)?$/', $image_name ) ) {
   568 			// Remove any `-1`, `-2`, etc. `wp_unique_filename()` will add the proper number.
   655 			// Remove any `-1`, `-2`, etc. `wp_unique_filename()` will add the proper number.
   569 			$image_name = preg_replace( '/-edited(-\d+)?$/', '-edited', $image_name );
   656 			$image_name = preg_replace( '/-edited(-\d+)?$/', '-edited', $image_name );
   570 		} else {
   657 		} else {
   571 			// Append `-edited` before the extension.
   658 			// Append `-edited` before the extension.
   622 		if ( ! empty( $image_alt ) ) {
   709 		if ( ! empty( $image_alt ) ) {
   623 			// update_post_meta() expects slashed.
   710 			// update_post_meta() expects slashed.
   624 			update_post_meta( $new_attachment_id, '_wp_attachment_image_alt', wp_slash( $image_alt ) );
   711 			update_post_meta( $new_attachment_id, '_wp_attachment_image_alt', wp_slash( $image_alt ) );
   625 		}
   712 		}
   626 
   713 
   627 		if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
   714 		if ( wp_is_serving_rest_request() ) {
   628 			// Set a custom header with the attachment_id.
   715 			/*
   629 			// Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
   716 			 * Set a custom header with the attachment_id.
       
   717 			 * Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
       
   718 			 */
   630 			header( 'X-WP-Upload-Attachment-ID: ' . $new_attachment_id );
   719 			header( 'X-WP-Upload-Attachment-ID: ' . $new_attachment_id );
   631 		}
   720 		}
   632 
   721 
   633 		// Generate image sub-sizes and meta.
   722 		// Generate image sub-sizes and meta.
   634 		$new_image_meta = wp_generate_attachment_metadata( $new_attachment_id, $saved['path'] );
   723 		$new_image_meta = wp_generate_attachment_metadata( $new_attachment_id, $saved['path'] );
   721 	 * @param WP_REST_Request $request Request object.
   810 	 * @param WP_REST_Request $request Request object.
   722 	 * @return WP_REST_Response Response object.
   811 	 * @return WP_REST_Response Response object.
   723 	 */
   812 	 */
   724 	public function prepare_item_for_response( $item, $request ) {
   813 	public function prepare_item_for_response( $item, $request ) {
   725 		// Restores the more descriptive, specific name for use within this method.
   814 		// Restores the more descriptive, specific name for use within this method.
   726 		$post     = $item;
   815 		$post = $item;
       
   816 
   727 		$response = parent::prepare_item_for_response( $post, $request );
   817 		$response = parent::prepare_item_for_response( $post, $request );
   728 		$fields   = $this->get_fields_for_response( $request );
   818 		$fields   = $this->get_fields_for_response( $request );
   729 		$data     = $response->get_data();
   819 		$data     = $response->get_data();
   730 
   820 
   731 		if ( in_array( 'description', $fields, true ) ) {
   821 		if ( in_array( 'description', $fields, true ) ) {
   764 		if ( in_array( 'media_details', $fields, true ) ) {
   854 		if ( in_array( 'media_details', $fields, true ) ) {
   765 			$data['media_details'] = wp_get_attachment_metadata( $post->ID );
   855 			$data['media_details'] = wp_get_attachment_metadata( $post->ID );
   766 
   856 
   767 			// Ensure empty details is an empty object.
   857 			// Ensure empty details is an empty object.
   768 			if ( empty( $data['media_details'] ) ) {
   858 			if ( empty( $data['media_details'] ) ) {
   769 				$data['media_details'] = new stdClass;
   859 				$data['media_details'] = new stdClass();
   770 			} elseif ( ! empty( $data['media_details']['sizes'] ) ) {
   860 			} elseif ( ! empty( $data['media_details']['sizes'] ) ) {
   771 
   861 
   772 				foreach ( $data['media_details']['sizes'] as $size => &$size_data ) {
   862 				foreach ( $data['media_details']['sizes'] as $size => &$size_data ) {
   773 
   863 
   774 					if ( isset( $size_data['mime-type'] ) ) {
   864 					if ( isset( $size_data['mime-type'] ) ) {
   795 						'mime_type'  => $post->post_mime_type,
   885 						'mime_type'  => $post->post_mime_type,
   796 						'source_url' => $full_src[0],
   886 						'source_url' => $full_src[0],
   797 					);
   887 					);
   798 				}
   888 				}
   799 			} else {
   889 			} else {
   800 				$data['media_details']['sizes'] = new stdClass;
   890 				$data['media_details']['sizes'] = new stdClass();
   801 			}
   891 			}
   802 		}
   892 		}
   803 
   893 
   804 		if ( in_array( 'post', $fields, true ) ) {
   894 		if ( in_array( 'post', $fields, true ) ) {
   805 			$data['post'] = ! empty( $post->post_parent ) ? (int) $post->post_parent : null;
   895 			$data['post'] = ! empty( $post->post_parent ) ? (int) $post->post_parent : null;
   965 
  1055 
   966 	/**
  1056 	/**
   967 	 * Handles an upload via raw POST data.
  1057 	 * Handles an upload via raw POST data.
   968 	 *
  1058 	 *
   969 	 * @since 4.7.0
  1059 	 * @since 4.7.0
   970 	 *
  1060 	 * @since 6.6.0 Added the `$time` parameter.
   971 	 * @param array $data    Supplied file data.
  1061 	 *
   972 	 * @param array $headers HTTP headers from the request.
  1062 	 * @param string      $data    Supplied file data.
       
  1063 	 * @param array       $headers HTTP headers from the request.
       
  1064 	 * @param string|null $time    Optional. Time formatted in 'yyyy/mm'. Default null.
   973 	 * @return array|WP_Error Data from wp_handle_sideload().
  1065 	 * @return array|WP_Error Data from wp_handle_sideload().
   974 	 */
  1066 	 */
   975 	protected function upload_from_data( $data, $headers ) {
  1067 	protected function upload_from_data( $data, $headers, $time = null ) {
   976 		if ( empty( $data ) ) {
  1068 		if ( empty( $data ) ) {
   977 			return new WP_Error(
  1069 			return new WP_Error(
   978 				'rest_upload_no_data',
  1070 				'rest_upload_no_data',
   979 				__( 'No data supplied.' ),
  1071 				__( 'No data supplied.' ),
   980 				array( 'status' => 400 )
  1072 				array( 'status' => 400 )
  1058 
  1150 
  1059 		$overrides = array(
  1151 		$overrides = array(
  1060 			'test_form' => false,
  1152 			'test_form' => false,
  1061 		);
  1153 		);
  1062 
  1154 
  1063 		$sideloaded = wp_handle_sideload( $file_data, $overrides );
  1155 		$sideloaded = wp_handle_sideload( $file_data, $overrides, $time );
  1064 
  1156 
  1065 		if ( isset( $sideloaded['error'] ) ) {
  1157 		if ( isset( $sideloaded['error'] ) ) {
  1066 			@unlink( $tmpfname );
  1158 			@unlink( $tmpfname );
  1067 
  1159 
  1068 			return new WP_Error(
  1160 			return new WP_Error(
  1109 		$filename = null;
  1201 		$filename = null;
  1110 
  1202 
  1111 		foreach ( $disposition_header as $value ) {
  1203 		foreach ( $disposition_header as $value ) {
  1112 			$value = trim( $value );
  1204 			$value = trim( $value );
  1113 
  1205 
  1114 			if ( strpos( $value, ';' ) === false ) {
  1206 			if ( ! str_contains( $value, ';' ) ) {
  1115 				continue;
  1207 				continue;
  1116 			}
  1208 			}
  1117 
  1209 
  1118 			list( $type, $attr_parts ) = explode( ';', $value, 2 );
  1210 			list( $type, $attr_parts ) = explode( ';', $value, 2 );
  1119 
  1211 
  1120 			$attr_parts = explode( ';', $attr_parts );
  1212 			$attr_parts = explode( ';', $attr_parts );
  1121 			$attributes = array();
  1213 			$attributes = array();
  1122 
  1214 
  1123 			foreach ( $attr_parts as $part ) {
  1215 			foreach ( $attr_parts as $part ) {
  1124 				if ( strpos( $part, '=' ) === false ) {
  1216 				if ( ! str_contains( $part, '=' ) ) {
  1125 					continue;
  1217 					continue;
  1126 				}
  1218 				}
  1127 
  1219 
  1128 				list( $key, $value ) = explode( '=', $part, 2 );
  1220 				list( $key, $value ) = explode( '=', $part, 2 );
  1129 
  1221 
  1135 			}
  1227 			}
  1136 
  1228 
  1137 			$filename = trim( $attributes['filename'] );
  1229 			$filename = trim( $attributes['filename'] );
  1138 
  1230 
  1139 			// Unquote quoted filename, but after trimming.
  1231 			// Unquote quoted filename, but after trimming.
  1140 			if ( substr( $filename, 0, 1 ) === '"' && substr( $filename, -1, 1 ) === '"' ) {
  1232 			if ( str_starts_with( $filename, '"' ) && str_ends_with( $filename, '"' ) ) {
  1141 				$filename = substr( $filename, 1, -1 );
  1233 				$filename = substr( $filename, 1, -1 );
  1142 			}
  1234 			}
  1143 		}
  1235 		}
  1144 
  1236 
  1145 		return $filename;
  1237 		return $filename;
  1176 
  1268 
  1177 	/**
  1269 	/**
  1178 	 * Handles an upload via multipart/form-data ($_FILES).
  1270 	 * Handles an upload via multipart/form-data ($_FILES).
  1179 	 *
  1271 	 *
  1180 	 * @since 4.7.0
  1272 	 * @since 4.7.0
  1181 	 *
  1273 	 * @since 6.6.0 Added the `$time` parameter.
  1182 	 * @param array $files   Data from the `$_FILES` superglobal.
  1274 	 *
  1183 	 * @param array $headers HTTP headers from the request.
  1275 	 * @param array       $files   Data from the `$_FILES` superglobal.
       
  1276 	 * @param array       $headers HTTP headers from the request.
       
  1277 	 * @param string|null $time    Optional. Time formatted in 'yyyy/mm'. Default null.
  1184 	 * @return array|WP_Error Data from wp_handle_upload().
  1278 	 * @return array|WP_Error Data from wp_handle_upload().
  1185 	 */
  1279 	 */
  1186 	protected function upload_from_file( $files, $headers ) {
  1280 	protected function upload_from_file( $files, $headers, $time = null ) {
  1187 		if ( empty( $files ) ) {
  1281 		if ( empty( $files ) ) {
  1188 			return new WP_Error(
  1282 			return new WP_Error(
  1189 				'rest_upload_no_data',
  1283 				'rest_upload_no_data',
  1190 				__( 'No data supplied.' ),
  1284 				__( 'No data supplied.' ),
  1191 				array( 'status' => 400 )
  1285 				array( 'status' => 400 )
  1223 		}
  1317 		}
  1224 
  1318 
  1225 		// Include filesystem functions to get access to wp_handle_upload().
  1319 		// Include filesystem functions to get access to wp_handle_upload().
  1226 		require_once ABSPATH . 'wp-admin/includes/file.php';
  1320 		require_once ABSPATH . 'wp-admin/includes/file.php';
  1227 
  1321 
  1228 		$file = wp_handle_upload( $files['file'], $overrides );
  1322 		$file = wp_handle_upload( $files['file'], $overrides, $time );
  1229 
  1323 
  1230 		if ( isset( $file['error'] ) ) {
  1324 		if ( isset( $file['error'] ) ) {
  1231 			return new WP_Error(
  1325 			return new WP_Error(
  1232 				'rest_upload_unknown_error',
  1326 				'rest_upload_unknown_error',
  1233 				$file['error'],
  1327 				$file['error'],
  1441 				'minimum'     => 0,
  1535 				'minimum'     => 0,
  1442 				'maximum'     => 100,
  1536 				'maximum'     => 100,
  1443 			),
  1537 			),
  1444 		);
  1538 		);
  1445 	}
  1539 	}
  1446 
       
  1447 }
  1540 }