Parent Issue
Part of #74333
Context
In client-side media processing, sub-size images (and, when format conversion applies, the main image) are encoded in the browser via the @wordpress/vips worker. The encoder needs a JPEG/WebP/AVIF quality value to use.
Today the client uses a single hardcoded constant (DEFAULT_OUTPUT_QUALITY = 0.82 in packages/upload-media/src/store/private-actions.ts), optionally overridden by a generic imageQuality setting. This bypasses WordPress's wp_editor_set_quality filter entirely, so any plugin or theme that tunes encode quality on the server has no effect on client-side-processed images.
This is the same class of problem solved for the output format in #75784 / #75793 ("Move image output format filtering to upload response"), and for EXIF rotation before that: per-file image-processing decisions belong in the per-attachment upload response where the real filename, MIME type, and target dimensions are available.
Problem
- The client-side encoder ignores
wp_editor_set_quality. A site that lowers or raises quality server-side gets inconsistent results between server-processed and client-processed uploads.
wp_editor_set_quality is size-aware since WP 6.8 — its signature is ( int $quality, string $mime_type, array $size ) (see WP_Image_Editor::set_quality()). Plugins can return a different quality per dimension (e.g. higher quality for the full image, lower for thumbnails). The client currently applies one flat quality to every size.
- Quality should be derived from the output MIME type (post
image_editor_output_format conversion), exactly as core's set_quality() does, not the input type.
Proposed Solution
Add an image_quality field to the attachment REST response (the Gutenberg_REST_Attachments_Controller), mirroring the existing image_output_format / image_save_progressive fields:
- The REST callback applies
wp_editor_set_quality with the resolved output MIME type and the full-image dimensions for default.
- when generating sub sizes on the client: For each registered image sub-size, it re-applies the filter with that size's width/height and includes the result under
sizes only when it differs from default (keeps the payload small).
packages/upload-media consumes image_quality instead of DEFAULT_OUTPUT_QUALITY: each sub-size resize/transcode uses sizes[name] ?? default (converted from 1-100 to the 0-1 scale the vips worker expects); the main-image transcode uses default. The hardcoded constant remains only as a final fallback when the field is absent (older Core).
Benefits
- Client-side-processed images honor
wp_editor_set_quality, matching server-side behavior.
- Per-size quality tuning works on the client.
- Keeps per-file processing logic in the upload response, consistent with
image_output_format, image_save_progressive, and exif_orientation.
References
Parent Issue
Part of #74333
Context
In client-side media processing, sub-size images (and, when format conversion applies, the main image) are encoded in the browser via the
@wordpress/vipsworker. The encoder needs a JPEG/WebP/AVIF quality value to use.Today the client uses a single hardcoded constant (
DEFAULT_OUTPUT_QUALITY = 0.82inpackages/upload-media/src/store/private-actions.ts), optionally overridden by a genericimageQualitysetting. This bypasses WordPress'swp_editor_set_qualityfilter entirely, so any plugin or theme that tunes encode quality on the server has no effect on client-side-processed images.This is the same class of problem solved for the output format in #75784 / #75793 ("Move image output format filtering to upload response"), and for EXIF rotation before that: per-file image-processing decisions belong in the per-attachment upload response where the real filename, MIME type, and target dimensions are available.
Problem
wp_editor_set_quality. A site that lowers or raises quality server-side gets inconsistent results between server-processed and client-processed uploads.wp_editor_set_qualityis size-aware since WP 6.8 — its signature is( int $quality, string $mime_type, array $size )(seeWP_Image_Editor::set_quality()). Plugins can return a different quality per dimension (e.g. higher quality for the full image, lower for thumbnails). The client currently applies one flat quality to every size.image_editor_output_formatconversion), exactly as core'sset_quality()does, not the input type.Proposed Solution
Add an
image_qualityfield to the attachment REST response (theGutenberg_REST_Attachments_Controller), mirroring the existingimage_output_format/image_save_progressivefields:wp_editor_set_qualitywith the resolved output MIME type and the full-image dimensions fordefault.sizesonly when it differs fromdefault(keeps the payload small).packages/upload-mediaconsumesimage_qualityinstead ofDEFAULT_OUTPUT_QUALITY: each sub-size resize/transcode usessizes[name] ?? default(converted from 1-100 to the 0-1 scale the vips worker expects); the main-image transcode usesdefault. The hardcoded constant remains only as a final fallback when the field is absent (older Core).Benefits
wp_editor_set_quality, matching server-side behavior.image_output_format,image_save_progressive, andexif_orientation.References
image_editor_output_formatdata to the full sized image upload response #75784