Editor: PHP backports for Client Side Media#10868
Editor: PHP backports for Client Side Media#10868adamsilverstein wants to merge 19 commits intoWordPress:trunkfrom
Conversation
Test using WordPress PlaygroundThe 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
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
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.
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>
westonruter
left a comment
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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.
src/wp-includes/media.php
Outdated
| foreach ( $tags as $tag ) { | ||
| $html = (string) str_replace( "<$tag", "<$tag crossorigin=\"anonymous\"", $html ); | ||
| } |
There was a problem hiding this comment.
This should use the HTML Tag Processor too as it has been leveraged above.
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. |
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. |
There was a problem hiding this comment.
| * @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 ) { |
There was a problem hiding this comment.
| 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 ) { |
There was a problem hiding this comment.
| 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 ) { |
There was a problem hiding this comment.
| protected function get_attachment_filesize( $attachment_id ) { | |
| protected function get_attachment_filesize( $attachment_id ): ?int { |
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 configurationsimage_size_threshold- Big image size threshold (default 2560px)image_output_formats- Output format mappings for image conversionjpeg_interlaced- Whether to use progressive/interlaced JPEG encodingpng_interlaced- Whether to use interlaced PNG encodinggif_interlaced- Whether to use interlaced GIF encodingREST 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 settingsimage_size_threshold- Big image size thresholdimage_output_formats- Format conversion mappingsREST API: Attachments Endpoint
New Fields
filename- Original attachment file namefilesize- File size in bytesexif_orientation- EXIF orientation value (1-8) for client-side rotation handlingNew Parameters
generate_sub_sizes- When false, disables server-side sub-size generation and EXIF rotationconvert_format- When false, disables automatic image format conversionNew Sideload Endpoint
Added
/wp/v2/media/{id}/sideloadendpoint 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_sizesfield handling for PDFs, which use thefallback_intermediate_image_sizesfilter instead ofwp_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:
crossorigin="anonymous"attributes to external resourcesWASM Support
Added
AddTypedirective for WebAssembly files to.htaccessrules, enabling serving.wasmfiles 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.