From dc738660b2a8278507928efaedbb97c2efadcc93 Mon Sep 17 00:00:00 2001 From: adamsilverstein Date: Sat, 18 Jul 2026 23:28:00 -0700 Subject: [PATCH 1/3] Media: Gate HEIC canvas fallback on __clientSideMediaProcessing The __heicUploadSupport flag was emitted under conditions identical to __clientSideMediaProcessing: both live behind the same wp_client_side_media_processing_enabled filter, so the separate flag carried no extra information. The browser-capability distinction is already made client-side in shouldEnableHeicCanvasProcessing(). Checking __clientSideMediaProcessing also fixes Safari HEIC conversion on core-only WordPress 7.1 installs (Trac 65648): core already emits that flag for all browsers, but has no equivalent of gutenberg_set_heic_upload_support_flag(), so the canvas fallback never activated there. --- lib/media/load.php | 32 ++++++++----------- .../src/components/provider/index.js | 4 +-- packages/block-library/src/image/edit.js | 6 +--- .../media-utils/src/utils/upload-media.ts | 1 - 4 files changed, 16 insertions(+), 27 deletions(-) diff --git a/lib/media/load.php b/lib/media/load.php index d53b460e17af1f..99b06a6273383d 100644 --- a/lib/media/load.php +++ b/lib/media/load.php @@ -199,17 +199,22 @@ function gutenberg_media_processing_filter_rest_index( WP_REST_Response $respons add_filter( 'rest_index', 'gutenberg_media_processing_filter_rest_index' ); /** - * Sets a global JS variable to indicate that HEIC canvas-based upload support is available. + * Sets a global JS variable to indicate that client-side media processing is enabled. * - * This flag is set whenever the media processing feature is enabled, - * regardless of whether the browser supports full VIPS-based processing. - * Browsers like Safari can use createImageBitmap() to decode HEIC images - * and convert them to JPEG for server-side sub-size generation. + * The flag gates both processing modes: the full VIPS/WASM pipeline (browsers + * that pass feature detection) and the HEIC canvas fallback used by browsers + * such as Safari that can decode HEIC via createImageBitmap() but lack + * SharedArrayBuffer support. The browser-capability check happens client-side. */ -function gutenberg_set_heic_upload_support_flag() { - wp_add_inline_script( 'wp-block-editor', 'window.__heicUploadSupport = true', 'before' ); +function gutenberg_set_client_side_media_processing_flag() { + // Re-check the filter at action time, since other plugins (loaded after Gutenberg) + // may have added a filter to disable client-side media processing. + if ( ! gutenberg_is_client_side_media_processing_enabled() ) { + return; + } + wp_add_inline_script( 'wp-block-editor', 'window.__clientSideMediaProcessing = true', 'before' ); } -add_action( 'admin_init', 'gutenberg_set_heic_upload_support_flag' ); +add_action( 'admin_init', 'gutenberg_set_client_side_media_processing_flag' ); /** * Deletes the source-format companion file when its attachment is deleted. @@ -258,17 +263,6 @@ function gutenberg_delete_heic_companion_file( int $post_id ): bool { // Everything below requires cross-origin isolation (Document-Isolation-Policy) // and SharedArrayBuffer support, which is only available in Chromium 137+. -/** - * Sets a global JS variable to indicate that client-side media processing is enabled. - */ -function gutenberg_set_client_side_media_processing_flag() { - if ( ! gutenberg_is_client_side_media_processing_enabled() ) { - return; - } - wp_add_inline_script( 'wp-block-editor', 'window.__clientSideMediaProcessing = true', 'before' ); -} -add_action( 'admin_init', 'gutenberg_set_client_side_media_processing_flag' ); - /** * Filters the list of rewrite rules formatted for output to an .htaccess file. * diff --git a/packages/block-editor/src/components/provider/index.js b/packages/block-editor/src/components/provider/index.js index 379aad102606a9..410f83d5495c2f 100644 --- a/packages/block-editor/src/components/provider/index.js +++ b/packages/block-editor/src/components/provider/index.js @@ -102,7 +102,7 @@ function shouldEnableClientSideMediaProcessing() { * * Returns true when: * 1. Full client-side processing is NOT available (otherwise it handles HEIC already) - * 2. The server has set the __heicUploadSupport flag + * 2. The server has set the __clientSideMediaProcessing flag * 3. The browser supports createImageBitmap + OffscreenCanvas (e.g. Safari) * * @return {boolean} Whether HEIC-only canvas processing should be enabled. @@ -118,7 +118,7 @@ function shouldEnableHeicCanvasProcessing() { return false; } - if ( ! window.__heicUploadSupport ) { + if ( ! window.__clientSideMediaProcessing ) { isHeicCanvasEnabledCache = false; return false; } diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index ff6cd3eddc3416..bf97311b99b0f5 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -353,11 +353,7 @@ export function ImageEdit( { const isSideloading = useSelect( ( select ) => { - if ( - ( ! window.__clientSideMediaProcessing && - ! window.__heicUploadSupport ) || - ! id - ) { + if ( ! window.__clientSideMediaProcessing || ! id ) { return false; } return select( uploadStore ).isUploadingById( id ); diff --git a/packages/media-utils/src/utils/upload-media.ts b/packages/media-utils/src/utils/upload-media.ts index 79c6fe0697101a..278b5c4ababf7a 100644 --- a/packages/media-utils/src/utils/upload-media.ts +++ b/packages/media-utils/src/utils/upload-media.ts @@ -22,7 +22,6 @@ import { UploadError } from './upload-error'; declare global { interface Window { __clientSideMediaProcessing?: boolean; - __heicUploadSupport?: boolean; } } From 15c86d9b90dbc1409c28587a3f9dc720e0748ef2 Mon Sep 17 00:00:00 2001 From: adamsilverstein Date: Sat, 18 Jul 2026 23:28:14 -0700 Subject: [PATCH 2/3] Make the HEIC snackbar e2e genuinely exercise the canvas mode The spec activated the disable-client-side-media-processing plugin, assuming __heicUploadSupport stayed set with the filter off. That plugin loads before Gutenberg (active_plugins is sorted), so the file-level filter check in lib/media/load.php skipped both flags and the spec passed vacuously through the traditional upload path: the fake HEIC's JPEG bytes are content-sniffed by wp_check_filetype_and_ext() and the file renamed to .jpg server-side either way. Instead, disable only cross-origin isolation via a new test plugin: without SharedArrayBuffer the vips pipeline fails feature detection while the server flag stays set, so the editor takes the HEIC canvas path in Chromium like Safari would. Also assert a sideload request happens, which distinguishes canvas conversion from a plain upload. --- .../disable-cross-origin-isolation.php | 18 +++++++++++ .../heic-upload-progress-snackbar.spec.js | 31 ++++++++++++++----- 2 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 packages/e2e-tests/plugins/disable-cross-origin-isolation.php diff --git a/packages/e2e-tests/plugins/disable-cross-origin-isolation.php b/packages/e2e-tests/plugins/disable-cross-origin-isolation.php new file mode 100644 index 00000000000000..f697a369183fab --- /dev/null +++ b/packages/e2e-tests/plugins/disable-cross-origin-isolation.php @@ -0,0 +1,18 @@ + { test.beforeAll( async ( { requestUtils } ) => { - // Disable full client-side media processing while leaving the - // HEIC canvas-conversion mode active (`window.__heicUploadSupport` - // is set regardless). This mirrors Safari, where full client-side - // processing is unsupported but HEIC files are still converted to - // JPEG via createImageBitmap + OffscreenCanvas before upload. + // Disable cross-origin isolation while leaving client-side media + // processing enabled: without SharedArrayBuffer the full VIPS + // pipeline fails feature detection, so the editor falls back to the + // HEIC canvas-conversion mode. This mirrors Safari, where full + // client-side processing is unsupported but HEIC files are still + // converted to JPEG via createImageBitmap + OffscreenCanvas before + // upload. await requestUtils.activatePlugin( - 'gutenberg-test-plugin-disable-client-side-media-processing' + 'gutenberg-test-plugin-disable-cross-origin-isolation' ); } ); @@ -31,7 +33,7 @@ test.describe( 'Upload progress snackbar (HEIC-only canvas mode) (@webkit)', () test.afterAll( async ( { requestUtils } ) => { await requestUtils.deactivatePlugin( - 'gutenberg-test-plugin-disable-client-side-media-processing' + 'gutenberg-test-plugin-disable-cross-origin-isolation' ); } ); @@ -59,6 +61,19 @@ test.describe( 'Upload progress snackbar (HEIC-only canvas mode) (@webkit)', () const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); + + // The canvas conversion mode sideloads the converted JPEG. A plain + // server-side upload never hits the sideload endpoint, so waiting for + // it proves the HEIC canvas path actually ran: the server also + // content-sniffs the fake HEIC's JPEG bytes and renames the file, so + // the src assertion below cannot tell the two paths apart on its own. + const sideloadRequest = page.waitForRequest( + ( request ) => + request.method() === 'POST' && + request.url().includes( 'sideload' ), + { timeout: 60_000 } + ); + await imageBlock .locator( 'data-testid=form-file-upload-input' ) .setInputFiles( { @@ -67,6 +82,8 @@ test.describe( 'Upload progress snackbar (HEIC-only canvas mode) (@webkit)', () buffer, } ); + await sideloadRequest; + const snackbarList = page.locator( '.components-snackbar-list' ); // A single file must use the single-file message throughout. The From 16616267dc8b5e6fbf89b54befe0e28e6ac0b6f5 Mon Sep 17 00:00:00 2001 From: adamsilverstein Date: Sat, 18 Jul 2026 23:30:29 -0700 Subject: [PATCH 3/3] Add changelog entries for #80452 --- packages/block-editor/CHANGELOG.md | 4 ++++ packages/block-library/CHANGELOG.md | 4 ++++ packages/media-utils/CHANGELOG.md | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md index 03d11dc03d2743..0408a1e91c9587 100644 --- a/packages/block-editor/CHANGELOG.md +++ b/packages/block-editor/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Bug Fixes + +- Gate the HEIC canvas conversion fallback on `window.__clientSideMediaProcessing` instead of the redundant `window.__heicUploadSupport` flag, fixing client-side HEIC conversion in Safari on core WordPress installs ([#80452](https://github.com/WordPress/gutenberg/pull/80452)). + ## 16.0.0 (2026-07-14) ### Internal diff --git a/packages/block-library/CHANGELOG.md b/packages/block-library/CHANGELOG.md index d7375f064b4ae2..be8ae8d0638e28 100644 --- a/packages/block-library/CHANGELOG.md +++ b/packages/block-library/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Internal + +- Image: Check only `window.__clientSideMediaProcessing` for sideloading status, following the removal of the redundant `window.__heicUploadSupport` flag ([#80452](https://github.com/WordPress/gutenberg/pull/80452)). + ## 10.2.0 (2026-07-14) ### Enhancements diff --git a/packages/media-utils/CHANGELOG.md b/packages/media-utils/CHANGELOG.md index 881432ec121dba..4f02a7a4d92375 100644 --- a/packages/media-utils/CHANGELOG.md +++ b/packages/media-utils/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Internal + +- Remove the `window.__heicUploadSupport` type declaration, following the removal of the redundant flag ([#80452](https://github.com/WordPress/gutenberg/pull/80452)). + ## 5.51.0 (2026-07-14) ### Enhancements