Media: Move image output format filtering to upload response#75793
Conversation
The image_editor_output_format filter was applied incorrectly in the REST index with wrong parameters (empty defaults, no filename context). Plugins couldn't make per-file decisions. This moves output format and progressive encoding data to the attachment upload response where actual file context is available. The client now reads image_output_format and image_save_progressive from the attachment response instead of generic settings from the REST index.
|
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: -100 B (0%) Total Size: 7.76 MB 📦 View Changed
ℹ️ View Unchanged
|
|
Flaky tests detected in 135290e. 🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/24813808972
|
|
As I mentioned on Trac: This was added to the index so that the desired output mapping is known client-side. If a plugin wants to convert all JPEGs to WebP for example, the client-side media handling can do it automatically. Of course it's not possible to pass a filename in that case. Updating documentation accordingly is reasonable IMO. An alternative would be to add some client-side settings to the upload store where the same kind of mapping could be done in JS. But that would break back compat. |
Co-authored-by: Weston Ruter <weston@ruter.net>
@swissspidy my intention here was to add the conversion path in the response to the original image upload. Like core, we always save the original uploaded image - even with output mapping, the original is always stored as is, only sub-sizes are mapped. As part of that upload response, we already include the missing_image_sizes and exif_rotation, what I am proposing here is we also include the output mapping (for the uploaded mime type) and interlace setting for the image in that initial response. Then the client can proceed with the resizing/rotation/transcoding as needed. |
Resolve conflicts: - private-actions.ts: Keep branch's approach of reading output format from attachment response instead of global settings - types.ts: Remove imageOutputFormats/interlaced from Settings, keep new imageQuality and mediaFinalize fields from trunk - wp-build templates: Apply trunk's function_exists removal while keeping branch's preload field changes
Remove duplicate settings/allImageSizes declarations that were introduced during merge conflict resolution. Fix equals sign alignment in attachments controller to satisfy PHPCS.
|
That means the original always needs to be uploaded first before you can do anything else in the browser, which is a bit of a drawback. Originally I was doing that last. But if we're fine with that, the change nakes sense. |
Co-authored-by: Weston Ruter <weston@ruter.net>
Its true what you say, processing is delayed until the original is uploaded which is a drawback, however it is a tradeoff and offers some advantages especially for filtering and backwards compatibility):
|
Isn't exif rotation detection best done client-side anyway? |
Resolve conflicts in lib/media/load.php and packages/upload-media/src/store/private-actions.ts after trunk restructured load.php into HEIC/full-processing tiers and renamed thumbnail source variables. PR intent preserved: the gutenberg_get_default_image_output_formats() helper and the image_output_formats / *_interlaced REST index fields are removed, and per-file format conversion is read from the attachment response rather than from settings.imageOutputFormats.
possibly, lets discuss further in a follow up issue. |
|
I'm going to do some additional manual testing before merging. |
|
This worked well in my local testing. Merging. |
@swissspidy follow up issue for discussion: #77582 |
Client-side uploads were sending convert_format=false, which disabled server-side format conversion. The replacement path tried to sideload a transcoded copy with image_size='original', but that code path only sets $metadata['original_image'] — it never updates _wp_attached_file or $metadata['file'], so wp_get_attachment_url() kept returning the unconverted JPEG even when a filter mapped JPEG to WebP. Let the server handle main-file conversion via its existing _wp_image_meta_replace_original logic. The client continues to handle sub-size conversion using the image_output_format hint in the upload response. Add PHPUnit coverage for both convert_format paths so the file-on-disk outcome is locked in.
* Move image output format filtering to upload response The image_editor_output_format filter was applied incorrectly in the REST index with wrong parameters (empty defaults, no filename context). Plugins couldn't make per-file decisions. This moves output format and progressive encoding data to the attachment upload response where actual file context is available. The client now reads image_output_format and image_save_progressive from the attachment response instead of generic settings from the REST index. * Update lib/media/class-gutenberg-rest-attachments-controller.php Co-authored-by: Weston Ruter <weston@ruter.net> * Fix duplicate variable declarations and PHPCS alignment Remove duplicate settings/allImageSizes declarations that were introduced during merge conflict resolution. Fix equals sign alignment in attachments controller to satisfy PHPCS. * Update lib/media/class-gutenberg-rest-attachments-controller.php Co-authored-by: Weston Ruter <weston@ruter.net> * Fix main-file output format mapping in client-side uploads Client-side uploads were sending convert_format=false, which disabled server-side format conversion. The replacement path tried to sideload a transcoded copy with image_size='original', but that code path only sets $metadata['original_image'] — it never updates _wp_attached_file or $metadata['file'], so wp_get_attachment_url() kept returning the unconverted JPEG even when a filter mapped JPEG to WebP. Let the server handle main-file conversion via its existing _wp_image_meta_replace_original logic. The client continues to handle sub-size conversion using the image_output_format hint in the upload response. Add PHPUnit coverage for both convert_format paths so the file-on-disk outcome is locked in. --------- Co-authored-by: Weston Ruter <weston@ruter.net> Co-authored-by: simison <87168+simison@users.noreply.github.com>
Core's re-introduced client-side media processing (changeset 62428) restored a pre-#75793 REST API root index that still exposes the file-less `image_output_formats`, `jpeg_interlaced`, `png_interlaced`, and `gif_interlaced` settings. When the plugin runs against Core trunk, these keys are present, so the `assertArrayNotHasKey` assertions in the media processing test fail. The proper fix lives in Core, where wordpress-develop#12007 removes these redundant index keys in favor of the per-attachment `image_output_format` and `image_save_progressive` response fields. Until that PR merges, disable the affected assertions and link to it so they can be reactivated. See WordPress/wordpress-develop#12007
Core's re-introduced client-side media processing (changeset 62428) restored a pre-#75793 REST API root index that still exposes the file-less `image_output_formats`, `jpeg_interlaced`, `png_interlaced`, and `gif_interlaced` settings. When the plugin runs against Core trunk, these keys are present, so the `assertArrayNotHasKey` assertions in the media processing test fail. The proper fix lives in Core, where wordpress-develop#12007 removes these redundant index keys in favor of the per-attachment `image_output_format` and `image_save_progressive` response fields. Until that PR merges, disable the affected assertions and link to it so they can be reactivated. See WordPress/wordpress-develop#12007
Core's re-introduced client-side media processing (changeset 62428) restored a pre-#75793 REST API root index that still exposes the file-less `image_output_formats`, `jpeg_interlaced`, `png_interlaced`, and `gif_interlaced` settings. When the plugin runs against Core trunk, these keys are present, so the `assertArrayNotHasKey` assertions in the media processing test fail. The proper fix lives in Core, where wordpress-develop#12007 removes these redundant index keys in favor of the per-attachment `image_output_format` and `image_save_progressive` response fields. Until that PR merges, disable the affected assertions and link to it so they can be reactivated. See WordPress/wordpress-develop#12007
Core's re-introduced client-side media processing (changeset 62428) restored a pre-#75793 REST API root index that still exposes the file-less `image_output_formats`, `jpeg_interlaced`, `png_interlaced`, and `gif_interlaced` settings. When the plugin runs against Core trunk, these keys are present, so the `assertArrayNotHasKey` assertions in the media processing test fail. The proper fix lives in Core, where wordpress-develop#12007 removes these redundant index keys in favor of the per-attachment `image_output_format` and `image_save_progressive` response fields. Until that PR merges, disable the affected assertions and link to it so they can be reactivated. See WordPress/wordpress-develop#12007
Summary
image_editor_output_formatfiltering from the REST API index to the per-file attachment upload response, where the actual filename and MIME type are available for plugins to make informed decisionsimage_output_formatandimage_save_progressivefields to the attachment REST response schemaimage_output_formats,jpeg_interlaced,png_interlaced,gif_interlacedfrom the REST indexCloses #75784.
Test plan
image_output_format(null by default) andimage_save_progressive(false by default) appear in the REST responseimage_editor_output_formatfilter (e.g., JPEG→WebP) and verify the per-fileimage_output_formatreflects it on upload/) no longer includesimage_output_formats,jpeg_interlaced,png_interlaced,gif_interlacednpm run test:unit packages/upload-mediavendor/bin/phpunit phpunit/media/🤖 Generated with Claude Code