Opened 4 weeks ago
Closed 3 weeks ago
#65648 closed defect (bug) (worksforme)
Media: Set `window.__heicUploadSupport` flag so Safari gets client-side HEIC conversion
| Reported by: | adamsilverstein | Owned by: | adamsilverstein |
|---|---|---|---|
| Priority: | normal | Milestone: | |
| Component: | Media | Version: | |
| Severity: | normal | Keywords: | has-patch needs-testing has-unit-tests |
| Cc: | Focuses: |
Description
WordPress 7.1's client-side media processing includes a HEIC canvas fallback in the block editor for browsers that cannot run the full WebAssembly (vips) pipeline. Safari is the primary target: it can decode HEIC natively via createImageBitmap() and convert to JPEG on a canvas, with no need for SharedArrayBuffer or cross-origin isolation.
That fallback is gated on the global window.__heicUploadSupport flag (see shouldEnableHeicCanvasProcessing() in @wordpress/block-editor), which core never sets. The Gutenberg plugin sets it via gutenberg_set_heic_upload_support_flag(), but core has no equivalent.
Steps to reproduce
- Run a core-only WordPress trunk (7.1) install over HTTPS, without the Gutenberg plugin.
- In Safari, open the block editor and upload a
.heicimage.
Expected: the image is converted to JPEG in the browser before upload.
Actual: no client-side conversion occurs; the HEIC file is uploaded as-is and conversion falls back entirely to the server (which requires Imagick with HEIC support).
Why Safari is affected
wp_set_up_cross_origin_isolation()only sendsDocument-Isolation-Policyfor Chromium 137+, so in SafaridetectClientSideMediaSupport()fails (no cross-origin isolation → noSharedArrayBuffer) and the full vips pipeline is disabled.- The editor then evaluates the HEIC-only canvas path, which returns early because
window.__heicUploadSupportis unset - before the browser capability check ever runs.
Proposed fix
Set window.__heicUploadSupport = true in wp_set_client_side_media_processing_flag(), alongside the existing window.__clientSideMediaProcessing flag. The flag respects the existing wp_client_side_media_processing_enabled filter, and the actual capability check (createImageBitmap + OffscreenCanvas + HEIC decode probe) still happens client-side, so setting it unconditionally is safe: Chromium browsers running the full pipeline ignore it.
PR (includes unit tests): https://github.com/WordPress/wordpress-develop/pull/12561
Change History (10)
This ticket was mentioned in PR #12561 on WordPress/wordpress-develop by @adamsilverstein.
4 weeks ago
#2
@adamsilverstein commented on PR #12561:
4 weeks ago
#3
I verified this fixes HEIC uploads for me in Safari. However, I notices a small visual glitch testing this, the image progress snackbar shows "1 of 2" even though I only uploaded one image. Chrome does not show this for the same image upload, its Safari specific.
I will open a follow up issue to work on this.
@adamsilverstein commented on PR #12561:
4 weeks ago
#4
I will open a follow up issue to work on this.
@andrewserong commented on PR #12561:
4 weeks ago
#5
The block editor's HEIC canvas fallback is gated on window.heicUploadSupport, but core never sets that flag. The Gutenberg plugin sets it via gutenberg_set_heic_upload_support_flag(), and core has no equivalent.
As a result, on a core-only WordPress 7.1 install, browsers that cannot use the full WebAssembly (vips) pipeline get no client-side HEIC conversion at all. This primarily affects Safari:
At face value this makes it sound like something that should be fixed within the Gutenberg code. I.e. in Gutenberg we can add if ( globalThis.IS_GUTENBERG_PLUGIN ) { branches if we need to fork behaviour based on if it's running in the plugin versus core.
For this particular PHP change, since the conditions where we output window.__clientSideMediaProcessing = true;' and window.__heicUploadSupport = true; are indentical, I don't really understand why the latter is required.
Sorry if I'm missing something obvious!
@adamsilverstein commented on PR #12561:
3 weeks ago
#6
The block editor's HEIC canvas fallback is gated on window.heicUploadSupport, but core never sets that flag. The Gutenberg plugin sets it via gutenberg_set_heic_upload_support_flag(), and core has no equivalent.
As a result, on a core-only WordPress 7.1 install, browsers that cannot use the full WebAssembly (vips) pipeline get no client-side HEIC conversion at all. This primarily affects Safari:
At face value this makes it sound like something that should be fixed within the Gutenberg code. I.e. in Gutenberg we can add
if ( globalThis.IS_GUTENBERG_PLUGIN ) {branches if we need to fork behaviour based on if it's running in the plugin versus core.
For this particular PHP change, since the conditions where we output
window.__clientSideMediaProcessing = true;'andwindow.__heicUploadSupport = true;are indentical, I don't really understand why the latter is required.
Sorry if I'm missing something obvious!
Hmm, let me look more carefully.
@adamsilverstein commented on PR #12561:
3 weeks ago
#7
For this particular PHP change, since the conditions where we output
window.__clientSideMediaProcessing = true;'andwindow.__heicUploadSupport = true;are indentical, I don't really understand why the latter is required.
@andrewserong Good catch!
Reviewing the code, the second flag carries no extra information, I'm not sure why we wound up adding that or why it would be useful. The cleaner fix is on the Gutenberg side: gate the HEIC canvas path on window.__clientSideMediaProcessing (which core already sets for all browsers when the filter allows) and drop __heicUploadSupport entirely - no IS_GUTENBERG_PLUGIN branching needed. I'll open a Gutenberg PR close this one as not needed.
This ticket was mentioned in PR #12589 on WordPress/wordpress-develop by @wprashed.
3 weeks ago
#8
Summary
Adds the window.heicUploadSupport flag when client-side media processing is enabled, allowing the block editor’s HEIC canvas fallback to run in browsers such as Safari.
Why
Core already sets window.clientSideMediaProcessing, but the HEIC-only canvas fallback is gated behind window.heicUploadSupport. Without this flag, Safari skips client-side HEIC conversion and uploads HEIC files as-is, leaving conversion entirely to server-side image processing.
Changes
Sets window.heicUploadSupport = true; in wp_set_client_side_media_processing_flag().
Adds PHPUnit coverage for:non-Chromium browsers such as Safari
Chromium 137+ browsers
disabled wp_client_side_media_processing_enabled filter
Testing
php -l src/wp-includes/media.php
php -l tests/phpunit/tests/media/wpSetClientSideMediaProcessingFlag.php
Targeted PHPUnit could not be run locally because the environment is missing project dependencies: dotenv for the npm test runner and no local vendor/ PHPUnit binary.
@adamsilverstein commented on PR #12561:
3 weeks ago
#9
Closing in favor of https://github.com/WordPress/gutenberg/pull/80452
#10
@
3 weeks ago
- Milestone 7.1
- Resolution → worksforme
- Status assigned → closed
Closing as not planned, see https://github.com/WordPress/wordpress-develop/pull/12561#issuecomment-5014649503.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
## Summary
The block editor's HEIC canvas fallback is gated on
window.__heicUploadSupport, but core never sets that flag. The Gutenberg plugin sets it viagutenberg_set_heic_upload_support_flag(), and core has no equivalent.As a result, on a core-only WordPress 7.1 install, browsers that cannot use the full WebAssembly (vips) pipeline get no client-side HEIC conversion at all. This primarily affects Safari:
Document-Isolation-Policyfor Chromium 137+ (wp_set_up_cross_origin_isolation()), so in SafaridetectClientSideMediaSupport()fails and the full vips pipeline is disabled.shouldEnableHeicCanvasProcessing()in@wordpress/block-editor), which requireswindow.__heicUploadSupport- never set by core - so it bails before even checking browser capability.Safari is exactly the browser this fallback was built for: it can decode HEIC natively via
createImageBitmap()and convert to JPEG on a canvas, without needing SharedArrayBuffer or cross-origin isolation.## Changes
window.__heicUploadSupport = trueinwp_set_client_side_media_processing_flag(), alongside the existing__clientSideMediaProcessingflag. It respects the samewp_client_side_media_processing_enabledfilter, so disabling client-side processing disables this path too. The browser-capability check (createImageBitmap+OffscreenCanvas+ successful HEIC decode) still happens client-side, so setting the flag for all browsers is safe - Chromium browsers with the full pipeline ignore it.## Testing