From 44b69f3459351d7e04fe91a4eaf320178a51be0f Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 26 Jul 2023 11:38:50 +0200 Subject: [PATCH 01/62] Add Auto-inserting blocks panel to block inspector --- ...-gutenberg-rest-block-types-controller.php | 82 +++++++++++++++++++ lib/experimental/editor-settings.php | 4 + lib/experimental/rest-api.php | 5 ++ lib/load.php | 1 + .../src/hooks/auto-inserting-blocks.js | 57 +++++++++++++ packages/block-editor/src/hooks/index.js | 1 + 6 files changed, 150 insertions(+) create mode 100644 lib/experimental/class-gutenberg-rest-block-types-controller.php create mode 100644 packages/block-editor/src/hooks/auto-inserting-blocks.js diff --git a/lib/experimental/class-gutenberg-rest-block-types-controller.php b/lib/experimental/class-gutenberg-rest-block-types-controller.php new file mode 100644 index 0000000000000..d10e95aa8044f --- /dev/null +++ b/lib/experimental/class-gutenberg-rest-block-types-controller.php @@ -0,0 +1,82 @@ +get_fields_for_response( $request ); + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; + + if ( rest_is_field_included( 'auto_insert', $fields ) ) { + // if ( isset( $block_type->$extra_field ) ) { + // $field = $block_type->$extra_field; + // } + $schema = $this->get_item_schema(); + $data = $response->get_data(); + $data['auto_insert'] = array( 'a' => 'b' ); + $data = $this->add_additional_fields_to_object( $data, $request ); + $data = $this->filter_response_by_context( $data, $context ); + //$data['auto_insert'] = rest_sanitize_value_from_schema( $field, $schema['properties'][ 'auto_insert' ] ); + } + + // $blocks = parse_blocks( $data['content'] ); + // $data['content'] = gutenberg_serialize_blocks( $blocks ); // Serialize or render? + + return rest_ensure_response( $data ); + } + + /** + * Retrieves the block type' schema, conforming to JSON Schema. + * + * @return array Item schema data. + */ + public function get_item_schema() { + $this->schema = parent::get_item_schema(); + + $auto_insert_schema = array( + 'description' => __( 'Auto-insertion.' ), + 'type' => 'object', + 'default' => array(), + 'properties' => array(), + 'context' => array( 'embed', 'view', 'edit' ), + 'readonly' => true, + ); + + $this->schema['properties'] = array_merge( + $this->schema['properties'], + array( + 'auto_insert' => $auto_insert_schema, + ) + ); + + return $this->add_additional_fields_schema( $this->schema ); + } +} diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php index c09b5cde0f16b..a9b7b18e75a5f 100644 --- a/lib/experimental/editor-settings.php +++ b/lib/experimental/editor-settings.php @@ -30,6 +30,10 @@ function gutenberg_enable_experiments() { if ( gutenberg_is_experiment_enabled( 'gutenberg-no-tinymce' ) ) { wp_add_inline_script( 'wp-block-library', 'window.__experimentalDisableTinymce = true', 'before' ); } + + if ( $gutenberg_experiments && array_key_exists( 'gutenberg-auto-inserting-blocks', $gutenberg_experiments ) ) { + wp_add_inline_script( 'wp-block-editor', 'window.__experimentalAutoInsertingBlocks = true', 'before' ); + } } add_action( 'admin_init', 'gutenberg_enable_experiments' ); diff --git a/lib/experimental/rest-api.php b/lib/experimental/rest-api.php index 8e548600b3875..09a57066daf08 100644 --- a/lib/experimental/rest-api.php +++ b/lib/experimental/rest-api.php @@ -19,6 +19,11 @@ function gutenberg_register_rest_block_patterns() { $block_patterns->register_routes(); } add_action( 'rest_api_init', 'gutenberg_register_rest_block_patterns' ); + function gutenberg_register_rest_block_types() { + $block_types = new Gutenberg_REST_Block_Types_Controller(); + $block_types->register_routes(); + } + add_action( 'rest_api_init', 'gutenberg_register_rest_block_types' ); } /** diff --git a/lib/load.php b/lib/load.php index 1db219dd68197..0c73777e1b8d9 100644 --- a/lib/load.php +++ b/lib/load.php @@ -72,6 +72,7 @@ function gutenberg_is_experiment_enabled( $name ) { require_once __DIR__ . '/experimental/class-gutenberg-rest-template-revision-count.php'; if ( gutenberg_is_experiment_enabled( 'gutenberg-auto-inserting-blocks' ) ) { require_once __DIR__ . '/experimental/class-gutenberg-rest-block-patterns-controller.php'; + require_once __DIR__ . '/experimental/class-gutenberg-rest-block-types-controller.php'; } require_once __DIR__ . '/experimental/rest-api.php'; } diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js new file mode 100644 index 0000000000000..62298aa0f7bcc --- /dev/null +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -0,0 +1,57 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; +import { addFilter } from '@wordpress/hooks'; +import { PanelBody } from '@wordpress/components'; +import { createHigherOrderComponent } from '@wordpress/compose'; +import { store as blocksStore } from '@wordpress/blocks'; + +/** + * Internal dependencies + */ +import { InspectorControls } from '../components'; +import { useSelect } from '@wordpress/data'; +import { useMemo } from 'react'; + +function AutoInsertingBlocksControl() { + const blocks = useSelect( ( select ) => { + const { getBlockTypes } = select( blocksStore ); + return getBlockTypes(); + }, [] ); + console.log( blocks ); + return ( + + + + ); +} + +export const withAutoInsertingBlocks = createHigherOrderComponent( + ( BlockEdit ) => { + return ( props ) => { + const blockName = props.name; + //console.log( blockName ); + + const blockEdit = ; + return ( + <> + { blockEdit } + + + ); + }; + }, + 'withAutoInsertingBlocks' +); + +if ( window?.__experimentalAutoInsertingBlocks ) { + addFilter( + 'editor.BlockEdit', + 'core/auto-inserting-blocks/with-inspector-control', + withAutoInsertingBlocks + ); +} diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js index 6834d859d2545..5e18c6a309d69 100644 --- a/packages/block-editor/src/hooks/index.js +++ b/packages/block-editor/src/hooks/index.js @@ -22,6 +22,7 @@ import './metadata'; import './metadata-name'; import './behaviors'; import './custom-fields'; +import './auto-inserting-blocks'; export { useCustomSides } from './dimensions'; export { useLayoutClasses, useLayoutStyles } from './layout'; From 31942c0e7541e2f10295f04682309226487aeec9 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Wed, 26 Jul 2023 11:58:12 +0200 Subject: [PATCH 02/62] Try register rest field approach --- lib/experimental/auto-inserting-blocks.php | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 90f3bdf15e509..a011e28641420 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -256,3 +256,29 @@ function gutenberg_serialize_block( $block ) { function gutenberg_serialize_blocks( $blocks ) { return implode( '', array_map( 'gutenberg_serialize_block', $blocks ) ); } + +/** + * Filterable version of `serialize_blocks()`. + * + * This function is identical to `serialize_blocks()`, except that it applies + * the `gutenberg_serialize_block` filter to each block before it is serialized. + * + * @see serialize_blocks() + */ +function gutenberg_register_auto_insert_rest_field() { + register_rest_field( + 'block-type', + 'autoinsert', + array( + 'get_callback' => function( $data ) { + var_dump( $data ); + return 'patata'; + }, + 'schema' => array( + 'description' => __( 'Auto Insert.', 'default' ), + 'type' => 'string', + ), + ) + ); +} +add_action( 'rest_api_init', 'gutenberg_register_auto_insert_rest_field' ); From 549367bb56af876aecf89617b3254c3e087300c2 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 26 Jul 2023 12:04:33 +0200 Subject: [PATCH 03/62] Placate linter --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 62298aa0f7bcc..878f341e755d4 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -6,13 +6,12 @@ import { addFilter } from '@wordpress/hooks'; import { PanelBody } from '@wordpress/components'; import { createHigherOrderComponent } from '@wordpress/compose'; import { store as blocksStore } from '@wordpress/blocks'; +import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ import { InspectorControls } from '../components'; -import { useSelect } from '@wordpress/data'; -import { useMemo } from 'react'; function AutoInsertingBlocksControl() { const blocks = useSelect( ( select ) => { @@ -33,7 +32,7 @@ function AutoInsertingBlocksControl() { export const withAutoInsertingBlocks = createHigherOrderComponent( ( BlockEdit ) => { return ( props ) => { - const blockName = props.name; + //const blockName = props.name; //console.log( blockName ); const blockEdit = ; From 0bf42531ca3034b7755d471c89b8a0e5f094ae16 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 26 Jul 2023 17:09:31 +0200 Subject: [PATCH 04/62] Remove Gutenberg_REST_Block_Types_Controller --- ...-gutenberg-rest-block-types-controller.php | 82 ------------------- lib/experimental/rest-api.php | 5 -- lib/load.php | 1 - 3 files changed, 88 deletions(-) delete mode 100644 lib/experimental/class-gutenberg-rest-block-types-controller.php diff --git a/lib/experimental/class-gutenberg-rest-block-types-controller.php b/lib/experimental/class-gutenberg-rest-block-types-controller.php deleted file mode 100644 index d10e95aa8044f..0000000000000 --- a/lib/experimental/class-gutenberg-rest-block-types-controller.php +++ /dev/null @@ -1,82 +0,0 @@ -get_fields_for_response( $request ); - $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; - - if ( rest_is_field_included( 'auto_insert', $fields ) ) { - // if ( isset( $block_type->$extra_field ) ) { - // $field = $block_type->$extra_field; - // } - $schema = $this->get_item_schema(); - $data = $response->get_data(); - $data['auto_insert'] = array( 'a' => 'b' ); - $data = $this->add_additional_fields_to_object( $data, $request ); - $data = $this->filter_response_by_context( $data, $context ); - //$data['auto_insert'] = rest_sanitize_value_from_schema( $field, $schema['properties'][ 'auto_insert' ] ); - } - - // $blocks = parse_blocks( $data['content'] ); - // $data['content'] = gutenberg_serialize_blocks( $blocks ); // Serialize or render? - - return rest_ensure_response( $data ); - } - - /** - * Retrieves the block type' schema, conforming to JSON Schema. - * - * @return array Item schema data. - */ - public function get_item_schema() { - $this->schema = parent::get_item_schema(); - - $auto_insert_schema = array( - 'description' => __( 'Auto-insertion.' ), - 'type' => 'object', - 'default' => array(), - 'properties' => array(), - 'context' => array( 'embed', 'view', 'edit' ), - 'readonly' => true, - ); - - $this->schema['properties'] = array_merge( - $this->schema['properties'], - array( - 'auto_insert' => $auto_insert_schema, - ) - ); - - return $this->add_additional_fields_schema( $this->schema ); - } -} diff --git a/lib/experimental/rest-api.php b/lib/experimental/rest-api.php index 09a57066daf08..8e548600b3875 100644 --- a/lib/experimental/rest-api.php +++ b/lib/experimental/rest-api.php @@ -19,11 +19,6 @@ function gutenberg_register_rest_block_patterns() { $block_patterns->register_routes(); } add_action( 'rest_api_init', 'gutenberg_register_rest_block_patterns' ); - function gutenberg_register_rest_block_types() { - $block_types = new Gutenberg_REST_Block_Types_Controller(); - $block_types->register_routes(); - } - add_action( 'rest_api_init', 'gutenberg_register_rest_block_types' ); } /** diff --git a/lib/load.php b/lib/load.php index 0c73777e1b8d9..1db219dd68197 100644 --- a/lib/load.php +++ b/lib/load.php @@ -72,7 +72,6 @@ function gutenberg_is_experiment_enabled( $name ) { require_once __DIR__ . '/experimental/class-gutenberg-rest-template-revision-count.php'; if ( gutenberg_is_experiment_enabled( 'gutenberg-auto-inserting-blocks' ) ) { require_once __DIR__ . '/experimental/class-gutenberg-rest-block-patterns-controller.php'; - require_once __DIR__ . '/experimental/class-gutenberg-rest-block-types-controller.php'; } require_once __DIR__ . '/experimental/rest-api.php'; } From 7cd7732a6c8b88bb4d4f2b6a5edbefa5d92f7c24 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 26 Jul 2023 17:12:01 +0200 Subject: [PATCH 05/62] Add auto_insert field to REST API response --- lib/experimental/auto-inserting-blocks.php | 30 ++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index a011e28641420..fff54b1ee5b24 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -257,23 +257,11 @@ function gutenberg_serialize_blocks( $blocks ) { return implode( '', array_map( 'gutenberg_serialize_block', $blocks ) ); } -/** - * Filterable version of `serialize_blocks()`. - * - * This function is identical to `serialize_blocks()`, except that it applies - * the `gutenberg_serialize_block` filter to each block before it is serialized. - * - * @see serialize_blocks() - */ function gutenberg_register_auto_insert_rest_field() { register_rest_field( 'block-type', - 'autoinsert', + 'auto_insert', array( - 'get_callback' => function( $data ) { - var_dump( $data ); - return 'patata'; - }, 'schema' => array( 'description' => __( 'Auto Insert.', 'default' ), 'type' => 'string', @@ -282,3 +270,19 @@ function gutenberg_register_auto_insert_rest_field() { ); } add_action( 'rest_api_init', 'gutenberg_register_auto_insert_rest_field' ); + +/** + * Add the `auto_insert` value into the API response. + * + * @since 6.4.0 Added 'auto_insert' property. + * + * @param WP_REST_Response $response The response object. + * @param WP_Block_Type $block_type The block type object. + */ +function filter_block_type_response( $response, $block_type ) { + $data = $response->get_data(); + $data['auto_insert'] = 'Test'; + $response->set_data( $data ); + return $response; +} +add_filter( 'rest_prepare_block_type', 'filter_block_type_response', 10, 2 ); From 742c20ebc11efd1488cda6399eeb4186e58c14ef Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 26 Jul 2023 17:39:46 +0200 Subject: [PATCH 06/62] Remove misleading console.log() statements --- .../src/hooks/auto-inserting-blocks.js | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 878f341e755d4..096dcf5e0578c 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -5,8 +5,8 @@ import { __ } from '@wordpress/i18n'; import { addFilter } from '@wordpress/hooks'; import { PanelBody } from '@wordpress/components'; import { createHigherOrderComponent } from '@wordpress/compose'; -import { store as blocksStore } from '@wordpress/blocks'; -import { useSelect } from '@wordpress/data'; +// import { store as blocksStore } from '@wordpress/blocks'; +// import { useSelect } from '@wordpress/data'; /** * Internal dependencies @@ -14,11 +14,11 @@ import { useSelect } from '@wordpress/data'; import { InspectorControls } from '../components'; function AutoInsertingBlocksControl() { - const blocks = useSelect( ( select ) => { - const { getBlockTypes } = select( blocksStore ); - return getBlockTypes(); - }, [] ); - console.log( blocks ); + // const blocks = useSelect( ( select ) => { + // const { getBlockTypes } = select( blocksStore ); + // return getBlockTypes(); + // }, [] ); + return ( { return ( props ) => { - //const blockName = props.name; - //console.log( blockName ); - const blockEdit = ; return ( <> From a2184a3ddc752d7dcd6850b989bdb8d4f1b28264 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 26 Jul 2023 17:40:16 +0200 Subject: [PATCH 07/62] Set auto_insert field to correct value --- lib/experimental/auto-inserting-blocks.php | 38 +++++++++++----------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index fff54b1ee5b24..6e00cfe7903bf 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -64,6 +64,19 @@ function gutenberg_auto_insert_block( $inserted_block, $relative_position, $anch }; } +function gutenberg_add_auto_insert_field_to_block_type_controller( $inserted_block, $position, $anchor_block ) { + return function( $response, $block_type ) use ( $inserted_block, $position, $anchor_block ){ + if ( $block_type->name !== $inserted_block ) { + return $response; + } + + $data = $response->get_data(); + $data['auto_insert'] = array( $anchor_block => $position ); + $response->set_data( $data ); + return $response; + }; +} + /** * Register blocks for auto-insertion, based on their block.json metadata. * @@ -135,7 +148,7 @@ function gutenberg_register_auto_inserted_blocks( $settings, $metadata ) { * @return void */ function gutenberg_register_auto_inserted_block( $inserted_block, $position, $anchor_block ) { - $inserted_block = array( + $inserted_block_array = array( 'blockName' => $inserted_block, 'attrs' => array(), 'innerHTML' => '', @@ -143,8 +156,11 @@ function gutenberg_register_auto_inserted_block( $inserted_block, $position, $an 'innerBlocks' => array(), ); - $inserter = gutenberg_auto_insert_block( $inserted_block, $position, $anchor_block ); + $inserter = gutenberg_auto_insert_block( $inserted_block_array, $position, $anchor_block ); add_filter( 'gutenberg_serialize_block', $inserter, 10, 1 ); + + $controller_extender = gutenberg_add_auto_insert_field_to_block_type_controller( $inserted_block, $position, $anchor_block ); + add_filter( 'rest_prepare_block_type', $controller_extender, 10, 2 ); } /** @@ -264,25 +280,9 @@ function gutenberg_register_auto_insert_rest_field() { array( 'schema' => array( 'description' => __( 'Auto Insert.', 'default' ), - 'type' => 'string', + 'type' => 'object', ), ) ); } add_action( 'rest_api_init', 'gutenberg_register_auto_insert_rest_field' ); - -/** - * Add the `auto_insert` value into the API response. - * - * @since 6.4.0 Added 'auto_insert' property. - * - * @param WP_REST_Response $response The response object. - * @param WP_Block_Type $block_type The block type object. - */ -function filter_block_type_response( $response, $block_type ) { - $data = $response->get_data(); - $data['auto_insert'] = 'Test'; - $response->set_data( $data ); - return $response; -} -add_filter( 'rest_prepare_block_type', 'filter_block_type_response', 10, 2 ); From ebb1da287f6828f5e55e2f6cfc1382497ed5f6fb Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 26 Jul 2023 17:44:19 +0200 Subject: [PATCH 08/62] Add TODO note --- lib/experimental/auto-inserting-blocks.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 6e00cfe7903bf..2beea9a71692c 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -71,6 +71,7 @@ function gutenberg_add_auto_insert_field_to_block_type_controller( $inserted_blo } $data = $response->get_data(); + // TODO: If auto_insert already exists, add the new key/value pair to the array. $data['auto_insert'] = array( $anchor_block => $position ); $response->set_data( $data ); return $response; From f248a6571eeb7d33417d3b1045ebe032b7e28d4c Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 27 Jul 2023 10:55:48 +0200 Subject: [PATCH 09/62] Allow auto-inserting into multiple locations --- lib/experimental/auto-inserting-blocks.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 2beea9a71692c..9ec4505910dac 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -70,9 +70,11 @@ function gutenberg_add_auto_insert_field_to_block_type_controller( $inserted_blo return $response; } - $data = $response->get_data(); - // TODO: If auto_insert already exists, add the new key/value pair to the array. - $data['auto_insert'] = array( $anchor_block => $position ); + $data = $response->get_data(); + if ( ! isset( $data['auto_insert'] ) ) { + $data['auto_insert'] = array(); + } + $data['auto_insert'][ $anchor_block ] = $position ; $response->set_data( $data ); return $response; }; From 7c53caca0a50be5d89edddbc434641c0ed36a454 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 27 Jul 2023 11:00:01 +0200 Subject: [PATCH 10/62] Add explanatory comment --- lib/experimental/auto-inserting-blocks.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 9ec4505910dac..474f00bc06f1e 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -162,6 +162,14 @@ function gutenberg_register_auto_inserted_block( $inserted_block, $position, $an $inserter = gutenberg_auto_insert_block( $inserted_block_array, $position, $anchor_block ); add_filter( 'gutenberg_serialize_block', $inserter, 10, 1 ); + /* + * The block-types REST API controller uses objects of the `WP_Block_Type` class, which are + * in turn created upon block type registration. However, that class does not contain + * an `auto_insert` property (and is not easily extensible), so we have to use a different + * mechanism to communicate to the controller which blocks have been registered for + * auto-insertion. We're doing so here (i.e. upon block registration), by adding a filter to + * the controller's response. + */ $controller_extender = gutenberg_add_auto_insert_field_to_block_type_controller( $inserted_block, $position, $anchor_block ); add_filter( 'rest_prepare_block_type', $controller_extender, 10, 2 ); } From 145773b4f57d96e27cf29027b31ffb2724d9fcea Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 27 Jul 2023 11:29:18 +0200 Subject: [PATCH 11/62] Formatting --- lib/experimental/auto-inserting-blocks.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 474f00bc06f1e..e8ad11699214d 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -65,7 +65,7 @@ function gutenberg_auto_insert_block( $inserted_block, $relative_position, $anch } function gutenberg_add_auto_insert_field_to_block_type_controller( $inserted_block, $position, $anchor_block ) { - return function( $response, $block_type ) use ( $inserted_block, $position, $anchor_block ){ + return function( $response, $block_type ) use ( $inserted_block, $position, $anchor_block ) { if ( $block_type->name !== $inserted_block ) { return $response; } @@ -74,7 +74,7 @@ function gutenberg_add_auto_insert_field_to_block_type_controller( $inserted_blo if ( ! isset( $data['auto_insert'] ) ) { $data['auto_insert'] = array(); } - $data['auto_insert'][ $anchor_block ] = $position ; + $data['auto_insert'][ $anchor_block ] = $position; $response->set_data( $data ); return $response; }; @@ -289,7 +289,7 @@ function gutenberg_register_auto_insert_rest_field() { 'block-type', 'auto_insert', array( - 'schema' => array( + 'schema' => array( 'description' => __( 'Auto Insert.', 'default' ), 'type' => 'object', ), From fc3c472998e1ee08a17895c4f4223b95518c4f87 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 1 Aug 2023 10:54:46 +0200 Subject: [PATCH 12/62] Add __experimentalAutoInsert to block.json schema --- schemas/json/block.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/schemas/json/block.json b/schemas/json/block.json index 41434f58e4727..d0c570e9e7098 100644 --- a/schemas/json/block.json +++ b/schemas/json/block.json @@ -859,6 +859,17 @@ "render": { "type": "string", "description": "Template file loaded on the server when rendering a block." + }, + "__experimentalAutoInsert": { + "type": "object", + "description": "Blocks to auto-insert this block next to.", + "patternProperties": { + "[a-zA-Z]": { + "type": "string", + "description": "Position relative to the block to auto-insert this block next to.", + "enum": [ "before", "after", "firstChild", "lastChild" ] + } + } } }, "required": [ "name", "title" ], From ea2e4eea364870c7e63c6bdbeb132a1dca43f866 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 1 Aug 2023 11:46:30 +0200 Subject: [PATCH 13/62] Expose auto_insert field via unstable__bootstrapServerSideBlockDefinitions --- lib/experimental/auto-inserting-blocks.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index e8ad11699214d..451c290bccf2b 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -129,6 +129,12 @@ function gutenberg_register_auto_inserted_blocks( $settings, $metadata ) { $settings['auto_insert'][ $anchor_block_name ] = $mapped_position; } + // TODO: Make work for blocks registered via direct call to gutenberg_register_auto_inserted_block(). + wp_add_inline_script( + 'wp-blocks', + 'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( array( $inserted_block_name => $settings ) ) . ');', + ); + return $settings; } add_filter( 'block_type_metadata_settings', 'gutenberg_register_auto_inserted_blocks', 10, 2 ); From cd06950ed7eb85be68e40ad5d773cdb1827fb304 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 1 Aug 2023 11:58:25 +0200 Subject: [PATCH 14/62] Filter fields --- lib/experimental/auto-inserting-blocks.php | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 451c290bccf2b..cbd533a3d9844 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -129,10 +129,34 @@ function gutenberg_register_auto_inserted_blocks( $settings, $metadata ) { $settings['auto_insert'][ $anchor_block_name ] = $mapped_position; } + // Copied from `get_block_editor_server_block_settings()`. + $fields_to_pick = array( + 'api_version' => 'apiVersion', + 'title' => 'title', + 'description' => 'description', + 'icon' => 'icon', + 'attributes' => 'attributes', + 'provides_context' => 'providesContext', + 'uses_context' => 'usesContext', + 'selectors' => 'selectors', + 'supports' => 'supports', + 'category' => 'category', + 'styles' => 'styles', + 'textdomain' => 'textdomain', + 'parent' => 'parent', + 'ancestor' => 'ancestor', + 'keywords' => 'keywords', + 'example' => 'example', + 'variations' => 'variations', + ); + $fields_to_pick[ 'auto_insert' ] = 'autoInsert'; + + $exposed_settings = array_intersect_key( $settings, $fields_to_pick ); + // TODO: Make work for blocks registered via direct call to gutenberg_register_auto_inserted_block(). wp_add_inline_script( 'wp-blocks', - 'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( array( $inserted_block_name => $settings ) ) . ');', + 'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( array( $inserted_block_name => $exposed_settings ) ) . ');', ); return $settings; From dc7e09c4b27bc9d611d6b40a32c4d42f3c6c7895 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 1 Aug 2023 11:58:52 +0200 Subject: [PATCH 15/62] Formatting --- lib/experimental/auto-inserting-blocks.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index cbd533a3d9844..627d08cb8b27e 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -149,7 +149,7 @@ function gutenberg_register_auto_inserted_blocks( $settings, $metadata ) { 'example' => 'example', 'variations' => 'variations', ); - $fields_to_pick[ 'auto_insert' ] = 'autoInsert'; + $fields_to_pick['auto_insert'] = 'autoInsert'; $exposed_settings = array_intersect_key( $settings, $fields_to_pick ); From d385c35d2a573db0bdc0fd1ae59f271e52921a11 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 1 Aug 2023 13:57:56 +0200 Subject: [PATCH 16/62] Show basic list of auto-inserted block names in panel --- .../src/hooks/auto-inserting-blocks.js | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 096dcf5e0578c..e7556ea59702a 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -5,26 +5,46 @@ import { __ } from '@wordpress/i18n'; import { addFilter } from '@wordpress/hooks'; import { PanelBody } from '@wordpress/components'; import { createHigherOrderComponent } from '@wordpress/compose'; -// import { store as blocksStore } from '@wordpress/blocks'; -// import { useSelect } from '@wordpress/data'; +import { store as blocksStore } from '@wordpress/blocks'; +import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ import { InspectorControls } from '../components'; -function AutoInsertingBlocksControl() { - // const blocks = useSelect( ( select ) => { - // const { getBlockTypes } = select( blocksStore ); - // return getBlockTypes(); - // }, [] ); +function AutoInsertingBlocksControl( props ) { + const blocks = useSelect( ( select ) => { + const { getBlockTypes } = select( blocksStore ); + return getBlockTypes(); + }, [] ); + + const autoInsertedBlocksForCurrentBlock = blocks.reduce( + ( autoInsertedBlocks, block ) => { + if ( ! block.autoInsert ) { + return autoInsertedBlocks; + } + + const name = Object.keys( block.autoInsert ).find( + ( n ) => n === props.blockName + ); + if ( name !== undefined ) { + autoInsertedBlocks[ block.name ] = block.autoInsert[ name ]; + } + return autoInsertedBlocks; + }, + {} + ); return ( - + + { Object.keys( autoInsertedBlocksForCurrentBlock ).map( + ( blockName ) => { + return
{ blockName }
; + } + ) } +
); } @@ -36,7 +56,7 @@ export const withAutoInsertingBlocks = createHigherOrderComponent( return ( <> { blockEdit } - + ); }; From 5868df52be198ba774b4f653a34b2dfb6c49b22c Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 1 Aug 2023 14:03:46 +0200 Subject: [PATCH 17/62] Show auto-inserted block title --- .../block-editor/src/hooks/auto-inserting-blocks.js | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index e7556ea59702a..b37dd79f20edc 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -29,21 +29,19 @@ function AutoInsertingBlocksControl( props ) { ( n ) => n === props.blockName ); if ( name !== undefined ) { - autoInsertedBlocks[ block.name ] = block.autoInsert[ name ]; + autoInsertedBlocks.push( block ); } return autoInsertedBlocks; }, - {} + [] ); return ( - { Object.keys( autoInsertedBlocksForCurrentBlock ).map( - ( blockName ) => { - return
{ blockName }
; - } - ) } + { autoInsertedBlocksForCurrentBlock.map( ( block ) => { + return
{ block.title }
; + } ) }
); From 012c69fc3067795a7dab349eb9aa137774e4d299 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 1 Aug 2023 14:06:40 +0200 Subject: [PATCH 18/62] Simplify --- .../src/hooks/auto-inserting-blocks.js | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index b37dd79f20edc..bc3e55feb8c25 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -19,21 +19,10 @@ function AutoInsertingBlocksControl( props ) { return getBlockTypes(); }, [] ); - const autoInsertedBlocksForCurrentBlock = blocks.reduce( - ( autoInsertedBlocks, block ) => { - if ( ! block.autoInsert ) { - return autoInsertedBlocks; - } - - const name = Object.keys( block.autoInsert ).find( - ( n ) => n === props.blockName - ); - if ( name !== undefined ) { - autoInsertedBlocks.push( block ); - } - return autoInsertedBlocks; - }, - [] + const autoInsertedBlocksForCurrentBlock = blocks.filter( + ( block ) => + block.autoInsert && + Object.keys( block.autoInsert ).includes( props.blockName ) ); return ( From 6d1f6dac31f94fe399e2002b4ded824d276e0ec2 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 1 Aug 2023 14:38:22 +0200 Subject: [PATCH 19/62] Basic list with icons --- .../src/hooks/auto-inserting-blocks.js | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index bc3e55feb8c25..f5f606ec374eb 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -11,7 +11,7 @@ import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ -import { InspectorControls } from '../components'; +import { BlockIcon, InspectorControls } from '../components'; function AutoInsertingBlocksControl( props ) { const blocks = useSelect( ( select ) => { @@ -29,7 +29,19 @@ function AutoInsertingBlocksControl( props ) { { autoInsertedBlocksForCurrentBlock.map( ( block ) => { - return
{ block.title }
; + return ( +
+ +
+

+ { block.title } +

+
+
+ ); } ) }
From 42338a4ec8035fbf52d3ceca2381affb167ee9f5 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 1 Aug 2023 15:15:32 +0200 Subject: [PATCH 20/62] Group by vendor --- .../src/hooks/auto-inserting-blocks.js | 47 ++++++++++++++----- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index f5f606ec374eb..64d6738708e8c 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -3,6 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { addFilter } from '@wordpress/hooks'; +import { Fragment } from '@wordpress/element'; import { PanelBody } from '@wordpress/components'; import { createHigherOrderComponent } from '@wordpress/compose'; import { store as blocksStore } from '@wordpress/blocks'; @@ -25,22 +26,44 @@ function AutoInsertingBlocksControl( props ) { Object.keys( block.autoInsert ).includes( props.blockName ) ); + // Group by block name prefix (before the slash). + const groupedAutoInsertedBlocks = autoInsertedBlocksForCurrentBlock.reduce( + ( acc, block ) => { + const [ prefix ] = block.name.split( '/' ); + if ( ! acc[ prefix ] ) { + acc[ prefix ] = []; + } + acc[ prefix ].push( block ); + return acc; + }, + {} + ); + return ( - { autoInsertedBlocksForCurrentBlock.map( ( block ) => { + { Object.keys( groupedAutoInsertedBlocks ).map( ( vendor ) => { return ( -
- -
-

- { block.title } -

-
-
+ +

{ vendor }

+ { groupedAutoInsertedBlocks[ vendor ].map( + ( block ) => { + return ( +
+ +
+

+ { block.title } +

+
+
+ ); + } + ) } +
); } ) }
From 8568c66d75bbea34dc7ddd7a02c3a785c7f9e249 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 3 Aug 2023 14:57:09 +0200 Subject: [PATCH 21/62] Nicer naming in grouping reduce call --- .../block-editor/src/hooks/auto-inserting-blocks.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 64d6738708e8c..81da06e622ef0 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -26,15 +26,15 @@ function AutoInsertingBlocksControl( props ) { Object.keys( block.autoInsert ).includes( props.blockName ) ); - // Group by block name prefix (before the slash). + // Group by block namespace (i.e. prefix before the slash). const groupedAutoInsertedBlocks = autoInsertedBlocksForCurrentBlock.reduce( - ( acc, block ) => { + ( groups, block ) => { const [ prefix ] = block.name.split( '/' ); - if ( ! acc[ prefix ] ) { - acc[ prefix ] = []; + if ( ! groups[ prefix ] ) { + groups[ prefix ] = []; } - acc[ prefix ].push( block ); - return acc; + groups[ prefix ].push( block ); + return groups; }, {} ); From 6cdb95d13e007f6b2c907b7190046d7e02f9f00a Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 3 Aug 2023 14:58:59 +0200 Subject: [PATCH 22/62] Implement basic toggle-controlled insertion --- .../src/hooks/auto-inserting-blocks.js | 68 ++++++++++++++----- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 81da06e622ef0..a05745f3d465f 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -3,23 +3,42 @@ */ import { __ } from '@wordpress/i18n'; import { addFilter } from '@wordpress/hooks'; -import { Fragment } from '@wordpress/element'; -import { PanelBody } from '@wordpress/components'; +import { Fragment, useState } from '@wordpress/element'; +import { PanelBody, ToggleControl } from '@wordpress/components'; import { createHigherOrderComponent } from '@wordpress/compose'; -import { store as blocksStore } from '@wordpress/blocks'; -import { useSelect } from '@wordpress/data'; +import { createBlock, store as blocksStore } from '@wordpress/blocks'; +import { useDispatch, useSelect } from '@wordpress/data'; /** * Internal dependencies */ -import { BlockIcon, InspectorControls } from '../components'; +import { InspectorControls } from '../components'; +import { store as blockEditorStore } from '../store'; function AutoInsertingBlocksControl( props ) { + // FIXME: Properly set toggle state based on presence of auto-inserted block. + const [ toggleStatus, setToggleStatus ] = useState( false ); + const blocks = useSelect( ( select ) => { const { getBlockTypes } = select( blocksStore ); return getBlockTypes(); }, [] ); + const { blockIndex, rootClientId } = useSelect( + ( select ) => { + const { getBlockIndex, getBlockRootClientId } = + select( blockEditorStore ); + const _rootClientId = getBlockRootClientId( props.clientId ); + return { + blockIndex: getBlockIndex( props.clientId ), + rootClientId: _rootClientId, + }; + }, + [ props.clientId ] + ); + + const { insertBlock } = useDispatch( blockEditorStore ); + const autoInsertedBlocksForCurrentBlock = blocks.filter( ( block ) => block.autoInsert && @@ -48,18 +67,30 @@ function AutoInsertingBlocksControl( props ) {

{ vendor }

{ groupedAutoInsertedBlocks[ vendor ].map( ( block ) => { + // TODO: Display block icon. + // return ( -
- -
-

- { block.title } -

-
-
+ { + if ( ! toggleStatus ) { + insertBlock( + createBlock( + block.name + ), + blockIndex + 1, + rootClientId, + false + ); + } + + setToggleStatus( + ! toggleStatus + ); + } } + /> ); } ) } @@ -78,7 +109,10 @@ export const withAutoInsertingBlocks = createHigherOrderComponent( return ( <> { blockEdit } - + ); }; From 41fa152737ed2e564ab4b3558675ddfe09e9d0d2 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 3 Aug 2023 15:18:13 +0200 Subject: [PATCH 23/62] Handle 'before' insertion --- .../src/hooks/auto-inserting-blocks.js | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index a05745f3d465f..4a1f2a45ac6dc 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -69,6 +69,14 @@ function AutoInsertingBlocksControl( props ) { ( block ) => { // TODO: Display block icon. // + + const relativePosition = + block.autoInsert[ props.blockName ]; + const insertionIndex = + relativePosition === 'after' + ? blockIndex + 1 + : blockIndex; + return ( { if ( ! toggleStatus ) { - insertBlock( - createBlock( - block.name - ), - blockIndex + 1, - rootClientId, - false - ); + if ( + [ + 'before', + 'after', + ].includes( + relativePosition + ) + ) { + insertBlock( + createBlock( + block.name + ), + insertionIndex, + rootClientId, + false + ); + } + // TODO: Implement first_child and last_child insertion. } setToggleStatus( From e4d32cc7f88c476520cd9754b54e9cbb9817f221 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 8 Aug 2023 14:53:42 +0200 Subject: [PATCH 24/62] Implement basic 'after' block removal --- .../src/hooks/auto-inserting-blocks.js | 95 ++++++++++++++----- 1 file changed, 70 insertions(+), 25 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 4a1f2a45ac6dc..29c7527d1ce74 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -3,7 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { addFilter } from '@wordpress/hooks'; -import { Fragment, useState } from '@wordpress/element'; +import { Fragment } from '@wordpress/element'; import { PanelBody, ToggleControl } from '@wordpress/components'; import { createHigherOrderComponent } from '@wordpress/compose'; import { createBlock, store as blocksStore } from '@wordpress/blocks'; @@ -16,34 +16,66 @@ import { InspectorControls } from '../components'; import { store as blockEditorStore } from '../store'; function AutoInsertingBlocksControl( props ) { - // FIXME: Properly set toggle state based on presence of auto-inserted block. - const [ toggleStatus, setToggleStatus ] = useState( false ); - - const blocks = useSelect( ( select ) => { - const { getBlockTypes } = select( blocksStore ); - return getBlockTypes(); - }, [] ); + const autoInsertedBlocksForCurrentBlock = useSelect( + ( select ) => { + const { getBlockTypes } = select( blocksStore ); + return getBlockTypes()?.filter( + ( block ) => + block.autoInsert && + Object.keys( block.autoInsert ).includes( props.blockName ) + ); + }, + [ props.blockName ] + ); - const { blockIndex, rootClientId } = useSelect( + const { blocks, blockIndex, rootClientId } = useSelect( ( select ) => { - const { getBlockIndex, getBlockRootClientId } = - select( blockEditorStore ); + const { + getBlock, + getBlockIndex, + getBlockRootClientId, + getNextBlockClientId, + } = select( blockEditorStore ); const _rootClientId = getBlockRootClientId( props.clientId ); + + // Iterate over all auto-inserted blocks after the current block, until there are no more + // Probably there won't be that many auto-inserted blocks. + // We still need to check everything after. + const _blocks = autoInsertedBlocksForCurrentBlock.reduce( + ( acc, block ) => { + const relativePosition = + block?.autoInsert?.[ props.blockName ]; + + if ( relativePosition === 'after' ) { + // Could do a `for` loop instead. + let clientId = props.clientId; + while ( + ( clientId = getNextBlockClientId( clientId ) ) + ) { + if ( + getBlock( clientId )?.blockName === + block.blockName + ) { + acc.after[ block.name ] = clientId; + return acc; + } + } + } + return acc; + }, + { before: {}, after: {}, firstChild: {}, lastChild: {} } + ); + return { blockIndex: getBlockIndex( props.clientId ), rootClientId: _rootClientId, + blocks: _blocks, }; }, - [ props.clientId ] + [ autoInsertedBlocksForCurrentBlock, props.blockName, props.clientId ] ); - const { insertBlock } = useDispatch( blockEditorStore ); - - const autoInsertedBlocksForCurrentBlock = blocks.filter( - ( block ) => - block.autoInsert && - Object.keys( block.autoInsert ).includes( props.blockName ) - ); + const { insertBlock, removeBlock } = useDispatch( blockEditorStore ); // Group by block namespace (i.e. prefix before the slash). const groupedAutoInsertedBlocks = autoInsertedBlocksForCurrentBlock.reduce( @@ -72,6 +104,14 @@ function AutoInsertingBlocksControl( props ) { const relativePosition = block.autoInsert[ props.blockName ]; + + let checked = false; + if ( relativePosition === 'after' ) { + checked = Object.keys( + blocks.after + ).includes( block.name ); + } + const insertionIndex = relativePosition === 'after' ? blockIndex + 1 @@ -79,11 +119,11 @@ function AutoInsertingBlocksControl( props ) { return ( { - if ( ! toggleStatus ) { + if ( ! checked ) { if ( [ 'before', @@ -102,11 +142,16 @@ function AutoInsertingBlocksControl( props ) { ); } // TODO: Implement first_child and last_child insertion. + } else if ( + // Remove block. + relativePosition === 'after' + ) { + const clientId = + blocks.after[ + block.name + ]; + removeBlock( clientId ); } - - setToggleStatus( - ! toggleStatus - ); } } /> ); From db4c7eb92440a7604c633da614b7ca64f818f161 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 8 Aug 2023 15:07:16 +0200 Subject: [PATCH 25/62] Implement basic 'before' block removal --- .../src/hooks/auto-inserting-blocks.js | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 29c7527d1ce74..d3c31deea3256 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -34,7 +34,7 @@ function AutoInsertingBlocksControl( props ) { getBlock, getBlockIndex, getBlockRootClientId, - getNextBlockClientId, + getAdjacentBlockClientId, } = select( blockEditorStore ); const _rootClientId = getBlockRootClientId( props.clientId ); @@ -46,24 +46,27 @@ function AutoInsertingBlocksControl( props ) { const relativePosition = block?.autoInsert?.[ props.blockName ]; - if ( relativePosition === 'after' ) { - // Could do a `for` loop instead. + if ( [ 'before', 'after' ].includes( relativePosition ) ) { + const direction = relativePosition === 'after' ? 1 : -1; let clientId = props.clientId; while ( - ( clientId = getNextBlockClientId( clientId ) ) + ( clientId = getAdjacentBlockClientId( + clientId, + direction + ) ) ) { if ( getBlock( clientId )?.blockName === block.blockName ) { - acc.after[ block.name ] = clientId; + acc[ block.name ] = clientId; return acc; } } } return acc; }, - { before: {}, after: {}, firstChild: {}, lastChild: {} } + {} ); return { @@ -105,12 +108,9 @@ function AutoInsertingBlocksControl( props ) { const relativePosition = block.autoInsert[ props.blockName ]; - let checked = false; - if ( relativePosition === 'after' ) { - checked = Object.keys( - blocks.after - ).includes( block.name ); - } + const checked = Object.keys( + blocks + ).includes( block.name ); const insertionIndex = relativePosition === 'after' @@ -143,13 +143,16 @@ function AutoInsertingBlocksControl( props ) { } // TODO: Implement first_child and last_child insertion. } else if ( - // Remove block. - relativePosition === 'after' + [ + 'before', + 'after', + ].includes( + relativePosition + ) ) { + // Remove block. const clientId = - blocks.after[ - block.name - ]; + blocks[ block.name ]; removeBlock( clientId ); } } } From feea87fc6ddc50ccb6963307e8b50a8143f52132 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 8 Aug 2023 15:41:59 +0200 Subject: [PATCH 26/62] Fix --- .../src/hooks/auto-inserting-blocks.js | 47 +++++++++---------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index d3c31deea3256..c68b94dec5e5f 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -55,10 +55,7 @@ function AutoInsertingBlocksControl( props ) { direction ) ) ) { - if ( - getBlock( clientId )?.blockName === - block.blockName - ) { + if ( getBlock( clientId )?.name === block.name ) { acc[ block.name ] = clientId; return acc; } @@ -123,15 +120,15 @@ function AutoInsertingBlocksControl( props ) { key={ block.title } label={ block.title } onChange={ () => { - if ( ! checked ) { - if ( - [ - 'before', - 'after', - ].includes( - relativePosition - ) - ) { + if ( + [ + 'before', + 'after', + ].includes( + relativePosition + ) + ) { + if ( ! checked ) { insertBlock( createBlock( block.name @@ -140,21 +137,19 @@ function AutoInsertingBlocksControl( props ) { rootClientId, false ); + } else { + // Remove block. + const clientId = + blocks[ + block.name + ]; + removeBlock( + clientId, + false + ); } - // TODO: Implement first_child and last_child insertion. - } else if ( - [ - 'before', - 'after', - ].includes( - relativePosition - ) - ) { - // Remove block. - const clientId = - blocks[ block.name ]; - removeBlock( clientId ); } + // TODO: Implement first_child and last_child insertion and removal. } } /> ); From bba74afe9ed4622404e51d5c3e6991783bc5ccb8 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 9 Aug 2023 13:55:31 +0200 Subject: [PATCH 27/62] Add inline TODO note --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index c68b94dec5e5f..63a5ecc35d341 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -49,6 +49,7 @@ function AutoInsertingBlocksControl( props ) { if ( [ 'before', 'after' ].includes( relativePosition ) ) { const direction = relativePosition === 'after' ? 1 : -1; let clientId = props.clientId; + // TODO: Also stop when we encounter a non-auto-inserted block. while ( ( clientId = getAdjacentBlockClientId( clientId, From 373939590e20fa0a14dcde2a370418e53c9660f3 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 9 Aug 2023 13:56:52 +0200 Subject: [PATCH 28/62] Implement first/last child insertion --- .../src/hooks/auto-inserting-blocks.js | 69 +++++++++++++++++-- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 63a5ecc35d341..79cbeaed1aee9 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -28,7 +28,7 @@ function AutoInsertingBlocksControl( props ) { [ props.blockName ] ); - const { blocks, blockIndex, rootClientId } = useSelect( + const { blocks, blockIndex, rootClientId, innerBlocksLength } = useSelect( ( select ) => { const { getBlock, @@ -61,6 +61,27 @@ function AutoInsertingBlocksControl( props ) { return acc; } } + } else if ( + [ 'first_child', 'last_child' ].includes( + relativePosition + ) + ) { + let clientId = props.clientId; + const { innerBlocks } = getBlock( clientId ); + // TODO: Keep iterating if it's not the last/first child. + if ( innerBlocks?.length ) { + if ( relativePosition === 'first_child' ) { + clientId = innerBlocks[ 0 ].clientId; + } else { + clientId = + innerBlocks[ innerBlocks.length - 1 ] + .clientId; + } + if ( getBlock( clientId )?.name === block.name ) { + acc[ block.name ] = clientId; + return acc; + } + } } return acc; }, @@ -69,6 +90,8 @@ function AutoInsertingBlocksControl( props ) { return { blockIndex: getBlockIndex( props.clientId ), + innerBlocksLength: getBlock( props.clientId )?.innerBlocks + ?.length, rootClientId: _rootClientId, blocks: _blocks, }; @@ -110,11 +133,6 @@ function AutoInsertingBlocksControl( props ) { blocks ).includes( block.name ); - const insertionIndex = - relativePosition === 'after' - ? blockIndex + 1 - : blockIndex; - return ( Date: Wed, 9 Aug 2023 14:21:50 +0200 Subject: [PATCH 29/62] Simplify --- .../src/hooks/auto-inserting-blocks.js | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 79cbeaed1aee9..5579718d6864b 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -66,21 +66,20 @@ function AutoInsertingBlocksControl( props ) { relativePosition ) ) { - let clientId = props.clientId; - const { innerBlocks } = getBlock( clientId ); + const { innerBlocks } = getBlock( props.clientId ); + + if ( ! innerBlocks?.length ) { + return acc; + } + + const { clientId } = innerBlocks.at( + relativePosition === 'first_child' ? 0 : -1 + ); + // TODO: Keep iterating if it's not the last/first child. - if ( innerBlocks?.length ) { - if ( relativePosition === 'first_child' ) { - clientId = innerBlocks[ 0 ].clientId; - } else { - clientId = - innerBlocks[ innerBlocks.length - 1 ] - .clientId; - } - if ( getBlock( clientId )?.name === block.name ) { - acc[ block.name ] = clientId; - return acc; - } + if ( getBlock( clientId )?.name === block.name ) { + acc[ block.name ] = clientId; + return acc; } } return acc; From 92442d08b05af11d6d3a14e7c53e6e8d92c8aabf Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 9 Aug 2023 14:40:39 +0200 Subject: [PATCH 30/62] Stop before/after check if we encounter a non-auto-inserted block --- .../block-editor/src/hooks/auto-inserting-blocks.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 5579718d6864b..ba282f9262dc2 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -49,7 +49,7 @@ function AutoInsertingBlocksControl( props ) { if ( [ 'before', 'after' ].includes( relativePosition ) ) { const direction = relativePosition === 'after' ? 1 : -1; let clientId = props.clientId; - // TODO: Also stop when we encounter a non-auto-inserted block. + while ( ( clientId = getAdjacentBlockClientId( clientId, @@ -60,6 +60,17 @@ function AutoInsertingBlocksControl( props ) { acc[ block.name ] = clientId; return acc; } + + // Stop if we encounter a non-auto-inserted block. + if ( + ! autoInsertedBlocksForCurrentBlock.some( + ( autoInsertedBlock ) => + autoInsertedBlock.name === + getBlock( clientId )?.name + ) + ) { + return acc; + } } } else if ( [ 'first_child', 'last_child' ].includes( From 8534c83c0312fd36ea7ac4db844ba2e36302f91e Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 9 Aug 2023 14:42:04 +0200 Subject: [PATCH 31/62] Add explanatory comment --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index ba282f9262dc2..7bd08b8e098c2 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -61,7 +61,8 @@ function AutoInsertingBlocksControl( props ) { return acc; } - // Stop if we encounter a non-auto-inserted block. + // Stop if we encounter a non-auto-inserted block. Any block on the other side + // of a manually inserted block cannot qualify as an auto-inserted block. if ( ! autoInsertedBlocksForCurrentBlock.some( ( autoInsertedBlock ) => From f0ad1502eb67b638044afbf7a2cbeb590ff69dc1 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 9 Aug 2023 14:48:14 +0200 Subject: [PATCH 32/62] Clarify comment --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 7bd08b8e098c2..4e4cd2a66fa39 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -38,9 +38,10 @@ function AutoInsertingBlocksControl( props ) { } = select( blockEditorStore ); const _rootClientId = getBlockRootClientId( props.clientId ); - // Iterate over all auto-inserted blocks after the current block, until there are no more - // Probably there won't be that many auto-inserted blocks. - // We still need to check everything after. + // It's possible that there are multiple auto-inserted blocks, so in order to + // locate them all, we have to iterate over all auto-inserted sibiling blocks + // before or after the current block, respectively. We stop iterating once there + // are no more blocks, or if we encounter a manually inserted block. const _blocks = autoInsertedBlocksForCurrentBlock.reduce( ( acc, block ) => { const relativePosition = From 6312e2da009adb52535de0cdfd82e5dc6e7cdcab Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 9 Aug 2023 14:50:02 +0200 Subject: [PATCH 33/62] Don't show panel if there are no auto-inserting blocks --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 4e4cd2a66fa39..cb0682953493e 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -113,6 +113,10 @@ function AutoInsertingBlocksControl( props ) { const { insertBlock, removeBlock } = useDispatch( blockEditorStore ); + if ( ! autoInsertedBlocksForCurrentBlock.length ) { + return null; + } + // Group by block namespace (i.e. prefix before the slash). const groupedAutoInsertedBlocks = autoInsertedBlocksForCurrentBlock.reduce( ( groups, block ) => { From 2d063f0fdce0a8cd43549e1cbfc57bf73abc54c5 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 9 Aug 2023 15:01:28 +0200 Subject: [PATCH 34/62] Consider other potentially auto-inserted first/last child blocks --- .../src/hooks/auto-inserting-blocks.js | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index cb0682953493e..10a3c90c8c5fa 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -85,14 +85,40 @@ function AutoInsertingBlocksControl( props ) { return acc; } - const { clientId } = innerBlocks.at( + // Note that the direction is reversed, compared to before/after: + // E.g. when looking for a potential last child, we have to start at the + // last element and then go backwards. + const direction = + relativePosition === 'last_child' ? -1 : 1; + let { clientId } = innerBlocks.at( relativePosition === 'first_child' ? 0 : -1 ); - // TODO: Keep iterating if it's not the last/first child. - if ( getBlock( clientId )?.name === block.name ) { - acc[ block.name ] = clientId; - return acc; + while ( clientId ) { + if ( getBlock( clientId )?.name === block.name ) { + acc[ block.name ] = clientId; + return acc; + } + + // Stop if we encounter a non-auto-inserted block. Any block on the other side + // of a manually inserted block cannot qualify as an auto-inserted block. + if ( + ! autoInsertedBlocksForCurrentBlock.some( + ( autoInsertedBlock ) => + autoInsertedBlock.name === + getBlock( clientId )?.name && + autoInsertedBlock.autoInsert[ + props.blockName + ] === relativePosition + ) + ) { + return acc; + } + + clientId = getAdjacentBlockClientId( + clientId, + direction + ); } } return acc; From 89cdb634f55b2847816690d1c2de75fd616f912f Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 14:50:12 +0200 Subject: [PATCH 35/62] Revert "Add __experimentalAutoInsert to block.json schema" This reverts commit c758751f01dca2532f44c5e10f1590818e66338c. --- schemas/json/block.json | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/schemas/json/block.json b/schemas/json/block.json index d0c570e9e7098..41434f58e4727 100644 --- a/schemas/json/block.json +++ b/schemas/json/block.json @@ -859,17 +859,6 @@ "render": { "type": "string", "description": "Template file loaded on the server when rendering a block." - }, - "__experimentalAutoInsert": { - "type": "object", - "description": "Blocks to auto-insert this block next to.", - "patternProperties": { - "[a-zA-Z]": { - "type": "string", - "description": "Position relative to the block to auto-insert this block next to.", - "enum": [ "before", "after", "firstChild", "lastChild" ] - } - } } }, "required": [ "name", "title" ], From 2d15887612eab2b8cda8363f4dcb83649116fda8 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 14:54:19 +0200 Subject: [PATCH 36/62] Remove now-obsolete comment --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 10a3c90c8c5fa..f600e9e9c2e70 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -249,7 +249,6 @@ function AutoInsertingBlocksControl( props ) { ); } } - // TODO: Implement first_child and last_child insertion and removal. } } /> ); From ab3a254e0190c9670be1f0a064f220810579fdb7 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 15:04:41 +0200 Subject: [PATCH 37/62] Simplify --- .../src/hooks/auto-inserting-blocks.js | 88 ++++++++----------- 1 file changed, 38 insertions(+), 50 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index f600e9e9c2e70..6793c4ba392f7 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -181,6 +181,18 @@ function AutoInsertingBlocksControl( props ) { key={ block.title } label={ block.title } onChange={ () => { + if ( checked ) { + // Remove block. + const clientId = + blocks[ block.name ]; + removeBlock( + clientId, + false + ); + return; + } + + // Insert block. if ( [ 'before', @@ -189,32 +201,20 @@ function AutoInsertingBlocksControl( props ) { relativePosition ) ) { - if ( ! checked ) { - const insertionIndex = - relativePosition === - 'after' - ? blockIndex + 1 - : blockIndex; + const insertionIndex = + relativePosition === + 'after' + ? blockIndex + 1 + : blockIndex; - insertBlock( - createBlock( - block.name - ), - insertionIndex, - rootClientId, - false - ); - } else { - // Remove block. - const clientId = - blocks[ - block.name - ]; - removeBlock( - clientId, - false - ); - } + insertBlock( + createBlock( + block.name + ), + insertionIndex, + rootClientId, + false + ); } else if ( [ 'first_child', @@ -223,31 +223,19 @@ function AutoInsertingBlocksControl( props ) { relativePosition ) ) { - if ( ! checked ) { - const insertionIndex = - relativePosition === - 'first_child' - ? 0 - : innerBlocksLength; - insertBlock( - createBlock( - block.name - ), - insertionIndex, - props.clientId, - false - ); - } else { - // Remove block. - const clientId = - blocks[ - block.name - ]; - removeBlock( - clientId, - false - ); - } + const insertionIndex = + relativePosition === + 'first_child' + ? 0 + : innerBlocksLength; + insertBlock( + createBlock( + block.name + ), + insertionIndex, + props.clientId, + false + ); } } } /> From 085cd859e05f6723772c3eeb41ee8d1fbf5e4313 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 15:11:48 +0200 Subject: [PATCH 38/62] Extract insertBlockIntoDesignatedLocation() function --- .../src/hooks/auto-inserting-blocks.js | 76 ++++++++----------- 1 file changed, 32 insertions(+), 44 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 6793c4ba392f7..fed7ab915733e 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -156,6 +156,34 @@ function AutoInsertingBlocksControl( props ) { {} ); + const insertBlockIntoDesignatedLocation = ( + blockName, + relativePosition + ) => { + if ( [ 'before', 'after' ].includes( relativePosition ) ) { + const insertionIndex = + relativePosition === 'after' ? blockIndex + 1 : blockIndex; + + insertBlock( + createBlock( blockName ), + insertionIndex, + rootClientId, + false + ); + } else if ( + [ 'first_child', 'last_child' ].includes( relativePosition ) + ) { + const insertionIndex = + relativePosition === 'first_child' ? 0 : innerBlocksLength; + insertBlock( + createBlock( blockName ), + insertionIndex, + props.clientId, + false + ); + } + }; + return ( @@ -193,50 +221,10 @@ function AutoInsertingBlocksControl( props ) { } // Insert block. - if ( - [ - 'before', - 'after', - ].includes( - relativePosition - ) - ) { - const insertionIndex = - relativePosition === - 'after' - ? blockIndex + 1 - : blockIndex; - - insertBlock( - createBlock( - block.name - ), - insertionIndex, - rootClientId, - false - ); - } else if ( - [ - 'first_child', - 'last_child', - ].includes( - relativePosition - ) - ) { - const insertionIndex = - relativePosition === - 'first_child' - ? 0 - : innerBlocksLength; - insertBlock( - createBlock( - block.name - ), - insertionIndex, - props.clientId, - false - ); - } + insertBlockIntoDesignatedLocation( + block.name, + relativePosition + ); } } /> ); From c4239412668815f06932b5270205327478348794 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 15:17:27 +0200 Subject: [PATCH 39/62] Clean up a bit --- .../src/hooks/auto-inserting-blocks.js | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index fed7ab915733e..913e3695f99f8 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -156,29 +156,21 @@ function AutoInsertingBlocksControl( props ) { {} ); - const insertBlockIntoDesignatedLocation = ( - blockName, - relativePosition - ) => { + const insertBlockIntoDesignatedLocation = ( block, relativePosition ) => { if ( [ 'before', 'after' ].includes( relativePosition ) ) { - const insertionIndex = - relativePosition === 'after' ? blockIndex + 1 : blockIndex; - insertBlock( - createBlock( blockName ), - insertionIndex, - rootClientId, + block, + relativePosition === 'after' ? blockIndex + 1 : blockIndex, + rootClientId, // Insert as a child of the current block's parent false ); } else if ( [ 'first_child', 'last_child' ].includes( relativePosition ) ) { - const insertionIndex = - relativePosition === 'first_child' ? 0 : innerBlocksLength; insertBlock( - createBlock( blockName ), - insertionIndex, - props.clientId, + block, + relativePosition === 'first_child' ? 0 : innerBlocksLength, + props.clientId, // Insert as a child of the current block. false ); } @@ -220,9 +212,9 @@ function AutoInsertingBlocksControl( props ) { return; } - // Insert block. + // Create and insert block. insertBlockIntoDesignatedLocation( - block.name, + createBlock( block.name ), relativePosition ); } } From a938ca0b200886d1f428c20df280839623776842 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 17:01:23 +0200 Subject: [PATCH 40/62] Accept any sibling blocks as after/before, and any child as first/last child --- .../src/hooks/auto-inserting-blocks.js | 91 ++++--------------- 1 file changed, 18 insertions(+), 73 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 913e3695f99f8..95c576b1ffc6e 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -30,50 +30,24 @@ function AutoInsertingBlocksControl( props ) { const { blocks, blockIndex, rootClientId, innerBlocksLength } = useSelect( ( select ) => { - const { - getBlock, - getBlockIndex, - getBlockRootClientId, - getAdjacentBlockClientId, - } = select( blockEditorStore ); + const { getBlock, getBlockIndex, getBlockRootClientId } = + select( blockEditorStore ); const _rootClientId = getBlockRootClientId( props.clientId ); - // It's possible that there are multiple auto-inserted blocks, so in order to - // locate them all, we have to iterate over all auto-inserted sibiling blocks - // before or after the current block, respectively. We stop iterating once there - // are no more blocks, or if we encounter a manually inserted block. const _blocks = autoInsertedBlocksForCurrentBlock.reduce( ( acc, block ) => { const relativePosition = block?.autoInsert?.[ props.blockName ]; - + let autoInsertedBlock; if ( [ 'before', 'after' ].includes( relativePosition ) ) { - const direction = relativePosition === 'after' ? 1 : -1; - let clientId = props.clientId; - - while ( - ( clientId = getAdjacentBlockClientId( - clientId, - direction - ) ) - ) { - if ( getBlock( clientId )?.name === block.name ) { - acc[ block.name ] = clientId; - return acc; - } + const siblings = getBlock( _rootClientId )?.innerBlocks; - // Stop if we encounter a non-auto-inserted block. Any block on the other side - // of a manually inserted block cannot qualify as an auto-inserted block. - if ( - ! autoInsertedBlocksForCurrentBlock.some( - ( autoInsertedBlock ) => - autoInsertedBlock.name === - getBlock( clientId )?.name - ) - ) { - return acc; - } - } + // Any of the current block's siblings (with the right block type) qualifies + // as an auto-inserted block (inserted `before` or `after` the current one), + // as the block might've been auto-inserted and then moved around a bit by the user. + autoInsertedBlock = siblings.find( + ( { name } ) => name === block.name + ); } else if ( [ 'first_child', 'last_child' ].includes( relativePosition @@ -81,45 +55,16 @@ function AutoInsertingBlocksControl( props ) { ) { const { innerBlocks } = getBlock( props.clientId ); - if ( ! innerBlocks?.length ) { - return acc; - } - - // Note that the direction is reversed, compared to before/after: - // E.g. when looking for a potential last child, we have to start at the - // last element and then go backwards. - const direction = - relativePosition === 'last_child' ? -1 : 1; - let { clientId } = innerBlocks.at( - relativePosition === 'first_child' ? 0 : -1 + // Any of the current block's child blocks (with the right block type) qualifies + // as an auto-inserted first or last child block, as the block might've been + // auto-inserted and then moved around a bit by the user. + autoInsertedBlock = innerBlocks.find( + ( { name } ) => name === block.name ); + } - while ( clientId ) { - if ( getBlock( clientId )?.name === block.name ) { - acc[ block.name ] = clientId; - return acc; - } - - // Stop if we encounter a non-auto-inserted block. Any block on the other side - // of a manually inserted block cannot qualify as an auto-inserted block. - if ( - ! autoInsertedBlocksForCurrentBlock.some( - ( autoInsertedBlock ) => - autoInsertedBlock.name === - getBlock( clientId )?.name && - autoInsertedBlock.autoInsert[ - props.blockName - ] === relativePosition - ) - ) { - return acc; - } - - clientId = getAdjacentBlockClientId( - clientId, - direction - ); - } + if ( autoInsertedBlock ) { + acc[ block.name ] = autoInsertedBlock.clientId; } return acc; }, From 406391cf03dd19a15f79c5051373a83291e6d452 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 18:55:27 +0200 Subject: [PATCH 41/62] Rename blocks variable to autoInsertedBlockClientIds --- .../src/hooks/auto-inserting-blocks.js | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 95c576b1ffc6e..06b25ef96cc29 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -28,14 +28,19 @@ function AutoInsertingBlocksControl( props ) { [ props.blockName ] ); - const { blocks, blockIndex, rootClientId, innerBlocksLength } = useSelect( + const { + autoInsertedBlockClientIds, + blockIndex, + rootClientId, + innerBlocksLength, + } = useSelect( ( select ) => { const { getBlock, getBlockIndex, getBlockRootClientId } = select( blockEditorStore ); const _rootClientId = getBlockRootClientId( props.clientId ); - const _blocks = autoInsertedBlocksForCurrentBlock.reduce( - ( acc, block ) => { + const _autoInsertedBlockClientIds = + autoInsertedBlocksForCurrentBlock.reduce( ( acc, block ) => { const relativePosition = block?.autoInsert?.[ props.blockName ]; let autoInsertedBlock; @@ -67,16 +72,14 @@ function AutoInsertingBlocksControl( props ) { acc[ block.name ] = autoInsertedBlock.clientId; } return acc; - }, - {} - ); + }, {} ); return { blockIndex: getBlockIndex( props.clientId ), innerBlocksLength: getBlock( props.clientId )?.innerBlocks ?.length, rootClientId: _rootClientId, - blocks: _blocks, + autoInsertedBlockClientIds: _autoInsertedBlockClientIds, }; }, [ autoInsertedBlocksForCurrentBlock, props.blockName, props.clientId ] @@ -137,7 +140,7 @@ function AutoInsertingBlocksControl( props ) { block.autoInsert[ props.blockName ]; const checked = Object.keys( - blocks + autoInsertedBlockClientIds ).includes( block.name ); return ( @@ -149,7 +152,9 @@ function AutoInsertingBlocksControl( props ) { if ( checked ) { // Remove block. const clientId = - blocks[ block.name ]; + autoInsertedBlockClientIds[ + block.name + ]; removeBlock( clientId, false From c91ce6515b10a984de601c2f826be7ed8f4d2bdb Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 19:03:35 +0200 Subject: [PATCH 42/62] Move code around a bit to make more intuitive --- .../src/hooks/auto-inserting-blocks.js | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 06b25ef96cc29..9aa473b0ecf7c 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -136,9 +136,6 @@ function AutoInsertingBlocksControl( props ) { // TODO: Display block icon. // - const relativePosition = - block.autoInsert[ props.blockName ]; - const checked = Object.keys( autoInsertedBlockClientIds ).includes( block.name ); @@ -149,24 +146,27 @@ function AutoInsertingBlocksControl( props ) { key={ block.title } label={ block.title } onChange={ () => { - if ( checked ) { - // Remove block. - const clientId = - autoInsertedBlockClientIds[ - block.name + if ( ! checked ) { + // Create and insert block. + const relativePosition = + block.autoInsert[ + props.blockName ]; - removeBlock( - clientId, - false + insertBlockIntoDesignatedLocation( + createBlock( + block.name + ), + relativePosition ); return; } - // Create and insert block. - insertBlockIntoDesignatedLocation( - createBlock( block.name ), - relativePosition - ); + // Remove block. + const clientId = + autoInsertedBlockClientIds[ + block.name + ]; + removeBlock( clientId, false ); } } /> ); From 7ab4cfe17c994c31f19fd73961b2a25b93fe535f Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 19:08:01 +0200 Subject: [PATCH 43/62] Add small TODO note --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 9aa473b0ecf7c..c05e05af16fa2 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -117,6 +117,7 @@ function AutoInsertingBlocksControl( props ) { ) { insertBlock( block, + // TODO: It'd be great if insertBlock() would accept negative indices for insertion. relativePosition === 'first_child' ? 0 : innerBlocksLength, props.clientId, // Insert as a child of the current block. false From ad8f3f2c28e2aefc2c0bc3b8c812592a21e437f5 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 19:27:25 +0200 Subject: [PATCH 44/62] Add another TODO note --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index c05e05af16fa2..7994e2b837efd 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -71,6 +71,12 @@ function AutoInsertingBlocksControl( props ) { if ( autoInsertedBlock ) { acc[ block.name ] = autoInsertedBlock.clientId; } + + // TOOD: If no auto-inserted block was found in any of its designated locations, + // we want to check if it's present elsewhere in the block tree. + // If it is, we'd consider it manually inserted and would want to remove the + // corresponding toggle from the block inspector panel. + return acc; }, {} ); From 965875f0ad5e6865581786fc9a33892a918d2715 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 19:31:52 +0200 Subject: [PATCH 45/62] Fix PHP lint errors --- lib/experimental/auto-inserting-blocks.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 627d08cb8b27e..e6b512204faea 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -149,6 +149,7 @@ function gutenberg_register_auto_inserted_blocks( $settings, $metadata ) { 'example' => 'example', 'variations' => 'variations', ); + // Add `auto_insert` to the list of fields to pick. $fields_to_pick['auto_insert'] = 'autoInsert'; $exposed_settings = array_intersect_key( $settings, $fields_to_pick ); @@ -156,7 +157,7 @@ function gutenberg_register_auto_inserted_blocks( $settings, $metadata ) { // TODO: Make work for blocks registered via direct call to gutenberg_register_auto_inserted_block(). wp_add_inline_script( 'wp-blocks', - 'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( array( $inserted_block_name => $exposed_settings ) ) . ');', + 'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( array( $inserted_block_name => $exposed_settings ) ) . ');' ); return $settings; From cdd56b2e2fb815a1bdb8324202b646881a862f7a Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 10 Aug 2023 19:52:02 +0200 Subject: [PATCH 46/62] Add missing PHPDoc, change some variable names --- lib/experimental/auto-inserting-blocks.php | 22 ++++++++++++++++++---- packages/blocks/src/api/registration.js | 12 ++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index e6b512204faea..19ae41c8fa1a3 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -64,9 +64,18 @@ function gutenberg_auto_insert_block( $inserted_block, $relative_position, $anch }; } -function gutenberg_add_auto_insert_field_to_block_type_controller( $inserted_block, $position, $anchor_block ) { - return function( $response, $block_type ) use ( $inserted_block, $position, $anchor_block ) { - if ( $block_type->name !== $inserted_block ) { +/** + * Add auto-insertion information to a block type's controller. + * + * @param array $inserted_block_type The type of block to insert. + * @param string $relative_position The position relative to the anchor block. + * Can be 'before', 'after', 'first_child', or 'last_child'. + * @param string $anchor_block_type The auto-inserted block will be inserted next to instances of this block type. + * @return callable A filter for the `rest_prepare_block_type` hook that adds an `auto_insert` field to the network response. + */ +function gutenberg_add_auto_insert_field_to_block_type_controller( $inserted_block_type, $position, $anchor_block_type ) { + return function( $response, $block_type ) use ( $inserted_block_type, $position, $anchor_block_type ) { + if ( $block_type->name !== $inserted_block_type ) { return $response; } @@ -74,7 +83,7 @@ function gutenberg_add_auto_insert_field_to_block_type_controller( $inserted_blo if ( ! isset( $data['auto_insert'] ) ) { $data['auto_insert'] = array(); } - $data['auto_insert'][ $anchor_block ] = $position; + $data['auto_insert'][ $anchor_block_type ] = $position; $response->set_data( $data ); return $response; }; @@ -315,6 +324,11 @@ function gutenberg_serialize_blocks( $blocks ) { return implode( '', array_map( 'gutenberg_serialize_block', $blocks ) ); } +/** + * Register the `auto_insert` field for the block-types REST API controller. + * + * @return void + */ function gutenberg_register_auto_insert_rest_field() { register_rest_field( 'block-type', diff --git a/packages/blocks/src/api/registration.js b/packages/blocks/src/api/registration.js index bf866b7a2143b..702582ff6489e 100644 --- a/packages/blocks/src/api/registration.js +++ b/packages/blocks/src/api/registration.js @@ -180,6 +180,17 @@ export function unstable__bootstrapServerSideBlockDefinitions( definitions ) { serverSideBlockDefinitions[ blockName ].selectors = definitions[ blockName ].selectors; } + + if ( + serverSideBlockDefinitions[ blockName ] + .__experimentalAutoInsert === undefined && + definitions[ blockName ].__experimentalAutoInsert + ) { + serverSideBlockDefinitions[ + blockName + ].__experimentalAutoInsert = + definitions[ blockName ].__experimentalAutoInsert; + } continue; } @@ -219,6 +230,7 @@ function getBlockSettingsFromMetadata( { textdomain, ...metadata } ) { 'styles', 'example', 'variations', + '__experimentalAutoInsert', ]; const settings = Object.fromEntries( From 15148161220b44662c8e431104c3bce0298e60f9 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 21 Aug 2023 14:38:09 -0400 Subject: [PATCH 47/62] Rename accumulator to clientIds --- .../src/hooks/auto-inserting-blocks.js | 85 ++++++++++--------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 7994e2b837efd..8c9f8d70cb4b6 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -40,45 +40,52 @@ function AutoInsertingBlocksControl( props ) { const _rootClientId = getBlockRootClientId( props.clientId ); const _autoInsertedBlockClientIds = - autoInsertedBlocksForCurrentBlock.reduce( ( acc, block ) => { - const relativePosition = - block?.autoInsert?.[ props.blockName ]; - let autoInsertedBlock; - if ( [ 'before', 'after' ].includes( relativePosition ) ) { - const siblings = getBlock( _rootClientId )?.innerBlocks; - - // Any of the current block's siblings (with the right block type) qualifies - // as an auto-inserted block (inserted `before` or `after` the current one), - // as the block might've been auto-inserted and then moved around a bit by the user. - autoInsertedBlock = siblings.find( - ( { name } ) => name === block.name - ); - } else if ( - [ 'first_child', 'last_child' ].includes( - relativePosition - ) - ) { - const { innerBlocks } = getBlock( props.clientId ); - - // Any of the current block's child blocks (with the right block type) qualifies - // as an auto-inserted first or last child block, as the block might've been - // auto-inserted and then moved around a bit by the user. - autoInsertedBlock = innerBlocks.find( - ( { name } ) => name === block.name - ); - } - - if ( autoInsertedBlock ) { - acc[ block.name ] = autoInsertedBlock.clientId; - } - - // TOOD: If no auto-inserted block was found in any of its designated locations, - // we want to check if it's present elsewhere in the block tree. - // If it is, we'd consider it manually inserted and would want to remove the - // corresponding toggle from the block inspector panel. - - return acc; - }, {} ); + autoInsertedBlocksForCurrentBlock.reduce( + ( clientIds, block ) => { + const relativePosition = + block?.autoInsert?.[ props.blockName ]; + let autoInsertedBlock; + if ( + [ 'before', 'after' ].includes( relativePosition ) + ) { + const siblings = + getBlock( _rootClientId )?.innerBlocks; + + // Any of the current block's siblings (with the right block type) qualifies + // as an auto-inserted block (inserted `before` or `after` the current one), + // as the block might've been auto-inserted and then moved around a bit by the user. + autoInsertedBlock = siblings.find( + ( { name } ) => name === block.name + ); + } else if ( + [ 'first_child', 'last_child' ].includes( + relativePosition + ) + ) { + const { innerBlocks } = getBlock( props.clientId ); + + // Any of the current block's child blocks (with the right block type) qualifies + // as an auto-inserted first or last child block, as the block might've been + // auto-inserted and then moved around a bit by the user. + autoInsertedBlock = innerBlocks.find( + ( { name } ) => name === block.name + ); + } + + if ( autoInsertedBlock ) { + clientIds[ block.name ] = + autoInsertedBlock.clientId; + } + + // TOOD: If no auto-inserted block was found in any of its designated locations, + // we want to check if it's present elsewhere in the block tree. + // If it is, we'd consider it manually inserted and would want to remove the + // corresponding toggle from the block inspector panel. + + return clientIds; + }, + {} + ); return { blockIndex: getBlockIndex( props.clientId ), From aa8dc07f4882c0a268cf94719146e6b81c7d41c4 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 21 Aug 2023 15:29:12 -0400 Subject: [PATCH 48/62] Use in operator --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 8c9f8d70cb4b6..2c4cbf8f3bf70 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -150,9 +150,9 @@ function AutoInsertingBlocksControl( props ) { // TODO: Display block icon. // - const checked = Object.keys( - autoInsertedBlockClientIds - ).includes( block.name ); + const checked = + block.name in + autoInsertedBlockClientIds; return ( Date: Mon, 21 Aug 2023 16:05:07 -0400 Subject: [PATCH 49/62] Improve REST API field description --- lib/experimental/auto-inserting-blocks.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 19ae41c8fa1a3..659aaffde48b9 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -335,7 +335,7 @@ function gutenberg_register_auto_insert_rest_field() { 'auto_insert', array( 'schema' => array( - 'description' => __( 'Auto Insert.', 'default' ), + 'description' => __( 'Block types that are automatically inserted next to this block, and their positions relative to it.', 'default' ), 'type' => 'object', ), ) From 550cc9eac6d8fbacd39a82460e9324139ad33484 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 25 Aug 2023 20:04:36 +0200 Subject: [PATCH 50/62] REVERT ME: Auto-insert Login/out block after Navigation --- packages/block-library/src/loginout/block.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/block-library/src/loginout/block.json b/packages/block-library/src/loginout/block.json index 3593961c09cfd..5c4fd272f0adb 100644 --- a/packages/block-library/src/loginout/block.json +++ b/packages/block-library/src/loginout/block.json @@ -32,5 +32,8 @@ "fontSize": true } } + }, + "__experimentalAutoInsert": { + "core/navigation": "after" } } From be01f29a102a5ae817b6514e1440f4b748fdde55 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 28 Aug 2023 16:01:28 +0200 Subject: [PATCH 51/62] Revert "REVERT ME: Auto-insert Login/out block after Navigation" This reverts commit 550cc9eac6d8fbacd39a82460e9324139ad33484. --- packages/block-library/src/loginout/block.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/block-library/src/loginout/block.json b/packages/block-library/src/loginout/block.json index 5c4fd272f0adb..3593961c09cfd 100644 --- a/packages/block-library/src/loginout/block.json +++ b/packages/block-library/src/loginout/block.json @@ -32,8 +32,5 @@ "fontSize": true } } - }, - "__experimentalAutoInsert": { - "core/navigation": "after" } } From 311ec1c8ba8dda06f45ebf190f86c2a63b782e91 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 28 Aug 2023 16:31:06 +0200 Subject: [PATCH 52/62] Move groupedAutoInsertedBlocks computation into first useSelect --- .../src/hooks/auto-inserting-blocks.js | 59 +++++++++++-------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 2c4cbf8f3bf70..c77de81968e04 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -16,17 +16,41 @@ import { InspectorControls } from '../components'; import { store as blockEditorStore } from '../store'; function AutoInsertingBlocksControl( props ) { - const autoInsertedBlocksForCurrentBlock = useSelect( - ( select ) => { - const { getBlockTypes } = select( blocksStore ); - return getBlockTypes()?.filter( - ( block ) => - block.autoInsert && - Object.keys( block.autoInsert ).includes( props.blockName ) - ); - }, - [ props.blockName ] - ); + const { autoInsertedBlocksForCurrentBlock, groupedAutoInsertedBlocks } = + useSelect( + ( select ) => { + const { getBlockTypes } = select( blocksStore ); + const _autoInsertedBlocksForCurrentBlock = + getBlockTypes()?.filter( + ( block ) => + block.autoInsert && + Object.keys( block.autoInsert ).includes( + props.blockName + ) + ); + + // Group by block namespace (i.e. prefix before the slash). + const _groupedAutoInsertedBlocks = + _autoInsertedBlocksForCurrentBlock?.reduce( + ( groups, block ) => { + const [ prefix ] = block.name.split( '/' ); + if ( ! groups[ prefix ] ) { + groups[ prefix ] = []; + } + groups[ prefix ].push( block ); + return groups; + }, + {} + ); + + return { + autoInsertedBlocksForCurrentBlock: + _autoInsertedBlocksForCurrentBlock, + groupedAutoInsertedBlocks: _groupedAutoInsertedBlocks, + }; + }, + [ props.blockName ] + ); const { autoInsertedBlockClientIds, @@ -104,19 +128,6 @@ function AutoInsertingBlocksControl( props ) { return null; } - // Group by block namespace (i.e. prefix before the slash). - const groupedAutoInsertedBlocks = autoInsertedBlocksForCurrentBlock.reduce( - ( groups, block ) => { - const [ prefix ] = block.name.split( '/' ); - if ( ! groups[ prefix ] ) { - groups[ prefix ] = []; - } - groups[ prefix ].push( block ); - return groups; - }, - {} - ); - const insertBlockIntoDesignatedLocation = ( block, relativePosition ) => { if ( [ 'before', 'after' ].includes( relativePosition ) ) { insertBlock( From 7dd82006fae445700f8c9a54bcb208683b3c23d2 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 28 Aug 2023 17:29:28 +0200 Subject: [PATCH 53/62] Rewrite auto-inserted block finding logic --- .../src/hooks/auto-inserting-blocks.js | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index c77de81968e04..a22da9b47b554 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -68,34 +68,33 @@ function AutoInsertingBlocksControl( props ) { ( clientIds, block ) => { const relativePosition = block?.autoInsert?.[ props.blockName ]; - let autoInsertedBlock; - if ( - [ 'before', 'after' ].includes( relativePosition ) - ) { - const siblings = - getBlock( _rootClientId )?.innerBlocks; - - // Any of the current block's siblings (with the right block type) qualifies - // as an auto-inserted block (inserted `before` or `after` the current one), - // as the block might've been auto-inserted and then moved around a bit by the user. - autoInsertedBlock = siblings.find( - ( { name } ) => name === block.name - ); - } else if ( - [ 'first_child', 'last_child' ].includes( - relativePosition - ) - ) { - const { innerBlocks } = getBlock( props.clientId ); - - // Any of the current block's child blocks (with the right block type) qualifies - // as an auto-inserted first or last child block, as the block might've been - // auto-inserted and then moved around a bit by the user. - autoInsertedBlock = innerBlocks.find( - ( { name } ) => name === block.name - ); + let candidates; + + switch ( relativePosition ) { + case 'before': + case 'after': + // Any of the current block's siblings (with the right block type) qualifies + // as an auto-inserted block (inserted `before` or `after` the current one), + // as the block might've been auto-inserted and then moved around a bit by the user. + candidates = + getBlock( _rootClientId )?.innerBlocks; + break; + + case 'first_child': + case 'last_child': + // Any of the current block's child blocks (with the right block type) qualifies + // as an auto-inserted first or last child block, as the block might've been + // auto-inserted and then moved around a bit by the user. + candidates = getBlock( + props.clientId + ).innerBlocks; + break; } + const autoInsertedBlock = candidates?.find( + ( { name } ) => name === block.name + ); + if ( autoInsertedBlock ) { clientIds[ block.name ] = autoInsertedBlock.clientId; From 64c70af3c6a37226f0f62ac1dbe44594bf7d26ef Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 28 Aug 2023 17:39:43 +0200 Subject: [PATCH 54/62] Rewrite block insertion function --- .../src/hooks/auto-inserting-blocks.js | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index a22da9b47b554..77fa0106b69a2 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -128,23 +128,27 @@ function AutoInsertingBlocksControl( props ) { } const insertBlockIntoDesignatedLocation = ( block, relativePosition ) => { - if ( [ 'before', 'after' ].includes( relativePosition ) ) { - insertBlock( - block, - relativePosition === 'after' ? blockIndex + 1 : blockIndex, - rootClientId, // Insert as a child of the current block's parent - false - ); - } else if ( - [ 'first_child', 'last_child' ].includes( relativePosition ) - ) { - insertBlock( - block, - // TODO: It'd be great if insertBlock() would accept negative indices for insertion. - relativePosition === 'first_child' ? 0 : innerBlocksLength, - props.clientId, // Insert as a child of the current block. - false - ); + switch ( relativePosition ) { + case 'before': + case 'after': + insertBlock( + block, + relativePosition === 'after' ? blockIndex + 1 : blockIndex, + rootClientId, // Insert as a child of the current block's parent + false + ); + break; + + case 'first_child': + case 'last_child': + insertBlock( + block, + // TODO: It'd be great if insertBlock() would accept negative indices for insertion. + relativePosition === 'first_child' ? 0 : innerBlocksLength, + props.clientId, // Insert as a child of the current block. + false + ); + break; } }; From 70c3787c26ba2ee4b350098559436f282de7e69e Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Mon, 28 Aug 2023 18:01:39 +0200 Subject: [PATCH 55/62] Fix PHPDoc --- lib/experimental/auto-inserting-blocks.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 659aaffde48b9..0819173d4c9dd 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -68,7 +68,7 @@ function gutenberg_auto_insert_block( $inserted_block, $relative_position, $anch * Add auto-insertion information to a block type's controller. * * @param array $inserted_block_type The type of block to insert. - * @param string $relative_position The position relative to the anchor block. + * @param string $position The position relative to the anchor block. * Can be 'before', 'after', 'first_child', or 'last_child'. * @param string $anchor_block_type The auto-inserted block will be inserted next to instances of this block type. * @return callable A filter for the `rest_prepare_block_type` hook that adds an `auto_insert` field to the network response. From 101455dbad3b52bab0bf27d5df899edaf0aa44c7 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 29 Aug 2023 09:54:50 +0200 Subject: [PATCH 56/62] Update REST API field description --- lib/experimental/auto-inserting-blocks.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 0819173d4c9dd..9eba2c411be36 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -335,7 +335,7 @@ function gutenberg_register_auto_insert_rest_field() { 'auto_insert', array( 'schema' => array( - 'description' => __( 'Block types that are automatically inserted next to this block, and their positions relative to it.', 'default' ), + 'description' => __( 'Block types that may be automatically inserted near this block and the associated relative position where they are inserted.', 'default' ), 'type' => 'object', ), ) From 769419c71a741af3a33ca42164cdb85d60260c97 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 29 Aug 2023 09:59:39 +0200 Subject: [PATCH 57/62] Use 'in' operator --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 77fa0106b69a2..0b6474396492a 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -22,11 +22,8 @@ function AutoInsertingBlocksControl( props ) { const { getBlockTypes } = select( blocksStore ); const _autoInsertedBlocksForCurrentBlock = getBlockTypes()?.filter( - ( block ) => - block.autoInsert && - Object.keys( block.autoInsert ).includes( - props.blockName - ) + ( { autoInsert } ) => + autoInsert && props.blockName in autoInsert ); // Group by block namespace (i.e. prefix before the slash). From 0204ddad0c5a1ba1a7f400002c5f6abd360632ad Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 29 Aug 2023 10:02:39 +0200 Subject: [PATCH 58/62] Rename 'prefix' to 'namespace' --- packages/block-editor/src/hooks/auto-inserting-blocks.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/hooks/auto-inserting-blocks.js b/packages/block-editor/src/hooks/auto-inserting-blocks.js index 0b6474396492a..266d9dd55fa67 100644 --- a/packages/block-editor/src/hooks/auto-inserting-blocks.js +++ b/packages/block-editor/src/hooks/auto-inserting-blocks.js @@ -30,11 +30,11 @@ function AutoInsertingBlocksControl( props ) { const _groupedAutoInsertedBlocks = _autoInsertedBlocksForCurrentBlock?.reduce( ( groups, block ) => { - const [ prefix ] = block.name.split( '/' ); - if ( ! groups[ prefix ] ) { - groups[ prefix ] = []; + const [ namespace ] = block.name.split( '/' ); + if ( ! groups[ namespace ] ) { + groups[ namespace ] = []; } - groups[ prefix ].push( block ); + groups[ namespace ].push( block ); return groups; }, {} From cd33697fcd2a7f012cd38455a9f1e97ecc7528d7 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 29 Aug 2023 10:21:52 +0200 Subject: [PATCH 59/62] Make schema more precise --- lib/experimental/auto-inserting-blocks.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 9eba2c411be36..263258a02f53a 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -335,10 +335,15 @@ function gutenberg_register_auto_insert_rest_field() { 'auto_insert', array( 'schema' => array( - 'description' => __( 'Block types that may be automatically inserted near this block and the associated relative position where they are inserted.', 'default' ), - 'type' => 'object', + 'description' => __( 'Block types that may be automatically inserted near this block and the associated relative position where they are inserted.', 'gutenberg' ), + 'patternProperties' => array( + '^[a-zA-Z0-9-]+/[a-zA-Z0-9-]+$' => array( + 'type' => 'string', + 'pattern' => '^before|after|first_child|last_child$', + ), + ), ), - ) + ), ); } add_action( 'rest_api_init', 'gutenberg_register_auto_insert_rest_field' ); From 1aa48e759655eb9ed1678582ea407e7c3a96439c Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 29 Aug 2023 10:29:40 +0200 Subject: [PATCH 60/62] Remove trailing comma from function call --- lib/experimental/auto-inserting-blocks.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 263258a02f53a..beb644e7657a0 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -343,7 +343,7 @@ function gutenberg_register_auto_insert_rest_field() { ), ), ), - ), + ) ); } add_action( 'rest_api_init', 'gutenberg_register_auto_insert_rest_field' ); From 65c892de8eb03eab6fa03338b979c9d19118f1a1 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 29 Aug 2023 10:29:56 +0200 Subject: [PATCH 61/62] Use enum in schema --- lib/experimental/auto-inserting-blocks.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index beb644e7657a0..3185f87fdbfa5 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -339,7 +339,7 @@ function gutenberg_register_auto_insert_rest_field() { 'patternProperties' => array( '^[a-zA-Z0-9-]+/[a-zA-Z0-9-]+$' => array( 'type' => 'string', - 'pattern' => '^before|after|first_child|last_child$', + 'enum' => array( 'before', 'after', 'first_child', 'last_child' ) ), ), ), From e10c5b3dea911a3973408b46629ba214329b58fd Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 29 Aug 2023 10:46:01 +0200 Subject: [PATCH 62/62] Formatting --- lib/experimental/auto-inserting-blocks.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/experimental/auto-inserting-blocks.php b/lib/experimental/auto-inserting-blocks.php index 3185f87fdbfa5..f4a650e110bf9 100644 --- a/lib/experimental/auto-inserting-blocks.php +++ b/lib/experimental/auto-inserting-blocks.php @@ -338,8 +338,8 @@ function gutenberg_register_auto_insert_rest_field() { 'description' => __( 'Block types that may be automatically inserted near this block and the associated relative position where they are inserted.', 'gutenberg' ), 'patternProperties' => array( '^[a-zA-Z0-9-]+/[a-zA-Z0-9-]+$' => array( - 'type' => 'string', - 'enum' => array( 'before', 'after', 'first_child', 'last_child' ) + 'type' => 'string', + 'enum' => array( 'before', 'after', 'first_child', 'last_child' ), ), ), ),