diff --git a/docs/reference-guides/block-api/block-patterns.md b/docs/reference-guides/block-api/block-patterns.md index f5aebbdef3a6a..12fac7b479361 100644 --- a/docs/reference-guides/block-api/block-patterns.md +++ b/docs/reference-guides/block-api/block-patterns.md @@ -3,10 +3,16 @@ Block Patterns are predefined block layouts, available from the patterns tab of the block inserter. Once inserted into content, the blocks are ready for additional or modified content and configuration. In this Document: -* [`register_block_pattern`](#register_block_pattern) -* [`unregister_block_pattern`](#unregister_block_pattern) -* [`register_block_pattern_category`](#register_block_pattern_category) -* [`unregister_block_pattern_category`](#unregister_block_pattern_category) +- [Patterns](#patterns) + - [Block Patterns](#block-patterns) + - [register_block_pattern](#register_block_pattern) + - [Unregistering Block Patterns](#unregistering-block-patterns) + - [unregister_block_pattern](#unregister_block_pattern) + - [Block Pattern Categories](#block-pattern-categories) + - [register_block_pattern_category](#register_block_pattern_category) + - [unregister_block_pattern_category](#unregister_block_pattern_category) + - [Block patterns contextual to block types and pattern transformations](#block-patterns-contextual-to-block-types-and-pattern-transformations) + - [Semantic block patterns](#semantic-block-patterns) ## Block Patterns @@ -27,6 +33,7 @@ The properties available for block patterns are: - `keywords` (optional): An array of aliases or keywords that help users discover the pattern while searching. - `viewportWidth` (optional): An integer specifying the intended width of the pattern to allow for a scaled preview of the pattern in the inserter. - `blockTypes` (optional): An array of block types that the pattern is intended to be used with. Each value needs to be the declared block's `name`. +- `postTypes` (optional): An array of post types that the pattern is restricted to be used with. The pattern will only be available when editing one of the post types passed on the array, for all the other post types the pattern is not available at all. - `inserter` (optional): By default, all patterns will appear in the inserter. To hide a pattern so that it can only be inserted programmatically, set the `inserter` to `false`. The following code sample registers a block pattern named 'my-plugin/my-awesome-pattern': diff --git a/lib/compat/wordpress-6.0/block-patterns.php b/lib/compat/wordpress-6.0/block-patterns.php index 0992f8b08964e..772b910deb866 100644 --- a/lib/compat/wordpress-6.0/block-patterns.php +++ b/lib/compat/wordpress-6.0/block-patterns.php @@ -44,168 +44,3 @@ function gutenberg_register_remote_theme_patterns() { } } } - -/** - * Register any patterns that the active theme may provide under its - * `./patterns/` directory. Each pattern is defined as a PHP file and defines - * its metadata using plugin-style headers. The minimum required definition is: - * - * /** - * * Title: My Pattern - * * Slug: my-theme/my-pattern - * * - * - * The output of the PHP source corresponds to the content of the pattern, e.g.: - * - *

- * - * If applicable, this will collect from both parent and child theme. - * - * Other settable fields include: - * - * - Description - * - Viewport Width - * - Categories (comma-separated values) - * - Keywords (comma-separated values) - * - Block Types (comma-separated values) - * - Inserter (yes/no) - * - * @since 6.0.0 - * @access private - * @internal - */ -function gutenberg_register_theme_block_patterns() { - $default_headers = array( - 'title' => 'Title', - 'slug' => 'Slug', - 'description' => 'Description', - 'viewportWidth' => 'Viewport Width', - 'categories' => 'Categories', - 'keywords' => 'Keywords', - 'blockTypes' => 'Block Types', - 'inserter' => 'Inserter', - ); - - // Register patterns for the active theme. If the theme is a child theme, - // let it override any patterns from the parent theme that shares the same slug. - $themes = array(); - $stylesheet = get_stylesheet(); - $template = get_template(); - if ( $stylesheet !== $template ) { - $themes[] = wp_get_theme( $stylesheet ); - } - $themes[] = wp_get_theme( $template ); - - foreach ( $themes as $theme ) { - $dirpath = $theme->get_stylesheet_directory() . '/patterns/'; - if ( ! is_dir( $dirpath ) || ! is_readable( $dirpath ) ) { - continue; - } - $files = glob( $dirpath . '*.php' ); - if ( $files ) { - foreach ( $files as $file ) { - $pattern_data = get_file_data( $file, $default_headers ); - - if ( empty( $pattern_data['slug'] ) ) { - _doing_it_wrong( - '_register_theme_block_patterns', - sprintf( - /* translators: %s: file name. */ - __( 'Could not register file "%s" as a block pattern ("Slug" field missing)', 'gutenberg' ), - $file - ), - '6.0.0' - ); - continue; - } - - if ( ! preg_match( '/^[A-z0-9\/_-]+$/', $pattern_data['slug'] ) ) { - _doing_it_wrong( - '_register_theme_block_patterns', - sprintf( - /* translators: %1s: file name; %2s: slug value found. */ - __( 'Could not register file "%1$s" as a block pattern (invalid slug "%2$s")', 'gutenberg' ), - $file, - $pattern_data['slug'] - ), - '6.0.0' - ); - } - - if ( WP_Block_Patterns_Registry::get_instance()->is_registered( $pattern_data['slug'] ) ) { - continue; - } - - // Title is a required property. - if ( ! $pattern_data['title'] ) { - _doing_it_wrong( - '_register_theme_block_patterns', - sprintf( - /* translators: %1s: file name; %2s: slug value found. */ - __( 'Could not register file "%s" as a block pattern ("Title" field missing)', 'gutenberg' ), - $file - ), - '6.0.0' - ); - continue; - } - - // For properties of type array, parse data as comma-separated. - foreach ( array( 'categories', 'keywords', 'blockTypes' ) as $property ) { - if ( ! empty( $pattern_data[ $property ] ) ) { - $pattern_data[ $property ] = array_filter( - preg_split( - '/[\s,]+/', - (string) $pattern_data[ $property ] - ) - ); - } else { - unset( $pattern_data[ $property ] ); - } - } - - // Parse properties of type int. - foreach ( array( 'viewportWidth' ) as $property ) { - if ( ! empty( $pattern_data[ $property ] ) ) { - $pattern_data[ $property ] = (int) $pattern_data[ $property ]; - } else { - unset( $pattern_data[ $property ] ); - } - } - - // Parse properties of type bool. - foreach ( array( 'inserter' ) as $property ) { - if ( ! empty( $pattern_data[ $property ] ) ) { - $pattern_data[ $property ] = in_array( - strtolower( $pattern_data[ $property ] ), - array( 'yes', 'true' ), - true - ); - } else { - unset( $pattern_data[ $property ] ); - } - } - - // Translate the pattern metadata. - $text_domain = $theme->get( 'TextDomain' ); - //phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText, WordPress.WP.I18n.NonSingularStringLiteralContext, WordPress.WP.I18n.NonSingularStringLiteralDomain, WordPress.WP.I18n.LowLevelTranslationFunction - $pattern_data['title'] = translate_with_gettext_context( $pattern_data['title'], 'Pattern title', $text_domain ); - if ( ! empty( $pattern_data['description'] ) ) { - //phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText, WordPress.WP.I18n.NonSingularStringLiteralContext, WordPress.WP.I18n.NonSingularStringLiteralDomain, WordPress.WP.I18n.LowLevelTranslationFunction - $pattern_data['description'] = translate_with_gettext_context( $pattern_data['description'], 'Pattern description', $text_domain ); - } - - // The actual pattern content is the output of the file. - ob_start(); - include $file; - $pattern_data['content'] = ob_get_clean(); - if ( ! $pattern_data['content'] ) { - continue; - } - - register_block_pattern( $pattern_data['slug'], $pattern_data ); - } - } - } -} -add_action( 'init', 'gutenberg_register_theme_block_patterns' ); diff --git a/lib/compat/wordpress-6.1/block-patterns.php b/lib/compat/wordpress-6.1/block-patterns.php new file mode 100644 index 0000000000000..7860aa6a1dd66 --- /dev/null +++ b/lib/compat/wordpress-6.1/block-patterns.php @@ -0,0 +1,177 @@ +

+ * + * If applicable, this will collect from both parent and child theme. + * + * Other settable fields include: + * + * - Description + * - Viewport Width + * - Categories (comma-separated values) + * - Keywords (comma-separated values) + * - Block Types (comma-separated values) + * - Post Types (comma-separated values) + * - Inserter (yes/no) + * + * @since 6.0.0 + * @access private + */ +function gutenberg_register_theme_block_patterns() { + $default_headers = array( + 'title' => 'Title', + 'slug' => 'Slug', + 'description' => 'Description', + 'viewportWidth' => 'Viewport Width', + 'categories' => 'Categories', + 'keywords' => 'Keywords', + 'blockTypes' => 'Block Types', + 'postTypes' => 'Post Types', + 'inserter' => 'Inserter', + ); + + /* + * Register patterns for the active theme. If the theme is a child theme, + * let it override any patterns from the parent theme that shares the same slug. + */ + $themes = array(); + $stylesheet = get_stylesheet(); + $template = get_template(); + if ( $stylesheet !== $template ) { + $themes[] = wp_get_theme( $stylesheet ); + } + $themes[] = wp_get_theme( $template ); + + foreach ( $themes as $theme ) { + $dirpath = $theme->get_stylesheet_directory() . '/patterns/'; + if ( ! is_dir( $dirpath ) || ! is_readable( $dirpath ) ) { + continue; + } + if ( file_exists( $dirpath ) ) { + $files = glob( $dirpath . '*.php' ); + if ( $files ) { + foreach ( $files as $file ) { + $pattern_data = get_file_data( $file, $default_headers ); + + if ( empty( $pattern_data['slug'] ) ) { + _doing_it_wrong( + '_register_theme_block_patterns', + sprintf( + /* translators: %s: file name. */ + __( 'Could not register file "%s" as a block pattern ("Slug" field missing)', 'gutenberg' ), + $file + ), + '6.0.0' + ); + continue; + } + + if ( ! preg_match( '/^[A-z0-9\/_-]+$/', $pattern_data['slug'] ) ) { + _doing_it_wrong( + '_register_theme_block_patterns', + sprintf( + /* translators: %1s: file name; %2s: slug value found. */ + __( 'Could not register file "%1$s" as a block pattern (invalid slug "%2$s")', 'gutenberg' ), + $file, + $pattern_data['slug'] + ), + '6.0.0' + ); + } + + if ( WP_Block_Patterns_Registry::get_instance()->is_registered( $pattern_data['slug'] ) ) { + continue; + } + + // Title is a required property. + if ( ! $pattern_data['title'] ) { + _doing_it_wrong( + '_register_theme_block_patterns', + sprintf( + /* translators: %1s: file name; %2s: slug value found. */ + __( 'Could not register file "%s" as a block pattern ("Title" field missing)', 'gutenberg' ), + $file + ), + '6.0.0' + ); + continue; + } + + // For properties of type array, parse data as comma-separated. + foreach ( array( 'categories', 'keywords', 'blockTypes', 'postTypes' ) as $property ) { + if ( ! empty( $pattern_data[ $property ] ) ) { + $pattern_data[ $property ] = array_filter( + preg_split( + '/[\s,]+/', + (string) $pattern_data[ $property ] + ) + ); + } else { + unset( $pattern_data[ $property ] ); + } + } + + // Parse properties of type int. + foreach ( array( 'viewportWidth' ) as $property ) { + if ( ! empty( $pattern_data[ $property ] ) ) { + $pattern_data[ $property ] = (int) $pattern_data[ $property ]; + } else { + unset( $pattern_data[ $property ] ); + } + } + + // Parse properties of type bool. + foreach ( array( 'inserter' ) as $property ) { + if ( ! empty( $pattern_data[ $property ] ) ) { + $pattern_data[ $property ] = in_array( + strtolower( $pattern_data[ $property ] ), + array( 'yes', 'true' ), + true + ); + } else { + unset( $pattern_data[ $property ] ); + } + } + + // Translate the pattern metadata. + $text_domain = $theme->get( 'TextDomain' ); + //phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText, WordPress.WP.I18n.NonSingularStringLiteralContext, WordPress.WP.I18n.NonSingularStringLiteralDomain, WordPress.WP.I18n.LowLevelTranslationFunction + $pattern_data['title'] = translate_with_gettext_context( $pattern_data['title'], 'Pattern title', $text_domain ); + if ( ! empty( $pattern_data['description'] ) ) { + //phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText, WordPress.WP.I18n.NonSingularStringLiteralContext, WordPress.WP.I18n.NonSingularStringLiteralDomain, WordPress.WP.I18n.LowLevelTranslationFunction + $pattern_data['description'] = translate_with_gettext_context( $pattern_data['description'], 'Pattern description', $text_domain ); + } + + // The actual pattern content is the output of the file. + ob_start(); + include $file; + $pattern_data['content'] = ob_get_clean(); + if ( ! $pattern_data['content'] ) { + continue; + } + + register_block_pattern( $pattern_data['slug'], $pattern_data ); + } + } + } + } +} +remove_action( 'init', '_register_theme_block_patterns' ); +add_action( 'init', 'gutenberg_register_theme_block_patterns' ); diff --git a/lib/compat/wordpress-6.1/class-gutenberg-rest-block-patterns-controller.php b/lib/compat/wordpress-6.1/class-gutenberg-rest-block-patterns-controller.php new file mode 100644 index 0000000000000..a19a34b523e8b --- /dev/null +++ b/lib/compat/wordpress-6.1/class-gutenberg-rest-block-patterns-controller.php @@ -0,0 +1,224 @@ +namespace = 'wp/v2'; + $this->rest_base = 'block-patterns/patterns'; + } + + /** + * Registers the routes for the objects of the controller. + * + * @since 6.0.0 + */ + public function register_routes() { + register_rest_route( + $this->namespace, + '/' . $this->rest_base, + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_items' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ), + true + ); + } + + /** + * Checks whether a given request has permission to read block patterns. + * + * @since 6.0.0 + * + * @param WP_REST_Request $request Full details about the request. + * @return true|WP_Error True if the request has read access, WP_Error object otherwise. + */ + public function get_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + if ( current_user_can( 'edit_posts' ) ) { + return true; + } + + foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) { + if ( current_user_can( $post_type->cap->edit_posts ) ) { + return true; + } + } + + return new WP_Error( + 'rest_cannot_view', + __( 'Sorry, you are not allowed to view the registered block patterns.', 'gutenberg' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + /** + * Retrieves all block patterns. + * + * @since 6.0.0 + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. + */ + public function get_items( $request ) { + if ( ! $this->remote_patterns_loaded ) { + // Load block patterns from w.org. + _load_remote_block_patterns(); // Patterns with the `core` keyword. + _load_remote_featured_patterns(); // Patterns in the `featured` category. + _register_remote_theme_patterns(); // Patterns requested by current theme. + + $this->remote_patterns_loaded = true; + } + + $response = array(); + $patterns = WP_Block_Patterns_Registry::get_instance()->get_all_registered(); + foreach ( $patterns as $pattern ) { + $prepared_pattern = $this->prepare_item_for_response( $pattern, $request ); + $response[] = $this->prepare_response_for_collection( $prepared_pattern ); + } + return rest_ensure_response( $response ); + } + + /** + * Prepare a raw block pattern before it gets output in a REST API response. + * + * @since 6.0.0 + * + * @param array $item Raw pattern as registered, before any changes. + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. + */ + public function prepare_item_for_response( $item, $request ) { + $fields = $this->get_fields_for_response( $request ); + $keys = array( + 'name' => 'name', + 'title' => 'title', + 'description' => 'description', + 'viewportWidth' => 'viewport_width', + 'blockTypes' => 'block_types', + 'postTypes' => 'post_types', + 'categories' => 'categories', + 'keywords' => 'keywords', + 'content' => 'content', + 'inserter' => 'inserter', + ); + $data = array(); + foreach ( $keys as $item_key => $rest_key ) { + if ( isset( $item[ $item_key ] ) && rest_is_field_included( $rest_key, $fields ) ) { + $data[ $rest_key ] = $item[ $item_key ]; + } + } + + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; + $data = $this->add_additional_fields_to_object( $data, $request ); + $data = $this->filter_response_by_context( $data, $context ); + return rest_ensure_response( $data ); + } + + /** + * Retrieves the block pattern schema, conforming to JSON Schema. + * + * @since 6.0.0 + * + * @return array Item schema data. + */ + public function get_item_schema() { + $schema = array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'title' => 'block-pattern', + 'type' => 'object', + 'properties' => array( + 'name' => array( + 'description' => __( 'The pattern name.', 'gutenberg' ), + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'title' => array( + 'description' => __( 'The pattern title, in human readable format.', 'gutenberg' ), + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'description' => array( + 'description' => __( 'The pattern detailed description.', 'gutenberg' ), + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'viewport_width' => array( + 'description' => __( 'The pattern viewport width for inserter preview.', 'gutenberg' ), + 'type' => 'number', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'block_types' => array( + 'description' => __( 'Block types that the pattern is intended to be used with.', 'gutenberg' ), + 'type' => 'array', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'post_types' => array( + 'description' => __( ' An array of post types that the pattern is restricted to be used with.', 'gutenberg' ), + 'type' => 'array', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'categories' => array( + 'description' => __( 'The pattern category slugs.', 'gutenberg' ), + 'type' => 'array', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'keywords' => array( + 'description' => __( 'The pattern keywords.', 'gutenberg' ), + 'type' => 'array', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'content' => array( + 'description' => __( 'The pattern content.', 'gutenberg' ), + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'inserter' => array( + 'description' => __( 'Determines whether the pattern is visible in inserter.', 'gutenberg' ), + 'type' => 'boolean', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + ), + ); + + return $this->add_additional_fields_schema( $schema ); + } +} diff --git a/lib/compat/wordpress-6.1/rest-api.php b/lib/compat/wordpress-6.1/rest-api.php index 30c68981c4f11..4ba0b328857b8 100644 --- a/lib/compat/wordpress-6.1/rest-api.php +++ b/lib/compat/wordpress-6.1/rest-api.php @@ -34,3 +34,12 @@ function gutenberg_update_post_types_rest_response( $response, $post_type ) { return $response; } add_filter( 'rest_prepare_post_type', 'gutenberg_update_post_types_rest_response', 10, 2 ); + +/** + * Registers the block patterns REST API routes. + */ +function gutenberg_register_gutenberg_rest_block_patterns() { + $block_patterns = new Gutenberg_REST_Block_Patterns_Controller(); + $block_patterns->register_routes(); +} +add_action( 'rest_api_init', 'gutenberg_register_gutenberg_rest_block_patterns', 100 ); diff --git a/lib/load.php b/lib/load.php index f7cad4597b692..887d5b7cc99e0 100644 --- a/lib/load.php +++ b/lib/load.php @@ -64,6 +64,7 @@ function gutenberg_is_experiment_enabled( $name ) { require_once __DIR__ . '/compat/wordpress-6.0/rest-api.php'; // WordPress 6.1 compat. + require_once __DIR__ . '/compat/wordpress-6.1/class-gutenberg-rest-block-patterns-controller.php'; require_once __DIR__ . '/compat/wordpress-6.1/class-gutenberg-rest-templates-controller.php'; require_once __DIR__ . '/compat/wordpress-6.1/rest-api.php'; @@ -131,6 +132,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.1/wp-theme-get-post-templates.php'; require __DIR__ . '/compat/wordpress-6.1/script-loader.php'; require __DIR__ . '/compat/wordpress-6.1/date-settings.php'; +require __DIR__ . '/compat/wordpress-6.1/block-patterns.php'; // Experimental features. remove_action( 'plugins_loaded', '_wp_theme_json_webfonts_handler' ); // Turns off WP 6.0's stopgap handler for Webfonts API. diff --git a/packages/core-data/src/resolvers.js b/packages/core-data/src/resolvers.js index d475a789b4ec7..b47e879ecc301 100644 --- a/packages/core-data/src/resolvers.js +++ b/packages/core-data/src/resolvers.js @@ -1,7 +1,16 @@ /** * External dependencies */ -import { find, includes, get, compact, uniq, map, mapKeys } from 'lodash'; +import { + camelCase, + compact, + find, + get, + includes, + map, + mapKeys, + uniq, +} from 'lodash'; /** * WordPress dependencies @@ -476,16 +485,7 @@ export const getBlockPatterns = path: '/wp/v2/block-patterns/patterns', } ); const patterns = map( restPatterns, ( pattern ) => - mapKeys( pattern, ( value, key ) => { - switch ( key ) { - case 'block_types': - return 'blockTypes'; - case 'viewport_width': - return 'viewportWidth'; - default: - return key; - } - } ) + mapKeys( pattern, ( value, key ) => camelCase( key ) ) ); dispatch( { type: 'RECEIVE_BLOCK_PATTERNS', patterns } ); }; diff --git a/packages/edit-post/src/components/start-page-options/index.js b/packages/edit-post/src/components/start-page-options/index.js index 3fc8740ca95b4..ce86984e032c2 100644 --- a/packages/edit-post/src/components/start-page-options/index.js +++ b/packages/edit-post/src/components/start-page-options/index.js @@ -3,7 +3,7 @@ */ import { Modal } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useState, useEffect } from '@wordpress/element'; +import { useState, useEffect, useMemo } from '@wordpress/element'; import { store as blockEditorStore, __experimentalBlockPatternsList as BlockPatternsList, @@ -17,15 +17,42 @@ import { store as editorStore } from '@wordpress/editor'; */ import { store as editPostStore } from '../../store'; +function useStartPatterns() { + // A pattern is a start pattern if it includes 'core/post-content' in its blockTypes, + // and it has no postTypes declares and the current post type is page or if + // the current post type is part of the postTypes declared. + const { blockPatternsWithPostContentBlockType, postType } = useSelect( + ( select ) => { + const { __experimentalGetPatternsByBlockTypes } = + select( blockEditorStore ); + const { getCurrentPostType } = select( editorStore ); + return { + // get pa + blockPatternsWithPostContentBlockType: + __experimentalGetPatternsByBlockTypes( + 'core/post-content' + ), + postType: getCurrentPostType(), + }; + }, + [] + ); + + return useMemo( () => { + // filter patterns without postTypes declared if the current postType is page + // or patterns that declare the current postType in its post type array. + return blockPatternsWithPostContentBlockType.filter( ( pattern ) => { + return ( + ( postType === 'page' && ! pattern.postTypes ) || + ( Array.isArray( pattern.postTypes ) && + pattern.postTypes.includes( postType ) ) + ); + } ); + }, [ postType, blockPatternsWithPostContentBlockType ] ); +} + function PatternSelection( { onChoosePattern } ) { - const { blockPatterns } = useSelect( ( select ) => { - const { __experimentalGetPatternsByBlockTypes } = - select( blockEditorStore ); - return { - blockPatterns: - __experimentalGetPatternsByBlockTypes( 'core/post-content' ), - }; - }, [] ); + const blockPatterns = useStartPatterns(); const shownBlockPatterns = useAsyncList( blockPatterns ); const { resetEditorBlocks } = useDispatch( editorStore ); return ( @@ -50,31 +77,28 @@ export default function StartPageOptions() { const [ modalState, setModalState ] = useState( START_PAGE_MODAL_STATES.INITIAL ); + const blockPatterns = useStartPatterns(); + const hasStartPattern = blockPatterns.length > 0; const shouldOpenModel = useSelect( ( select ) => { - if ( modalState !== START_PAGE_MODAL_STATES.INITIAL ) { + if ( + ! hasStartPattern || + modalState !== START_PAGE_MODAL_STATES.INITIAL + ) { return false; } - const { __experimentalGetPatternsByBlockTypes } = - select( blockEditorStore ); - const { - getCurrentPostType, - getEditedPostContent, - isEditedPostSaveable, - } = select( editorStore ); + const { getEditedPostContent, isEditedPostSaveable } = + select( editorStore ); const { isEditingTemplate, isFeatureActive } = select( editPostStore ); return ( - getCurrentPostType() === 'page' && ! isEditedPostSaveable() && '' === getEditedPostContent() && ! isEditingTemplate() && - ! isFeatureActive( 'welcomeGuide' ) && - __experimentalGetPatternsByBlockTypes( 'core/post-content' ) - .length >= 1 + ! isFeatureActive( 'welcomeGuide' ) ); }, - [ modalState ] + [ modalState, hasStartPattern ] ); useEffect( () => {