diff --git a/lib/compat/wordpress-6.2/class-gutenberg-rest-pattern-directory-controller-6-2.php b/lib/compat/wordpress-6.2/class-gutenberg-rest-pattern-directory-controller-6-2.php
index e96ee976748ff..7043140c23fcf 100644
--- a/lib/compat/wordpress-6.2/class-gutenberg-rest-pattern-directory-controller-6-2.php
+++ b/lib/compat/wordpress-6.2/class-gutenberg-rest-pattern-directory-controller-6-2.php
@@ -10,127 +10,6 @@
* Controller which provides REST endpoint for block patterns from wordpress.org/patterns.
*/
class Gutenberg_REST_Pattern_Directory_Controller_6_2 extends WP_REST_Pattern_Directory_Controller {
- /**
- * Registers the necessary REST API routes.
- *
- * @since 5.8.0
- * @since 6.2.0 Added pattern directory categories endpoint.
- */
- public function register_routes() {
- register_rest_route(
- $this->namespace,
- '/' . $this->rest_base . '/categories',
- array(
- array(
- 'methods' => WP_REST_Server::READABLE,
- 'callback' => array( $this, 'get_pattern_categories' ),
- 'permission_callback' => array( $this, 'get_items_permissions_check' ),
- ),
- )
- );
-
- parent::register_routes();
- }
-
- /**
- * Retrieve block patterns categories.
- *
- * @since 6.2.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_pattern_categories( $request ) {
- $query_args = array( 'locale' => get_user_locale() );
- $transient_key = 'wp_remote_block_pattern_categories_' . md5( serialize( $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_pattern_categories = get_site_transient( $transient_key );
-
- if ( ! $raw_pattern_categories ) {
- $api_url = 'http://api.wordpress.org/patterns/1.0/?categories&' . build_query( $query_args );
- 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_pattern_categories = json_decode( wp_remote_retrieve_body( $wporg_response ) );
- if ( is_wp_error( $wporg_response ) ) {
- $raw_pattern_categories = $wporg_response;
-
- } elseif ( ! is_array( $raw_pattern_categories ) ) {
- // HTTP request succeeded, but response data is invalid.
- $raw_pattern_categories = new WP_Error(
- 'pattern_directory_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_pattern_categories, $cache_ttl );
- }
-
- if ( is_wp_error( $raw_pattern_categories ) ) {
- $raw_pattern_categories->add_data( array( 'status' => 500 ) );
-
- return $raw_pattern_categories;
- }
-
- $response = array();
-
- if ( $raw_pattern_categories ) {
- foreach ( $raw_pattern_categories as $category ) {
- $response[] = $this->prepare_response_for_collection(
- $this->prepare_pattern_category_for_response( $category, $request )
- );
- }
- }
-
- return new WP_REST_Response( $response );
- }
-
- /**
- * Prepare a raw block pattern category before it gets output in a REST API response.
- *
- * @since 6.2.0
- *
- * @param object $item Raw pattern category from api.wordpress.org, before any changes.
- * @param WP_REST_Request $request Request object.
- * @return WP_REST_Response
- */
- public function prepare_pattern_category_for_response( $item, $request ) {
- $raw_pattern_category = array(
- 'id' => absint( $item->id ),
- 'name' => sanitize_text_field( $item->name ),
- 'slug' => sanitize_title_with_dashes( $item->slug ),
- );
-
- $prepared_pattern_category = $this->add_additional_fields_to_object( $raw_pattern_category, $request );
-
- return new WP_REST_Response( $prepared_pattern_category );
- }
-
/**
* Search and retrieve block patterns metadata
*
@@ -174,7 +53,7 @@ public function get_items( $request ) {
$transient_key = $this->get_transient_key( $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.
*/
@@ -186,7 +65,7 @@ public function get_items( $request ) {
$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
diff --git a/lib/compat/wordpress-6.2/rest-api.php b/lib/compat/wordpress-6.2/rest-api.php
index 6161885d020d7..86e7031cb794f 100644
--- a/lib/compat/wordpress-6.2/rest-api.php
+++ b/lib/compat/wordpress-6.2/rest-api.php
@@ -14,15 +14,6 @@ function gutenberg_register_rest_block_pattern_categories() {
}
add_action( 'rest_api_init', 'gutenberg_register_rest_block_pattern_categories' );
-/**
- * Registers the block pattern directory.
- */
-function gutenberg_register_rest_pattern_directory() {
- $pattern_directory_controller = new Gutenberg_REST_Pattern_Directory_Controller_6_2();
- $pattern_directory_controller->register_routes();
-}
-add_action( 'rest_api_init', 'gutenberg_register_rest_pattern_directory' );
-
/**
* Registers the block patterns REST API routes.
*/
diff --git a/lib/compat/wordpress-6.3/class-gutenberg-rest-pattern-directory-controller-6-3.php b/lib/compat/wordpress-6.3/class-gutenberg-rest-pattern-directory-controller-6-3.php
new file mode 100644
index 0000000000000..1d1ba16571bc4
--- /dev/null
+++ b/lib/compat/wordpress-6.3/class-gutenberg-rest-pattern-directory-controller-6-3.php
@@ -0,0 +1,133 @@
+namespace,
+ '/' . $this->rest_base . '/categories',
+ array(
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_pattern_categories' ),
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
+ ),
+ )
+ );
+
+ parent::register_routes();
+ }
+
+ /**
+ * Retrieve block patterns categories.
+ *
+ * @since 6.3.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_pattern_categories( $request ) {
+ $query_args = array( 'locale' => get_user_locale() );
+ $transient_key = 'wp_remote_block_pattern_categories_' . md5( serialize( $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_pattern_categories = get_site_transient( $transient_key );
+
+ if ( ! $raw_pattern_categories ) {
+ $api_url = 'http://api.wordpress.org/patterns/1.0/?categories&' . build_query( $query_args );
+ 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_pattern_categories = json_decode( wp_remote_retrieve_body( $wporg_response ) );
+ if ( is_wp_error( $wporg_response ) ) {
+ $raw_pattern_categories = $wporg_response;
+
+ } elseif ( ! is_array( $raw_pattern_categories ) ) {
+ // HTTP request succeeded, but response data is invalid.
+ $raw_pattern_categories = new WP_Error(
+ 'pattern_directory_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_pattern_categories, $cache_ttl );
+ }
+
+ if ( is_wp_error( $raw_pattern_categories ) ) {
+ $raw_pattern_categories->add_data( array( 'status' => 500 ) );
+
+ return $raw_pattern_categories;
+ }
+
+ $response = array();
+
+ if ( $raw_pattern_categories ) {
+ foreach ( $raw_pattern_categories as $category ) {
+ $response[] = $this->prepare_response_for_collection(
+ $this->prepare_pattern_category_for_response( $category, $request )
+ );
+ }
+ }
+
+ return new WP_REST_Response( $response );
+ }
+
+ /**
+ * Prepare a raw block pattern category before it gets output in a REST API response.
+ *
+ * @since 6.3.0
+ *
+ * @param object $item Raw pattern category from api.wordpress.org, before any changes.
+ * @param WP_REST_Request $request Request object.
+ * @return WP_REST_Response
+ */
+ public function prepare_pattern_category_for_response( $item, $request ) {
+ $raw_pattern_category = array(
+ 'id' => absint( $item->id ),
+ 'name' => sanitize_text_field( $item->name ),
+ 'slug' => sanitize_title_with_dashes( $item->slug ),
+ );
+
+ $prepared_pattern_category = $this->add_additional_fields_to_object( $raw_pattern_category, $request );
+
+ return new WP_REST_Response( $prepared_pattern_category );
+ }
+}
diff --git a/lib/compat/wordpress-6.3/rest-api.php b/lib/compat/wordpress-6.3/rest-api.php
new file mode 100644
index 0000000000000..55a45df07d593
--- /dev/null
+++ b/lib/compat/wordpress-6.3/rest-api.php
@@ -0,0 +1,15 @@
+register_routes();
+}
+add_action( 'rest_api_init', 'gutenberg_register_rest_pattern_directory' );
diff --git a/lib/load.php b/lib/load.php
index e400d2f8211b3..5a58d40d63d6b 100644
--- a/lib/load.php
+++ b/lib/load.php
@@ -48,6 +48,10 @@ function gutenberg_is_experiment_enabled( $name ) {
require_once __DIR__ . '/compat/wordpress-6.2/block-patterns.php';
require_once __DIR__ . '/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php';
+ // WordPress 6.3 compat.
+ require_once __DIR__ . '/compat/wordpress-6.3/class-gutenberg-rest-pattern-directory-controller-6-3.php';
+ require_once __DIR__ . '/compat/wordpress-6.3/rest-api.php';
+
// Experimental.
if ( ! class_exists( 'WP_Rest_Customizer_Nonces' ) ) {
require_once __DIR__ . '/experimental/class-wp-rest-customizer-nonces.php';
diff --git a/phpunit/class-wp-rest-pattern-directory-controller-test.php b/phpunit/class-wp-rest-pattern-directory-controller-test.php
index c05e6b4be114f..12ed9ca9152d0 100644
--- a/phpunit/class-wp-rest-pattern-directory-controller-test.php
+++ b/phpunit/class-wp-rest-pattern-directory-controller-test.php
@@ -53,7 +53,7 @@ public static function wpSetUpBeforeClass( $factory ) {
self::$http_request_urls = array();
- static::$controller = new Gutenberg_REST_Pattern_Directory_Controller_6_2();
+ static::$controller = new Gutenberg_REST_Pattern_Directory_Controller_6_3();
}
public static function wpTearDownAfterClass() {