diff --git a/package-lock.json b/package-lock.json
index 85adeb5c4b5634..6852e3b67333f1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -56227,7 +56227,9 @@
"@shopify/web-worker": "^6.4.0",
"@wordpress/api-fetch": "file:../api-fetch",
"@wordpress/blob": "file:../blob",
+ "@wordpress/compose": "file:../compose",
"@wordpress/data": "file:../data",
+ "@wordpress/element": "file:../element",
"@wordpress/i18n": "file:../i18n",
"@wordpress/preferences": "file:../preferences",
"@wordpress/private-apis": "file:../private-apis",
diff --git a/packages/block-editor/src/components/provider/index.js b/packages/block-editor/src/components/provider/index.js
index abbb122ae3a0e0..38e67f23e60518 100644
--- a/packages/block-editor/src/components/provider/index.js
+++ b/packages/block-editor/src/components/provider/index.js
@@ -4,6 +4,8 @@
import { useDispatch } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import { SlotFillProvider } from '@wordpress/components';
+//eslint-disable-next-line import/no-extraneous-dependencies -- Experimental package, not published.
+import { MediaUploadProvider } from '@wordpress/upload-media';
/**
* Internal dependencies
@@ -14,12 +16,13 @@ import { store as blockEditorStore } from '../../store';
import { BlockRefsProvider } from './block-refs-provider';
import { unlock } from '../../lock-unlock';
import KeyboardShortcuts from '../keyboard-shortcuts';
+import useMediaUploadSettings from './use-media-upload-settings';
/** @typedef {import('@wordpress/data').WPDataRegistry} WPDataRegistry */
export const ExperimentalBlockEditorProvider = withRegistryProvider(
( props ) => {
- const { children, settings, stripExperimentalSettings = false } = props;
+ const { settings, stripExperimentalSettings = false } = props;
const { __experimentalUpdateSettings } = unlock(
useDispatch( blockEditorStore )
@@ -44,12 +47,27 @@ export const ExperimentalBlockEditorProvider = withRegistryProvider(
// Syncs the entity provider with changes in the block-editor store.
useBlockSync( props );
- return (
+ const children = (
{ ! settings?.isPreviewMode && }
- { children }
+ { props.children }
);
+
+ const mediaUploadSettings = useMediaUploadSettings( settings );
+
+ if ( window.__experimentalMediaProcessing ) {
+ return (
+
+ { children }
+
+ );
+ }
+
+ return children;
}
);
diff --git a/packages/block-editor/src/components/provider/use-media-upload-settings.js b/packages/block-editor/src/components/provider/use-media-upload-settings.js
new file mode 100644
index 00000000000000..cb8e3b70246854
--- /dev/null
+++ b/packages/block-editor/src/components/provider/use-media-upload-settings.js
@@ -0,0 +1,23 @@
+/**
+ * WordPress dependencies
+ */
+import { useMemo } from '@wordpress/element';
+
+/**
+ * React hook used to compute the media upload settings to use in the post editor.
+ *
+ * @param {Object} settings Media upload settings prop.
+ *
+ * @return {Object} Media upload settings.
+ */
+function useMediaUploadSettings( settings ) {
+ return useMemo(
+ () => ( {
+ mediaUpload: settings.mediaUpload,
+ mediaSideload: settings.__experimentalMediaSideload,
+ } ),
+ [ settings ]
+ );
+}
+
+export default useMediaUploadSettings;
diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js
index 170ec96c107288..6df2610812df45 100644
--- a/packages/editor/src/components/provider/use-block-editor-settings.js
+++ b/packages/editor/src/components/provider/use-block-editor-settings.js
@@ -22,6 +22,7 @@ import {
*/
import inserterMediaCategories from '../media-categories';
import { mediaUpload } from '../../utils';
+import { default as mediaSideload } from '../../utils/media-sideload';
import { store as editorStore } from '../../store';
import { unlock } from '../../lock-unlock';
import { useGlobalStylesContext } from '../global-styles-provider';
@@ -294,6 +295,9 @@ function useBlockEditorSettings( settings, postType, postId, renderingMode ) {
isDistractionFree,
keepCaretInsideBlock,
mediaUpload: hasUploadPermissions ? mediaUpload : undefined,
+ __experimentalMediaSideload: hasUploadPermissions
+ ? mediaSideload
+ : undefined,
__experimentalBlockPatterns: blockPatterns,
[ selectBlockPatternsKey ]: ( select ) => {
const { hasFinishedResolution, getBlockPatternsForPostType } =
diff --git a/packages/editor/src/utils/media-sideload/index.js b/packages/editor/src/utils/media-sideload/index.js
new file mode 100644
index 00000000000000..b4aa133fb2d63e
--- /dev/null
+++ b/packages/editor/src/utils/media-sideload/index.js
@@ -0,0 +1,13 @@
+/**
+ * WordPress dependencies
+ */
+import { privateApis } from '@wordpress/media-utils';
+
+/**
+ * Internal dependencies
+ */
+import { unlock } from '../../lock-unlock';
+
+const { sideloadMedia: mediaSideload = () => {} } = unlock( privateApis );
+
+export default mediaSideload;
diff --git a/packages/editor/src/utils/media-sideload/index.native.js b/packages/editor/src/utils/media-sideload/index.native.js
new file mode 100644
index 00000000000000..d84a912ec92de0
--- /dev/null
+++ b/packages/editor/src/utils/media-sideload/index.native.js
@@ -0,0 +1 @@
+export default function mediaSideload() {}
diff --git a/packages/upload-media/package.json b/packages/upload-media/package.json
index 0711ebb12231ab..72523c1bb33a14 100644
--- a/packages/upload-media/package.json
+++ b/packages/upload-media/package.json
@@ -29,7 +29,9 @@
"@shopify/web-worker": "^6.4.0",
"@wordpress/api-fetch": "file:../api-fetch",
"@wordpress/blob": "file:../blob",
+ "@wordpress/compose": "file:../compose",
"@wordpress/data": "file:../data",
+ "@wordpress/element": "file:../element",
"@wordpress/i18n": "file:../i18n",
"@wordpress/preferences": "file:../preferences",
"@wordpress/private-apis": "file:../private-apis",
diff --git a/packages/upload-media/src/components/provider/index.tsx b/packages/upload-media/src/components/provider/index.tsx
new file mode 100644
index 00000000000000..0bc187e6a1d861
--- /dev/null
+++ b/packages/upload-media/src/components/provider/index.tsx
@@ -0,0 +1,25 @@
+/**
+ * WordPress dependencies
+ */
+import { useEffect } from '@wordpress/element';
+import { useDispatch } from '@wordpress/data';
+
+/**
+ * Internal dependencies
+ */
+import withRegistryProvider from './with-registry-provider';
+import { unlock } from '../../lock-unlock';
+import { store as uploadStore } from '../../store';
+
+const MediaUploadProvider = withRegistryProvider( ( props: any ) => {
+ const { children, settings } = props;
+ const { updateSettings } = unlock( useDispatch( uploadStore ) );
+
+ useEffect( () => {
+ updateSettings( settings );
+ }, [ settings, updateSettings ] );
+
+ return <>{ children }>;
+} );
+
+export default MediaUploadProvider;
diff --git a/packages/upload-media/src/components/provider/with-registry-provider.tsx b/packages/upload-media/src/components/provider/with-registry-provider.tsx
new file mode 100644
index 00000000000000..9a47a5601d33ed
--- /dev/null
+++ b/packages/upload-media/src/components/provider/with-registry-provider.tsx
@@ -0,0 +1,59 @@
+/**
+ * WordPress dependencies
+ */
+import { useState } from '@wordpress/element';
+import { useRegistry, createRegistry, RegistryProvider } from '@wordpress/data';
+import { createHigherOrderComponent } from '@wordpress/compose';
+
+/**
+ * Internal dependencies
+ */
+import { storeConfig } from '../../store';
+import { STORE_NAME as mediaUploadStoreName } from '../../store/constants';
+
+type WPDataRegistry = ReturnType< typeof createRegistry >;
+
+function getSubRegistry(
+ subRegistries: WeakMap< WPDataRegistry, WPDataRegistry >,
+ registry: WPDataRegistry,
+ useSubRegistry: boolean
+) {
+ if ( ! useSubRegistry ) {
+ return registry;
+ }
+ let subRegistry = subRegistries.get( registry );
+ if ( ! subRegistry ) {
+ subRegistry = createRegistry( {}, registry );
+ subRegistry.registerStore( mediaUploadStoreName, storeConfig );
+ subRegistries.set( registry, subRegistry );
+ }
+ return subRegistry;
+}
+
+const withRegistryProvider = createHigherOrderComponent(
+ ( WrappedComponent ) =>
+ ( { useSubRegistry = true, ...props } ) => {
+ const registry = useRegistry() as unknown as WPDataRegistry;
+ const [ subRegistries ] = useState<
+ WeakMap< WPDataRegistry, WPDataRegistry >
+ >( () => new WeakMap() );
+ const subRegistry = getSubRegistry(
+ subRegistries,
+ registry,
+ useSubRegistry
+ );
+
+ if ( subRegistry === registry ) {
+ return ;
+ }
+
+ return (
+
+
+
+ );
+ },
+ 'withRegistryProvider'
+);
+
+export default withRegistryProvider;
diff --git a/packages/upload-media/src/index.ts b/packages/upload-media/src/index.ts
index 63a756727b25f3..406439a5d96f69 100644
--- a/packages/upload-media/src/index.ts
+++ b/packages/upload-media/src/index.ts
@@ -5,6 +5,7 @@ import { store as uploadStore } from './store';
export { uploadStore as store };
+export { default as MediaUploadProvider } from './components/provider';
export { UploadError } from './upload-error';
export type {
diff --git a/packages/upload-media/src/store/constants.ts b/packages/upload-media/src/store/constants.ts
new file mode 100644
index 00000000000000..ad0960cf62f46d
--- /dev/null
+++ b/packages/upload-media/src/store/constants.ts
@@ -0,0 +1 @@
+export const STORE_NAME = 'core/upload-media';
diff --git a/packages/upload-media/src/store/index.ts b/packages/upload-media/src/store/index.ts
index c6a42f6cd395ba..c74f59ea7a7cf3 100644
--- a/packages/upload-media/src/store/index.ts
+++ b/packages/upload-media/src/store/index.ts
@@ -12,9 +12,24 @@ import * as privateSelectors from './private-selectors';
import * as actions from './actions';
import * as privateActions from './private-actions';
import { unlock } from '../lock-unlock';
+import { STORE_NAME } from './constants';
-export const STORE_NAME = 'core/upload-media';
+/**
+ * Media upload data store configuration.
+ *
+ * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#registerStore
+ */
+export const storeConfig = {
+ reducer,
+ selectors,
+ actions,
+};
+/**
+ * Store definition for the media upload namespace.
+ *
+ * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore
+ */
export const store = createReduxStore( STORE_NAME, {
reducer,
selectors,
diff --git a/packages/upload-media/tsconfig.json b/packages/upload-media/tsconfig.json
index 2862cfa4bb1c8c..bd7ebfb1023d14 100644
--- a/packages/upload-media/tsconfig.json
+++ b/packages/upload-media/tsconfig.json
@@ -10,7 +10,9 @@
"references": [
{ "path": "../api-fetch" },
{ "path": "../blob" },
+ { "path": "../compose" },
{ "path": "../data" },
+ { "path": "../element" },
{ "path": "../i18n" },
{ "path": "../private-apis" },
{ "path": "../url" },