Changeset 58262
- Timestamp:
- 05/31/2024 01:17:50 AM (4 months ago)
- Location:
- trunk
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/class-wp-theme-json-resolver.php
r58185 r58262 745 745 return $variations; 746 746 } 747 748 /** 749 * Resolves relative paths in theme.json styles to theme absolute paths 750 * and returns them in an array that can be embedded 751 * as the value of `_link` object in REST API responses. 752 * 753 * @since 6.6.0 754 * 755 * @param WP_Theme_JSON $theme_json A theme json instance. 756 * @return array An array of resolved paths. 757 */ 758 public static function get_resolved_theme_uris( $theme_json ) { 759 $resolved_theme_uris = array(); 760 761 if ( ! $theme_json instanceof WP_Theme_JSON ) { 762 return $resolved_theme_uris; 763 } 764 765 $theme_json_data = $theme_json->get_raw_data(); 766 767 // Top level styles. 768 $background_image_url = isset( $theme_json_data['styles']['background']['backgroundImage']['url'] ) ? $theme_json_data['styles']['background']['backgroundImage']['url'] : null; 769 770 /* 771 * The same file convention when registering web fonts. 772 * See: WP_Font_Face_Resolver:: to_theme_file_uri. 773 */ 774 $placeholder = 'file:./'; 775 if ( 776 isset( $background_image_url ) && 777 is_string( $background_image_url ) && 778 // Skip if the src doesn't start with the placeholder, as there's nothing to replace. 779 str_starts_with( $background_image_url, $placeholder ) 780 ) { 781 $file_type = wp_check_filetype( $background_image_url ); 782 $src_url = str_replace( $placeholder, '', $background_image_url ); 783 $resolved_theme_uri = array( 784 'name' => $background_image_url, 785 'href' => sanitize_url( get_theme_file_uri( $src_url ) ), 786 'target' => 'styles.background.backgroundImage.url', 787 ); 788 if ( isset( $file_type['type'] ) ) { 789 $resolved_theme_uri['type'] = $file_type['type']; 790 } 791 $resolved_theme_uris[] = $resolved_theme_uri; 792 } 793 794 return $resolved_theme_uris; 795 } 796 797 /** 798 * Resolves relative paths in theme.json styles to theme absolute paths 799 * and merges them with incoming theme JSON. 800 * 801 * @since 6.6.0 802 * 803 * @param WP_Theme_JSON $theme_json A theme json instance. 804 * @return WP_Theme_JSON Theme merged with resolved paths, if any found. 805 */ 806 public static function resolve_theme_file_uris( $theme_json ) { 807 $resolved_urls = static::get_resolved_theme_uris( $theme_json ); 808 if ( empty( $resolved_urls ) ) { 809 return $theme_json; 810 } 811 812 $resolved_theme_json_data = array( 813 'version' => WP_Theme_JSON::LATEST_SCHEMA, 814 ); 815 816 foreach ( $resolved_urls as $resolved_url ) { 817 $path = explode( '.', $resolved_url['target'] ); 818 _wp_array_set( $resolved_theme_json_data, $path, $resolved_url['href'] ); 819 } 820 821 $theme_json->merge( new WP_Theme_JSON( $resolved_theme_json_data ) ); 822 823 return $theme_json; 824 } 747 825 } -
trunk/src/wp-includes/global-styles-and-settings.php
r58026 r58262 140 140 * @since 5.9.0 141 141 * @since 6.1.0 Added 'base-layout-styles' support. 142 * @since 6.6.0 Resolves relative paths in theme.json styles to theme absolute paths. 142 143 * 143 144 * @param array $types Optional. Types of styles to load. … … 180 181 } 181 182 182 $tree = WP_Theme_JSON_Resolver::get_merged_data(); 183 183 $tree = WP_Theme_JSON_Resolver::resolve_theme_file_uris( WP_Theme_JSON_Resolver::get_merged_data() ); 184 184 $supports_theme_json = wp_theme_has_theme_json(); 185 185 186 if ( empty( $types ) && ! $supports_theme_json ) { 186 187 $types = array( 'variables', 'presets', 'base-layout-styles' ); -
trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php
r58225 r58262 290 290 * 291 291 * @since 5.9.0 292 * @since 6.6.0 Added custom relative theme file URIs to `_links`. 292 293 * 293 294 * @param WP_Post $post Global Styles post object. … … 299 300 $is_global_styles_user_theme_json = isset( $raw_config['isGlobalStylesUserThemeJSON'] ) && true === $raw_config['isGlobalStylesUserThemeJSON']; 300 301 $config = array(); 302 $theme_json = null; 301 303 if ( $is_global_styles_user_theme_json ) { 302 $config = ( new WP_Theme_JSON( $raw_config, 'custom' ) )->get_raw_data(); 304 $theme_json = new WP_Theme_JSON( $raw_config, 'custom' ); 305 $config = $theme_json->get_raw_data(); 303 306 } 304 307 … … 342 345 if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { 343 346 $links = $this->prepare_links( $post->ID ); 347 348 // Only return resolved URIs for get requests to user theme JSON. 349 if ( $theme_json ) { 350 $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme_json ); 351 if ( ! empty( $resolved_theme_uris ) ) { 352 $links['https://api.w.org/theme-file'] = $resolved_theme_uris; 353 } 354 } 355 344 356 $response->add_links( $links ); 345 357 if ( ! empty( $links['self']['href'] ) ) { … … 516 528 * 517 529 * @since 5.9.0 530 * @since 6.6.0 Added custom relative theme file URIs to `_links`. 518 531 * 519 532 * @param WP_REST_Request $request The request instance. … … 550 563 551 564 if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { 552 $links = array(565 $links = array( 553 566 'self' => array( 554 567 'href' => rest_url( sprintf( '%s/%s/themes/%s', $this->namespace, $this->rest_base, $request['stylesheet'] ) ), 555 568 ), 556 569 ); 570 $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme ); 571 if ( ! empty( $resolved_theme_uris ) ) { 572 $links['https://api.w.org/theme-file'] = $resolved_theme_uris; 573 } 557 574 $response->add_links( $links ); 558 575 } … … 592 609 * @since 6.0.0 593 610 * @since 6.2.0 Returns parent theme variations, if they exist. 611 * @since 6.6.0 Added custom relative theme file URIs to `_links` for each item. 594 612 * 595 613 * @param WP_REST_Request $request The request instance. … … 607 625 } 608 626 627 $response = array(); 609 628 $variations = WP_Theme_JSON_Resolver::get_style_variations(); 610 629 611 return rest_ensure_response( $variations ); 630 foreach ( $variations as $variation ) { 631 $variation_theme_json = new WP_Theme_JSON( $variation ); 632 $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $variation_theme_json ); 633 $data = rest_ensure_response( $variation ); 634 if ( ! empty( $resolved_theme_uris ) ) { 635 $data->add_links( 636 array( 637 'https://api.w.org/theme-file' => $resolved_theme_uris, 638 ) 639 ); 640 } 641 $response[] = $this->prepare_response_for_collection( $data ); 642 } 643 644 return rest_ensure_response( $response ); 612 645 } 613 646 -
trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php
r58225 r58262 269 269 * 270 270 * @since 6.3.0 271 * @since 6.6.0 Added resolved URI links to the response. 271 272 * 272 273 * @param WP_Post $post Post revision object. … … 282 283 } 283 284 284 $fields = $this->get_fields_for_response( $request ); 285 $data = array(); 285 $fields = $this->get_fields_for_response( $request ); 286 $data = array(); 287 $theme_json = null; 286 288 287 289 if ( ! empty( $global_styles_config['styles'] ) || ! empty( $global_styles_config['settings'] ) ) { 288 $global_styles_config = ( new WP_Theme_JSON( $global_styles_config, 'custom' ) )->get_raw_data(); 290 $theme_json = new WP_Theme_JSON( $global_styles_config, 'custom' ); 291 $global_styles_config = $theme_json->get_raw_data(); 289 292 if ( rest_is_field_included( 'settings', $fields ) ) { 290 293 $data['settings'] = ! empty( $global_styles_config['settings'] ) ? $global_styles_config['settings'] : new stdClass(); … … 323 326 } 324 327 325 $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; 326 $data = $this->add_additional_fields_to_object( $data, $request ); 327 $data = $this->filter_response_by_context( $data, $context ); 328 329 return rest_ensure_response( $data ); 328 $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; 329 $data = $this->add_additional_fields_to_object( $data, $request ); 330 $data = $this->filter_response_by_context( $data, $context ); 331 $response = rest_ensure_response( $data ); 332 $resolved_theme_uris = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme_json ); 333 334 if ( ! empty( $resolved_theme_uris ) ) { 335 $response->add_links( 336 array( 337 'https://api.w.org/theme-file' => $resolved_theme_uris, 338 ) 339 ); 340 } 341 342 return $response; 330 343 } 331 344 -
trunk/tests/phpunit/data/themedir1/block-theme/styles/variation-b.json
r55231 r58262 15 15 } 16 16 } 17 }, 18 "styles": { 19 "background": { 20 "backgroundImage": { 21 "url": "file:./assets/sugarloaf-mountain.jpg" 22 } 23 } 17 24 } 18 25 } -
trunk/tests/phpunit/tests/rest-api/rest-global-styles-controller.php
r57662 r58262 35 35 parent::set_up(); 36 36 switch_theme( 'tt1-blocks' ); 37 add_filter( 'theme_file_uri', array( $this, 'filter_theme_file_uri' ) ); 38 } 39 40 public function tear_down() { 41 remove_filter( 'theme_file_uri', array( $this, 'filter_theme_file_uri' ) ); 42 parent::tear_down(); 37 43 } 38 44 … … 80 86 } 81 87 88 /* 89 * This filter callback normalizes the return value from `get_theme_file_uri` 90 * to guard against changes in test environments. 91 * The test suite otherwise returns full system dir path, e.g., 92 * /var/www/tests/phpunit/includes/../data/themedir1/block-theme/assets/sugarloaf-mountain.jpg 93 */ 94 public function filter_theme_file_uri( $file ) { 95 $file_name = substr( strrchr( $file, '/' ), 1 ); 96 return 'https://example.org/wp-content/themes/example-theme/assets/' . $file_name; 97 } 98 82 99 /** 83 100 * @covers WP_REST_Global_Styles_Controller::register_routes … … 120 137 } 121 138 139 /** 140 * Tests a GET request to the global styles variations endpoint. 141 * 142 * @covers WP_REST_Global_Styles_Controller::get_theme_items 143 * @ticket 61273 144 */ 122 145 public function test_get_theme_items() { 123 146 wp_set_current_user( self::$admin_id ); … … 129 152 array( 130 153 'version' => 2, 131 'title' => 'variation-a',132 154 'settings' => array( 133 155 'blocks' => array( … … 147 169 ), 148 170 ), 171 'title' => 'variation-a', 149 172 ), 150 173 array( 151 174 'version' => 2, 152 'title' => 'variation-b',153 175 'settings' => array( 154 176 'blocks' => array( … … 165 187 ), 166 188 ), 189 ), 190 ), 191 ), 192 'styles' => array( 193 'background' => array( 194 'backgroundImage' => array( 195 'url' => 'file:./assets/sugarloaf-mountain.jpg', 196 ), 197 ), 198 ), 199 'title' => 'variation-b', 200 '_links' => array( 201 'curies' => array( 202 array( 203 'name' => 'wp', 204 'href' => 'https://api.w.org/{rel}', 205 'templated' => true, 206 ), 207 ), 208 'wp:theme-file' => array( 209 array( 210 'href' => 'https://example.org/wp-content/themes/example-theme/assets/sugarloaf-mountain.jpg', 211 'name' => 'file:./assets/sugarloaf-mountain.jpg', 212 'target' => 'styles.background.backgroundImage.url', 213 'type' => 'image/jpeg', 167 214 ), 168 215 ), -
trunk/tests/phpunit/tests/theme/wpThemeJsonResolver.php
r57885 r58262 104 104 add_filter( 'stylesheet_root', array( $this, 'filter_set_theme_root' ) ); 105 105 add_filter( 'template_root', array( $this, 'filter_set_theme_root' ) ); 106 add_filter( 'theme_file_uri', array( $this, 'filter_theme_file_uri' ) ); 106 107 $this->queries = array(); 107 108 // Clear caches. … … 114 115 wp_clean_themes_cache(); 115 116 unset( $GLOBALS['wp_themes'] ); 117 remove_filter( 'theme_file_uri', array( $this, 'filter_theme_file_uri' ) ); 116 118 117 119 // Reset data between tests. 118 120 wp_clean_theme_json_cache(); 119 121 parent::tear_down(); 122 } 123 124 /* 125 * This filter callback normalizes the return value from `get_theme_file_uri` 126 * to guard against changes in test environments. 127 * The test suite otherwise returns full system dir path, e.g., 128 * /var/www/tests/phpunit/includes/../data/themedir1/block-theme/assets/sugarloaf-mountain.jpg 129 */ 130 public function filter_theme_file_uri( $file ) { 131 $file_name = substr( strrchr( $file, '/' ), 1 ); 132 return 'https://example.org/wp-content/themes/example-theme/assets/' . $file_name; 120 133 } 121 134 … … 1177 1190 $this->assertTrue( $default_presets_for_block ); 1178 1191 } 1192 1193 /** 1194 * Tests that relative paths are resolved and merged into the theme.json data. 1195 * 1196 * @covers WP_Theme_JSON_Resolver::resolve_theme_file_uris 1197 * @ticket 61273 1198 */ 1199 public function test_resolve_theme_file_uris() { 1200 $theme_json = new WP_Theme_JSON( 1201 array( 1202 'version' => WP_Theme_JSON::LATEST_SCHEMA, 1203 'styles' => array( 1204 'background' => array( 1205 'backgroundImage' => array( 1206 'url' => 'file:./assets/image.png', 1207 ), 1208 ), 1209 ), 1210 ) 1211 ); 1212 1213 $expected_data = array( 1214 'version' => WP_Theme_JSON::LATEST_SCHEMA, 1215 'styles' => array( 1216 'background' => array( 1217 'backgroundImage' => array( 1218 'url' => 'https://example.org/wp-content/themes/example-theme/assets/image.png', 1219 ), 1220 ), 1221 ), 1222 ); 1223 1224 $actual = WP_Theme_JSON_Resolver::resolve_theme_file_uris( $theme_json ); 1225 1226 $this->assertSame( $expected_data, $actual->get_raw_data() ); 1227 } 1228 1229 /** 1230 * Tests that them uris are resolved and bundled with other metadata in an array. 1231 * 1232 * @covers WP_Theme_JSON_Resolver::get_resolved_theme_uris 1233 * @ticket 61273 1234 */ 1235 public function test_get_resolved_theme_uris() { 1236 $theme_json = new WP_Theme_JSON( 1237 array( 1238 'version' => WP_Theme_JSON::LATEST_SCHEMA, 1239 'styles' => array( 1240 'background' => array( 1241 'backgroundImage' => array( 1242 'url' => 'file:./assets/image.png', 1243 ), 1244 ), 1245 ), 1246 ) 1247 ); 1248 1249 $expected_data = array( 1250 array( 1251 'name' => 'file:./assets/image.png', 1252 'href' => 'https://example.org/wp-content/themes/example-theme/assets/image.png', 1253 'target' => 'styles.background.backgroundImage.url', 1254 'type' => 'image/png', 1255 ), 1256 ); 1257 1258 $actual = WP_Theme_JSON_Resolver::get_resolved_theme_uris( $theme_json ); 1259 1260 $this->assertSame( $expected_data, $actual ); 1261 } 1179 1262 }
Note: See TracChangeset
for help on using the changeset viewer.