Skip to content

Media: Skip server-side scaling during client-side media processing#12689

Open
itzmekhokan wants to merge 1 commit into
WordPress:trunkfrom
itzmekhokan:fix/65708-heic-orphaned-scaled-file
Open

Media: Skip server-side scaling during client-side media processing#12689
itzmekhokan wants to merge 1 commit into
WordPress:trunkfrom
itzmekhokan:fix/65708-heic-orphaned-scaled-file

Conversation

@itzmekhokan

Copy link
Copy Markdown

When an attachment is uploaded with generate_sub_sizes set to false, the client generates all derivatives itself — including the scaled full-size image it later supplies through the sideload endpoint. create_item() already suppressed thumbnail generation and EXIF rotation in this case, but not the "big image" downscaling gated by the big_image_size_threshold filter.

What the problem was:

  • A large client-converted image (e.g. a HEIC converted to JPEG in the browser) was still scaled server-side to a -scaled file, which became the attached file while the untouched upload was recorded as original_image.
  • The client's subsequent scaled sideload then collided with that -scaled file and was renamed -scaled-1; the thumbnails inherited the numbered name.
  • The server-generated full-size file was left orphaned on disk and remained after the Media Library item was permanently deleted.

What the fix does:

  • Disables big_image_size_threshold alongside the existing client-side processing filters in create_item(), and removes it again in remove_client_side_media_processing_filters().
  • The uploaded full-size image is stored untouched, so the client's scaled sideload records it as original_image and keeps the plain -scaled name.

Approach and why:

  • generate_sub_sizes = false is the contract that the client owns all derivative generation, which includes the scaled full-size image. Server-side scaling in that mode duplicates the client's work and causes the collision. Suppressing it is the minimal, consistent change — it sits directly beside the three filters already applied for the same purpose.

Trac ticket: https://core.trac.wordpress.org/ticket/65708

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 4.8
Used for: Ticket analysis, code implementation, and tests. All changes were reviewed and validated by me.


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.

When an attachment is uploaded with `generate_sub_sizes` set to false the
client generates all derivatives itself, including the scaled full-size
image it later supplies through the sideload endpoint. The upload handler
already suppressed thumbnail generation and EXIF rotation in this case, but
not the "big image" downscaling gated by the `big_image_size_threshold`
filter.

As a result a large client-converted image (for example a HEIC converted to
JPEG in the browser) was still scaled server-side to a `-scaled` file, which
became the attached file while the untouched upload was recorded as
`original_image`. The client's later scaled sideload then collided with that
`-scaled` file and was renamed `-scaled-1`, the thumbnails inherited the
numbered name, and the server-generated full-size file was left orphaned on
disk.

Disable `big_image_size_threshold` alongside the existing client-side
processing filters so the uploaded full-size image is stored untouched and
the client's scaled sideload records it as `original_image` as intended.

Fixes #65708.
Copilot AI review requested due to automatic review settings July 25, 2026 03:44

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the REST attachments upload flow to better support client-side media processing when generate_sub_sizes=false, ensuring the server does not also perform “big image” downscaling (which can create -scaled filename collisions and leave stray files on disk).

Changes:

  • Disable server-side big-image downscaling (big_image_size_threshold) during REST uploads when generate_sub_sizes is explicitly false.
  • Ensure the new filter is removed alongside the existing client-side-processing-related filters.
  • Add a PHPUnit REST controller test that reproduces the -scaled collision scenario and asserts the corrected behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
tests/phpunit/tests/rest-api/rest-attachments-controller.php Adds coverage verifying big-image scaling is skipped on upload when the client owns derivative generation, preventing -scaled collisions.
src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Disables big_image_size_threshold during create_item() when generate_sub_sizes=false, and removes the filter during cleanup.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@github-actions

Copy link
Copy Markdown

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 props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props khokansardar.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants