diff --git a/lib/compat/wordpress-6.0/block-patterns.php b/lib/compat/wordpress-6.0/block-patterns.php new file mode 100644 index 00000000000000..ff0547031529c6 --- /dev/null +++ b/lib/compat/wordpress-6.0/block-patterns.php @@ -0,0 +1,48 @@ +get_pattern_settings(); + if ( empty( $pattern_settings ) ) { + return; + } + $request = new WP_REST_Request( 'GET', '/wp/v2/pattern-directory/patterns' ); + $request['slug'] = implode( ',', $pattern_settings ); + $response = rest_do_request( $request ); + if ( $response->is_error() ) { + return; + } + $patterns = $response->get_data(); + $patterns_registry = WP_Block_Patterns_Registry::get_instance(); + foreach ( $patterns as $pattern ) { + $pattern_name = sanitize_title( $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 ); + } + } +} + +add_action( + 'init', + function() { + $should_load_remote = apply_filters( 'should_load_remote_block_patterns', true ); + if ( ! get_theme_support( 'core-block-patterns' ) || ! $should_load_remote ) { + return; + } + gutenberg_register_remote_theme_patterns(); + } +); diff --git a/lib/compat/wordpress-6.0/class-gutenberg-rest-pattern-directory-controller.php b/lib/compat/wordpress-6.0/class-gutenberg-rest-pattern-directory-controller.php new file mode 100644 index 00000000000000..6c5f7f85e38108 --- /dev/null +++ b/lib/compat/wordpress-6.0/class-gutenberg-rest-pattern-directory-controller.php @@ -0,0 +1,141 @@ + get_user_locale(), + 'wp-version' => $wp_version, // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UndefinedVariable -- it's defined in `version.php` above. + 'gutenberg-version' => $gutenberg_data['Version'], + ); + + $category_id = $request['category']; + $keyword_id = $request['keyword']; + $search_term = $request['search']; + $slug = $request['slug']; + + if ( $category_id ) { + $query_args['pattern-categories'] = $category_id; + } + + if ( $keyword_id ) { + $query_args['pattern-keywords'] = $keyword_id; + } + + if ( $search_term ) { + $query_args['search'] = $search_term; + } + + if ( $slug ) { + $query_args['slug'] = $slug; + } + + /* + * Include a hash of the query args, so that different requests are stored in + * separate caches. + * + * MD5 is chosen for its speed, low-collision rate, universal availability, and to stay + * under the character limit for `_site_transient_timeout_{...}` keys. + * + * @link https://stackoverflow.com/questions/3665247/fastest-hash-for-non-cryptographic-uses + */ + $transient_key = 'wp_remote_block_patterns_' . md5( implode( '-', $query_args ) ); + + /* + * Use network-wide transient to improve performance. The locale is the only site + * configuration that affects the response, and it's included in the transient key. + */ + $raw_patterns = get_site_transient( $transient_key ); + + if ( ! $raw_patterns ) { + $api_url = add_query_arg( + array_map( 'rawurlencode', $query_args ), + 'http://api.wordpress.org/patterns/1.0/' + ); + + if ( wp_http_supports( array( 'ssl' ) ) ) { + $api_url = set_url_scheme( $api_url, 'https' ); + } + + /* + * Default to a short TTL, to mitigate cache stampedes on high-traffic sites. + * This assumes that most errors will be short-lived, e.g., packet loss that causes the + * first request to fail, but a follow-up one will succeed. The value should be high + * enough to avoid stampedes, but low enough to not interfere with users manually + * re-trying a failed request. + */ + $cache_ttl = 5; + $wporg_response = wp_remote_get( $api_url ); + $raw_patterns = json_decode( wp_remote_retrieve_body( $wporg_response ) ); + + if ( is_wp_error( $wporg_response ) ) { + $raw_patterns = $wporg_response; + + } elseif ( ! is_array( $raw_patterns ) ) { + // HTTP request succeeded, but response data is invalid. + $raw_patterns = new WP_Error( + 'pattern_api_failed', + sprintf( + /* translators: %s: Support forums URL. */ + __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the support forums.', 'gutenberg' ), + __( 'https://wordpress.org/support/forums/', 'gutenberg' ) + ), + array( + 'response' => wp_remote_retrieve_body( $wporg_response ), + ) + ); + + } else { + // Response has valid data. + $cache_ttl = HOUR_IN_SECONDS; + } + + set_site_transient( $transient_key, $raw_patterns, $cache_ttl ); + } + + if ( is_wp_error( $raw_patterns ) ) { + $raw_patterns->add_data( array( 'status' => 500 ) ); + + return $raw_patterns; + } + + $response = array(); + + if ( $raw_patterns ) { + foreach ( $raw_patterns as $pattern ) { + $response[] = $this->prepare_response_for_collection( + $this->prepare_item_for_response( $pattern, $request ) + ); + } + } + + return new WP_REST_Response( $response ); + } +} diff --git a/lib/compat/wordpress-5.9/class-wp-theme-json-gutenberg.php b/lib/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php similarity index 99% rename from lib/compat/wordpress-5.9/class-wp-theme-json-gutenberg.php rename to lib/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php index 9d10266d0505a6..9247491c1a4854 100644 --- a/lib/compat/wordpress-5.9/class-wp-theme-json-gutenberg.php +++ b/lib/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php @@ -208,6 +208,7 @@ class WP_Theme_JSON_Gutenberg { 'settings', 'styles', 'templateParts', + 'patterns', 'version', ); @@ -675,6 +676,18 @@ public function get_custom_templates() { return $custom_templates; } + /** + * Returns the current theme's wanted patterns(slugs) to be + * registered from Pattern Directory. + * + * @return array|null + */ + public function get_pattern_settings() { + if ( isset( $this->theme_json['patterns'] ) && is_array( $this->theme_json['patterns'] ) ) { + return $this->theme_json['patterns']; + } + } + /** * Returns the template part data of current theme. * diff --git a/lib/compat/wordpress-6.0/rest-api.php b/lib/compat/wordpress-6.0/rest-api.php index 5816f518d64784..8ccbf4f35b0b0a 100644 --- a/lib/compat/wordpress-6.0/rest-api.php +++ b/lib/compat/wordpress-6.0/rest-api.php @@ -13,3 +13,13 @@ function gutenberg_register_global_styles_endpoints() { $editor_settings->register_routes(); } add_action( 'rest_api_init', 'gutenberg_register_global_styles_endpoints' ); + + +/** + * Registers the block pattern directory. + */ +function gutenberg_register_rest_pattern_directory() { + $pattern_directory_controller = new Gutenberg_REST_Pattern_Directory_Controller(); + $pattern_directory_controller->register_routes(); +} +add_filter( 'rest_api_init', 'gutenberg_register_rest_pattern_directory' ); diff --git a/lib/load.php b/lib/load.php index 7b62bd40d9f12e..da9abcad0fc120 100644 --- a/lib/load.php +++ b/lib/load.php @@ -85,7 +85,6 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-5.9/theme-templates.php'; require __DIR__ . '/editor-settings.php'; require __DIR__ . '/compat/wordpress-5.9/class-wp-theme-json-schema-gutenberg.php'; -require __DIR__ . '/compat/wordpress-5.9/class-wp-theme-json-gutenberg.php'; require __DIR__ . '/compat/wordpress-5.9/class-wp-theme-json-resolver-gutenberg.php'; require __DIR__ . '/compat/wordpress-5.9/theme.php'; require __DIR__ . '/compat/wordpress-5.9/admin-menu.php'; @@ -99,7 +98,10 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.0/post-lock.php'; require __DIR__ . '/compat/wordpress-6.0/blocks.php'; require __DIR__ . '/compat/wordpress-6.0/class-gutenberg-rest-global-styles-controller.php'; +require __DIR__ . '/compat/wordpress-6.0/class-gutenberg-rest-pattern-directory-controller.php'; +require __DIR__ . '/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php'; require __DIR__ . '/compat/wordpress-6.0/rest-api.php'; +require __DIR__ . '/compat/wordpress-6.0/block-patterns.php'; require __DIR__ . '/compat/experimental/blocks.php'; require __DIR__ . '/blocks.php'; diff --git a/schemas/json/theme.json b/schemas/json/theme.json index 9fd1241f59fed0..a21710fe4626b5 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -1243,6 +1243,13 @@ "required": [ "name" ], "additionalProperties": false } + }, + "patterns": { + "description": "An array of pattern slugs to be registered from the Pattern Directory.", + "type": "array", + "items": { + "type": "string" + } } }, "required": [ "version" ], diff --git a/test/emptytheme/theme.json b/test/emptytheme/theme.json index 4f478f46c4bb7b..9ea5f123e88f65 100644 --- a/test/emptytheme/theme.json +++ b/test/emptytheme/theme.json @@ -6,5 +6,6 @@ "contentSize": "840px", "wideSize": "1100px" } - } -} \ No newline at end of file + }, + "patterns": ["short-text-surrounded-by-round-images", "partner-logos" ] +}