wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php:654Sideloads an external image from a URL into the media library.
$requestWP_REST_RequestWP_REST_Response|WP_ErrorOne hook fires while WP_REST_Attachments_Controller::create_item_from_url() runs, in this order:
Fires after a single attachment is completely created or updated via the REST API.
protected function create_item_from_url( WP_REST_Request $request ) { // Sideloading downloads and stores a file, so require the upload capability. if ( ! current_user_can( 'upload_files' ) ) { return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to upload media on this site.' ), array( 'status' => rest_authorization_required_code() ) ); } require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/image.php'; $url = $request['url']; $post_id = ! empty( $request['post'] ) ? (int) $request['post'] : 0; // Derive the filename from the URL path before downloading anything. $url_path = wp_parse_url( $url, PHP_URL_PATH ); $filename = $url_path ? wp_basename( $url_path ) : ''; if ( '' === $filename ) { return new WP_Error( 'rest_invalid_url', __( 'Could not determine a filename from the provided URL.' ), array( 'status' => 400 ) ); } /* * Only download URLs whose extension maps to an allowed image MIME type. * The sideload handler would reject other types anyway (via * wp_check_filetype_and_ext()), but checking first avoids downloading * files that can never be accepted, such as PHP scripts. */ $filetype = wp_check_filetype( $filename ); if ( ! $filetype['type'] || ! str_starts_with( $filetype['type'], 'image/' ) ) { return new WP_Error( 'rest_invalid_url', __( 'The provided URL does not point to a supported image file.' ), array( 'status' => 400 ) ); } /* * Cap the download at the same size the site would accept as a direct * upload. check_upload_size() only applies on multisite, so without a * ceiling here a single site has no limit at all on this path: the * `upload_max_filesize` and `post_max_size` directives bound a request * body, not a fetch the server makes itself. * * When `wp_max_upload_size` returns 0, no ceiling is applied. */ $max_size = (int) wp_max_upload_size(); /* * Download the remote file with WordPress's HTTP API, which validates * the host and blocks requests to private or local addresses. This is * the same primitive core's media_sideload_image() relies on. * * `limit_response_size` stops the transfer once the limit is passed, * so an oversized remote file is never written to disk in full. One * byte over the ceiling is enough to fail the size check below. */ $limit_response_size = static function ( $args ) use ( $max_size ) { $args['limit_response_size'] = $max_size + 1; return $args; }; if ( $max_size > 0 ) { add_filter( 'http_request_args', $limit_response_size ); } $tmp_file = download_url( $url ); if ( $max_size > 0 ) { remove_filter( 'http_request_args', $limit_response_size ); } if ( is_wp_error( $tmp_file ) ) { return $tmp_file;Introduced in 7.1.0.
Signature, return type and hooks compared across 1 parsed release.
src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.