[wp-trac] [WordPress Trac] #65330: REST API: Allow a single sideloaded file to be registered under multiple image sizes

WordPress Trac noreply at wordpress.org
Fri May 22 23:29:25 UTC 2026


#65330: REST API: Allow a single sideloaded file to be registered under multiple
image sizes
-----------------------------+--------------------------------------
 Reporter:  adamsilverstein  |      Owner:  adamsilverstein
     Type:  enhancement      |     Status:  assigned
 Priority:  normal           |  Milestone:  7.1
Component:  General          |    Version:
 Severity:  normal           |   Keywords:  has-patch has-unit-tests
  Focuses:                   |
-----------------------------+--------------------------------------
 Part of the client-side media processing feature being re-introduced for
 7.1 (see #64919, originally #62243). Builds on #65329 (deferring sideload
 metadata writes to the finalize endpoint).

 When client-side media processing is enabled, the editor generates each
 registered image sub-size in the browser and sideloads it to the
 attachment. Several registered sizes frequently resolve to the **same**
 dimensions (identical width, height, and crop). Generating and uploading a
 separate file for each of those sizes is wasteful: it produces duplicate
 files on disk and one HTTP request per size.

 The client now groups sizes that share dimensions, uploads a single file,
 and registers it under every matching size name. This ticket adds the REST
 API support for that.

 == Proposed change ==

 * The sideload endpoint's `image_size` parameter and the finalize
 endpoint's `sub_sizes[].image_size` property now accept **a string or an
 array of strings**.
 * `sideload_item()` returns the shared sub-size payload (dimensions, file,
 mime type, filesize) when given an array. `finalize_item()` then writes
 that one file into `metadata['sizes']` under each size name in the array,
 in the single metadata write introduced in #65329.
 * Arrays only ever carry regular sub-sizes. The special `original` and
 `scaled` keys remain scalar, since they map to single, distinct files.

 == Validation ==

 The size names are validated per-item with a `validate_callback` rather
 than a schema `enum`:

 * `rest_is_array()` treats a scalar string as a single-element list (via
 `wp_parse_list()`), so a `('string', 'array')` multi-type alone cannot
 enforce an enum.
 * The callback checks each item against the current list of registered
 sizes (`wp_get_registered_image_subsizes()` plus `original`, `scaled`, and
 `full`). Reading the list at validation time (rather than route-
 registration time) means sizes registered later, for example via
 `add_image_size()`, are accepted. The previous static `$valid_image_sizes`
 array computed in `register_routes()` is removed.
 * Invalid or non-string items are rejected with `rest_not_in_enum` (400).

 == Patch ==

 The PHP change is a backport of the merged Gutenberg PR:

 * Gutenberg PR: [https://github.com/WordPress/gutenberg/pull/77036
 WordPress/gutenberg#77036, Deduplicate client-side image sizes with
 matching dimensions]
 * Core backport PR: [https://github.com/adamsilverstein/wordpress-
 develop/pull/49 adamsilverstein/wordpress-develop#49]

 The backport is stacked on the #65329 patch
 ([https://github.com/adamsilverstein/wordpress-develop/pull/48
 adamsilverstein/wordpress-develop#48]); that should land first.

 Files touched:

 * `src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-
 controller.php`
 * `tests/phpunit/tests/rest-api/rest-attachments-controller.php`

 The JavaScript counterpart (grouping client-side sizes with matching
 dimensions before upload) ships through the normal Gutenberg to Core
 package sync and is not part of this PHP patch.

 == Tests ==

 * `test_sideload_image_size_array`: sideload one file with `image_size`
 set to `array( 'thumbnail', 'medium' )`, finalize, and assert both sizes
 are registered in metadata and reference the same physical file.
 * `test_sideload_image_size_invalid`: an array containing an unregistered
 size name (`not-a-real-size`) is rejected with a 400.

 ---

 **Note:** the tests in PR #49 currently use `@ticket 64737` (the sideload
 endpoint ticket). Once this ticket is posted and Trac assigns a number,
 add or swap the `@ticket` annotations to the new number.

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/65330>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list