+ );
+ },
+ migrate( attributes ) {
+ if ( isGalleryV2Enabled() ) {
+ return runV2Migration( attributes );
+ }
+
+ return attributes;
},
-];
+};
-export default deprecated;
+export default [ v6, v5, v4, v3, v2, v1 ];
diff --git a/packages/block-library/src/gallery/edit-wrapper.js b/packages/block-library/src/gallery/edit-wrapper.js
index 0e101dfa85e216..2c81271902d312 100644
--- a/packages/block-library/src/gallery/edit-wrapper.js
+++ b/packages/block-library/src/gallery/edit-wrapper.js
@@ -1,47 +1,27 @@
/**
* WordPress dependencies
*/
-import { store as blockEditorStore } from '@wordpress/block-editor';
-import { useSelect } from '@wordpress/data';
+import { compose } from '@wordpress/compose';
+import { withNotices } from '@wordpress/components';
/**
* Internal dependencies
*/
import EditWithInnerBlocks from './edit';
import EditWithoutInnerBlocks from './v1/edit';
+import { isGalleryV2Enabled } from './shared';
/*
* Using a wrapper around the logic to load the edit for v1 of Gallery block
* or the refactored version with InnerBlocks. This is to prevent conditional
* use of hooks lint errors if adding this logic to the top of the edit component.
*/
-export default function GalleryEditWrapper( props ) {
- const { attributes, clientId } = props;
-
- const innerBlockImages = useSelect(
- ( select ) => {
- return select( blockEditorStore ).getBlock( clientId )?.innerBlocks;
- },
- [ clientId ]
- );
-
- const __unstableGalleryWithImageBlocks = useSelect( ( select ) => {
- const settings = select( blockEditorStore ).getSettings();
- return settings.__unstableGalleryWithImageBlocks;
- }, [] );
-
- // This logic is used to infer version information from content with higher
- // precedence than the flag. New galleries (and existing empty galleries) will
- // honor the flag.
- const hasNewVersionContent = !! innerBlockImages?.length;
- const hasOldVersionContent =
- 0 < attributes?.ids?.length || 0 < attributes?.images?.length;
- if (
- hasOldVersionContent ||
- ( ! hasNewVersionContent && ! __unstableGalleryWithImageBlocks )
- ) {
+function GalleryEditWrapper( props ) {
+ if ( ! isGalleryV2Enabled() ) {
return ;
}
return ;
}
+
+export default compose( [ withNotices ] )( GalleryEditWrapper );
diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js
index e7cbe537c4922d..492275995ca269 100644
--- a/packages/block-library/src/gallery/edit.js
+++ b/packages/block-library/src/gallery/edit.js
@@ -154,7 +154,7 @@ function GalleryEdit( props ) {
useEffect( () => {
newImages?.forEach( ( newImage ) => {
updateBlockAttributes( newImage.clientId, {
- ...buildImageAttributes( false, newImage.attributes ),
+ ...buildImageAttributes( newImage.attributes ),
id: newImage.id,
align: undefined,
} );
@@ -186,26 +186,24 @@ function GalleryEdit( props ) {
* it already existed in the gallery. If the image is in fact new, we need
* to apply the gallery's current settings to the image.
*
- * @param {Object} existingBlock Existing Image block that still exists after gallery update.
- * @param {Object} image Media object for the actual image.
- * @return {Object} Attributes to set on the new image block.
+ * @param {Object} imageAttributes Media object for the actual image.
+ * @return {Object} Attributes to set on the new image block.
*/
- function buildImageAttributes( existingBlock, image ) {
- if ( existingBlock ) {
- return existingBlock.attributes;
- }
+ function buildImageAttributes( imageAttributes ) {
+ const image = imageAttributes.id
+ ? find( imageData, { id: imageAttributes.id } )
+ : null;
let newClassName;
- if ( image.className && image.className !== '' ) {
- newClassName = image.className;
+ if ( imageAttributes.className && imageAttributes.className !== '' ) {
+ newClassName = imageAttributes.className;
} else {
newClassName = preferredStyle
? `is-style-${ preferredStyle }`
: undefined;
}
-
return {
- ...pickRelevantMediaFiles( image, sizeSlug ),
+ ...pickRelevantMediaFiles( imageAttributes, sizeSlug ),
...getHrefAndDestination( image, linkTo ),
...getUpdatedLinkTargetSettings( linkTarget, attributes ),
className: newClassName,
diff --git a/packages/block-library/src/gallery/save.js b/packages/block-library/src/gallery/save.js
index 781b96d2aedbe9..655a1823020fc5 100644
--- a/packages/block-library/src/gallery/save.js
+++ b/packages/block-library/src/gallery/save.js
@@ -16,9 +16,10 @@ import {
* Internal dependencies
*/
import saveWithoutInnerBlocks from './v1/save';
+import { isGalleryV2Enabled } from './shared';
export default function saveWithInnerBlocks( { attributes } ) {
- if ( attributes?.ids?.length > 0 || attributes?.images?.length > 0 ) {
+ if ( ! isGalleryV2Enabled() ) {
return saveWithoutInnerBlocks( { attributes } );
}
diff --git a/packages/block-library/src/gallery/shared.js b/packages/block-library/src/gallery/shared.js
index 0de4e8586c33ab..e2c2e717d0f707 100644
--- a/packages/block-library/src/gallery/shared.js
+++ b/packages/block-library/src/gallery/shared.js
@@ -21,3 +21,19 @@ export const pickRelevantMediaFiles = ( image, sizeSlug = 'large' ) => {
}
return imageProps;
};
+
+/**
+ * The new gallery block format is not compatible with the use_BalanceTags option
+ * in WP versions <= 5.8 https://core.trac.wordpress.org/ticket/54130. The
+ * window.wp.galleryBlockV2Enabled flag is set in lib/compat.php. This method
+ * can be removed when minimum supported WP version >=5.9.
+ */
+export function isGalleryV2Enabled() {
+ // We want to fail early here, at least during beta testing phase, to ensure
+ // there aren't instances where undefined values cause false negatives.
+ if ( ! window.wp || typeof window.wp.galleryBlockV2Enabled !== 'boolean' ) {
+ throw 'window.wp.galleryBlockV2Enabled is not defined';
+ }
+
+ return window.wp.galleryBlockV2Enabled;
+}
diff --git a/packages/block-library/src/gallery/transforms.js b/packages/block-library/src/gallery/transforms.js
index f5fe6b341cd9e6..36106b4bb0664a 100644
--- a/packages/block-library/src/gallery/transforms.js
+++ b/packages/block-library/src/gallery/transforms.js
@@ -8,8 +8,6 @@ import { filter, every, toString } from 'lodash';
*/
import { createBlock } from '@wordpress/blocks';
import { createBlobURL } from '@wordpress/blob';
-import { select } from '@wordpress/data';
-import { store as blockEditorStore } from '@wordpress/block-editor';
import { addFilter } from '@wordpress/hooks';
/**
@@ -24,7 +22,7 @@ import {
LINK_DESTINATION_ATTACHMENT as DEPRECATED_LINK_DESTINATION_ATTACHMENT,
LINK_DESTINATION_MEDIA as DEPRECATED_LINK_DESTINATION_MEDIA,
} from './v1/constants';
-import { pickRelevantMediaFiles } from './shared';
+import { pickRelevantMediaFiles, isGalleryV2Enabled } from './shared';
const parseShortcodeIds = ( ids ) => {
if ( ! ids ) {
@@ -49,9 +47,8 @@ const parseShortcodeIds = ( ids ) => {
* @return {Block} The transformed block.
*/
function updateThirdPartyTransformToGallery( block ) {
- const settings = select( blockEditorStore ).getSettings();
if (
- settings.__unstableGalleryWithImageBlocks &&
+ isGalleryV2Enabled() &&
block.name === 'core/gallery' &&
block.attributes?.images.length > 0
) {
@@ -145,8 +142,7 @@ const transforms = {
const validImages = filter( attributes, ( { url } ) => url );
- const settings = select( blockEditorStore ).getSettings();
- if ( settings.__unstableGalleryWithImageBlocks ) {
+ if ( isGalleryV2Enabled() ) {
const innerBlocks = validImages.map( ( image ) => {
return createBlock( 'core/image', image );
} );
@@ -184,10 +180,7 @@ const transforms = {
images: {
type: 'array',
shortcode: ( { named: { ids } } ) => {
- const settings = select(
- blockEditorStore
- ).getSettings();
- if ( ! settings.__unstableGalleryWithImageBlocks ) {
+ if ( ! isGalleryV2Enabled() ) {
return parseShortcodeIds( ids ).map( ( id ) => ( {
id: toString( id ),
} ) );
@@ -197,10 +190,7 @@ const transforms = {
ids: {
type: 'array',
shortcode: ( { named: { ids } } ) => {
- const settings = select(
- blockEditorStore
- ).getSettings();
- if ( ! settings.__unstableGalleryWithImageBlocks ) {
+ if ( ! isGalleryV2Enabled() ) {
return parseShortcodeIds( ids );
}
},
@@ -208,10 +198,7 @@ const transforms = {
shortCodeTransforms: {
type: 'array',
shortcode: ( { named: { ids } } ) => {
- const settings = select(
- blockEditorStore
- ).getSettings();
- if ( settings.__unstableGalleryWithImageBlocks ) {
+ if ( isGalleryV2Enabled() ) {
return parseShortcodeIds( ids ).map( ( id ) => ( {
id: parseInt( id ),
} ) );
@@ -227,10 +214,7 @@ const transforms = {
linkTo: {
type: 'string',
shortcode: ( { named: { link } } ) => {
- const settings = select(
- blockEditorStore
- ).getSettings();
- if ( ! settings.__unstableGalleryWithImageBlocks ) {
+ if ( ! isGalleryV2Enabled() ) {
switch ( link ) {
case 'post':
return DEPRECATED_LINK_DESTINATION_ATTACHMENT;
@@ -273,8 +257,7 @@ const transforms = {
);
},
transform( files ) {
- const settings = select( blockEditorStore ).getSettings();
- if ( settings.__unstableGalleryWithImageBlocks ) {
+ if ( isGalleryV2Enabled() ) {
const innerBlocks = files.map( ( file ) =>
createBlock( 'core/image', {
url: createBlobURL( file ),
@@ -299,8 +282,7 @@ const transforms = {
type: 'block',
blocks: [ 'core/image' ],
transform: ( { align, images, ids, sizeSlug }, innerBlocks ) => {
- const settings = select( blockEditorStore ).getSettings();
- if ( settings.__unstableGalleryWithImageBlocks ) {
+ if ( isGalleryV2Enabled() ) {
if ( innerBlocks.length > 0 ) {
return innerBlocks.map(
( {
diff --git a/packages/block-library/src/gallery/use-mobile-warning.js b/packages/block-library/src/gallery/use-mobile-warning.js
index 6567d8f73349b7..95d0f4c86432fc 100644
--- a/packages/block-library/src/gallery/use-mobile-warning.js
+++ b/packages/block-library/src/gallery/use-mobile-warning.js
@@ -20,7 +20,7 @@ export default function useMobileWarning( newImages ) {
createWarningNotice(
__(
- 'Editing this Gallery in the WordPress mobile app requires version 18.2 or higher.'
+ 'If you want to edit the gallery you just added in the mobile app, to avoid losing any data please make sure you use version 18.2 of the app or above.'
),
{ type: 'snackbar', explicitDismiss: true }
);
diff --git a/packages/block-library/src/gallery/v1/edit.js b/packages/block-library/src/gallery/v1/edit.js
index cfa1755445d8a0..ca57494142feb9 100644
--- a/packages/block-library/src/gallery/v1/edit.js
+++ b/packages/block-library/src/gallery/v1/edit.js
@@ -24,10 +24,8 @@ import {
ToggleControl,
withNotices,
RangeControl,
- ToolbarButton,
} from '@wordpress/components';
import {
- BlockControls,
MediaPlaceholder,
InspectorControls,
useBlockProps,
@@ -53,7 +51,6 @@ import {
LINK_DESTINATION_MEDIA,
LINK_DESTINATION_NONE,
} from './constants';
-import UpdateGalleryModal from './update-gallery-modal';
const MAX_COLUMNS = 8;
const linkOptions = [
@@ -102,13 +99,10 @@ function GalleryEdit( props ) {
mediaUpload,
getMedia,
wasBlockJustInserted,
- __unstableGalleryWithImageBlocks,
} = useSelect( ( select ) => {
const settings = select( blockEditorStore ).getSettings();
return {
- __unstableGalleryWithImageBlocks:
- settings.__unstableGalleryWithImageBlocks,
imageSizes: settings.imageSizes,
mediaUpload: settings.mediaUpload,
getMedia: select( coreStore ).getMedia,
@@ -414,10 +408,6 @@ function GalleryEdit( props ) {
/>
);
- const [ isUpdateOpen, setUpdateOpen ] = useState( false );
- const openUpdateModal = () => setUpdateOpen( true );
- const closeUpdateModal = () => setUpdateOpen( false );
-
const blockProps = useBlockProps();
if ( ! hasImages ) {
@@ -466,24 +456,7 @@ function GalleryEdit( props ) {
) }
- { /* TODO: Remove platform condition when native conversion is ready */ }
- { Platform.isWeb && __unstableGalleryWithImageBlocks && (
-
-
- { __( 'Update' ) }
-
-
- ) }
- { Platform.isWeb && isUpdateOpen && (
-
- ) }
+
{ noticeUI }
() => {
- let link;
- const {
- attributes: { sizeSlug, linkTo, images, caption },
- } = getBlock( clientId );
-
- switch ( linkTo ) {
- case 'post':
- link = LINK_DESTINATION_ATTACHMENT;
- break;
- case 'file':
- link = LINK_DESTINATION_MEDIA;
- break;
- default:
- link = LINK_DESTINATION_NONE;
- break;
- }
- const innerBlocks = images.map( ( image ) =>
- createBlock( 'core/image', {
- id: image.id ? parseInt( image.id, 10 ) : null,
- url: image.url,
- alt: image.alt,
- caption: image.caption,
- linkDestination: link,
- } )
- );
-
- replaceBlocks(
- clientId,
- createBlock(
- 'core/gallery',
- { sizeSlug, linkTo: link, caption },
- innerBlocks
- )
- );
-};
-
-export default function UpdateGalleryModal( { onClose, clientId } ) {
- const { getBlock } = useSelect( blockEditorStore );
- const { replaceBlocks } = useDispatch( blockEditorStore );
- return (
-
-
- { __(
- 'Updating to the new format adds the ability to use custom links or styles on individual images in the gallery, and makes it easier to add or move them around.'
- ) }
-
-
-
-
-
-
-
- );
-}
diff --git a/packages/edit-post/src/editor.native.js b/packages/edit-post/src/editor.native.js
index ea9dbf9eeaab0e..7f71d7f68ad278 100644
--- a/packages/edit-post/src/editor.native.js
+++ b/packages/edit-post/src/editor.native.js
@@ -30,6 +30,11 @@ class Editor extends Component {
constructor( props ) {
super( ...arguments );
+ // need to set this globally to avoid race with deprecations
+ // defaulting to true to avoid issues with a not-yet-cached value
+ const { galleryWithImageBlocks = true } = props;
+ window.wp.galleryBlockV2Enabled = galleryWithImageBlocks;
+
if ( props.initialHtmlModeEnabled && props.mode === 'visual' ) {
// enable html mode if the initial mode the parent wants it but we're not already in it
this.props.switchEditorMode( 'text' );
diff --git a/packages/editor/src/components/provider/index.native.js b/packages/editor/src/components/provider/index.native.js
index 059b98eb459374..ace8b1f01da136 100644
--- a/packages/editor/src/components/provider/index.native.js
+++ b/packages/editor/src/components/provider/index.native.js
@@ -75,6 +75,7 @@ class NativeEditorProvider extends Component {
this.post.type,
this.post
);
+
this.getEditorSettings = memize(
( settings, capabilities ) => ( {
...settings,
@@ -90,16 +91,10 @@ class NativeEditorProvider extends Component {
}
componentDidMount() {
- const {
- capabilities,
- locale,
- updateSettings,
- galleryWithImageBlocks,
- } = this.props;
+ const { capabilities, locale, updateSettings } = this.props;
updateSettings( {
...capabilities,
- ...{ __unstableGalleryWithImageBlocks: galleryWithImageBlocks },
...this.getThemeColors( this.props ),
locale,
} );
@@ -149,14 +144,11 @@ class NativeEditorProvider extends Component {
);
this.subscriptionParentUpdateEditorSettings = subscribeUpdateEditorSettings(
- ( editorSettings ) => {
- updateSettings( {
- ...{
- __unstableGalleryWithImageBlocks:
- editorSettings.galleryWithImageBlocks,
- },
- ...this.getThemeColors( editorSettings ),
- } );
+ ( { galleryWithImageBlocks, ...editorSettings } ) => {
+ if ( typeof galleryWithImageBlocks === 'boolean' ) {
+ window.wp.galleryBlockV2Enabled = galleryWithImageBlocks;
+ }
+ updateSettings( this.getThemeColors( editorSettings ) );
}
);
diff --git a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java
index bdbe2402671987..860a68419dcb3a 100644
--- a/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java
+++ b/packages/react-native-bridge/android/react-native-bridge/src/main/java/org/wordpress/mobile/ReactNativeGutenbergBridge/RNReactNativeGutenbergBridgeModule.java
@@ -60,6 +60,7 @@ public class RNReactNativeGutenbergBridgeModule extends ReactContextBaseJavaModu
private static final String MAP_KEY_THEME_UPDATE_COLORS = "colors";
private static final String MAP_KEY_THEME_UPDATE_GRADIENTS = "gradients";
private static final String MAP_KEY_THEME_UPDATE_RAW_STYLES = "rawStyles";
+ private static final String MAP_KEY_GALLERY_WITH_IMAGE_BLOCKS = "galleryWithImageBlocks";
public static final String MAP_KEY_MEDIA_FINAL_SAVE_RESULT_SUCCESS_VALUE = "success";
private static final String MAP_KEY_IS_PREFERRED_COLOR_SCHEME_DARK = "isPreferredColorSchemeDark";
@@ -149,6 +150,13 @@ public void updateTheme(@Nullable Bundle editorTheme) {
Serializable gradients = editorTheme.getSerializable(MAP_KEY_THEME_UPDATE_GRADIENTS);
Serializable rawStyles = editorTheme.getSerializable(MAP_KEY_THEME_UPDATE_RAW_STYLES);
+ // We must assign null here to distinguish between a missing value and false
+ Boolean galleryWithImageBlocks = null;
+ if (editorTheme.containsKey(MAP_KEY_GALLERY_WITH_IMAGE_BLOCKS)) {
+ galleryWithImageBlocks = editorTheme.getBoolean(MAP_KEY_GALLERY_WITH_IMAGE_BLOCKS);
+ }
+
+
if (colors != null) {
writableMap.putArray(MAP_KEY_THEME_UPDATE_COLORS, Arguments.fromList((ArrayList)colors));
}
@@ -161,6 +169,10 @@ public void updateTheme(@Nullable Bundle editorTheme) {
writableMap.putString(MAP_KEY_THEME_UPDATE_RAW_STYLES, rawStyles.toString());
}
+ if (galleryWithImageBlocks != null) {
+ writableMap.putBoolean(MAP_KEY_GALLERY_WITH_IMAGE_BLOCKS, galleryWithImageBlocks);
+ }
+
emitToJS(EVENT_NAME_UPDATE_EDITOR_SETTINGS, writableMap);
}
diff --git a/packages/react-native-bridge/ios/Gutenberg.swift b/packages/react-native-bridge/ios/Gutenberg.swift
index b926c36cb3bf30..318a9796a2e9b0 100644
--- a/packages/react-native-bridge/ios/Gutenberg.swift
+++ b/packages/react-native-bridge/ios/Gutenberg.swift
@@ -199,7 +199,10 @@ public class Gutenberg: NSObject {
private func properties(from editorSettings: GutenbergEditorSettings?) -> [String : Any] {
var settingsUpdates = [String : Any]()
settingsUpdates["isFSETheme"] = editorSettings?.isFSETheme ?? false
- settingsUpdates["galleryWithImageBlocks"] = editorSettings?.galleryWithImageBlocks ?? false
+
+ if let galleryWithImageBlocks = editorSettings?.galleryWithImageBlocks {
+ settingsUpdates["galleryWithImageBlocks"] = galleryWithImageBlocks
+ }
if let rawStyles = editorSettings?.rawStyles {
settingsUpdates["rawStyles"] = rawStyles
diff --git a/test/integration/__snapshots__/blocks-raw-handling.test.js.snap b/test/integration/__snapshots__/blocks-raw-handling.test.js.snap
index 2a4ddbf8f5efac..6e3a6b8a84795f 100644
--- a/test/integration/__snapshots__/blocks-raw-handling.test.js.snap
+++ b/test/integration/__snapshots__/blocks-raw-handling.test.js.snap
@@ -57,8 +57,8 @@ exports[`rawHandler should convert HTML post to blocks with minimal content chan
+
+
diff --git a/test/unit/config/global-mocks.js b/test/unit/config/global-mocks.js
index 0398af83c3a0b3..29ca4ce94d4a6a 100644
--- a/test/unit/config/global-mocks.js
+++ b/test/unit/config/global-mocks.js
@@ -9,3 +9,16 @@ jest.mock( '@wordpress/compose', () => {
] ),
};
} );
+
+/**
+ * The new gallery block format is not compatible with the use_BalanceTags option
+ * so a flag is set in lib/compat.php to allow disabling the new block in this instance.
+ * This flag needs to be mocked here to ensure tests and fixtures run with the v2
+ * version of the Gallery block enabled.
+ *
+ * Note: This should be removed when the minimum required WP version is >= 5.9.
+ *
+ */
+if ( ! window.wp?.galleryBlockV2Enabled ) {
+ window.wp = { ...window.wp, galleryBlockV2Enabled: true };
+}