Make WordPress Core

Opened 8 weeks ago

Closed 6 weeks ago

Last modified 5 weeks ago

#65481 closed enhancement (fixed)

REST API: Support registering one sideloaded file under multiple image sizes

Reported by: adamsilverstein Owned by: adamsilverstein
Priority: normal Milestone: 7.1
Component: REST API Version: trunk
Severity: normal Keywords: has-patch needs-testing has-unit-tests commit
Cc: Focuses:

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

  1. 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
    
  2. Upload an image through the client-side media flow (the sideload + finalize REST endpoints).
  3. 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_size parameter and the finalize endpoint's sub_sizes[].image_size now 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 / scaled keys 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-item validate_callback.
  • test_sideload_route_accepts_scaled_image_size — exercises the validate_callback path (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.

Attachments (1)

65481-rest-api-multiple-image-sizes.patch (31.8 KB ) - added by sachinrajcp123 8 weeks ago.

Download all attachments as: .zip

Change History (8)

This ticket was mentioned in PR #12001 on WordPress/wordpress-develop by @adamsilverstein.


8 weeks ago
#1

## 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

  • The sideload endpoint's image_size parameter and the finalize endpoint's sub_sizes[].image_size now accept a string or an array of strings.
  • Because rest_is_array() treats scalar strings as single-element lists (via wp_parse_list()), a oneOf/multi-type schema cannot enforce the enum on its own. The enum is validated per-item via a validate_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 special original/scaled keys remain scalar).

## Notes

  • The JS counterpart (client-side grouping of matching sizes) ships via the Gutenberg → Core package sync.
  • Tests: added test_sideload_image_size_array and test_sideload_image_size_invalid. Validated locally with php -l + PHPCS (WordPress-Core). Full PHPUnit runs in upstream CI.

#2 @sanayasir
7 weeks ago

Tested the proposed changes and verified that the functionality is working as expected.

### Testing Performed

  • Uploaded images through the media workflow.
  • Verified that image uploads completed successfully without errors.
  • Confirmed there were no JavaScript console errors.
  • Confirmed there were no failed REST API requests during upload.
  • Verified general media and featured image functionality to ensure no regressions were introduced.

### Results

  • Upload process completed successfully.
  • Media items were created correctly.
  • Featured image functionality continued to work as expected.
  • No issues were observed during testing.

Based on the testing performed, the patch appears to be functioning correctly and no regressions were identified.

#3 @adamsilverstein
6 weeks ago

  • Keywords commit added
  • Owner set to adamsilverstein
  • Status newassigned

This one is approved for commit.

#4 @adamsilverstein
6 weeks ago

  • Resolutionfixed
  • Status assignedclosed

In 62609:

REST API: Support registering one sideloaded file under multiple image sizes.

When multiple registered sizes resolve to identical dimensions (width, height, crop), the client can now group them, upload one file, and reference it from every matching size name instead of encoding, transferring, and storing duplicates. The sideload endpoint's image_size parameter and the finalize endpoint's sub_sizes[].image_size now accept either a string or an array of strings.

See related Gutenberg work: https://github.com/WordPress/gutenberg/pull/77036.

Props adamsilverstein, westonruter, swissspidy, sachinrajcp123, sanayasir.
Fixes #65481.

#5 @adamsilverstein
5 weeks ago

#65330 was marked as a duplicate.

#6 @adamsilverstein
5 weeks ago

#65330 was marked as a duplicate.

#7 @adamsilverstein
5 weeks ago

#65330 was marked as a duplicate.

Note: See TracTickets for help on using tickets.