Opened 3 weeks ago
Last modified 5 days ago
#65661 new enhancement
Media: Enable client-side media uploads in the Media Library
| Reported by: | adamsilverstein | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | Media | Version: | |
| Severity: | normal | Keywords: | has-patch needs-testing has-unit-tests |
| Cc: | Focuses: |
Description
WordPress 7.1 introduced client-side media processing (wasm-vips): in a cross-origin isolated context, the block editor uploads the original image via the REST API and generates sub-sizes in the browser, which are then sideloaded and finalized. This offloads image processing from the server, works on hosts without Imagick/GD constraints, and speeds up uploads.
However, the pipeline currently only runs in the block editor. The Media Library grid (wp-admin/upload.php) — one of the primary places users upload media — still uploads via wp.Uploader/plupload to async-upload.php, with all image processing done server-side. Users uploading through the Media Library miss out on client-side processing entirely, and the two surfaces behave inconsistently.
Proposed change
Extend the client-side pipeline to the Media Library grid:
- Cross-origin isolation on the grid. Hook a new
wp_set_up_media_library_cross_origin_isolation()onload-upload.php, reusing the existingwp_start_cross_origin_isolation_output_buffer()(Document-Isolation-Policy, Chromium 137+). Gated to grid mode and to users withupload_files. List mode is untouched: it has no pipeline integration, so it should not carry isolation side effects.
- Route grid uploads through the pipeline. A new
media-library-uploadadmin script configures the@wordpress/upload-mediastore and intercepts plupload'sFilesAddedevent at a higher priority, routing each file through the pipeline (REST upload of the original, client-side thumbnails, sideload, finalize). The grid UI is preserved: the script mirrors wp-plupload's placeholder tiles, upload progress, queue reset, and error sidebar.
- Graceful degradation. When the browser is not cross-origin isolated (e.g. non-Chromium browsers, older Chromium) or lacks client-side support (no SharedArrayBuffer, low memory, data-saver mode), the script no-ops and the classic plupload flow keeps handling uploads unchanged. Degradation, never data loss.
The implementation was developed and validated in the client-side-media-everywhere plugin (PR #49), where the equivalent end-to-end suite passes on Chromium, Firefox, and WebKit against core trunk.
Scope notes
- In scope:
upload.phpgrid mode — both drag-and-drop and "Add New", which flow through the single gridwp.Uploaderinstance. - Out of scope (follow-ups): the list-mode "Add New" uploader (
media-new.php, a separate uploader path) and abeforeunloadwarning while uploads are in flight.
Testing instructions
- Use Chrome 137+ on a secure origin (HTTPS or localhost).
- Go to Media > Library in grid mode and upload a JPEG via drag-and-drop or "Add New".
- In DevTools > Network, observe a POST to
/wp/v2/media, one or more POSTs to/wp/v2/media/<id>/sideload, one POST to/wp/v2/media/<id>/finalize, and no request toasync-upload.php. - Confirm the grid tile shows progress and resolves to the finished attachment, and that sub-sizes exist in the attachment metadata.
- In Firefox/Safari (or list mode), confirm uploads still work via the classic
async-upload.phppath.
The PR includes 17 new PHPUnit tests and a Playwright E2E spec covering the isolation header, the REST upload flow, and the error path.
PR: https://github.com/WordPress/wordpress-develop/pull/12585
Change History (8)
This ticket was mentioned in PR #12585 on WordPress/wordpress-develop by @adamsilverstein.
3 weeks ago
#1
- Keywords has-unit-tests added
#3
@
3 weeks ago
Test Report
I tested this ticket on my local WordPress setup and successfully reproduced the behavior described in the ticket.
Before applying the patch:
Uploading images from Media → Library (Grid View) continued to use the existing Media Library upload flow.
The Grid View was not integrated with the client-side media processing pipeline available in the Block Editor, resulting in inconsistent upload behavior between the two interfaces.
Expected after applying the patch:
Grid View uploads should use the client-side media processing pipeline via the REST API while preserving the existing upload UI.
Unsupported browsers and List View should continue using the classic upload flow.
Result:
I was able to reproduce the issue on my local WordPress setup, and the observed behavior matches the ticket description.
#4
@
2 weeks ago
- Summary Media: Enable client-side media uploads in the Media Library grid → Media: Enable client-side media uploads in the Media Library
#5
follow-up:
↓ 6
@
2 weeks ago
Thanks for testing @sanayasir! I have updated the PR to also cover the media library list view screen, can you give it another test.
Also if possible, please try as many different image formats as possible including heic, webp, avif and animated gif or png and report the results.
#6
in reply to: ↑ 5
@
12 days ago
Yes, sure! @adamsilverstein I’ll test the updated PR, including the Media Library List View and the different image formats, and report the results.
#7
@
11 days ago
## Patch Testing Feedback
I successfully reproduced and tested the reported issue using the proposed changes.
The Media Library Grid upload flow was tested using Chrome 137+ on a secure origin. When uploading an image through both drag-and-drop and the Add New interface, the upload was successfully routed through the client-side media processing pipeline. The expected REST API requests to /wp/v2/media, /wp/v2/media/<id>/sideload, and /wp/v2/media/<id>/finalize were observed, and no request to async-upload.php was made.
The uploaded media appeared correctly in the Media Library Grid, upload progress was displayed as expected, and the generated image sub-sizes were successfully created.
I also verified the fallback behavior in an unsupported environment and confirmed that uploads continue to work using the existing async-upload.php flow. Media Library List View also continues to use the existing upload flow without introducing unwanted side effects.
Overall, the patch works as expected and successfully extends client-side media processing to the Media Library Grid while maintaining graceful degradation for unsupported environments.
@adamsilverstein commented on PR #12585:
5 days ago
#8
Note: we should make sure we bring over the improved HEIC upload error messages from https://github.com/WordPress/gutenberg/pull/81130 in this PR.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
## What
WordPress 7.1's client-side media pipeline (wasm-vips) only runs in the block editor: it swaps the editor's
mediaUploadsetting and never touches the Media Library grid, which uploads viawp.Uploader/plupload toasync-upload.php. This PR extends the pipeline to the Media Library grid atupload.php, so grid uploads are processed in the browser (REST upload of the original, client-side thumbnails, sideload, finalize) instead of server-side.This ports client-side-media-everywhere PR #49 (see issue #44) into core, adapted to core's DIP-only isolation model.
## How
Commit 1 - Extend cross-origin isolation to the grid. Hooks a new
wp_set_up_media_library_cross_origin_isolation()onload-upload.php, reusing core's existingwp_start_cross_origin_isolation_output_buffer()(Document-Isolation-Policy, Chromium 137+). It is gated to grid mode (resolved the same wayupload.phpresolves it later in the request, via a newwp_get_media_library_mode()) and to users withupload_files. Unlike the plugin, no COEP/COOP fallback path is needed: core's isolation is DIP-only across all screens.Commit 2 - Route grid uploads through the pipeline. A new
media-library-uploadscript (vanilla IIFE insrc/js/_enqueues/admin/, matching the surrounding admin scripts) configures the@wordpress/upload-mediastore viaMediaUploadProvider(useSubRegistry: false), wrapswp.Uploader.prototype.initto interceptFilesAddedat a higher plupload priority, and routes each file through the store while mirroring wp-plupload's placeholder tiles, progress, queue reset, and error sidebar so the grid UI works unchanged.mediaSideload/mediaFinalizeare thinapiFetchwrappers rather than the private@wordpress/media-utilsAPIs. The script is enqueued from theupload.phpgrid branch viawp_enqueue_media_library_upload(), with pipeline settings (wp_get_media_library_upload_settings(): max upload size, allowed mime types, registered sub-sizes, big-image threshold, strip-meta and bit-depth filters) passed as an inline script. When the browser is not cross-origin isolated or lacks client-side support, the script no-ops and classic plupload keeps handling uploads - degradation, never data loss.Commit 3 - E2E coverage. New spec asserting the DIP header on
upload.phpgrid (and its absence in list mode), the happy-path upload (create + sideload + finalize via REST, zeroasync-upload.phprequests), and the disallowed-file-type error path. Playwright's Chromium ships without Document-Isolation-Policy support, so the upload assertions skip when the context is not isolated; the header assertions always run.## Testing
wpMediaLibraryCrossOriginIsolation.php,wpEnqueueMediaLibraryUpload.php) pass locally, as does the existingwpCrossOriginIsolation.phpsuite.## Scope
In:
upload.phpgrid mode - drag-and-drop and "Add New", both of which flow through the one gridwp.Uploader.Out: list-mode "Add New" /
media-new.php(separate uploader path) and abeforeunloadguard for in-progress uploads; both are follow-up candidates.