We won’t append a unique string to the filename if the settings are configured to do so (#41621)
* Create media library component * Use media library component instead of the MediaUpload from the @wordpress/media-utils * Remove UploadFilesMenuItemm from the DownloadsMenu until we solve the insecure file upload using the wp/v2/media endpoint * Remove the @woocommerce/components/MediaUploader from downloads block until we solve the insecure file upload using the wp/v2/media endpoint * Remove the FormFileUpload from EditDownloadsModal until we solve the insecure file upload using the wp/v2/media endpoint * Add changelog file
This commit is contained in:
parent
633bf40f13
commit
5a513cc9a6
|
@ -0,0 +1,4 @@
|
||||||
|
Significance: minor
|
||||||
|
Type: add
|
||||||
|
|
||||||
|
append a unique string to the filename if the settings are configured to do so
|
|
@ -10,13 +10,11 @@ import { chevronDown, chevronUp } from '@wordpress/icons';
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { DownloadsMenuProps } from './types';
|
import { DownloadsMenuProps } from './types';
|
||||||
import { UploadFilesMenuItem } from '../upload-files-menu-item';
|
|
||||||
import { MediaLibraryMenuItem } from '../media-library-menu-item';
|
import { MediaLibraryMenuItem } from '../media-library-menu-item';
|
||||||
import { InsertUrlMenuItem } from '../insert-url-menu-item';
|
import { InsertUrlMenuItem } from '../insert-url-menu-item';
|
||||||
|
|
||||||
export function DownloadsMenu( {
|
export function DownloadsMenu( {
|
||||||
allowedTypes,
|
allowedTypes,
|
||||||
maxUploadFileSize,
|
|
||||||
onUploadSuccess,
|
onUploadSuccess,
|
||||||
onUploadError,
|
onUploadError,
|
||||||
}: DownloadsMenuProps ) {
|
}: DownloadsMenuProps ) {
|
||||||
|
@ -38,16 +36,6 @@ export function DownloadsMenu( {
|
||||||
renderContent={ ( { onClose } ) => (
|
renderContent={ ( { onClose } ) => (
|
||||||
<div className="components-dropdown-menu__menu">
|
<div className="components-dropdown-menu__menu">
|
||||||
<MenuGroup>
|
<MenuGroup>
|
||||||
<UploadFilesMenuItem
|
|
||||||
allowedTypes={ allowedTypes }
|
|
||||||
maxUploadFileSize={ maxUploadFileSize }
|
|
||||||
onUploadSuccess={ ( files ) => {
|
|
||||||
onUploadSuccess( files );
|
|
||||||
onClose();
|
|
||||||
} }
|
|
||||||
onUploadError={ onUploadError }
|
|
||||||
/>
|
|
||||||
|
|
||||||
<MediaLibraryMenuItem
|
<MediaLibraryMenuItem
|
||||||
allowedTypes={ allowedTypes }
|
allowedTypes={ allowedTypes }
|
||||||
onUploadSuccess={ ( files ) => {
|
onUploadSuccess={ ( files ) => {
|
||||||
|
|
|
@ -1,17 +1,14 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
import { ChangeEvent } from 'react';
|
|
||||||
import { __, sprintf } from '@wordpress/i18n';
|
import { __, sprintf } from '@wordpress/i18n';
|
||||||
import { createElement, useState } from '@wordpress/element';
|
import { createElement, useState } from '@wordpress/element';
|
||||||
import { trash } from '@wordpress/icons';
|
import { trash } from '@wordpress/icons';
|
||||||
import { useDispatch, useSelect } from '@wordpress/data';
|
import { useDispatch } from '@wordpress/data';
|
||||||
import { recordEvent } from '@woocommerce/tracks';
|
import { recordEvent } from '@woocommerce/tracks';
|
||||||
import { ImageGallery, ImageGalleryItem } from '@woocommerce/components';
|
import { ImageGallery, ImageGalleryItem } from '@woocommerce/components';
|
||||||
import { uploadMedia } from '@wordpress/media-utils';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
FormFileUpload,
|
|
||||||
Modal,
|
Modal,
|
||||||
BaseControl,
|
BaseControl,
|
||||||
// @ts-expect-error `__experimentalInputControl` does exist.
|
// @ts-expect-error `__experimentalInputControl` does exist.
|
||||||
|
@ -34,28 +31,14 @@ export interface Image {
|
||||||
|
|
||||||
export const EditDownloadsModal: React.FC< EditDownloadsModalProps > = ( {
|
export const EditDownloadsModal: React.FC< EditDownloadsModalProps > = ( {
|
||||||
downloableItem,
|
downloableItem,
|
||||||
maxUploadFileSize = 10000000,
|
|
||||||
onCancel,
|
onCancel,
|
||||||
onChange,
|
onChange,
|
||||||
onRemove,
|
onRemove,
|
||||||
onSave,
|
onSave,
|
||||||
onUploadSuccess,
|
|
||||||
onUploadError,
|
|
||||||
} ) => {
|
} ) => {
|
||||||
const { createNotice } = useDispatch( 'core/notices' );
|
const { createNotice } = useDispatch( 'core/notices' );
|
||||||
const [ isCopingToClipboard, setIsCopingToClipboard ] =
|
const [ isCopingToClipboard, setIsCopingToClipboard ] =
|
||||||
useState< boolean >( false );
|
useState< boolean >( false );
|
||||||
const [ isFileUploading, setIsFileUploading ] =
|
|
||||||
useState< boolean >( false );
|
|
||||||
|
|
||||||
const { allowedMimeTypes } = useSelect( ( select ) => {
|
|
||||||
const { getEditorSettings } = select( 'core/editor' );
|
|
||||||
return getEditorSettings();
|
|
||||||
} );
|
|
||||||
|
|
||||||
const allowedTypes = allowedMimeTypes
|
|
||||||
? Object.values( allowedMimeTypes )
|
|
||||||
: [];
|
|
||||||
|
|
||||||
const { id = 0, file = '', name = '' } = downloableItem;
|
const { id = 0, file = '', name = '' } = downloableItem;
|
||||||
|
|
||||||
|
@ -96,21 +79,6 @@ export const EditDownloadsModal: React.FC< EditDownloadsModalProps > = ( {
|
||||||
setIsCopingToClipboard( false );
|
setIsCopingToClipboard( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleFormFileUploadChange(
|
|
||||||
event: ChangeEvent< HTMLInputElement >
|
|
||||||
) {
|
|
||||||
setIsFileUploading( true );
|
|
||||||
const filesList = event.currentTarget.files as FileList;
|
|
||||||
await uploadMedia( {
|
|
||||||
allowedTypes,
|
|
||||||
filesList,
|
|
||||||
maxUploadFileSize,
|
|
||||||
onFileChange: onUploadSuccess,
|
|
||||||
onError: onUploadError,
|
|
||||||
} );
|
|
||||||
setIsFileUploading( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={ sprintf(
|
title={ sprintf(
|
||||||
|
@ -145,21 +113,10 @@ export const EditDownloadsModal: React.FC< EditDownloadsModalProps > = ( {
|
||||||
<DownloadsCustomImage />
|
<DownloadsCustomImage />
|
||||||
) }
|
) }
|
||||||
</ImageGallery>
|
</ImageGallery>
|
||||||
<FormFileUpload
|
|
||||||
onChange={ handleFormFileUploadChange }
|
<div className="components-form-file-upload">
|
||||||
render={ ( { openFileDialog } ) => (
|
<p>{ name }</p>
|
||||||
<div>
|
</div>
|
||||||
<p>{ name }</p>
|
|
||||||
<Button
|
|
||||||
onClick={ openFileDialog }
|
|
||||||
isBusy={ isFileUploading }
|
|
||||||
disabled={ isFileUploading }
|
|
||||||
>
|
|
||||||
{ __( 'Replace', 'woocommerce' ) }
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
) }
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<BaseControl
|
<BaseControl
|
||||||
id={ 'file-name-help' }
|
id={ 'file-name-help' }
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
import { closeSmall } from '@wordpress/icons';
|
import { closeSmall } from '@wordpress/icons';
|
||||||
import { MediaItem } from '@wordpress/media-utils';
|
import { MediaItem } from '@wordpress/media-utils';
|
||||||
import { useWooBlockProps } from '@woocommerce/block-templates';
|
import { useWooBlockProps } from '@woocommerce/block-templates';
|
||||||
import { ListItem, MediaUploader, Sortable } from '@woocommerce/components';
|
import { ListItem, Sortable } from '@woocommerce/components';
|
||||||
import { Product, ProductDownload } from '@woocommerce/data';
|
import { Product, ProductDownload } from '@woocommerce/data';
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore No types for this exist yet.
|
// @ts-ignore No types for this exist yet.
|
||||||
|
@ -24,7 +24,6 @@ import { useEntityProp } from '@wordpress/core-data';
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { UploadsBlockAttributes } from './types';
|
import { UploadsBlockAttributes } from './types';
|
||||||
import { UploadImage } from './upload-image';
|
|
||||||
import { DownloadsMenu } from './downloads-menu';
|
import { DownloadsMenu } from './downloads-menu';
|
||||||
import { ProductEditorBlockEditProps } from '../../../types';
|
import { ProductEditorBlockEditProps } from '../../../types';
|
||||||
import {
|
import {
|
||||||
|
@ -250,50 +249,36 @@ export function Edit( {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="wp-block-woocommerce-product-downloads-field__body">
|
<div className="wp-block-woocommerce-product-downloads-field__body">
|
||||||
<MediaUploader
|
{ ! Boolean( downloads.length ) && (
|
||||||
label={
|
<div className="wp-block-woocommerce-product-downloads-field__drop-zone-content">
|
||||||
! Boolean( downloads.length ) ? (
|
<p className="wp-block-woocommerce-product-downloads-field__drop-zone-label">
|
||||||
<div className="wp-block-woocommerce-product-downloads-field__drop-zone-content">
|
{ createInterpolateElement(
|
||||||
<UploadImage />
|
__(
|
||||||
<p className="wp-block-woocommerce-product-downloads-field__drop-zone-label">
|
'Supported file types: <Types /> and more. <link>View all</link>',
|
||||||
{ createInterpolateElement(
|
'woocommerce'
|
||||||
__(
|
),
|
||||||
'Supported file types: <Types /> and more. <link>View all</link>',
|
{
|
||||||
'woocommerce'
|
Types: (
|
||||||
),
|
<Fragment>
|
||||||
{
|
PNG, JPG, PDF, PPT, DOC, MP3, MP4
|
||||||
Types: (
|
</Fragment>
|
||||||
<Fragment>
|
),
|
||||||
PNG, JPG, PDF, PPT, DOC,
|
link: (
|
||||||
MP3, MP4
|
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
||||||
</Fragment>
|
<a
|
||||||
),
|
href="https://codex.wordpress.org/Uploading_Files"
|
||||||
link: (
|
target="_blank"
|
||||||
// eslint-disable-next-line jsx-a11y/anchor-has-content
|
rel="noreferrer"
|
||||||
<a
|
onClick={ ( event ) =>
|
||||||
href="https://codex.wordpress.org/Uploading_Files"
|
event.stopPropagation()
|
||||||
target="_blank"
|
}
|
||||||
rel="noreferrer"
|
/>
|
||||||
onClick={ ( event ) =>
|
),
|
||||||
event.stopPropagation()
|
}
|
||||||
}
|
) }
|
||||||
/>
|
</p>
|
||||||
),
|
</div>
|
||||||
}
|
) }
|
||||||
) }
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
''
|
|
||||||
)
|
|
||||||
}
|
|
||||||
buttonText=""
|
|
||||||
allowedMediaTypes={ allowedTypes }
|
|
||||||
multipleSelect={ 'add' }
|
|
||||||
onUpload={ handleFileUpload }
|
|
||||||
onFileUploadChange={ handleFileUpload }
|
|
||||||
onError={ handleUploadError }
|
|
||||||
/>
|
|
||||||
|
|
||||||
{ Boolean( downloads.length ) && (
|
{ Boolean( downloads.length ) && (
|
||||||
<Sortable className="wp-block-woocommerce-product-downloads-field__table">
|
<Sortable className="wp-block-woocommerce-product-downloads-field__table">
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
/**
|
/**
|
||||||
* External dependencies
|
* External dependencies
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { MenuItem } from '@wordpress/components';
|
import { MenuItem } from '@wordpress/components';
|
||||||
import { createElement, useEffect, useState } from '@wordpress/element';
|
import { createElement, useEffect, useState } from '@wordpress/element';
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { media } from '@wordpress/icons';
|
import { media } from '@wordpress/icons';
|
||||||
import { MediaItem, MediaUpload } from '@wordpress/media-utils';
|
import { MediaItem } from '@wordpress/media-utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { MediaLibraryMenuItemProps } from './types';
|
import { MediaLibraryMenuItemProps } from './types';
|
||||||
|
import { MediaLibrary } from '../media-library';
|
||||||
|
|
||||||
const MODAL_CLASS_NAME =
|
const MODAL_CLASS_NAME =
|
||||||
'woocommerce-media-library-menu-item__upload_files_modal';
|
'woocommerce-media-library-menu-item__upload_files_modal';
|
||||||
|
@ -39,8 +39,8 @@ export function MediaLibraryMenuItem( {
|
||||||
[ uploadFilesModalOpen ]
|
[ uploadFilesModalOpen ]
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleMediaUploadSelect( value: unknown ) {
|
function handleMediaUploadSelect( value: MediaItem[] ) {
|
||||||
onUploadSuccess( value as MediaItem[] );
|
onUploadSuccess( value );
|
||||||
}
|
}
|
||||||
|
|
||||||
function uploadFilesClickHandler( openMediaUploadModal: () => void ) {
|
function uploadFilesClickHandler( openMediaUploadModal: () => void ) {
|
||||||
|
@ -51,13 +51,16 @@ export function MediaLibraryMenuItem( {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MediaUpload
|
<MediaLibrary
|
||||||
modalClass={ MODAL_CLASS_NAME }
|
className={ MODAL_CLASS_NAME }
|
||||||
onSelect={ handleMediaUploadSelect }
|
|
||||||
allowedTypes={ allowedTypes }
|
allowedTypes={ allowedTypes }
|
||||||
// @ts-expect-error - TODO multiple also accepts string.
|
multiple="add"
|
||||||
multiple={ 'add' }
|
uploaderParams={ {
|
||||||
render={ ( { open } ) => (
|
type: 'downloadable_product',
|
||||||
|
} }
|
||||||
|
onSelect={ handleMediaUploadSelect }
|
||||||
|
>
|
||||||
|
{ ( { open } ) => (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
icon={ media }
|
icon={ media }
|
||||||
iconPosition="left"
|
iconPosition="left"
|
||||||
|
@ -67,6 +70,6 @@ export function MediaLibraryMenuItem( {
|
||||||
{ __( 'Media Library', 'woocommerce' ) }
|
{ __( 'Media Library', 'woocommerce' ) }
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
) }
|
) }
|
||||||
/>
|
</MediaLibrary>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
export * from './media-library';
|
||||||
|
export * from './types';
|
|
@ -0,0 +1,94 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { useEffect, useMemo } from '@wordpress/element';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
import { MediaLibraryProps } from './types';
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
declare const wp: any;
|
||||||
|
|
||||||
|
export function MediaLibrary( {
|
||||||
|
allowedTypes,
|
||||||
|
modalTitle,
|
||||||
|
modalButtonText,
|
||||||
|
multiple,
|
||||||
|
className,
|
||||||
|
uploaderParams,
|
||||||
|
children,
|
||||||
|
onSelect,
|
||||||
|
}: MediaLibraryProps ) {
|
||||||
|
const mediaLibraryModal = useMemo(
|
||||||
|
function createMediaLibraryModal() {
|
||||||
|
const media = wp.media( {
|
||||||
|
title: modalTitle,
|
||||||
|
library: {
|
||||||
|
type: allowedTypes,
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
text: modalButtonText,
|
||||||
|
},
|
||||||
|
multiple,
|
||||||
|
states: [
|
||||||
|
new wp.media.controller.Library( {
|
||||||
|
title: modalTitle,
|
||||||
|
library: wp.media.query(),
|
||||||
|
multiple,
|
||||||
|
priority: 20,
|
||||||
|
filterable: 'all',
|
||||||
|
} ),
|
||||||
|
],
|
||||||
|
} );
|
||||||
|
|
||||||
|
return media;
|
||||||
|
},
|
||||||
|
[ allowedTypes, modalTitle, modalButtonText, multiple ]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
function initializeEvents() {
|
||||||
|
function handleSelect() {
|
||||||
|
const mediaItems = mediaLibraryModal
|
||||||
|
.state()
|
||||||
|
.get( 'selection' )
|
||||||
|
.toJSON();
|
||||||
|
|
||||||
|
onSelect( mediaItems );
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleReady() {
|
||||||
|
mediaLibraryModal.uploader.options.uploader.params =
|
||||||
|
uploaderParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaLibraryModal.on( 'select', handleSelect );
|
||||||
|
mediaLibraryModal.on( 'ready', handleReady );
|
||||||
|
|
||||||
|
return function unmountMediaLibraryModal() {
|
||||||
|
mediaLibraryModal.off( 'select', handleSelect );
|
||||||
|
mediaLibraryModal.off( 'ready', handleReady );
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[ mediaLibraryModal, uploaderParams, onSelect ]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() =>
|
||||||
|
function unmountMediaLibraryModal() {
|
||||||
|
mediaLibraryModal.remove();
|
||||||
|
},
|
||||||
|
[ mediaLibraryModal ]
|
||||||
|
);
|
||||||
|
|
||||||
|
function openMediaLibraryModal() {
|
||||||
|
mediaLibraryModal.$el.addClass( className );
|
||||||
|
mediaLibraryModal.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
return children( {
|
||||||
|
open: openMediaLibraryModal,
|
||||||
|
} );
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
import { MediaItem } from '@wordpress/media-utils';
|
||||||
|
|
||||||
|
export type ChildrenProps = {
|
||||||
|
open(): void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MediaLibraryProps = {
|
||||||
|
allowedTypes?: string[];
|
||||||
|
modalTitle?: string;
|
||||||
|
modalButtonText?: string;
|
||||||
|
multiple?: boolean | 'add';
|
||||||
|
className?: string;
|
||||||
|
uploaderParams?: Record< string, string >;
|
||||||
|
children( props: ChildrenProps ): JSX.Element;
|
||||||
|
onSelect( selection: MediaItem[] ): void;
|
||||||
|
};
|
Loading…
Reference in New Issue