@wordpress/media-utils
Version:
WordPress Media Upload Utils.
176 lines (161 loc) • 5.29 kB
text/typescript
/**
* WordPress dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { createBlobURL, revokeBlobURL } from '@wordpress/blob';
/**
* Internal dependencies
*/
import type {
AdditionalData,
Attachment,
OnChangeHandler,
OnErrorHandler,
} from './types';
import { uploadToServer } from './upload-to-server';
import { validateMimeType } from './validate-mime-type';
import { validateMimeTypeForUser } from './validate-mime-type-for-user';
import { validateFileSize } from './validate-file-size';
import { UploadError } from './upload-error';
declare global {
interface Window {
__clientSideMediaProcessing?: boolean;
}
}
interface UploadMediaArgs {
// Additional data to include in the request.
additionalData?: AdditionalData;
// Array with the types of media that can be uploaded, if unset all types are allowed.
allowedTypes?: string[];
// List of files.
filesList: File[];
// Maximum upload size in bytes allowed for the site.
maxUploadFileSize?: number;
// Function called when an error happens.
onError?: OnErrorHandler;
// Function called each time a file or a temporary representation of the file is available.
onFileChange?: OnChangeHandler;
// List of allowed mime types and file extensions.
wpAllowedMimeTypes?: Record< string, string > | null;
// Abort signal.
signal?: AbortSignal;
// Whether to allow multiple files to be uploaded.
multiple?: boolean;
}
/**
* Upload a media file when the file upload button is activated
* or when adding a file to the editor via drag & drop.
*
* @param $0 Parameters object passed to the function.
* @param $0.allowedTypes Array with the types of media that can be uploaded, if unset all types are allowed.
* @param $0.additionalData Additional data to include in the request.
* @param $0.filesList List of files.
* @param $0.maxUploadFileSize Maximum upload size in bytes allowed for the site.
* @param $0.onError Function called when an error happens.
* @param $0.onFileChange Function called each time a file or a temporary representation of the file is available.
* @param $0.wpAllowedMimeTypes List of allowed mime types and file extensions.
* @param $0.signal Abort signal.
* @param $0.multiple Whether to allow multiple files to be uploaded.
*/
export function uploadMedia( {
wpAllowedMimeTypes,
allowedTypes,
additionalData = {},
filesList,
maxUploadFileSize,
onError,
onFileChange,
signal,
multiple = true,
}: UploadMediaArgs ) {
if ( ! multiple && filesList.length > 1 ) {
onError?.( new Error( __( 'Only one file can be used here.' ) ) );
return;
}
const validFiles = [];
const filesSet: Array< Partial< Attachment > | null > = [];
const setAndUpdateFiles = ( index: number, value: Attachment | null ) => {
// For client-side media processing, this is handled by the upload-media package.
if ( ! window.__clientSideMediaProcessing ) {
if ( filesSet[ index ]?.url ) {
revokeBlobURL( filesSet[ index ].url );
}
}
filesSet[ index ] = value;
onFileChange?.(
filesSet.filter( ( attachment ) => attachment !== null )
);
};
for ( const mediaFile of filesList ) {
// Verify if user is allowed to upload this mime type.
// Defer to the server when type not detected.
try {
validateMimeTypeForUser( mediaFile, wpAllowedMimeTypes );
} catch ( error: unknown ) {
onError?.( error as Error );
continue;
}
// Check if the caller (e.g. a block) supports this mime type.
// Defer to the server when type not detected.
try {
validateMimeType( mediaFile, allowedTypes );
} catch ( error: unknown ) {
onError?.( error as Error );
continue;
}
// Verify if file is greater than the maximum file upload size allowed for the site.
try {
validateFileSize( mediaFile, maxUploadFileSize );
} catch ( error: unknown ) {
onError?.( error as Error );
continue;
}
validFiles.push( mediaFile );
// For client-side media processing, this is handled by the upload-media package.
if ( ! window.__clientSideMediaProcessing ) {
// Set temporary URL to create placeholder media file, this is replaced
// with final file from media gallery when upload is `done` below.
filesSet.push( { url: createBlobURL( mediaFile ) } );
onFileChange?.( filesSet as Array< Partial< Attachment > > );
}
}
validFiles.map( async ( file, index ) => {
try {
const attachment = await uploadToServer(
file,
additionalData,
signal
);
setAndUpdateFiles( index, attachment );
} catch ( error ) {
// Reset to empty on failure.
setAndUpdateFiles( index, null );
// @wordpress/api-fetch throws any response that isn't in the 200 range as-is.
let message: string;
if (
typeof error === 'object' &&
error !== null &&
'message' in error
) {
message =
typeof error.message === 'string'
? error.message
: String( error.message );
} else {
message = sprintf(
// translators: %s: file name
__( 'Error while uploading file %s to the media library.' ),
file.name
);
}
onError?.(
new UploadError( {
code: 'GENERAL',
message,
file,
cause: error instanceof Error ? error : undefined,
} )
);
}
} );
}