diff --git a/lib/compat/wordpress-6.2/script-loader.php b/lib/compat/wordpress-6.2/script-loader.php
index e08bfa6e46ca8..aed58ef98122b 100644
--- a/lib/compat/wordpress-6.2/script-loader.php
+++ b/lib/compat/wordpress-6.2/script-loader.php
@@ -137,7 +137,8 @@ function gutenberg_resolve_assets_override() {
'block_editor_settings_all',
function( $settings ) {
// We must override what core is passing now.
- $settings['__unstableResolvedAssets'] = gutenberg_resolve_assets_override();
+ $settings['__unstableResolvedAssets'] = gutenberg_resolve_assets_override();
+ $settings['__unstableIsBlockBasedTheme'] = wp_is_block_theme();
return $settings;
},
100
diff --git a/packages/block-library/src/freeform/edit.js b/packages/block-library/src/freeform/edit.js
index ab9a2257f87e4..c41a78ca5c042 100644
--- a/packages/block-library/src/freeform/edit.js
+++ b/packages/block-library/src/freeform/edit.js
@@ -6,10 +6,10 @@ import {
useBlockProps,
store as blockEditorStore,
} from '@wordpress/block-editor';
-import { debounce } from '@wordpress/compose';
+import { debounce, useRefEffect } from '@wordpress/compose';
import { useSelect } from '@wordpress/data';
import { ToolbarGroup } from '@wordpress/components';
-import { useEffect, useRef } from '@wordpress/element';
+import { useEffect, useRef, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { BACKSPACE, DELETE, F10, isKeyboardEvent } from '@wordpress/keycodes';
@@ -17,6 +17,7 @@ import { BACKSPACE, DELETE, F10, isKeyboardEvent } from '@wordpress/keycodes';
* Internal dependencies
*/
import ConvertToBlocksButton from './convert-to-blocks-button';
+import ModalEdit from './modal';
const { wp } = window;
@@ -36,17 +37,44 @@ function isTmceEmpty( editor ) {
return /^\n?$/.test( body.innerText || body.textContent );
}
-export default function ClassicEdit( {
+export default function FreeformEdit( props ) {
+ const { clientId } = props;
+ const canRemove = useSelect(
+ ( select ) => select( blockEditorStore ).canRemoveBlock( clientId ),
+ [ clientId ]
+ );
+ const [ isIframed, setIsIframed ] = useState( false );
+ const ref = useRefEffect( ( element ) => {
+ setIsIframed( element.ownerDocument !== document );
+ }, [] );
+
+ return (
+ <>
+ { canRemove && (
+
+
+
+
+
+ ) }
+
+ { isIframed ? (
+
+ ) : (
+
+ ) }
+
+ >
+ );
+}
+
+function ClassicEdit( {
clientId,
attributes: { content },
setAttributes,
onReplace,
} ) {
const { getMultiSelectedBlockClientIds } = useSelect( blockEditorStore );
- const canRemove = useSelect(
- ( select ) => select( blockEditorStore ).canRemoveBlock( clientId ),
- [ clientId ]
- );
const didMount = useRef( false );
useEffect( () => {
@@ -225,28 +253,19 @@ export default function ClassicEdit( {
/* eslint-disable jsx-a11y/no-static-element-interactions */
return (
<>
- { canRemove && (
-
-
-
-
-
- ) }
-
+
+
>
);
/* eslint-enable jsx-a11y/no-static-element-interactions */
diff --git a/packages/block-library/src/freeform/modal.js b/packages/block-library/src/freeform/modal.js
new file mode 100644
index 0000000000000..67338be91fa86
--- /dev/null
+++ b/packages/block-library/src/freeform/modal.js
@@ -0,0 +1,111 @@
+/**
+ * WordPress dependencies
+ */
+import { BlockControls, store } from '@wordpress/block-editor';
+import {
+ ToolbarGroup,
+ ToolbarButton,
+ Modal,
+ Button,
+} from '@wordpress/components';
+import { useEffect, useState, RawHTML } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { useSelect } from '@wordpress/data';
+
+function ClassicEdit( props ) {
+ const styles = useSelect(
+ ( select ) => select( store ).getSettings().styles
+ );
+ useEffect( () => {
+ const { baseURL, suffix, settings } = window.wpEditorL10n.tinymce;
+
+ window.tinymce.EditorManager.overrideDefaults( {
+ base_url: baseURL,
+ suffix,
+ } );
+
+ window.wp.oldEditor.initialize( props.id, {
+ tinymce: {
+ ...settings,
+ height: 500,
+ setup( editor ) {
+ editor.on( 'init', () => {
+ const doc = editor.getDoc();
+ styles.forEach( ( { css } ) => {
+ const styleEl = doc.createElement( 'style' );
+ styleEl.innerHTML = css;
+ doc.head.appendChild( styleEl );
+ } );
+ } );
+ },
+ },
+ } );
+
+ return () => {
+ window.wp.oldEditor.remove( props.id );
+ };
+ }, [] );
+
+ return ;
+}
+
+export default function ModalEdit( props ) {
+ const {
+ clientId,
+ attributes: { content },
+ setAttributes,
+ onReplace,
+ } = props;
+ const [ isOpen, setOpen ] = useState( false );
+ const id = `editor-${ clientId }`;
+ const label = __( 'Classic Edit' );
+
+ return (
+ <>
+
+
+ setOpen( true ) }>
+ { label }
+
+
+
+ { content && { content } }
+ { ( isOpen || ! content ) && (
+
+
+
{ label }
+
+
+
+
+
+
+
+ ) }
+ >
+ );
+}
diff --git a/packages/e2e-test-utils/src/create-reusable-block.js b/packages/e2e-test-utils/src/create-reusable-block.js
index 3bf2e33aeb34f..ec35e07390847 100644
--- a/packages/e2e-test-utils/src/create-reusable-block.js
+++ b/packages/e2e-test-utils/src/create-reusable-block.js
@@ -4,6 +4,7 @@
import { insertBlock } from './inserter';
import { clickMenuItem } from './click-menu-item';
import { clickBlockToolbarButton } from './click-block-toolbar-button';
+import { canvas } from './canvas';
/**
* Creates a simple reusable block with a paragraph block.
@@ -33,7 +34,7 @@ export const createReusableBlock = async ( content, title ) => {
);
// Check that we have a reusable block on the page
- const block = await page.waitForSelector(
+ const block = await canvas().waitForSelector(
'.block-editor-block-list__block[data-type="core/block"]'
);
expect( block ).not.toBeNull();
diff --git a/packages/e2e-tests/specs/site-editor/multi-entity-saving.test.js b/packages/e2e-tests/specs/site-editor/multi-entity-saving.test.js
index 592d7781856a4..2d4d1a396b725 100644
--- a/packages/e2e-tests/specs/site-editor/multi-entity-saving.test.js
+++ b/packages/e2e-tests/specs/site-editor/multi-entity-saving.test.js
@@ -15,6 +15,7 @@ import {
visitSiteEditor,
enterEditMode,
deleteAllTemplates,
+ canvas,
} from '@wordpress/e2e-test-utils';
describe( 'Multi-entity save flow', () => {
@@ -94,8 +95,8 @@ describe( 'Multi-entity save flow', () => {
it( 'Save flow should work as expected.', async () => {
await createNewPost();
// Edit the page some.
- await page.waitForSelector( '.editor-post-title' );
- await page.click( '.editor-post-title' );
+ await canvas().waitForSelector( '.editor-post-title' );
+ await canvas().click( '.editor-post-title' );
await page.keyboard.type( 'Test Post...' );
await page.keyboard.press( 'Enter' );
@@ -110,8 +111,8 @@ describe( 'Multi-entity save flow', () => {
// Add a reusable block and edit it.
await createReusableBlock( 'Hi!', 'Test' );
- await page.waitForSelector( 'p[data-type="core/paragraph"]' );
- await page.click( 'p[data-type="core/paragraph"]' );
+ await canvas().waitForSelector( 'p[data-type="core/paragraph"]' );
+ await canvas().click( 'p[data-type="core/paragraph"]' );
await page.keyboard.type( 'Oh!' );
// Should trigger multi-entity save button once template part edited.
@@ -169,7 +170,7 @@ describe( 'Multi-entity save flow', () => {
} );
// Update the post.
- await page.click( '.editor-post-title' );
+ await canvas().click( '.editor-post-title' );
await page.keyboard.type( '...more title!' );
// Verify update button is enabled.
@@ -182,9 +183,9 @@ describe( 'Multi-entity save flow', () => {
await assertExistence( saveA11ySelector, false );
// Update reusable block again.
- await page.click( 'p[data-type="core/paragraph"]' );
+ await canvas().click( 'p[data-type="core/paragraph"]' );
// We need to click again due to the clickthrough overlays in reusable blocks.
- await page.click( 'p[data-type="core/paragraph"]' );
+ await canvas().click( 'p[data-type="core/paragraph"]' );
await page.keyboard.type( 'R!' );
// Multi-entity saving should be enabled.
@@ -203,19 +204,19 @@ describe( 'Multi-entity save flow', () => {
);
const editableSiteTitleSelector =
'.wp-block-site-title a[contenteditable="true"]';
- await page.waitForSelector( editableSiteTitleSelector );
- await page.focus( editableSiteTitleSelector );
+ await canvas().waitForSelector( editableSiteTitleSelector );
+ await canvas().focus( editableSiteTitleSelector );
await page.keyboard.type( '...' );
await insertBlock( 'Site Tagline' );
// Wait for the placeholder.
- await page.waitForXPath(
+ await canvas().waitForXPath(
'//span[@data-rich-text-placeholder="Write site taglineā¦"]'
);
const editableSiteTagLineSelector =
'.wp-block-site-tagline[contenteditable="true"]';
- await page.waitForSelector( editableSiteTagLineSelector );
- await page.focus( editableSiteTagLineSelector );
+ await canvas().waitForSelector( editableSiteTagLineSelector );
+ await canvas().focus( editableSiteTagLineSelector );
await page.keyboard.type( 'Just another WordPress site' );
await clickButton( 'Publish' );
diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js
index 8062e9d51dada..ab708d3e87dbf 100644
--- a/packages/edit-post/src/components/visual-editor/index.js
+++ b/packages/edit-post/src/components/visual-editor/index.js
@@ -119,6 +119,7 @@ export default function VisualEditor( { styles } ) {
editedPostTemplate = {},
wrapperBlockName,
wrapperUniqueId,
+ isBlockBasedTheme,
} = useSelect( ( select ) => {
const {
isFeatureActive,
@@ -137,7 +138,8 @@ export default function VisualEditor( { styles } ) {
_wrapperBlockName = 'core/post-content';
}
- const supportsTemplateMode = getEditorSettings().supportsTemplateMode;
+ const editorSettings = getEditorSettings();
+ const supportsTemplateMode = editorSettings.supportsTemplateMode;
const canEditTemplate = select( coreStore ).canUser(
'create',
'templates'
@@ -155,6 +157,7 @@ export default function VisualEditor( { styles } ) {
: undefined,
wrapperBlockName: _wrapperBlockName,
wrapperUniqueId: getCurrentPostId(),
+ isBlockBasedTheme: editorSettings.__unstableIsBlockBasedTheme,
};
}, [] );
const { isCleanNewPost } = useSelect( editorStore );
@@ -336,6 +339,7 @@ export default function VisualEditor( { styles } ) {
>
{
await use( new CommentsBlockUtils( { page, admin, requestUtils } ) );
},
+ editor: async ( { page }, use ) => {
+ await use( new Editor( { page, hasIframe: true } ) );
+ },
} );
test.describe( 'Comments', () => {
@@ -45,14 +52,15 @@ test.describe( 'Comments', () => {
test( 'We show no results message if there are no comments', async ( {
admin,
editor,
- page,
requestUtils,
} ) => {
await requestUtils.deleteAllComments();
await admin.createNewPost();
await editor.insertBlock( { name: 'core/comments' } );
await expect(
- page.locator( 'role=document[name="Block: Comment Template"i]' )
+ editor.canvas.locator(
+ 'role=document[name="Block: Comment Template"i]'
+ )
).toContainText( 'No results found.' );
} );
@@ -145,7 +153,6 @@ test.describe( 'Comments', () => {
test( 'A button allows the block to switch from legacy mode to editable mode', async ( {
admin,
editor,
- page,
} ) => {
await admin.createNewPost();
await editor.insertBlock( {
@@ -153,7 +160,9 @@ test.describe( 'Comments', () => {
attributes: { legacy: true, textColor: 'vivid-purple' },
} );
- const block = page.locator( 'role=document[name="Block: Comments"i]' );
+ const block = editor.canvas.locator(
+ 'role=document[name="Block: Comments"i]'
+ );
const warning = block.locator( '.block-editor-warning' );
const placeholder = block.locator(
'.wp-block-comments__legacy-placeholder'
@@ -163,7 +172,9 @@ test.describe( 'Comments', () => {
await expect( warning ).toBeVisible();
await expect( placeholder ).toBeVisible();
- await page.click( 'role=button[name="Switch to editable mode"i]' );
+ await editor.canvas.click(
+ 'role=button[name="Switch to editable mode"i]'
+ );
const commentTemplate = block.locator(
'role=document[name="Block: Comment Template"i]'
@@ -301,8 +312,12 @@ test.describe( 'Post Comments', () => {
await commentsBlockUtils.hideWelcomeGuide();
// Check that the Post Comments block has been replaced with Comments.
- await expect( page.locator( '.wp-block-post-comments' ) ).toBeHidden();
- await expect( page.locator( '.wp-block-comments' ) ).toBeVisible();
+ await expect(
+ editor.canvas.locator( '.wp-block-post-comments' )
+ ).toBeHidden();
+ await expect(
+ editor.canvas.locator( '.wp-block-comments' )
+ ).toBeVisible();
// Check the block definition has changed.
const content = await editor.getEditedPostContent();