From 384062ed166d87fe04d9174a7cdefc4e3b535e2b Mon Sep 17 00:00:00 2001 From: adamsilverstein Date: Thu, 5 Nov 2026 13:40:43 -0500 Subject: [PATCH] Media: Keep one list of the image formats the upload pipeline takes. The formats were listed twice, once to route files to the pipeline and once to type the media frame's placeholder tiles, so adding a format (eg. JPEG XL) meant finding both. Both now read one list in media-upload-pipeline.js, exposed to media-frame-upload.js as `wp.mediaUploadPipeline.getImageSubtype()`, with a pointer to the upload-media constants it mirrors. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018vwYjTNtbdhcmnECA2bZxP --- src/js/_enqueues/admin/media-frame-upload.js | 16 +++---- .../_enqueues/admin/media-upload-pipeline.js | 44 +++++++++++++++---- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/js/_enqueues/admin/media-frame-upload.js b/src/js/_enqueues/admin/media-frame-upload.js index f5af17d7991d2..cc4e6105f73bb 100644 --- a/src/js/_enqueues/admin/media-frame-upload.js +++ b/src/js/_enqueues/admin/media-frame-upload.js @@ -200,18 +200,12 @@ percent: file.percent, }; - /* - * Early mime type scanning for images, as wp-plupload.js does, - * extended with the formats the client-side pipeline accepts. - */ - const image = /(?:jpe?g|png|gif|webp|avif|heic|heif)$/i.exec( - file.name - ); - if ( image ) { + // Early mime type scanning for images, as wp-plupload.js does, + // for the formats the pipeline processes. + const subtype = pipeline.getImageSubtype( file.name ); + if ( subtype ) { attributes.type = 'image'; - // `jpg` is not a valid subtype, so map it to `jpeg`. - const subtype = image[ 0 ].toLowerCase(); - attributes.subtype = 'jpg' === subtype ? 'jpeg' : subtype; + attributes.subtype = subtype; } const model = wp.media.model.Attachment.create( attributes ); diff --git a/src/js/_enqueues/admin/media-upload-pipeline.js b/src/js/_enqueues/admin/media-upload-pipeline.js index d1783353183fd..865465fd48936 100644 --- a/src/js/_enqueues/admin/media-upload-pipeline.js +++ b/src/js/_enqueues/admin/media-upload-pipeline.js @@ -38,6 +38,11 @@ window.wp = window.wp || {}; const imageSizeCount = Object.keys( settings.allImageSizes || {} ).length; + // Image subtypes the pipeline processes. Keep in sync with + // CLIENT_SIDE_SUPPORTED_MIME_TYPES and HEIC_MIME_TYPES in the + // upload-media package. + const IMAGE_SUBTYPES = [ 'jpeg', 'png', 'gif', 'webp', 'avif', 'heic', 'heif' ]; + /** * Recursively appends data to a FormData object, supporting nested objects. * @@ -412,23 +417,43 @@ window.wp = window.wp || {}; return configured && isStoreConfigured(); } + /** + * Gets the image subtype of a file name the pipeline can process. + * + * @param {string} fileName A file name. + * @return {string|null} The subtype, eg. `jpeg` for `photo.jpg`, or + * null when the pipeline does not process it. + */ + function getImageSubtype( fileName ) { + const match = /\.([a-z0-9]+)$/i.exec( fileName || '' ); + if ( ! match ) { + return null; + } + // `jpg` is not a valid subtype, so map it to `jpeg`. + const extension = match[ 1 ].toLowerCase(); + const subtype = 'jpg' === extension ? 'jpeg' : extension; + return IMAGE_SUBTYPES.includes( subtype ) ? subtype : null; + } + /** * Whether a file is an image the client-side pipeline can process. * - * Mirrors the formats the upload-media store processes in the browser: - * the wasm-vips formats, plus HEIC and HEIF, which it converts. A HEIC - * file is also matched by its extension, since browsers on platforms - * without a HEIC codec may give it no type at all. + * A HEIC file is also matched by its extension, since browsers on + * platforms without a HEIC codec may give it no type at all. * * @param {plupload.File} file A file added to the plupload queue. * @return {boolean} True when the pipeline should take the file. */ function isPipelineFile( file ) { - return ( - /^image\/(?:jpeg|png|gif|webp|avif|heic|heif)$/i.test( - file.type || '' - ) || /\.hei[cf]$/i.test( file.name || '' ) - ); + const type = ( file.type || '' ).toLowerCase(); + if ( + type.startsWith( 'image/' ) && + IMAGE_SUBTYPES.includes( type.slice( 6 ) ) + ) { + return true; + } + const subtype = getImageSubtype( file.name ); + return 'heic' === subtype || 'heif' === subtype; } /** @@ -759,5 +784,6 @@ window.wp = window.wp || {}; isReady: isReady, routeBatch: routeBatch, getErrorText: getErrorText, + getImageSubtype: getImageSubtype, }; } )( window.wp );