From 363ed924630edcca2cc6a3d201385ab8df4dcab1 Mon Sep 17 00:00:00 2001 From: Felix Arntz Date: Mon, 6 Feb 2023 19:38:08 +0000 Subject: [PATCH] Editor: Support the `block_types` and `viewport_width` props for remote patterns fetched from Pattern Directory. Props ntsekouras, ironprogrammer, hellofromtonya, flixos90. Fixes #57611. git-svn-id: https://develop.svn.wordpress.org/trunk@55234 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/block-patterns.php | 51 +++++++++++++++---- ...s-wp-rest-pattern-directory-controller.php | 12 ++++- .../blocks/pattern-directory/browse-all.json | 9 ++-- .../pattern-directory/browse-category-2.json | 6 ++- .../pattern-directory/browse-keyword-11.json | 9 ++-- .../pattern-directory/search-button.json | 12 +++-- 6 files changed, 77 insertions(+), 22 deletions(-) diff --git a/src/wp-includes/block-patterns.php b/src/wp-includes/block-patterns.php index ff3d03cd43..eb008cd4a2 100644 --- a/src/wp-includes/block-patterns.php +++ b/src/wp-includes/block-patterns.php @@ -158,11 +158,38 @@ function _register_core_block_patterns_and_categories() { ); } +/** + * Normalize the pattern properties to camelCase. + * + * The API's format is snake_case, `register_block_pattern()` expects camelCase. + * + * @since 6.2.0 + * @access private + * + * @param array $pattern Pattern as returned from the Pattern Directory API. + * @return array Normalized pattern. + */ +function wp_normalize_remote_block_pattern( $pattern ) { + if ( isset( $pattern['block_types'] ) ) { + $pattern['blockTypes'] = $pattern['block_types']; + unset( $pattern['block_types'] ); + } + + if ( isset( $pattern['viewport_width'] ) ) { + $pattern['viewportWidth'] = $pattern['viewport_width']; + unset( $pattern['viewport_width'] ); + } + + return (array) $pattern; +} + /** * Register Core's official patterns from wordpress.org/patterns. * * @since 5.8.0 * @since 5.9.0 The $current_screen argument was removed. + * @since 6.2.0 Normalize the pattern from the API (snake_case) to the + * format expected by `register_block_pattern` (camelCase). * * @param WP_Screen $deprecated Unused. Formerly the screen that the current request was triggered from. */ @@ -196,9 +223,10 @@ function _load_remote_block_patterns( $deprecated = null ) { } $patterns = $response->get_data(); - foreach ( $patterns as $settings ) { - $pattern_name = 'core/' . sanitize_title( $settings['title'] ); - register_block_pattern( $pattern_name, (array) $settings ); + foreach ( $patterns as $pattern ) { + $normalized_pattern = wp_normalize_remote_block_pattern( $pattern ); + $pattern_name = 'core/' . sanitize_title( $normalized_pattern['title'] ); + register_block_pattern( $pattern_name, $normalized_pattern ); } } } @@ -207,6 +235,8 @@ function _load_remote_block_patterns( $deprecated = null ) { * Register `Featured` (category) patterns from wordpress.org/patterns. * * @since 5.9.0 + * @since 6.2.0 Normalized the pattern from the API (snake_case) to the + * format expected by `register_block_pattern()` (camelCase). */ function _load_remote_featured_patterns() { $supports_core_patterns = get_theme_support( 'core-block-patterns' ); @@ -226,14 +256,14 @@ function _load_remote_featured_patterns() { return; } $patterns = $response->get_data(); - + $registry = WP_Block_Patterns_Registry::get_instance(); foreach ( $patterns as $pattern ) { - $pattern_name = sanitize_title( $pattern['title'] ); - $registry = WP_Block_Patterns_Registry::get_instance(); + $normalized_pattern = wp_normalize_remote_block_pattern( $pattern ); + $pattern_name = sanitize_title( $normalized_pattern['title'] ); // Some patterns might be already registered as core patterns with the `core` prefix. $is_registered = $registry->is_registered( $pattern_name ) || $registry->is_registered( "core/$pattern_name" ); if ( ! $is_registered ) { - register_block_pattern( $pattern_name, (array) $pattern ); + register_block_pattern( $pattern_name, $normalized_pattern ); } } } @@ -243,6 +273,8 @@ function _load_remote_featured_patterns() { * `theme.json` file. * * @since 6.0.0 + * @since 6.2.0 Normalized the pattern from the API (snake_case) to the + * format expected by `register_block_pattern()` (camelCase). * @access private */ function _register_remote_theme_patterns() { @@ -269,11 +301,12 @@ function _register_remote_theme_patterns() { $patterns = $response->get_data(); $patterns_registry = WP_Block_Patterns_Registry::get_instance(); foreach ( $patterns as $pattern ) { - $pattern_name = sanitize_title( $pattern['title'] ); + $normalized_pattern = wp_normalize_remote_block_pattern( $pattern ); + $pattern_name = sanitize_title( $normalized_pattern['title'] ); // Some patterns might be already registered as core patterns with the `core` prefix. $is_registered = $patterns_registry->is_registered( $pattern_name ) || $patterns_registry->is_registered( "core/$pattern_name" ); if ( ! $is_registered ) { - register_block_pattern( $pattern_name, (array) $pattern ); + register_block_pattern( $pattern_name, $normalized_pattern ); } } } diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php index 4ba3712c8d..0260561866 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php @@ -103,7 +103,7 @@ class WP_REST_Pattern_Directory_Controller extends WP_REST_Controller { 'search' => true, 'slug' => true, ); - $query_args = array_intersect_key( $request->get_params(), $valid_query_args ); + $query_args = array_intersect_key( $request->get_params(), $valid_query_args ); $query_args['locale'] = get_user_locale(); $query_args['wp-version'] = $wp_version; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- it's defined in `version.php` above. @@ -202,6 +202,7 @@ class WP_REST_Pattern_Directory_Controller extends WP_REST_Controller { 'keywords' => array_map( 'sanitize_text_field', explode( ',', $raw_pattern->meta->wpop_keywords ) ), 'description' => sanitize_text_field( $raw_pattern->meta->wpop_description ), 'viewport_width' => absint( $raw_pattern->meta->wpop_viewport_width ), + 'block_types' => array_map( 'sanitize_text_field', $raw_pattern->meta->wpop_block_types ), ); $prepared_pattern = $this->add_additional_fields_to_object( $prepared_pattern, $request ); @@ -224,6 +225,7 @@ class WP_REST_Pattern_Directory_Controller extends WP_REST_Controller { * Retrieves the block pattern's schema, conforming to JSON Schema. * * @since 5.8.0 + * @since 6.2.0 Added `'block_types'` to schema. * * @return array Item schema data. */ @@ -286,6 +288,14 @@ class WP_REST_Pattern_Directory_Controller extends WP_REST_Controller { 'type' => 'integer', 'context' => array( 'view', 'edit', 'embed' ), ), + + 'block_types' => array( + 'description' => __( 'The block types which can use this pattern.' ), + 'type' => 'array', + 'uniqueItems' => true, + 'items' => array( 'type' => 'string' ), + 'context' => array( 'view', 'embed' ), + ), ), ); diff --git a/tests/phpunit/data/blocks/pattern-directory/browse-all.json b/tests/phpunit/data/blocks/pattern-directory/browse-all.json index 8d0d2d4ba3..27dca1b4b3 100644 --- a/tests/phpunit/data/blocks/pattern-directory/browse-all.json +++ b/tests/phpunit/data/blocks/pattern-directory/browse-all.json @@ -10,7 +10,8 @@ "spay_email": "", "wpop_description": "A heading preceded by a chapter number, and followed by a paragraph.", "wpop_keywords": "blog post", - "wpop_viewport_width": 1000 + "wpop_viewport_width": 1000, + "wpop_block_types": [ "core/heading" ] }, "category_slugs": [ "text" ], "keyword_slugs": [ "core" ], @@ -27,7 +28,8 @@ "spay_email": "", "wpop_description": "A large hero section with an example background image and a heading in the center.", "wpop_keywords": "header, hero", - "wpop_viewport_width": 1000 + "wpop_viewport_width": 1000, + "wpop_block_types": [] }, "category_slugs": [ "header" ], "keyword_slugs": [ "core" ], @@ -44,7 +46,8 @@ "spay_email": "", "wpop_description": "A large hero section with a bright gradient background, a big heading and a filled button.", "wpop_keywords": "call to action, hero section", - "wpop_viewport_width": 1000 + "wpop_viewport_width": 1000, + "wpop_block_types": [] }, "category_slugs": [ "header" ], "keyword_slugs": [ "core" ], diff --git a/tests/phpunit/data/blocks/pattern-directory/browse-category-2.json b/tests/phpunit/data/blocks/pattern-directory/browse-category-2.json index 1fce1a0f80..f5d4b289db 100644 --- a/tests/phpunit/data/blocks/pattern-directory/browse-category-2.json +++ b/tests/phpunit/data/blocks/pattern-directory/browse-category-2.json @@ -10,7 +10,8 @@ "spay_email": "", "wpop_description": "Three filled buttons with rounded corners, side by side.", "wpop_keywords": "", - "wpop_viewport_width": 600 + "wpop_viewport_width": 600, + "wpop_block_types": [] }, "category_slugs": [ "buttons" ], "keyword_slugs": [ "core" ], @@ -27,7 +28,8 @@ "spay_email": "", "wpop_description": "Two buttons, one filled and one outlined, side by side.", "wpop_keywords": "", - "wpop_viewport_width": 500 + "wpop_viewport_width": 500, + "wpop_block_types": [] }, "category_slugs": [ "buttons" ], "keyword_slugs": [ "core" ], diff --git a/tests/phpunit/data/blocks/pattern-directory/browse-keyword-11.json b/tests/phpunit/data/blocks/pattern-directory/browse-keyword-11.json index 383d7eff61..360dcdfb84 100644 --- a/tests/phpunit/data/blocks/pattern-directory/browse-keyword-11.json +++ b/tests/phpunit/data/blocks/pattern-directory/browse-keyword-11.json @@ -10,7 +10,8 @@ "spay_email": "", "wpop_description": "A heading preceded by a chapter number, and followed by a paragraph.", "wpop_keywords": "", - "wpop_viewport_width": 1000 + "wpop_viewport_width": 1000, + "wpop_block_types": [] }, "category_slugs": [ "text" ], "keyword_slugs": [ "core" ], @@ -27,7 +28,8 @@ "spay_email": "", "wpop_description": "A large hero section with an example background image and a heading in the center.", "wpop_keywords": "", - "wpop_viewport_width": 1000 + "wpop_viewport_width": 1000, + "wpop_block_types": [] }, "category_slugs": [ "header" ], "keyword_slugs": [ "core" ], @@ -44,7 +46,8 @@ "spay_email": "", "wpop_description": "A large hero section with a bright gradient background, a big heading and a filled button.", "wpop_keywords": "", - "wpop_viewport_width": 1000 + "wpop_viewport_width": 1000, + "wpop_block_types": [] }, "category_slugs": [ "header" ], "keyword_slugs": [ "core" ], diff --git a/tests/phpunit/data/blocks/pattern-directory/search-button.json b/tests/phpunit/data/blocks/pattern-directory/search-button.json index 10e5c6036f..4a6f86de8a 100644 --- a/tests/phpunit/data/blocks/pattern-directory/search-button.json +++ b/tests/phpunit/data/blocks/pattern-directory/search-button.json @@ -10,7 +10,8 @@ "spay_email": "", "wpop_description": "A large hero section with a bright gradient background, a big heading and a filled button.", "wpop_keywords": "", - "wpop_viewport_width": 1000 + "wpop_viewport_width": 1000, + "wpop_block_types": [] }, "category_slugs": [ "header" ], "keyword_slugs": [ "core" ], @@ -27,7 +28,8 @@ "spay_email": "", "wpop_description": "Three small columns of text, each with an outlined button with rounded corners at the bottom.", "wpop_keywords": "", - "wpop_viewport_width": 1000 + "wpop_viewport_width": 1000, + "wpop_block_types": [] }, "category_slugs": [ "columns" ], "keyword_slugs": [ "core" ], @@ -44,7 +46,8 @@ "spay_email": "", "wpop_description": "Three filled buttons with rounded corners, side by side.", "wpop_keywords": "", - "wpop_viewport_width": 600 + "wpop_viewport_width": 600, + "wpop_block_types": [] }, "category_slugs": [ "buttons" ], "keyword_slugs": [ "core" ], @@ -61,7 +64,8 @@ "spay_email": "", "wpop_description": "Two buttons, one filled and one outlined, side by side.", "wpop_keywords": "", - "wpop_viewport_width": 500 + "wpop_viewport_width": 500, + "wpop_block_types": [] }, "category_slugs": [ "buttons" ], "keyword_slugs": [ "core" ],