Media: Generate identically-dimensioned sub-sizes only once#12506
Media: Generate identically-dimensioned sub-sizes only once#12506thisismyurl wants to merge 1 commit into
Conversation
Sub-sizes are stored on disk by their dimensions, so two registered sizes with the same width, height, and crop resolve to the same file. _wp_make_subsizes() previously re-encoded and re-wrote that file once per size name, which slows uploads and can cause timeouts when many sizes are registered (for example a plugin size equal to a core size). Group sizes by their resulting file and generate each once, sharing the result with every size name that requested it. The stored metadata is unchanged; only the redundant image work is removed. Adds a regression test asserting identical sizes trigger a single make_subsize() call and share one file. Props thisismyurl. See #61925.
|
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 Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
There was a problem hiding this comment.
Pull request overview
This PR optimizes intermediate image sub-size generation by deduplicating work when multiple registered image size names would produce the same on-disk {width}x{height} file, avoiding redundant re-encodes/writes during uploads.
Changes:
- Group requested sub-sizes by a signature (width/height/crop) so each unique output is generated once and shared across all requesting size names in
_wp_make_subsizes(). - Apply the same deduplication to both the
make_subsize()path and themulti_resize()fallback path. - Add a PHPUnit regression test using a GD editor spy to assert identical sizes only trigger one generation call and share metadata.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/wp-admin/includes/image.php |
Groups identical requested sub-sizes so only one file is generated per unique (width/height/crop), and shares the resulting metadata across size names. |
tests/phpunit/tests/image/makeSubsizes.php |
Adds a regression test ensuring identical size requests only generate once and both names reference the same resulting meta entry. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| foreach ( $size_groups as $signature => $group ) { | ||
| $unique_sizes[ $signature ] = $group['data']; | ||
| } | ||
|
|
||
| $created_sizes = $editor->multi_resize( $unique_sizes ); |
| public function tear_down() { | ||
| remove_all_filters( 'wp_image_editors' ); | ||
| $this->remove_added_uploads(); | ||
|
|
||
| parent::tear_down(); | ||
| } |
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
Intermediate sub-sizes are written to disk named by their dimensions (
{name}-{width}x{height}.{ext}, fromWP_Image_Editor::get_suffix()). So when two registered sizes share the same width, height, and crop, they resolve to the same file._wp_make_subsizes()currently callsmake_subsize()once per size name, which re-encodes and re-writes that identical file a second time. The reporter's example is a WooCommerce install wherewoocommerce_gallery_thumbnailhappens to equal the corethumbnailsize; with many sizes registered this redundant work slows uploads and is a common cause of upload timeouts.The fix groups the requested sizes by their resulting file (width, height, crop) before generating, produces each unique file once, and assigns the result to every size name that requested it. Because the sub-sizes were already sharing a filename, the stored
sizesmetadata is unchanged. The only thing removed is the duplicate image work.A couple of notes on the approach:
make_subsize()loop and themulti_resize()fallback both benefit. The incrementalwp_update_attachment_metadata()save after each generated file is preserved, so a partial result still survives an error or timeout part-way through.The regression test registers two identical sizes plus one distinct size and, using a
WP_Image_Editor_GDsubclass that countsmake_subsize()calls, asserts two files are generated rather than three, and that both identical size names reference the same file. It fails without the grouping (three calls) and passes with it.One disclosure on verification: this box has no Docker/
wp-env, so I could not run the full PHPUnit suite locally. I proved the grouping logic with a standalone harness and wrote the committed test to the PHPUnit harness with@ticket 61925; it needs GD (it skips otherwise) and I'd appreciate a CI run confirming it.Trac ticket: https://core.trac.wordpress.org/ticket/61925
Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 4.8
Used for: Helping trace the sub-size generation path and draft the regression test. I reviewed, tested, and take responsibility for the final code.
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.