diff --git a/lib/class-wp-rest-block-editor-settings-controller.php b/lib/class-wp-rest-block-editor-settings-controller.php index 6c7aa8d77d2c48..77f4a5187b4835 100644 --- a/lib/class-wp-rest-block-editor-settings-controller.php +++ b/lib/class-wp-rest-block-editor-settings-controller.php @@ -75,8 +75,8 @@ public function get_items_permissions_check( $request ) {// phpcs:ignore Variabl * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { - $context = ! empty( $request['context'] ) ? $request['context'] : 'post-editor'; - $settings = gutenberg_get_block_editor_settings( $context ); + $editor_context = new WP_Block_Editor_Context(); + $settings = gutenberg_get_block_editor_settings( array(), $editor_context ); return rest_ensure_response( $settings ); } diff --git a/lib/block-editor.php b/lib/compat/wordpress-5.8/block-editor.php similarity index 62% rename from lib/block-editor.php rename to lib/compat/wordpress-5.8/block-editor.php index 922dd87ce032db..f7efc7f1ebf6d5 100644 --- a/lib/block-editor.php +++ b/lib/compat/wordpress-5.8/block-editor.php @@ -69,26 +69,30 @@ function gutenberg_get_default_block_categories() { * * @since 10.5.0 * - * @param string|WP_Post $editor_name_or_post The name of the editor (e.g. 'post-editor') - * or the post object. - * + * @param WP_Post|WP_Block_Editor_Context $post_or_block_editor_context The current post object or + * the block editor context. * @return array[] Array of categories for block types. */ -function gutenberg_get_block_categories( $editor_name_or_post ) { - // Assume the post editor when the WP_Post object passed. - $editor_name = is_object( $editor_name_or_post ) ? 'post-editor' : $editor_name_or_post; - $default_categories = gutenberg_get_default_block_categories(); +function gutenberg_get_block_categories( $post_or_block_editor_context ) { + $block_categories = gutenberg_get_default_block_categories(); + $block_editor_context = $post_or_block_editor_context instanceof WP_Post ? + new WP_Block_Editor_Context( + array( + 'post' => $post_or_block_editor_context, + ) + ) : $post_or_block_editor_context; /** * Filters the default array of categories for block types. * * @since 5.8.0 * - * @param array[] $default_categories Array of categories for block types. + * @param array[] $block_categories Array of categories for block types. + * @param WP_Block_Editor_Context $block_editor_context The current block editor context. */ - $block_categories = apply_filters( 'block_categories_all', $default_categories ); - if ( 'post-editor' === $editor_name ) { - $post = is_object( $editor_name_or_post ) ? $editor_name_or_post : get_post(); + $block_categories = apply_filters( 'block_categories_all', $block_categories, $block_editor_context ); + if ( ! empty( $block_editor_context->post ) ) { + $post = $block_editor_context->post; /** * Filters the default array of categories for block types. @@ -115,25 +119,26 @@ function gutenberg_get_block_categories( $editor_name_or_post ) { * * @since 10.5.0 * - * @param string $editor_name The name of the editor (e.g. 'post-editor'). + * @param WP_Block_Editor_Context $block_editor_context The current block editor context. * * @return bool|array Array of block type slugs, or boolean to enable/disable all. */ -function gutenberg_get_allowed_block_types( $editor_name ) { +function gutenberg_get_allowed_block_types( $block_editor_context ) { $allowed_block_types = true; /** - * Filters the allowed block types for the given editor, defaulting to true (all - * registered block types supported). + * Filters the allowed block types for all editor types, defaulting to `true` + * (all registered block types supported). * * @since 5.8.0 * - * @param bool|array $allowed_block_types Array of block type slugs, or - * boolean to enable/disable all. + * @param bool|array $allowed_block_types Array of block type slugs, or + * boolean to enable/disable all. + * @param WP_Block_Editor_Context $block_editor_context The current block editor context. */ - $allowed_block_types = apply_filters( 'allowed_block_types_all', $allowed_block_types ); - if ( 'post-editor' === $editor_name ) { - $post = get_post(); + $allowed_block_types = apply_filters( 'allowed_block_types_all', $allowed_block_types, $block_editor_context ); + if ( ! empty( $block_editor_context->post ) ) { + $post = $block_editor_context->post; /** * Filters the allowed block types for the editor, defaulting to true (all @@ -251,31 +256,32 @@ function gutenberg_get_default_block_editor_settings() { * * @since 10.5.0 * - * @param string $editor_name The name of the editor (e.g. 'post-editor'). - * @param array $custom_settings Optional custom settings to use with the editor type. + * @param array $custom_settings Custom settings to use with the given editor type. + * @param WP_Block_Editor_Context $block_editor_context The current block editor context. * * @return array The contextualized block editor settings. */ -function gutenberg_get_block_editor_settings( $editor_name, $custom_settings = array() ) { +function gutenberg_get_block_editor_settings( $custom_settings, $block_editor_context ) { $editor_settings = array_merge( - gutenberg_get_default_block_editor_settings( $editor_name ), + gutenberg_get_default_block_editor_settings(), array( - 'allowedBlockTypes' => gutenberg_get_allowed_block_types( $editor_name ), - 'blockCategories' => gutenberg_get_block_categories( $editor_name ), + 'allowedBlockTypes' => gutenberg_get_allowed_block_types( $block_editor_context ), + 'blockCategories' => gutenberg_get_block_categories( $block_editor_context ), ), $custom_settings ); /** - * Filters the settings to pass to the block editor for all editor types. + * Filters the settings to pass to the block editor for all editor type. * * @since 5.8.0 * - * @param array $editor_settings Default editor settings. + * @param array $editor_settings Default editor settings. + * @param WP_Block_Editor_Context $block_editor_context The current block editor context. */ - $editor_settings = apply_filters( 'block_editor_settings_all', $editor_settings ); - if ( 'post-editor' === $editor_name ) { - $post = get_post(); + $editor_settings = apply_filters( 'block_editor_settings_all', $editor_settings, $block_editor_context ); + if ( ! empty( $block_editor_context->post ) ) { + $post = $block_editor_context->post; /** * Filters the settings to pass to the block editor. @@ -291,3 +297,77 @@ function gutenberg_get_block_editor_settings( $editor_name, $custom_settings = a return $editor_settings; } + +/** + * Preloads common data used with the block editor by specifying an array of + * REST API paths that will be preloaded for a given block editor context. + * + * @see https://core.trac.wordpress.org/ticket/52920 + * + * @since 10.7.0 + * + * @global WP_Post $post Global post object. + * + * @param array $preload_paths List of paths to preload. + * @param WP_Block_Editor_Context $block_editor_context The current block editor context. + * + * @return void + */ +function gutenberg_block_editor_rest_api_preload( array $preload_paths, $block_editor_context ) { + global $post; + + /** + * Filters the array of REST API paths that will be used to preloaded common data + * to use with the block editor. + * + * @since 5.8.0 + * + * @param string[] $preload_paths Array of paths to preload. + */ + $preload_paths = apply_filters( 'block_editor_rest_api_preload_paths', $preload_paths, $block_editor_context ); + if ( ! empty( $block_editor_context->post ) ) { + $selected_post = $block_editor_context->post; + + /** + * Preload common data by specifying an array of REST API paths that will be preloaded. + * + * Filters the array of paths that will be preloaded. + * + * @since 5.0.0 + * @deprecated 5.8.0 The hook transitioned to support also screens that don't contain $post instance. + * + * @param string[] $preload_paths Array of paths to preload. + * @param WP_Post $selected_post Post being edited. + */ + $preload_paths = apply_filters_deprecated( 'block_editor_preload_paths', array( $preload_paths, $selected_post ), '5.8.0', 'block_editor_rest_api_preload_paths' ); + } + + if ( empty( $preload_paths ) ) { + return; + } + + /* + * Ensure the global $post remains the same after API data is preloaded. + * Because API preloading can call the_content and other filters, plugins + * can unexpectedly modify $post. + */ + $backup_global_post = ! empty( $post ) ? clone $post : $post; + + $preload_data = array_reduce( + $preload_paths, + 'rest_preload_api_request', + array() + ); + + // Restore the global $post as it was before API preloading. + $post = $backup_global_post; + + wp_add_inline_script( + 'wp-api-fetch', + sprintf( + 'wp.apiFetch.use( wp.apiFetch.createPreloadingMiddleware( %s ) );', + wp_json_encode( $preload_data ) + ), + 'after' + ); +} diff --git a/lib/compat/wordpress-5.8/class-wp-block-editor-context.php b/lib/compat/wordpress-5.8/class-wp-block-editor-context.php new file mode 100644 index 00000000000000..9f146c8b86146d --- /dev/null +++ b/lib/compat/wordpress-5.8/class-wp-block-editor-context.php @@ -0,0 +1,35 @@ +post = $settings['post']; + } + } +} diff --git a/lib/compat/wordpress-5.8.php b/lib/compat/wordpress-5.8/index.php similarity index 93% rename from lib/compat/wordpress-5.8.php rename to lib/compat/wordpress-5.8/index.php index 0129fa91c4a7ca..71040f3b190d16 100644 --- a/lib/compat/wordpress-5.8.php +++ b/lib/compat/wordpress-5.8/index.php @@ -7,6 +7,12 @@ * @package gutenberg */ +if ( ! class_exists( 'WP_Block_Editor_Context' ) ) { + require_once __DIR__ . '/class-wp-block-editor-context.php'; +} + +require_once __DIR__ . '/block-editor.php'; + if ( ! function_exists( 'build_query_vars_from_query_block' ) ) { /** * Helper function that constructs a WP_Query args array from diff --git a/lib/load.php b/lib/load.php index 12f4f4942c7470..66b85974f2a7da 100644 --- a/lib/load.php +++ b/lib/load.php @@ -83,7 +83,7 @@ function gutenberg_is_experiment_enabled( $name ) { require_once __DIR__ . '/widgets-page.php'; require __DIR__ . '/compat.php'; -require __DIR__ . '/compat/wordpress-5.8.php'; +require __DIR__ . '/compat/wordpress-5.8/index.php'; require __DIR__ . '/utils.php'; require __DIR__ . '/editor-settings.php'; @@ -110,7 +110,6 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/full-site-editing/edit-site-export.php'; require __DIR__ . '/blocks.php'; -require __DIR__ . '/block-editor.php'; require __DIR__ . '/block-patterns.php'; require __DIR__ . '/client-assets.php'; require __DIR__ . '/demo.php'; diff --git a/lib/widgets-customize.php b/lib/widgets-customize.php index be8169487b79fe..bb2013f8c65474 100644 --- a/lib/widgets-customize.php +++ b/lib/widgets-customize.php @@ -116,7 +116,8 @@ function gutenberg_customize_widgets_init() { return; } - $settings = array_merge( + $customizer_context = new WP_Block_Editor_Context(); + $settings = array_merge( gutenberg_get_default_block_editor_settings(), gutenberg_get_legacy_widget_settings() ); @@ -137,7 +138,7 @@ function gutenberg_customize_widgets_init() { wp_add_inline_script( 'wp-blocks', - sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( gutenberg_get_block_categories( 'widgets_customizer' ) ) ), + sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( gutenberg_get_block_categories( $customizer_context ) ) ), 'after' ); diff --git a/lib/widgets-page.php b/lib/widgets-page.php index 1ba9d44c9732da..06376c2c71e396 100644 --- a/lib/widgets-page.php +++ b/lib/widgets-page.php @@ -34,7 +34,8 @@ function gutenberg_widgets_init( $hook ) { add_filter( 'admin_body_class', 'gutenberg_widgets_editor_add_admin_body_classes' ); - $settings = array_merge( + $widgets_editor_context = new WP_Block_Editor_Context(); + $settings = array_merge( gutenberg_get_default_block_editor_settings(), gutenberg_get_legacy_widget_settings() ); @@ -60,7 +61,7 @@ function gutenberg_widgets_init( $hook ) { wp_add_inline_script( 'wp-blocks', - sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( gutenberg_get_block_categories( 'widgets_editor' ) ) ), + sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( gutenberg_get_block_categories( $widgets_editor_context ) ) ), 'after' ); diff --git a/phpunit/block-editor-test.php b/phpunit/class-block-editor-test.php similarity index 67% rename from phpunit/block-editor-test.php rename to phpunit/class-block-editor-test.php index 633f7987ddbf24..3f19167b2bc54e 100644 --- a/phpunit/block-editor-test.php +++ b/phpunit/class-block-editor-test.php @@ -66,6 +66,24 @@ function filter_set_block_editor_settings_post( $editor_settings, $post ) { ); } + /** + * @ticket 52920 + */ + function test_block_editor_context_no_settings() { + $context = new WP_Block_Editor_Context(); + + $this->assertNull( $context->post ); + } + + /** + * @ticket 52920 + */ + function test_block_editor_context_post() { + $context = new WP_Block_Editor_Context( array( 'post' => get_post() ) ); + + $this->assertSame( get_post(), $context->post ); + } + /** * @ticket 52920 * @expectedDeprecated block_categories @@ -96,7 +114,8 @@ function test_get_block_categories_deprecated_filter_post_object() { function test_get_block_categories_deprecated_filter_post_editor() { add_filter( 'block_categories', array( $this, 'filter_set_block_categories_post' ), 10, 2 ); - $block_categories = gutenberg_get_block_categories( 'post-editor' ); + $post_editor_context = new WP_Block_Editor_Context( array( 'post' => get_post() ) ); + $block_categories = gutenberg_get_block_categories( $post_editor_context ); remove_filter( 'block_categories', array( $this, 'filter_set_block_categories_post' ) ); @@ -116,7 +135,8 @@ function test_get_block_categories_deprecated_filter_post_editor() { * @ticket 52920 */ function test_get_allowed_block_types_default() { - $allowed_block_types = gutenberg_get_allowed_block_types( 'post-editor' ); + $post_editor_context = new WP_Block_Editor_Context( array( 'post' => get_post() ) ); + $allowed_block_types = gutenberg_get_allowed_block_types( $post_editor_context ); $this->assertTrue( $allowed_block_types ); } @@ -128,7 +148,8 @@ function test_get_allowed_block_types_default() { function test_get_allowed_block_types_deprecated_filter_post_editor() { add_filter( 'allowed_block_types', array( $this, 'filter_set_allowed_block_types_post' ), 10, 2 ); - $allowed_block_types = gutenberg_get_allowed_block_types( 'post-editor' ); + $post_editor_context = new WP_Block_Editor_Context( array( 'post' => get_post() ) ); + $allowed_block_types = gutenberg_get_allowed_block_types( $post_editor_context ); remove_filter( 'allowed_block_types', array( $this, 'filter_set_allowed_block_types_post' ) ); @@ -265,7 +286,8 @@ function filter_block_editor_settings_my_editor( $editor_settings ) { add_filter( 'block_categories_all', 'filter_block_categories_my_editor', 10, 1 ); add_filter( 'block_editor_settings_all', 'filter_block_editor_settings_my_editor', 10, 1 ); - $settings = gutenberg_get_block_editor_settings( 'my-editor' ); + $my_editor_context = new WP_Block_Editor_Context(); + $settings = gutenberg_get_block_editor_settings( array(), $my_editor_context ); remove_filter( 'allowed_block_types_all', 'filter_allowed_block_types_my_editor' ); remove_filter( 'block_categories_all', 'filter_block_categories_my_editor' ); @@ -290,10 +312,10 @@ function filter_block_editor_settings_my_editor( $editor_settings ) { * @expectedDeprecated block_editor_settings */ function test_get_block_editor_settings_deprecated_filter_post_editor() { - // This filter needs to run last to account for other filters registered in the plugin. - add_filter( 'block_editor_settings', array( $this, 'filter_set_block_editor_settings_post' ), PHP_INT_MAX, 2 ); + add_filter( 'block_editor_settings', array( $this, 'filter_set_block_editor_settings_post' ), 10, 2 ); - $settings = gutenberg_get_block_editor_settings( 'post-editor' ); + $post_editor_context = new WP_Block_Editor_Context( array( 'post' => get_post() ) ); + $settings = gutenberg_get_block_editor_settings( array(), $post_editor_context ); remove_filter( 'block_editor_settings', array( $this, 'filter_set_block_editor_settings_post' ) ); @@ -304,4 +326,71 @@ function test_get_block_editor_settings_deprecated_filter_post_editor() { $settings ); } + + /** + * @ticket 52920 + */ + function test_block_editor_rest_api_preload_no_paths() { + $editor_context = new WP_Block_Editor_Context(); + gutenberg_block_editor_rest_api_preload( array(), $editor_context ); + + $after = implode( '', wp_scripts()->registered['wp-api-fetch']->extra['after'] ); + $this->assertNotContains( 'wp.apiFetch.createPreloadingMiddleware', $after ); + } + + /** + * @ticket 52920 + * @expectedDeprecated block_editor_preload_paths + */ + function test_block_editor_rest_api_preload_deprecated_filter_post_editor() { + function filter_remove_preload_paths( $preload_paths, $post ) { + if ( empty( $post ) ) { + return $preload_paths; + } + return array(); + } + add_filter( 'block_editor_preload_paths', 'filter_remove_preload_paths', 10, 2 ); + + $post_editor_context = new WP_Block_Editor_Context( array( 'post' => get_post() ) ); + gutenberg_block_editor_rest_api_preload( + array( + array( '/wp/v2/blocks', 'OPTIONS' ), + ), + $post_editor_context + ); + + remove_filter( 'block_editor_preload_paths', 'filter_remove_preload_paths' ); + + $after = implode( '', wp_scripts()->registered['wp-api-fetch']->extra['after'] ); + $this->assertNotContains( 'wp.apiFetch.createPreloadingMiddleware', $after ); + } + + /** + * @ticket 52920 + */ + function test_block_editor_rest_api_preload_filter_all() { + function filter_add_preload_paths( $preload_paths, WP_Block_Editor_Context $context ) { + if ( empty( $context->post ) ) { + array_push( $preload_paths, array( '/wp/v2/types', 'OPTIONS' ) ); + } + + return $preload_paths; + } + add_filter( 'block_editor_rest_api_preload_paths', 'filter_add_preload_paths', 10, 2 ); + + $editor_context = new WP_Block_Editor_Context(); + gutenberg_block_editor_rest_api_preload( + array( + array( '/wp/v2/blocks', 'OPTIONS' ), + ), + $editor_context + ); + + remove_filter( 'block_editor_rest_api_preload_paths', 'filter_add_preload_paths' ); + + $after = implode( '', wp_scripts()->registered['wp-api-fetch']->extra['after'] ); + $this->assertContains( 'wp.apiFetch.createPreloadingMiddleware', $after ); + $this->assertContains( '"\/wp\/v2\/blocks"', $after ); + $this->assertContains( '"\/wp\/v2\/types"', $after ); + } }