diff --git a/gutenberg.php b/gutenberg.php
index a8e822b1ea4ee..7ab481538e32c 100644
--- a/gutenberg.php
+++ b/gutenberg.php
@@ -43,14 +43,16 @@ function gutenberg_menu() {
'gutenberg'
);
- add_submenu_page(
- 'gutenberg',
- __( 'Widgets (beta)', 'gutenberg' ),
- __( 'Widgets (beta)', 'gutenberg' ),
- 'edit_theme_options',
- 'gutenberg-widgets',
- 'the_gutenberg_widgets'
- );
+ if ( get_option( 'gutenberg-experiments' ) && array_key_exists( 'gutenberg-widget-experiments', get_option( 'gutenberg-experiments' ) ) ) {
+ add_submenu_page(
+ 'gutenberg',
+ __( 'Widgets (beta)', 'gutenberg' ),
+ __( 'Widgets (beta)', 'gutenberg' ),
+ 'edit_theme_options',
+ 'gutenberg-widgets',
+ 'the_gutenberg_widgets'
+ );
+ }
if ( current_user_can( 'edit_posts' ) ) {
$submenu['gutenberg'][] = array(
@@ -65,6 +67,15 @@ function gutenberg_menu() {
'https://developer.wordpress.org/block-editor/',
);
}
+
+ add_submenu_page(
+ 'gutenberg',
+ __( 'Experiments Settings', 'gutenberg' ),
+ __( 'Experiments', 'gutenberg' ),
+ 'edit_posts',
+ 'gutenberg-experiments',
+ 'the_gutenberg_experiments'
+ );
}
add_action( 'admin_menu', 'gutenberg_menu' );
diff --git a/lib/experiments-page.php b/lib/experiments-page.php
new file mode 100644
index 0000000000000..0ca203444dc81
--- /dev/null
+++ b/lib/experiments-page.php
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+ __( 'Enable Widgets Screen and Legacy Widget Block', 'gutenberg' ),
+ 'id' => 'gutenberg-widget-experiments',
+ )
+ );
+ add_settings_field(
+ 'gutenberg-menu-block',
+ __( 'Menu Block', 'gutenberg' ),
+ 'gutenberg_display_experiment_field',
+ 'gutenberg-experiments',
+ 'gutenberg_experiments_section',
+ array(
+ 'label' => __( 'Enable Navigation Menu Block', 'gutenberg' ),
+ 'id' => 'gutenberg-menu-block',
+ )
+ );
+ register_setting(
+ 'gutenberg-experiments',
+ 'gutenberg-experiments'
+ );
+}
+
+add_action( 'admin_init', 'gutenberg_initialize_experiments_settings' );
+
+/**
+ * Display a checkbox field for a Gutenberg experiment.
+ *
+ * @since 6.3.0
+ *
+ * @param array $args ( $label, $id ).
+ */
+function gutenberg_display_experiment_field( $args ) {
+ $options = get_option( 'gutenberg-experiments' );
+ $value = isset( $options[ $args['id'] ] ) ? 1 : 0;
+ ?>
+
+
+
+
+ $experiments_exist ? array_key_exists( 'gutenberg-widget-experiments', get_option( 'gutenberg-experiments' ) ) : false,
+ '__experimentalEnableMenuBlock' => $experiments_exist ? array_key_exists( 'gutenberg-menu-block', get_option( 'gutenberg-experiments' ) ) : false,
+ );
+ return array_merge( $settings, $experiments_settings );
+}
+add_filter( 'block_editor_settings', 'gutenberg_experiments_editor_settings' );
diff --git a/lib/load.php b/lib/load.php
index c34a8d4fc4d40..f97db4e38eb89 100644
--- a/lib/load.php
+++ b/lib/load.php
@@ -35,4 +35,5 @@
require dirname( __FILE__ ) . '/demo.php';
require dirname( __FILE__ ) . '/widgets.php';
require dirname( __FILE__ ) . '/widgets-page.php';
+require dirname( __FILE__ ) . '/experiments-page.php';
require dirname( __FILE__ ) . '/customizer.php';
diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md
index 36a256f93cb68..477c8657e40db 100644
--- a/packages/block-editor/README.md
+++ b/packages/block-editor/README.md
@@ -382,7 +382,9 @@ The default editor settings
bodyPlaceholder string Empty post placeholder
titlePlaceholder string Empty title placeholder
codeEditingEnabled string Whether or not the user can switch to the code editor
- \_\_experimentalCanUserUseUnfilteredHTML string Whether the user should be able to use unfiltered HTML or the HTML should be filtered e.g., to remove elements considered insecure like iframes.
+ **experimentalCanUserUseUnfilteredHTML string Whether the user should be able to use unfiltered HTML or the HTML should be filtered e.g., to remove elements considered insecure like iframes.
+ **experimentalEnableLegacyWidgetBlock boolean Whether the user has enabled the Legacy Widget Block
+ \_\_experimentalEnableMenuBlock boolean Whether the user has enabled the Menu Block
# **SkipToSelectedBlock**
diff --git a/packages/block-editor/src/store/defaults.js b/packages/block-editor/src/store/defaults.js
index 1f91e29c7e2f5..885a8b79f7fb0 100644
--- a/packages/block-editor/src/store/defaults.js
+++ b/packages/block-editor/src/store/defaults.js
@@ -28,6 +28,8 @@ export const PREFERENCES_DEFAULTS = {
* titlePlaceholder string Empty title placeholder
* codeEditingEnabled string Whether or not the user can switch to the code editor
* __experimentalCanUserUseUnfilteredHTML string Whether the user should be able to use unfiltered HTML or the HTML should be filtered e.g., to remove elements considered insecure like iframes.
+ * __experimentalEnableLegacyWidgetBlock boolean Whether the user has enabled the Legacy Widget Block
+ * __experimentalEnableMenuBlock boolean Whether the user has enabled the Menu Block
*/
export const SETTINGS_DEFAULTS = {
alignWide: false,
@@ -144,5 +146,7 @@ export const SETTINGS_DEFAULTS = {
availableLegacyWidgets: {},
hasPermissionsToManageWidgets: false,
__experimentalCanUserUseUnfilteredHTML: false,
+ __experimentalEnableLegacyWidgetBlock: false,
+ __experimentalEnableMenuBlock: false,
};
diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js
index a9a9b78f34ca9..0d313bc171b20 100644
--- a/packages/block-library/src/index.js
+++ b/packages/block-library/src/index.js
@@ -62,6 +62,23 @@ import * as tagCloud from './tag-cloud';
import * as classic from './classic';
+/**
+ * Function to register an individual block.
+ *
+ * @param {Object} block The block to be registered.
+ *
+ */
+const registerBlock = ( block ) => {
+ if ( ! block ) {
+ return;
+ }
+ const { metadata, settings, name } = block;
+ if ( metadata ) {
+ unstable__bootstrapServerSideBlockDefinitions( { [ name ]: metadata } ); // eslint-disable-line camelcase
+ }
+ registerBlockType( name, settings );
+};
+
/**
* Function to register core blocks provided by the block editor.
*
@@ -104,11 +121,8 @@ export const registerCoreBlocks = () => {
mediaText,
latestComments,
latestPosts,
- process.env.GUTENBERG_PHASE === 2 ? legacyWidget : null,
missing,
more,
- process.env.GUTENBERG_PHASE === 2 ? navigationMenu : null,
- process.env.GUTENBERG_PHASE === 2 ? navigationMenuItem : null,
nextpage,
preformatted,
pullquote,
@@ -124,16 +138,7 @@ export const registerCoreBlocks = () => {
textColumns,
verse,
video,
- ].forEach( ( block ) => {
- if ( ! block ) {
- return;
- }
- const { metadata, settings, name } = block;
- if ( metadata ) {
- unstable__bootstrapServerSideBlockDefinitions( { [ name ]: metadata } ); // eslint-disable-line camelcase
- }
- registerBlockType( name, settings );
- } );
+ ].forEach( registerBlock );
setDefaultBlockName( paragraph.name );
if ( window.wp && window.wp.oldEditor ) {
@@ -145,3 +150,25 @@ export const registerCoreBlocks = () => {
setGroupingBlockName( group.name );
}
};
+
+/**
+ * Function to register experimental core blocks depending on editor settings.
+ *
+ * @param {Object} settings Editor settings.
+ *
+ * @example
+ * ```js
+ * import { __experimentalRegisterExperimentalCoreBlocks } from '@wordpress/block-library';
+ *
+ * __experimentalRegisterExperimentalCoreBlocks( settings );
+ * ```
+ */
+export const __experimentalRegisterExperimentalCoreBlocks = process.env.GUTENBERG_PHASE === 2 ? ( settings ) => {
+ const { __experimentalEnableLegacyWidgetBlock, __experimentalEnableMenuBlock } = settings;
+
+ [
+ __experimentalEnableLegacyWidgetBlock ? legacyWidget : null,
+ __experimentalEnableMenuBlock ? navigationMenu : null,
+ __experimentalEnableMenuBlock ? navigationMenuItem : null,
+ ].forEach( registerBlock );
+} : undefined;
diff --git a/packages/block-library/src/navigation-menu/index.js b/packages/block-library/src/navigation-menu/index.js
index 8ca8e0c3fe560..a7343c61100b4 100644
--- a/packages/block-library/src/navigation-menu/index.js
+++ b/packages/block-library/src/navigation-menu/index.js
@@ -26,7 +26,7 @@ export const settings = {
align: [ 'wide', 'full' ],
anchor: true,
html: false,
- inserter: false,
+ inserter: true,
},
edit,
diff --git a/packages/e2e-test-utils/src/enable-experimental-features.js b/packages/e2e-test-utils/src/enable-experimental-features.js
new file mode 100644
index 0000000000000..fcb47843b54b9
--- /dev/null
+++ b/packages/e2e-test-utils/src/enable-experimental-features.js
@@ -0,0 +1,27 @@
+/**
+ * WordPress dependencies
+ */
+import { addQueryArgs } from '@wordpress/url';
+
+/**
+ * Internal dependencies
+ */
+import { visitAdminPage } from './visit-admin-page';
+
+/**
+ * Enables experimental features from the plugin settings section.
+ *
+ * @param {Array} features Array of {string} selectors of settings to enable. Assumes they can be enabled with one click.
+ */
+export async function enableExperimentalFeatures( features ) {
+ const query = addQueryArgs( '', {
+ page: 'gutenberg-experiments',
+ } );
+ await visitAdminPage( '/admin.php', query );
+
+ await Promise.all( features.map( async ( feature ) => {
+ await page.waitForSelector( feature );
+ await page.click( feature );
+ await page.click( '#submit' );
+ } ) );
+}
diff --git a/packages/e2e-test-utils/src/index.js b/packages/e2e-test-utils/src/index.js
index c6839ac84f1d5..06d898b31fc37 100644
--- a/packages/e2e-test-utils/src/index.js
+++ b/packages/e2e-test-utils/src/index.js
@@ -11,6 +11,7 @@ export { createURL } from './create-url';
export { deactivatePlugin } from './deactivate-plugin';
export { disablePrePublishChecks } from './disable-pre-publish-checks';
export { dragAndResize } from './drag-and-resize';
+export { enableExperimentalFeatures } from './enable-experimental-features';
export { enablePageDialogAccept } from './enable-page-dialog-accept';
export { enablePrePublishChecks } from './enable-pre-publish-checks';
export { ensureSidebarOpened } from './ensure-sidebar-opened';
diff --git a/packages/e2e-tests/specs/block-transforms.test.js b/packages/e2e-tests/specs/block-transforms.test.js
index 89d14bf524491..381facd4c0067 100644
--- a/packages/e2e-tests/specs/block-transforms.test.js
+++ b/packages/e2e-tests/specs/block-transforms.test.js
@@ -19,6 +19,7 @@ import {
getEditedPostContent,
hasBlockSwitcher,
createNewPost,
+ enableExperimentalFeatures,
setPostContent,
selectBlockByClientId,
transformBlockTo,
@@ -99,6 +100,7 @@ describe( 'Block transforms', () => {
const transformStructure = {};
beforeAll( async () => {
+ await enableExperimentalFeatures( [ '#gutenberg-widget-experiments', '#gutenberg-menu-block' ] );
await createNewPost();
for ( const fileBase of fileBasenames ) {
diff --git a/packages/edit-post/src/index.js b/packages/edit-post/src/index.js
index 8027695313a6f..531f8e1c0267e 100644
--- a/packages/edit-post/src/index.js
+++ b/packages/edit-post/src/index.js
@@ -7,7 +7,7 @@ import '@wordpress/editor';
import '@wordpress/nux';
import '@wordpress/viewport';
import '@wordpress/notices';
-import { registerCoreBlocks } from '@wordpress/block-library';
+import { registerCoreBlocks, __experimentalRegisterExperimentalCoreBlocks } from '@wordpress/block-library';
import { render, unmountComponentAtNode } from '@wordpress/element';
/**
@@ -65,8 +65,10 @@ export function reinitializeEditor( postType, postId, target, settings, initialE
export function initializeEditor( id, postType, postId, settings, initialEdits ) {
const target = document.getElementById( id );
const reboot = reinitializeEditor.bind( null, postType, postId, target, settings, initialEdits );
-
registerCoreBlocks();
+ if ( process.env.GUTENBERG_PHASE === 2 ) {
+ __experimentalRegisterExperimentalCoreBlocks( settings );
+ }
// Show a console log warning if the browser is not in Standards rendering mode.
const documentMode = document.compatMode === 'CSS1Compat' ? 'Standards' : 'Quirks';
diff --git a/packages/edit-widgets/src/index.js b/packages/edit-widgets/src/index.js
index 16035513da954..7efa0d6c5a4dd 100644
--- a/packages/edit-widgets/src/index.js
+++ b/packages/edit-widgets/src/index.js
@@ -3,7 +3,7 @@
*/
import '@wordpress/notices';
import { render } from '@wordpress/element';
-import { registerCoreBlocks } from '@wordpress/block-library';
+import { registerCoreBlocks, __experimentalRegisterExperimentalCoreBlocks } from '@wordpress/block-library';
/**
* Internal dependencies
@@ -21,6 +21,9 @@ import CustomizerEditWidgetsInitializer from './components/customizer-edit-widge
*/
export function initialize( id, settings ) {
registerCoreBlocks();
+ if ( process.env.GUTENBERG_PHASE === 2 ) {
+ __experimentalRegisterExperimentalCoreBlocks( settings );
+ }
render(
{
beforeAll( () => {
unstable__bootstrapServerSideBlockDefinitions( require( './server-registered.json' ) );
-
+ const settings = { __experimentalEnableLegacyWidgetBlock: true, __experimentalEnableMenuBlock: true };
// Load all hooks that modify blocks
require( '../../../packages/editor/src/hooks' );
registerCoreBlocks();
+ if ( process.env.GUTENBERG_PHASE === 2 ) {
+ __experimentalRegisterExperimentalCoreBlocks( settings );
+ }
} );
blockBasenames.forEach( ( basename ) => {