diff -r be944660c56a -r 3d72ae0968f4 wp/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php --- a/wp/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php Wed Sep 21 18:19:35 2022 +0200 +++ b/wp/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php Tue Sep 27 16:37:53 2022 +0200 @@ -17,6 +17,12 @@ class WP_REST_Themes_Controller extends WP_REST_Controller { /** + * Matches theme's directory: `/themes///` or `/themes//`. + * Excludes invalid directory name characters: `/:<>*?"|`. + */ + const PATTERN = '[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?'; + + /** * Constructor. * * @since 5.0.0 @@ -50,12 +56,13 @@ register_rest_route( $this->namespace, - '/' . $this->rest_base . '/(?P[\w-]+)', + sprintf( '/%s/(?P%s)', $this->rest_base, self::PATTERN ), array( 'args' => array( 'stylesheet' => array( - 'description' => __( "The theme's stylesheet. This uniquely identifies the theme." ), - 'type' => 'string', + 'description' => __( "The theme's stylesheet. This uniquely identifies the theme." ), + 'type' => 'string', + 'sanitize_callback' => array( $this, '_sanitize_stylesheet_callback' ), ), ), array( @@ -69,6 +76,18 @@ } /** + * Sanitize the stylesheet to decode endpoint. + * + * @since 5.9.0 + * + * @param string $stylesheet The stylesheet name. + * @return string Sanitized stylesheet. + */ + public function _sanitize_stylesheet_callback( $stylesheet ) { + return urldecode( $stylesheet ); + } + + /** * Checks if a given request has access to read the theme. * * @since 5.0.0 @@ -204,12 +223,15 @@ * Prepares a single theme output for response. * * @since 5.0.0 + * @since 5.9.0 Renamed `$theme` to `$item` to match parent class for PHP 8 named parameter support. * - * @param WP_Theme $theme Theme object. + * @param WP_Theme $item Theme object. * @param WP_REST_Request $request Request object. * @return WP_REST_Response Response object. */ - public function prepare_item_for_response( $theme, $request ) { + public function prepare_item_for_response( $item, $request ) { + // Restores the more descriptive, specific name for use within this method. + $theme = $item; $data = array(); $fields = $this->get_fields_for_response( $request ); @@ -311,6 +333,21 @@ $response->add_links( $this->prepare_links( $theme ) ); + if ( $theme->get_stylesheet() === wp_get_theme()->get_stylesheet() ) { + // This creates a record for the active theme if not existent. + $id = WP_Theme_JSON_Resolver::get_user_global_styles_post_id(); + } else { + $user_cpt = WP_Theme_JSON_Resolver::get_user_data_from_wp_global_styles( $theme ); + $id = isset( $user_cpt['ID'] ) ? $user_cpt['ID'] : null; + } + + if ( $id ) { + $response->add_link( + 'https://api.w.org/user-global-styles', + rest_url( 'wp/v2/global-styles/' . $id ) + ); + } + /** * Filters theme data returned from the REST API. *