diff -r be944660c56a -r 3d72ae0968f4 wp/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php --- a/wp/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php Wed Sep 21 18:19:35 2022 +0200 +++ b/wp/wp-includes/rest-api/endpoints/class-wp-rest-pattern-directory-controller.php Tue Sep 27 16:37:53 2022 +0200 @@ -25,8 +25,8 @@ * @since 5.8.0 */ public function __construct() { - $this->namespace = 'wp/v2'; - $this->rest_base = 'pattern-directory'; + $this->namespace = 'wp/v2'; + $this->rest_base = 'pattern-directory'; } /** @@ -51,7 +51,7 @@ } /** - * Checks whether a given request has permission to view the local pattern directory. + * Checks whether a given request has permission to view the local block pattern directory. * * @since 5.8.0 * @@ -80,6 +80,7 @@ * Search and retrieve block patterns metadata * * @since 5.8.0 + * @since 6.0.0 Added 'slug' to request. * * @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. @@ -100,6 +101,7 @@ $category_id = $request['category']; $keyword_id = $request['keyword']; $search_term = $request['search']; + $slug = $request['slug']; if ( $category_id ) { $query_args['pattern-categories'] = $category_id; @@ -113,16 +115,11 @@ $query_args['search'] = $search_term; } - /* - * 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 ) ); + if ( $slug ) { + $query_args['slug'] = $slug; + } + + $transient_key = $this->get_transient_key( $query_args ); /* * Use network-wide transient to improve performance. The locale is the only site @@ -131,11 +128,7 @@ $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/' - ); - + $api_url = 'http://api.wordpress.org/patterns/1.0/?' . build_query( $query_args ); if ( wp_http_supports( array( 'ssl' ) ) ) { $api_url = set_url_scheme( $api_url, 'https' ); } @@ -159,7 +152,7 @@ $raw_patterns = new WP_Error( 'pattern_api_failed', sprintf( - /* translators: %s: Support forums URL. */ + /* 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.' ), __( 'https://wordpress.org/support/forums/' ) ), @@ -196,21 +189,24 @@ } /** - * Prepare a raw pattern before it's output in an API response. + * Prepare a raw block pattern before it gets output in a REST API response. * * @since 5.8.0 + * @since 5.9.0 Renamed `$raw_pattern` to `$item` to match parent class for PHP 8 named parameter support. * - * @param object $raw_pattern A pattern from api.wordpress.org, before any changes. - * @param WP_REST_Request $request Request object. + * @param object $item Raw pattern from api.wordpress.org, before any changes. + * @param WP_REST_Request $request Request object. * @return WP_REST_Response */ - public function prepare_item_for_response( $raw_pattern, $request ) { + public function prepare_item_for_response( $item, $request ) { + // Restores the more descriptive, specific name for use within this method. + $raw_pattern = $item; $prepared_pattern = array( 'id' => absint( $raw_pattern->id ), 'title' => sanitize_text_field( $raw_pattern->title->rendered ), 'content' => wp_kses_post( $raw_pattern->pattern_content ), 'categories' => array_map( 'sanitize_title', $raw_pattern->category_slugs ), - 'keywords' => array_map( 'sanitize_title', $raw_pattern->keyword_slugs ), + '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 ), ); @@ -220,19 +216,19 @@ $response = new WP_REST_Response( $prepared_pattern ); /** - * Filters the REST API response for a pattern. + * Filters the REST API response for a block pattern. * * @since 5.8.0 * * @param WP_REST_Response $response The response object. - * @param object $raw_pattern The unprepared pattern. + * @param object $raw_pattern The unprepared block pattern. * @param WP_REST_Request $request The request object. */ return apply_filters( 'rest_prepare_block_pattern', $response, $raw_pattern, $request ); } /** - * Retrieves the pattern's schema, conforming to JSON Schema. + * Retrieves the block pattern's schema, conforming to JSON Schema. * * @since 5.8.0 * @@ -252,21 +248,21 @@ 'description' => __( 'The pattern ID.' ), 'type' => 'integer', 'minimum' => 1, - 'context' => array( 'view', 'embed' ), + 'context' => array( 'view', 'edit', 'embed' ), ), 'title' => array( 'description' => __( 'The pattern title, in human readable format.' ), 'type' => 'string', 'minLength' => 1, - 'context' => array( 'view', 'embed' ), + 'context' => array( 'view', 'edit', 'embed' ), ), 'content' => array( 'description' => __( 'The pattern content.' ), 'type' => 'string', 'minLength' => 1, - 'context' => array( 'view', 'embed' ), + 'context' => array( 'view', 'edit', 'embed' ), ), 'categories' => array( @@ -274,28 +270,28 @@ 'type' => 'array', 'uniqueItems' => true, 'items' => array( 'type' => 'string' ), - 'context' => array( 'view', 'embed' ), + 'context' => array( 'view', 'edit', 'embed' ), ), 'keywords' => array( - 'description' => __( "The pattern's keyword slugs." ), + 'description' => __( "The pattern's keywords." ), 'type' => 'array', 'uniqueItems' => true, 'items' => array( 'type' => 'string' ), - 'context' => array( 'view', 'embed' ), + 'context' => array( 'view', 'edit', 'embed' ), ), 'description' => array( 'description' => __( 'A description of the pattern.' ), 'type' => 'string', 'minLength' => 1, - 'context' => array( 'view', 'embed' ), + 'context' => array( 'view', 'edit', 'embed' ), ), 'viewport_width' => array( 'description' => __( 'The preferred width of the viewport when previewing a pattern, in pixels.' ), 'type' => 'integer', - 'context' => array( 'view', 'embed' ), + 'context' => array( 'view', 'edit', 'embed' ), ), ), ); @@ -304,7 +300,7 @@ } /** - * Retrieves the search params for the patterns collection. + * Retrieves the search parameters for the block pattern's collection. * * @since 5.8.0 * @@ -332,8 +328,13 @@ 'minimum' => 1, ); + $query_params['slug'] = array( + 'description' => __( 'Limit results to those matching a pattern (slug).' ), + 'type' => 'array', + ); + /** - * Filter collection parameters for the pattern directory controller. + * Filter collection parameters for the block pattern directory controller. * * @since 5.8.0 * @@ -341,4 +342,36 @@ */ return apply_filters( 'rest_pattern_directory_collection_params', $query_params ); } + + /* + * 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 + * + * @since 6.0.0 + * + * @param array $query_args Query arguments to generate a transient key from. + * @return string Transient key. + */ + protected function get_transient_key( $query_args ) { + + if ( isset( $query_args['slug'] ) ) { + // This is an additional precaution because the "sort" function expects an array. + $query_args['slug'] = wp_parse_list( $query_args['slug'] ); + + // Empty arrays should not affect the transient key. + if ( empty( $query_args['slug'] ) ) { + unset( $query_args['slug'] ); + } else { + // Sort the array so that the transient key doesn't depend on the order of slugs. + sort( $query_args['slug'] ); + } + } + + return 'wp_remote_block_patterns_' . md5( serialize( $query_args ) ); + } }