Deduplicate client-side image sizes with matching dimensions#77036
Conversation
Group thumbnail size names by their effective dimensions (width, height, crop) before generating sideload items. When multiple registered sizes share the same dimensions, only one physical file is generated and the server registers it under all matching size names in attachment metadata. Extends the sideload endpoint's image_size parameter to accept an array of size names, so one upload can be registered for multiple sizes. Fixes #77035
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
Size Change: +72 B (0%) Total Size: 7.75 MB 📦 View Changed
ℹ️ View Unchanged
|
|
Flaky tests detected in e1f2c01. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/24695476831
|
swissspidy
left a comment
There was a problem hiding this comment.
Tests would be nice, but otherwise LGTM
|
Note: I will create a core backport for these changes once the client side media feature has been restored to core. |
Extend the sideload REST controller tests to cover the new behaviour of accepting an array of image_size names, including the happy path where one physical file is registered under multiple sizes in attachment metadata, and backwards compatibility when a single-element array is passed. On the JavaScript side, add regression tests ensuring that sizes with matching dimensions but different crop values are treated as distinct groups, and that three or more sizes sharing identical dimensions collapse into a single sideload request.
Resolve conflicts by adapting the image_size array support to the new finalize architecture: sideload_item now returns the array in sub_size_data verbatim, and finalize_item registers the file under each size name when image_size is an array. Update SubSizeData.image_size TypeScript type and the sub_sizes schema accordingly.
Added some additional test coverage in 850cf35 |
Restore the newline that was lost between the final else branch and the return statement during the merge conflict resolution, which caused PHPCS to flag tab alignment between the closing brace and the return.
…sertion" This reverts commit 6b47f61.
The oneOf schema with {type: string} and {type: array} sub-schemas caused
a "matches more than one of the expected formats" error on newer
WordPress core because rest_is_array() treats scalar strings as
single-element lists (via wp_parse_list). Both schemas matched a plain
string, and rest_find_one_matching_schema() requires exactly one match.
Replace the oneOf schemas with type: [string, array]. For the sideload
endpoint, move the enum validation into a validate_callback so that
sizes registered after route-registration (e.g. via add_image_size() in
tests) are still honored, and so the check applies correctly to both
string and array inputs.
* Deduplicate client-side image sizes with matching dimensions Group thumbnail size names by their effective dimensions (width, height, crop) before generating sideload items. When multiple registered sizes share the same dimensions, only one physical file is generated and the server registers it under all matching size names in attachment metadata. Extends the sideload endpoint's image_size parameter to accept an array of size names, so one upload can be registered for multiple sizes. Fixes #77035 * Add test coverage for image_size array deduplication Extend the sideload REST controller tests to cover the new behaviour of accepting an array of image_size names, including the happy path where one physical file is registered under multiple sizes in attachment metadata, and backwards compatibility when a single-element array is passed. On the JavaScript side, add regression tests ensuring that sizes with matching dimensions but different crop values are treated as distinct groups, and that three or more sizes sharing identical dimensions collapse into a single sideload request. * Fix PHPCS coding standards in sideload_item Restore the newline that was lost between the final else branch and the return statement during the merge conflict resolution, which caused PHPCS to flag tab alignment between the closing brace and the return. * TEMP: Add diagnostic message to regular_sub_sizes finalize assertion * Revert "TEMP: Add diagnostic message to regular_sub_sizes finalize assertion" This reverts commit 6b47f61. * Fix schema validation for string image_size against newer WordPress core The oneOf schema with {type: string} and {type: array} sub-schemas caused a "matches more than one of the expected formats" error on newer WordPress core because rest_is_array() treats scalar strings as single-element lists (via wp_parse_list). Both schemas matched a plain string, and rest_find_one_matching_schema() requires exactly one match. Replace the oneOf schemas with type: [string, array]. For the sideload endpoint, move the enum validation into a validate_callback so that sizes registered after route-registration (e.g. via add_image_size() in tests) are still honored, and so the check applies correctly to both string and array inputs.
The feature shipping target moved from 7.0 to 7.1 (per #76756). Bring the architecture explanation and how-to guide up to date with the post-7.0-cycle state of the code: - Reposition introductions around 7.1 with 7.0 as the groundwork cycle. - HEIC/HEIF: document the canvas-based fallback path (createImageBitmap, HTMLImageElement+OffscreenCanvas, HEIC container parsing + WebCodecs VideoDecoder), JPEG companion file, and isHeicCanvasSupported() gate. - AVIF: note the wp_prevent_unsupported_mime_type_uploads bypass when generate_sub_sizes=false (#76371). - Batch thumbnail generation via image.copyMemory() / thumbnailImage() (#76979). - Sub-size deduplication via image_size: string|string[] on the sideload route (#77036). - Single VIPS instance via promise caching (#76780). - Build-output trimming: remove vips-jxl.wasm (#76639), skip non-min worker (#76615), skip WASM-inlined sourcemaps (#75993). - COI: <img> excluded from cross-origin attribute injection (#76618). - Loosened feature-detection thresholds: 2 cores, 3g (#76616). - Post-saving lock fix: Save Draft now respects the lock (#76973). - convert_format declared as boolean on sideload route (#77565). - Fix incorrect REST index settings list (only image_sizes and image_size_threshold are exposed). - Remove references to client_side_supported_mime_types filter (PR #76549 was closed unmerged); state the supported MIME set is fixed at CLIENT_SIDE_SUPPORTED_MIME_TYPES. Refs #75111.
Backport ticket: https://core.trac.wordpress.org/ticket/65330 / PR: adamsilverstein/wordpress-develop#48 |
Summary
When themes register image sizes with the same dimensions as WordPress built-in sizes (e.g., Twenty Eleven's
largeis 768x1024, same asmedium_large), client-side media processing creates duplicate physical files with-1suffixes. Server-side uploads handle this correctly.This PR fixes the issue by:
sizesToGenerateby effective dimensions (width, height, crop) before the sideload loop. Only one physical file is generated per unique dimension set, and all matching size names are passed to the server in a single sideload request.image_sizeparameter to accept an array of size names, so one uploaded file is registered under all matching sizes in attachment metadata.Changes
packages/upload-media/src/store/private-actions.ts— Group sizes by dimensions using aMap, pass array of names when multiple sizes share dimensionspackages/upload-media/src/store/types.ts— Updateimage_sizetype tostring | string[]lib/media/class-gutenberg-rest-attachments-controller.php— AcceptoneOfstring or array forimage_sizeparam, loop over all names when registering in metadatapackages/upload-media/src/store/test/actions.ts— Add test verifying deduplication behaviorTest plan
Test on trunk vs PR:
-1suffixes in the uploads directoryFixes #77035