Opened 5 hours ago
Last modified 5 hours ago
#65481 new enhancement
REST API: Support registering one sideloaded file under multiple image sizes
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Milestone: | 7.1 | Priority: | normal |
| Severity: | normal | Version: | trunk |
| Component: | REST API | Keywords: | has-patch needs-testing has-unit-tests |
| Focuses: | Cc: |
Description
Summary
When several registered image sizes resolve to the same dimensions (width, height, crop), the client-side media pipeline currently generates and uploads a separate physical file for each one. That is wasteful: identical files are encoded, transferred, and stored multiple times under different size names.
This change lets the client group sizes that share dimensions, upload one file, and register that single file under every matching size name.
Steps to reproduce
- Register two or more image sizes that resolve to identical dimensions, e.g.:
<?php add_image_size( 'size_a', 800, 600, true ); add_image_size( 'size_b', 800, 600, true ); // same dimensions as size_a
- Upload an image through the client-side media flow (the sideload + finalize REST endpoints).
- Inspect the generated files on disk and the attachment metadata.
Expected: a single physical file is generated for the shared dimensions and referenced by both size_a and size_b.
Actual (before this change): a separate, byte-identical file is generated for each size.
Proposed change
Allow the sideload and finalize endpoints to accept either a single size name or an array of size names:
- The sideload endpoint's
image_sizeparameter and the finalize endpoint'ssub_sizes[].image_sizenow accept a string or an array of strings. sideload_item()returns the shared sub-size payload (dimensions, filename, filesize) for an array of sizes.finalize_item()writes / registers the file under each size name in the array.- Arrays only carry regular sub-sizes; the special
original/scaledkeys remain scalar.
Validation detail
Because rest_is_array() treats a scalar string as a single-element list (via wp_parse_list()), a oneOf / multi-type schema cannot enforce the size-name enum on its own. The enum is therefore validated per item via a validate_callback. This has the side benefit of picking up sizes registered after route registration (e.g. via add_image_size()), which a static enum baked in at register_rest_route() time would miss.
Patch
The patch is available as wordpress-develop PR #12001, a backport of Gutenberg #77036.
Files touched:
src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php(+167 / −55)tests/phpunit/tests/rest-api/rest-attachments-controller.php(+294 / −7)tests/qunit/fixtures/wp-api-generated.js(+51 / −12, regenerated)
Tests
test_sideload_image_size_array— a single sideloaded file registers correctly under multiple size names.test_sideload_image_size_invalid— an invalid size name is rejected by the per-itemvalidate_callback.test_sideload_route_accepts_scaled_image_size— exercises thevalidate_callbackpath (replaces the prior enum-based assertion, which broke when the enum schema key was removed).
Validated locally with php -l and PHPCS (WordPress-Core); full PHPUnit runs in CI.
Notes
- The JS counterpart (client-side grouping of matching sizes) ships via the Gutenberg → Core package sync.
- This PR shares the sideload route changes with PR #12003 (Gutenberg #75888 — move metadata writing to finalize, tracked by Trac #65329). #12003 should be reviewed / merged first; #12001's diff bundles those changes so it remains standalone-mergeable.
## What
Core backport of Gutenberg #77036 — Deduplicate client-side image sizes with matching dimensions.
This PR shares the sideload route changes with #12003 (GB #75888 — move metadata writing to finalize). It should be reviewed/merged first; this PR's diff includes #12003's changes for standalone-mergeability. Part of the client-side-media restore stack (see #11324).
## Why
When several registered image sizes resolve to the same dimensions (width, height, crop), generating a separate file per size is wasteful. The client groups them and uploads one file, then registers it under every matching size name.
## How
image_sizeparameter and the finalize endpoint'ssub_sizes[].image_sizenow accept a string or an array of strings.rest_is_array()treats scalar strings as single-element lists (viawp_parse_list()), aoneOf/multi-type schema cannot enforce the enum on its own. The enum is validated per-item via avalidate_callback, which also picks up sizes registered after route registration (e.g.add_image_size()).sideload_item()returns the shared sub-size payload for an array;finalize_item()writes the file under each size name. Arrays only carry regular sub-sizes (the specialoriginal/scaledkeys remain scalar).## Notes
test_sideload_image_size_arrayandtest_sideload_image_size_invalid. Validated locally withphp -l+ PHPCS (WordPress-Core). Full PHPUnit runs in upstream CI.