Make WordPress Core

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: adamsilverstein's profile adamsilverstein 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

  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 5 hours ago.

Download all attachments as: .zip

Change History (2)

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


5 hours 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.
Note: See TracTickets for help on using tickets.