From b819f638e270d406cccb9c9e1da60022ec25ee14 Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Mon, 3 Jul 2023 13:36:14 +0300 Subject: [PATCH] Try: Aggressive TinyMCE deprecation (#50387) * Add experiment setting field * Set a global when experiment enabled * Load Classic block only when experiment is not enabled * Do not enqueue any TinyMCE assets if experiment is enabled * Do not enqueue editor if experiment enabled * Set and utilize a cookie when tinymce is requested * Safeer cookie access on the server side * Add a script to force TinyMCE usage for testing * Move experiment toggle to the higheest priority * Add PHP comments and fix coding standards * Rename class file * More CS * Use gutenberg_is_experiment_enabled() * Cleanup lines from rebase * Backend detection of classic block instances * Comment the cookie testing code again * Fix code style * Consider the freeform block, or any raw HTML to be Unknown block * Proper post object existence testing * Register classic block if server declares it's needed * A custom message when converting from classic block * Improve content length check `empty()` will return `true` if we pass the '0' string. * Expand comment on classic block registration * Move example TinyMCE usage code up * Use a query argument instead of a cookie * Rename proxy trap * Fix the comment * Rename another function * Improve the classic block load conditions comment * Further polish the conditions comment * Fix a fatal in the wp-admin dashboard --- lib/client-assets.php | 8 +- lib/experimental/assets/tinymce-proxy.js | 14 ++++ lib/experimental/class--wp-editors.php | 27 +++++++ lib/experimental/disable-tinymce.php | 86 ++++++++++++++++++++++ lib/experimental/editor-settings.php | 3 + lib/experiments-page.php | 12 +++ lib/load.php | 6 +- packages/block-library/src/index.js | 19 ++++- packages/block-library/src/missing/edit.js | 42 ++++++++--- 9 files changed, 203 insertions(+), 14 deletions(-) create mode 100644 lib/experimental/assets/tinymce-proxy.js create mode 100644 lib/experimental/class--wp-editors.php create mode 100644 lib/experimental/disable-tinymce.php diff --git a/lib/client-assets.php b/lib/client-assets.php index 9757e4b7ff24a8..99aa7f147ecbfc 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -203,7 +203,13 @@ function gutenberg_register_packages_scripts( $scripts ) { // Add dependencies that cannot be detected and generated by build tools. switch ( $handle ) { case 'wp-block-library': - array_push( $dependencies, 'editor' ); + if ( + ! gutenberg_is_experiment_enabled( 'gutenberg-no-tinymce' ) || + ! empty( $_GET['requiresTinymce'] ) || + gutenberg_post_being_edited_requires_classic_block() + ) { + array_push( $dependencies, 'editor' ); + } break; case 'wp-edit-post': diff --git a/lib/experimental/assets/tinymce-proxy.js b/lib/experimental/assets/tinymce-proxy.js new file mode 100644 index 00000000000000..91c9e74bb74ed8 --- /dev/null +++ b/lib/experimental/assets/tinymce-proxy.js @@ -0,0 +1,14 @@ +async function reloadWithTinymce() { + const currentUrl = new URL( window.location.href ); + currentUrl.searchParams.set( 'requiresTinymce', '1' ); + window.location.href = currentUrl; +} + +window.tinymce = new Proxy( + {}, + { + get: reloadWithTinymce, + set: reloadWithTinymce, + apply: reloadWithTinymce, + } +); diff --git a/lib/experimental/class--wp-editors.php b/lib/experimental/class--wp-editors.php new file mode 100644 index 00000000000000..bc49ea80a99421 --- /dev/null +++ b/lib/experimental/class--wp-editors.php @@ -0,0 +1,27 @@ +window.wp.needsClassicBlock = true;'; +} +add_action( 'admin_footer', 'gutenberg_declare_classic_block_necessary' ); + +// If user has already requested TinyMCE, we're ending the experiment. +if ( ! empty( $_GET['requiresTinymce'] ) || gutenberg_post_being_edited_requires_classic_block() ) { + return; +} + + +/** + * Disable TinyMCE by introducing a placeholder `_WP_Editors` class. + */ +function gutenberg_disable_tinymce() { + require __DIR__ . '/class--wp-editors.php'; +} + +add_action( 'admin_init', 'gutenberg_disable_tinymce' ); + +/** + * Enqueue TinyMCE proxy script. + * Detects TinyMCE usage and sets the `requiresTinymce` query argument to stop disabling TinyMCE loading. + */ +function gutenberg_enqueue_tinymce_proxy() { + wp_enqueue_script( 'gutenberg-tinymce-proxy', plugins_url( 'assets/tinymce-proxy.js', __FILE__ ) ); +} + +add_action( 'admin_enqueue_scripts', 'gutenberg_enqueue_tinymce_proxy' ); + +/** + * Example TinyMCE usage used for testing. + * Uncomment line 8 in this file to enable. + */ +function gutenberg_test_tinymce_access() { + echo ''; +} + +/** + * Whether the current editor contains a classic block instance. + * + * @return bool True if the editor contains a classic block, false otherwse. + */ +function gutenberg_post_being_edited_requires_classic_block() { + if ( ! is_admin() ) { + return false; + } + + // Handle the post editor. + if ( ! empty( $_GET['post'] ) && ! empty( $_GET['action'] ) && 'edit' === $_GET['action'] ) { + $current_post = get_post( intval( $_GET['post'] ) ); + if ( ! $current_post || is_wp_error( $current_post ) ) { + return false; + } + + $content = $current_post->post_content; + } + + if ( empty( $content ) ) { + return false; + } + + $parsed_blocks = parse_blocks( $content ); + foreach ( $parsed_blocks as $block ) { + if ( empty( $block['blockName'] ) && strlen( trim( $block['innerHTML'] ) ) > 0 ) { + return true; + } + } + + return false; +} diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php index eaa314946ab9a3..15d964e2deec72 100644 --- a/lib/experimental/editor-settings.php +++ b/lib/experimental/editor-settings.php @@ -90,6 +90,9 @@ function gutenberg_enable_experiments() { wp_add_inline_script( 'wp-block-editor', 'window.__experimentalInteractivityAPI = true', 'before' ); } + if ( gutenberg_is_experiment_enabled( 'gutenberg-no-tinymce' ) ) { + wp_add_inline_script( 'wp-block-library', 'window.__experimentalDisableTinymce = true', 'before' ); + } } add_action( 'admin_init', 'gutenberg_enable_experiments' ); diff --git a/lib/experiments-page.php b/lib/experiments-page.php index a2df41908aa257..de1d3dbce71a14 100644 --- a/lib/experiments-page.php +++ b/lib/experiments-page.php @@ -89,6 +89,18 @@ function gutenberg_initialize_experiments_settings() { ) ); + add_settings_field( + 'gutenberg-no-tinymce', + __( 'Disable TinyMCE and Classic block', 'gutenberg' ), + 'gutenberg_display_experiment_field', + 'gutenberg-experiments', + 'gutenberg_experiments_section', + array( + 'label' => __( 'Disable TinyMCE and Classic block', 'gutenberg' ), + 'id' => 'gutenberg-no-tinymce', + ) + ); + register_setting( 'gutenberg-experiments', 'gutenberg-experiments' diff --git a/lib/load.php b/lib/load.php index fbba502d2f5aae..6d3638bf969134 100644 --- a/lib/load.php +++ b/lib/load.php @@ -108,6 +108,11 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/experimental/navigation-theme-opt-in.php'; require __DIR__ . '/experimental/kses.php'; require __DIR__ . '/experimental/l10n.php'; + +if ( gutenberg_is_experiment_enabled( 'gutenberg-no-tinymce' ) ) { + require __DIR__ . '/experimental/disable-tinymce.php'; +} + if ( gutenberg_is_experiment_enabled( 'gutenberg-interactivity-api-core-blocks' ) ) { require __DIR__ . '/experimental/interactivity-api/blocks.php'; } @@ -123,7 +128,6 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/experimental/interactivity-api/directives/wp-style.php'; require __DIR__ . '/experimental/interactivity-api/directives/wp-text.php'; - // Fonts API. if ( ! class_exists( 'WP_Fonts' ) ) { // Fonts API files. diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js index 2b4a0f2fb95f2a..911bd0c37451ee 100644 --- a/packages/block-library/src/index.js +++ b/packages/block-library/src/index.js @@ -142,7 +142,6 @@ const getAllBlocks = () => { buttons, calendar, categories, - ...( window.wp && window.wp.oldEditor ? [ classic ] : [] ), // Only add the classic block in WP Context. code, column, columns, @@ -229,6 +228,24 @@ const getAllBlocks = () => { queryTitle, postAuthorBiography, ]; + + // When in a WordPress context, conditionally + // add the classic block and TinyMCE editor + // under any of the following conditions: + // - the current post contains a classic block + // - the experiment to disable TinyMCE isn't active. + // - a query argument specifies that TinyMCE should be loaded + if ( + window?.wp?.oldEditor && + ( window?.wp?.needsClassicBlock || + ! window?.__experimentalDisableTinymce || + !! new URLSearchParams( window?.location?.search ).get( + 'requiresTinymce' + ) ) + ) { + blocks.push( classic ); + } + return blocks.filter( Boolean ); }; diff --git a/packages/block-library/src/missing/edit.js b/packages/block-library/src/missing/edit.js index 1ef143a639ed06..f7aef453b5447c 100644 --- a/packages/block-library/src/missing/edit.js +++ b/packages/block-library/src/missing/edit.js @@ -16,22 +16,46 @@ import { safeHTML } from '@wordpress/dom'; function MissingBlockWarning( { attributes, convertToHTML, clientId } ) { const { originalName, originalUndelimitedContent } = attributes; const hasContent = !! originalUndelimitedContent; - const hasHTMLBlock = useSelect( + const { hasFreeformBlock, hasHTMLBlock } = useSelect( ( select ) => { const { canInsertBlockType, getBlockRootClientId } = select( blockEditorStore ); - return canInsertBlockType( - 'core/html', - getBlockRootClientId( clientId ) - ); + return { + hasFreeformBlock: canInsertBlockType( + 'core/freeform', + getBlockRootClientId( clientId ) + ), + hasHTMLBlock: canInsertBlockType( + 'core/html', + getBlockRootClientId( clientId ) + ), + }; }, [ clientId ] ); const actions = []; let messageHTML; - if ( hasContent && hasHTMLBlock ) { + + const convertToHtmlButton = ( + + ); + + if ( hasContent && ! hasFreeformBlock && ! originalName ) { + if ( hasHTMLBlock ) { + messageHTML = __( + 'It appears you are trying to use the deprecated Classic block. You can leave this block intact, convert its content to a Custom HTML block, or remove it entirely. Alternatively, you can refresh the page to use the Classic block.' + ); + actions.push( convertToHtmlButton ); + } else { + messageHTML = __( + 'It appears you are trying to use the deprecated Classic block. You can leave this block intact, or remove it entirely. Alternatively, you can refresh the page to use the Classic block.' + ); + } + } else if ( hasContent && hasHTMLBlock ) { messageHTML = sprintf( /* translators: %s: block name */ __( @@ -39,11 +63,7 @@ function MissingBlockWarning( { attributes, convertToHTML, clientId } ) { ), originalName ); - actions.push( - - ); + actions.push( convertToHtmlButton ); } else { messageHTML = sprintf( /* translators: %s: block name */