Skip to content

Editor: PHP backports for Client Side Media#10868

Draft
adamsilverstein wants to merge 19 commits intoWordPress:trunkfrom
adamsilverstein:backport-preload-changes-for-csm-70
Draft

Editor: PHP backports for Client Side Media#10868
adamsilverstein wants to merge 19 commits intoWordPress:trunkfrom
adamsilverstein:backport-preload-changes-for-csm-70

Conversation

@adamsilverstein
Copy link
Member

@adamsilverstein adamsilverstein commented Feb 4, 2026

This PR contains the PHP backports for the client-side media processing feature, enabling the editor to perform client-side image resizing, thumbnail generation, and format conversion using WebAssembly.

Preloaded Settings

The following site settings are now preloaded in both the post editor and site editor:

  • image_sizes - Available image size configurations
  • image_size_threshold - Big image size threshold (default 2560px)
  • image_output_formats - Output format mappings for image conversion
  • jpeg_interlaced - Whether to use progressive/interlaced JPEG encoding
  • png_interlaced - Whether to use interlaced PNG encoding
  • gif_interlaced - Whether to use interlaced GIF encoding

REST API: Index Endpoint

Added media processing settings to the REST API index (/wp-json/wp/v2/):

  • image_sizes - All registered image sizes with dimensions and crop settings
  • image_size_threshold - Big image size threshold
  • image_output_formats - Format conversion mappings

REST API: Attachments Endpoint

New Fields

  • filename - Original attachment file name
  • filesize - File size in bytes
  • exif_orientation - EXIF orientation value (1-8) for client-side rotation handling

New Parameters

  • generate_sub_sizes - When false, disables server-side sub-size generation and EXIF rotation
  • convert_format - When false, disables automatic image format conversion

New Sideload Endpoint

Added /wp/v2/media/{id}/sideload endpoint for uploading sub-sized images to an existing attachment. Used by client-side media processing to upload generated image sizes without creating new attachments. Supports both images and PDFs.

PDF Improvements

Improved missing_image_sizes field handling for PDFs, which use the fallback_intermediate_image_sizes filter instead of wp_get_missing_image_subsizes().

Cross-Origin Isolation

Added COOP (Cross-Origin-Opener-Policy) and COEP (Cross-Origin-Embedder-Policy) headers in the block editor to enable SharedArrayBuffer for WebAssembly-based processing. Includes:

  • Output buffer to automatically add crossorigin="anonymous" attributes to external resources
  • Media templates updated with crossorigin attributes for audio, img, and video tags

WASM Support

Added AddType directive for WebAssembly files to .htaccess rules, enabling serving .wasm files for client-side media processing libraries like wasm-vips.

Tests

Updated REST API tests for the new attachment fields and sideload endpoint.


Gutenberg PRs:

Gutenberg tracking issue: WordPress/gutenberg#75062

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


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.

@github-actions
Copy link

github-actions bot commented Feb 4, 2026

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

  • The Plugin and Theme Directories cannot be accessed within Playground.
  • 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.

Add filename and filesize REST fields to the attachments endpoint
for client-side media processing. The filename returns the original
attachment file name, and filesize returns the file size in bytes.
Add exif_orientation field to the attachments REST endpoint for
client-side EXIF rotation handling. Values 1-8 follow the EXIF
specification, where 1 means no rotation is needed.
Add generate_sub_sizes and convert_format parameters to the
attachments POST endpoint for client-side media processing control.
When generate_sub_sizes is false, server-side sub-size generation
and EXIF rotation are disabled. When convert_format is false,
automatic image format conversion is disabled.
Add sideload endpoint at /wp/v2/media/{id}/sideload for uploading
sub-sized images to an existing attachment. Used by client-side media
processing to upload generated image sizes without creating new
attachments. Supports both images and PDFs.
Add PDF-specific handling for the missing_image_sizes field in the
attachments endpoint. PDFs use fallback_intermediate_image_sizes
filter to determine which thumbnail sizes should be generated,
unlike regular images which use wp_get_missing_image_subsizes().
Add COOP and COEP headers in the block editor to enable
SharedArrayBuffer for WebAssembly-based client-side media processing.
Includes output buffer to automatically add crossorigin="anonymous"
attributes to external resources.
Add AddType directive for WebAssembly files to the mod_rewrite_rules
filter. This enables serving .wasm files for client-side media
processing using libraries like wasm-vips.
Override wp_print_media_templates to add crossorigin="anonymous"
attributes to audio, img, and video tags. Required for cross-origin
isolation compliance in the media library modal.
@adamsilverstein adamsilverstein changed the title Editor: Add REST API preloaded paths for client-side media processing Editor: PHP back posrts for client-side media Feb 5, 2026
@adamsilverstein adamsilverstein changed the title Editor: PHP back posrts for client-side media Editor: PHP backports for client-side media Feb 5, 2026
@adamsilverstein adamsilverstein changed the title Editor: PHP backports for client-side media Editor: PHP backports for Client Side Media Feb 5, 2026
@adamsilverstein adamsilverstein self-assigned this Feb 5, 2026
adamsilverstein and others added 2 commits February 4, 2026 22:10
Update test_get_item_schema to expect 32 properties instead of 29,
adding assertions for the new filename, filesize, and exif_orientation
fields. Add the sideload endpoint to expected routes in schema test.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Member

@westonruter westonruter left a comment

Choose a reason for hiding this comment

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

Sorry for what may be an unsolicited early review, as the PR is still a draft.

}

/**
* Filters the list of rewrite rules formatted for output to an .htaccess file.
Copy link
Member

Choose a reason for hiding this comment

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

What about for Nginx?

Copy link
Member Author

Choose a reason for hiding this comment

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

With help from Claude:

Nginx's default mime.types file has included application/wasm since at least 2017 (see nginx/nginx@aef7dd8), so most Nginx servers already serve .wasm files with the correct MIME type out of the box.

The AddType directive here is a safety net for older Apache configurations that might not have it. WordPress has no mechanism to modify Nginx configuration (it only manages .htaccess).

That said, it might be worth adding a note in the dev notes that server administrators on Nginx (or other servers) with custom/stripped-down MIME type configurations should ensure application/wasm is present. Planning on a dev note already, so I'll make sure to add something on this. Also might be worth checking that the server fallback kicks in when wasm type isn't configured correctly on the server.

Comment on lines 6530 to 6532
foreach ( $tags as $tag ) {
$html = (string) str_replace( "<$tag", "<$tag crossorigin=\"anonymous\"", $html );
}
Copy link
Member

Choose a reason for hiding this comment

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

This should use the HTML Tag Processor too as it has been leveraged above.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done in cbc0328

@adamsilverstein
Copy link
Member Author

Sorry for what may be an unsolicited early review, as the PR is still a draft.

No worries, happy to have your feedback. Indeed I started working on this pr before the Gutenberg work had merged to get ahead and be more prepared - so it may change a bit, but probably not much at this point.

adamsilverstein and others added 7 commits February 13, 2026 22:10
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Co-authored-by: Weston Ruter <westonruter@gmail.com>
Replace naive str_replace with WP_HTML_Tag_Processor for
adding crossorigin attributes to media template tags. Since
templates live inside <script type="text/html"> tags (raw
text per the HTML spec), extract each script block's content
and process it as a standalone HTML fragment.
EXIF orientation value 0 (undefined/no EXIF data) was being
used as-is instead of falling through to the default of 1.
Add a > 0 guard so orientation values of 0 or negative are
treated as no rotation needed.
Add new media endpoint args (generate_sub_sizes, convert_format),
sideload route, image size settings, and filename/filesize fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* The arguments for `CREATABLE` requests are
* checked for required values and may fall-back to a given default.
* Default WP_REST_Server::CREATABLE.
* @return array Endpoint arguments.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
* @return array Endpoint arguments.
* @return array<string, array<string, mixed>> Endpoint arguments.

* Default WP_REST_Server::CREATABLE.
* @return array Endpoint arguments.
*/
public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
public function get_endpoint_args_for_item_schema( string $method = WP_REST_Server::CREATABLE ): array {

* @param int $attachment_id Attachment ID.
* @return string|null Attachment file name, or null if not found.
*/
protected function get_attachment_filename( $attachment_id ) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
protected function get_attachment_filename( $attachment_id ) {
protected function get_attachment_filename( $attachment_id ): ?string {

* @param int $attachment_id Attachment ID.
* @return int|null Attachment file size in bytes, or null if not available.
*/
protected function get_attachment_filesize( $attachment_id ) {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
protected function get_attachment_filesize( $attachment_id ) {
protected function get_attachment_filesize( $attachment_id ): ?int {

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