Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,46 @@ public function register_routes() {
'callback' => array( $this, 'finalize_item' ),
'permission_callback' => array( $this, 'edit_media_item_permissions_check' ),
'args' => array(
'id' => array(
'id' => array(
'description' => __( 'Unique identifier for the attachment.' ),
'type' => 'integer',
),
'sub_sizes' => array(
'description' => __( 'Array of sub-size metadata collected from sideload responses.' ),
'type' => 'array',
'default' => array(),
'items' => array(
'type' => 'object',
'properties' => array(
'image_size' => array(
'type' => 'string',
'required' => true,
),
'width' => array(
'type' => 'integer',
'minimum' => 1,
),
'height' => array(
'type' => 'integer',
'minimum' => 1,
),
'file' => array(
'type' => 'string',
),
'mime_type' => array(
'type' => 'string',
'pattern' => '^image/.*',
),
'filesize' => array(
'type' => 'integer',
'minimum' => 1,
),
'original_image' => array(
'type' => 'string',
),
),
),
),
),
),
'allow_batch' => $this->allow_batch,
Expand Down Expand Up @@ -2082,16 +2118,19 @@ public function sideload_item( WP_REST_Request $request ) {

$image_size = $request['image_size'];

$metadata = wp_get_attachment_metadata( $attachment_id, true );

if ( ! $metadata ) {
$metadata = array();
}
// Build sub-size data to return to the client.
// The client accumulates these and sends them all to the finalize
// endpoint, which writes the metadata in a single operation. This
// avoids the read-modify-write race that concurrent sideloads for the
// same attachment would otherwise hit.
$sub_size_data = array(
'image_size' => $image_size,
);

if ( 'original' === $image_size ) {
$metadata['original_image'] = wp_basename( $path );
$sub_size_data['file'] = wp_basename( $path );
} elseif ( 'scaled' === $image_size ) {
// The current attached file is the original; record it as original_image.
// Record the current attached file as the original.
$current_file = get_attached_file( $attachment_id, true );

if ( ! $current_file ) {
Expand All @@ -2102,7 +2141,7 @@ public function sideload_item( WP_REST_Request $request ) {
);
}

$metadata['original_image'] = wp_basename( $current_file );
$sub_size_data['original_image'] = wp_basename( $current_file );

// Validate the scaled image before updating the attached file.
$size = wp_getimagesize( $path );
Expand All @@ -2117,6 +2156,7 @@ public function sideload_item( WP_REST_Request $request ) {
}

// Update the attached file to point to the scaled version.
// This writes to _wp_attached_file meta, not _wp_attachment_metadata.
if (
get_attached_file( $attachment_id, true ) !== $path &&
! update_attached_file( $attachment_id, $path )
Expand All @@ -2128,42 +2168,21 @@ public function sideload_item( WP_REST_Request $request ) {
);
}

$metadata['width'] = $size[0];
$metadata['height'] = $size[1];
$metadata['filesize'] = $filesize;
$metadata['file'] = _wp_relative_upload_path( $path );
$sub_size_data['width'] = $size[0];
$sub_size_data['height'] = $size[1];
$sub_size_data['filesize'] = $filesize;
$sub_size_data['file'] = _wp_relative_upload_path( $path );
} else {
$metadata['sizes'] = $metadata['sizes'] ?? array();

$size = wp_getimagesize( $path );

$metadata['sizes'][ $image_size ] = array(
'width' => $size ? $size[0] : 0,
'height' => $size ? $size[1] : 0,
'file' => wp_basename( $path ),
'mime-type' => $type,
'filesize' => wp_filesize( $path ),
);
}

wp_update_attachment_metadata( $attachment_id, $metadata );

$response_request = new WP_REST_Request(
WP_REST_Server::READABLE,
rest_get_route_for_post( $attachment_id )
);

$response_request['context'] = 'edit';

if ( isset( $request['_fields'] ) ) {
$response_request['_fields'] = $request['_fields'];
$sub_size_data['width'] = $size ? $size[0] : 0;
$sub_size_data['height'] = $size ? $size[1] : 0;
$sub_size_data['file'] = wp_basename( $path );
$sub_size_data['mime_type'] = $type;
$sub_size_data['filesize'] = wp_filesize( $path );
}

$response = $this->prepare_item_for_response( get_post( $attachment_id ), $response_request );

$response->header( 'Location', rest_url( rest_get_route_for_post( $attachment_id ) ) );

return $response;
return rest_ensure_response( $sub_size_data );
}

/**
Expand Down Expand Up @@ -2215,9 +2234,11 @@ private static function filter_wp_unique_filename( $filename, $dir, $number, $at
/**
* Finalizes an attachment after client-side media processing.
*
* Triggers the 'wp_generate_attachment_metadata' filter so that
* server-side plugins can process the attachment after all client-side
* operations (upload, thumbnail generation, sideloads) are complete.
* Applies the sub-size metadata collected from sideload responses in a
* single metadata update, then triggers the 'wp_generate_attachment_metadata'
* filter so that server-side plugins can process the attachment after all
* client-side operations (upload, thumbnail generation, sideloads) are
* complete.
*
* @since 7.1.0
*
Expand All @@ -2237,6 +2258,35 @@ public function finalize_item( WP_REST_Request $request ) {
$metadata = array();
}

// Apply all sub-size metadata collected from sideload responses.
$sub_sizes = $request['sub_sizes'] ?? array();

foreach ( $sub_sizes as $sub_size ) {
$image_size = $sub_size['image_size'];

if ( 'original' === $image_size ) {
$metadata['original_image'] = $sub_size['file'];
} elseif ( 'scaled' === $image_size ) {
if ( ! empty( $sub_size['original_image'] ) ) {
$metadata['original_image'] = $sub_size['original_image'];
}
$metadata['width'] = $sub_size['width'] ?? 0;
$metadata['height'] = $sub_size['height'] ?? 0;
$metadata['filesize'] = $sub_size['filesize'] ?? 0;
$metadata['file'] = $sub_size['file'] ?? '';
} else {
$metadata['sizes'] = $metadata['sizes'] ?? array();

$metadata['sizes'][ $image_size ] = array(
'width' => $sub_size['width'] ?? 0,
'height' => $sub_size['height'] ?? 0,
'file' => $sub_size['file'] ?? '',
'mime-type' => $sub_size['mime_type'] ?? '',
'filesize' => $sub_size['filesize'] ?? 0,
);
}
}

/** This filter is documented in wp-admin/includes/image.php */
$metadata = apply_filters( 'wp_generate_attachment_metadata', $metadata, $attachment_id, 'update' );

Expand Down
Loading
Loading