Skip to content

REST API: Expose size-aware encode quality on attachment responses - #11856

Closed
adamsilverstein wants to merge 16 commits into
WordPress:trunkfrom
adamsilverstein:add/rest-image-quality-field
Closed

REST API: Expose size-aware encode quality on attachment responses#11856
adamsilverstein wants to merge 16 commits into
WordPress:trunkfrom
adamsilverstein:add/rest-image-quality-field

Conversation

@adamsilverstein

@adamsilverstein adamsilverstein commented May 18, 2026

Copy link
Copy Markdown
Member

Summary

Adds an image_quality field to the media attachment REST response. It reports the value of the wp_editor_set_quality filter, resolved against the output MIME type (after image_editor_output_format):

  • default — the filtered quality (1-100) for the full-size image
  • sizes — per-registered-size overrides, included only where the filtered value diverges from default (keeps the payload small)

wp_editor_set_quality has been size-aware since 6.8 (( int $quality, string $mime_type, array $size )), so the filter is re-applied per registered sub-size using that size's dimensions.

This lets client-side media processing (which encodes sub-sizes in the browser) honor a site's configured encode quality instead of a hardcoded default, mirroring the existing exif_orientation field on the same controller.

Backports from Gutenberg

Testing

  • phpunit --filter test_image_quality — schema, default, and size-aware-filter cases
  • phpunit --filter test_get_item_schema — property count updated 32 → 33

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

Proposed commit message

REST API: Expose size-aware encode quality on attachment responses.

Add an `image_quality` field to the media attachment REST response reporting the `wp_editor_set_quality` filter value, resolved against the output MIME type after `image_editor_output_format`. The `default` key carries the filtered quality (1-100) for the full-size image, while `sizes` lists per-registered-size overrides only where they diverge from `default`. 

See related Gutenberg pull request: https://github.com/WordPress/gutenberg/pull/78420.

Props westonruter, timothyblynjacobs.
Fixes #65262.

Add an image_quality field to the media attachment REST response
reporting the wp_editor_set_quality value resolved against the
output MIME type. The default value applies to the full-size image;
per-registered-size overrides are listed under sizes only where the
filtered value diverges from the default.

This lets client-side media processing encode images at the quality
the site has configured, instead of a hardcoded default, mirroring
the existing exif_orientation field.

Props adamsilverstein.
@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The 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

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@TimothyBJacobs

Copy link
Copy Markdown
Member

Should there be a helper function extracted? Looks like quite a bit of logic that will need to stay in sync.

@adamsilverstein adamsilverstein self-assigned this May 19, 2026
@adamsilverstein

adamsilverstein commented May 19, 2026

Copy link
Copy Markdown
Member Author

Should there be a helper function extracted? Looks like quite a bit of logic that will need to stay in sync.

My understanding is that the code will only live in Gutenberg only to support older WordPress versions where the helper wouldn't be available. I believe they only support back a few versions (2?) though, so it can get removed from Gutenberg after some time. Although a helper still might be useful to contain the logic, will consider.

Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Outdated
Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Outdated
Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Outdated
Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Outdated
adamsilverstein and others added 3 commits May 21, 2026 12:50
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Resolve the encode quality WordPress would apply for a given output MIME
type and dimensions without instantiating an image editor, mirroring
WP_Image_Editor::set_quality(): the per-format default, the
wp_editor_set_quality filter, the jpeg_quality filter for JPEG output,
and a clamp to the valid 1-100 range.

This gives callers outside an editor instance, such as the REST API
reporting the quality client-side processing should use, a single
authoritative resolver instead of re-deriving the logic by hand.
Resolve image_quality through the new wp_get_image_encode_quality()
helper so the reported value includes the legacy jpeg_quality filter for
JPEG output (matching WP_Image_Editor::set_quality()) and stays in sync
with core's quality logic instead of duplicating it for the full size
and each sub-size.

Bound the schema integers to 1-100 and enumerate the registered
sub-sizes under "sizes" so the schema documents exactly which keys may
appear.
@adamsilverstein

adamsilverstein commented May 21, 2026

Copy link
Copy Markdown
Member Author

Pushed updates addressing the review:

  • @TimothyBJacobs extracted the shared logic into wp_get_image_encode_quality( $mime_type, $size, $default_quality ) in wp-includes/media.php. The Gutenberg PR now calls this funciton if available.
    • I left WP_Image_Editor::set_quality() itself untouched here: the canonical docblocks for wp_editor_set_quality/jpeg_quality live in that method and are referenced across core via "documented in wp-includes/class-wp-image-editor.php", so having set_quality() adopt the helper is cleaner as a follow-up. Happy to do it in this PR if you'd prefer.
  • @westonruter the reported value now includes jpeg_quality for JPEG output, the schema integers are bounded 1-100, and sizes enumerates the registered sub-sizes.
  • Added unit tests for the helper (defaults, both filters, out-of-range clamping) and a jpeg_quality case on the REST response.

Replace the placeholder ticket number now that the canonical ticket is
open (the duplicate was closed).
Comment thread src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php Outdated
adamsilverstein and others added 3 commits May 28, 2026 13:50
…ontroller.php

Co-authored-by: Weston Ruter <westonruter@gmail.com>
wp_get_image_encode_quality() clamped values above 100 to 100, which
diverges from WP_Image_Editor::set_quality(): that method resets any
out-of-range value (below 0 or above 100) to the per-format default and
only squashes 0 to 1. Mirror that behavior so the REST-reported quality
matches what the server actually applies, and so the clamps-out-of-range
test (150 -> 82, 0 -> 1) passes.
@adamsilverstein
adamsilverstein marked this pull request as ready for review June 29, 2026 15:50
@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 adamsilverstein, westonruter, timothyblynjacobs.

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

@adamsilverstein

Copy link
Copy Markdown
Member Author

Should there be a helper function extracted? Looks like quite a bit of logic that will need to stay in sync.

My understanding is that the code will only live in Gutenberg only to support older WordPress versions where the helper wouldn't be available. I believe they only support back a few versions (2?) though, so it can get removed from Gutenberg after some time. Although a helper still might be useful to contain the logic, will consider.

moved logic to a helper as suggested. GB now consumes from this function if available - https://github.com/WordPress/gutenberg/pull/78420/changes#diff-2a14b3375a43081acbcd01a95fe0441eb10ff35c57d9161860d79bdbd3bf2becR998

adamsilverstein and others added 5 commits July 1, 2026 13:52
…ty-field

# Conflicts:
#	src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
#	tests/phpunit/tests/rest-api/rest-attachments-controller.php
adamsilverstein added a commit to WordPress/gutenberg that referenced this pull request Jul 2, 2026
Apply Weston's suggestions from the review and mirror the minor
robustness changes he amended to the core counterpart
(WordPress/wordpress-develop#11856) so the two stay in sync:

- Accept the PHPStan-typed docblock on the encode-quality helper and
  add native type hints, renaming the parameter to $mime_type to match
  the core wp_get_image_encode_quality() signature.
- Cast get_post_mime_type() to string and clamp the full-size
  dimensions to non-negative ints before deriving quality.
- Add the out-of-range reset comment and drop the redundant int cast on
  return so the inline fallback mirrors core exactly.
@adamsilverstein

Copy link
Copy Markdown
Member Author

Thanks for the reviews @westonruter - I've aligned this as closely as possible with the Gutenberg PR and both should be ready to go.

…ty-field

# Conflicts:
#	src/wp-includes/media.php
@westonruter

Copy link
Copy Markdown
Member

oh, there is a PHPUnit failure:

There was 1 failure:

1) WP_Test_REST_Attachments_Controller::test_sideload_animated_video_companions_write_metadata
Sideloading animated_video should succeed.
Failed asserting that 400 is identical to 200.

/var/www/tests/phpunit/tests/rest-api/rest-attachments-controller.php:3881
phpvfscomposer:///var/www/vendor/phpunit/phpunit/phpunit:106
/var/www/vendor/bin/phpunit:118

@adamsilverstein

Copy link
Copy Markdown
Member Author

oh, there is a PHPUnit failure:

That was from another commit and should be fixed in trunk. Updating to be sure.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

A commit was made that fixes the Trac ticket referenced in the description of this pull request.

SVN changeset: 62630
GitHub commit: 4d6a707

This PR will be closed, but please confirm the accuracy of this and reopen if there is more work to be done.

@github-actions github-actions Bot closed this Jul 2, 2026
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.

3 participants