Changeset 56500
- Timestamp:
- 08/31/2023 09:47:40 PM (13 months ago)
- Location:
- trunk
- Files:
-
- 42 added
- 1 deleted
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/phpcs.xml.dist
r56392 r56500 260 260 <element value="WP_Tests_Image_Resize_UnitTestCase"/> 261 261 <element value="WP_Theme_UnitTestCase"/> 262 <element value="WP_Font_Face_UnitTestCase"/> 262 263 263 264 <!-- Mock classes. --> -
trunk/src/wp-admin/includes/admin-filters.php
r56199 r56500 169 169 // Append '(Draft)' to draft page titles in the privacy page dropdown. 170 170 add_filter( 'list_pages', '_wp_privacy_settings_filter_draft_page_titles', 10, 2 ); 171 172 // Font management. 173 add_action( 'admin_print_styles', 'wp_print_font_faces', 50 ); -
trunk/src/wp-includes/block-editor.php
r56047 r56500 362 362 ob_start(); 363 363 wp_print_styles(); 364 wp_print_font_faces(); 364 365 $styles = ob_get_clean(); 365 366 -
trunk/src/wp-includes/default-filters.php
r56140 r56500 359 359 add_action( 'after_switch_theme', '_wp_sidebars_changed' ); 360 360 add_action( 'wp_print_styles', 'print_emoji_styles' ); 361 add_action( 'plugins_loaded', '_wp_theme_json_webfonts_handler' );362 361 363 362 if ( isset( $_GET['replytocom'] ) ) { … … 720 719 add_action( 'init', 'wp_create_initial_post_meta' ); 721 720 721 // Font management. 722 add_action( 'wp_head', 'wp_print_font_faces', 50 ); 723 722 724 unset( $filter, $action ); -
trunk/src/wp-includes/deprecated.php
r56249 r56500 5368 5368 return $colors; 5369 5369 } 5370 5371 /** 5372 * Runs the theme.json webfonts handler. 5373 * 5374 * Using `WP_Theme_JSON_Resolver`, it gets the fonts defined 5375 * in the `theme.json` for the current selection and style 5376 * variations, validates the font-face properties, generates 5377 * the '@font-face' style declarations, and then enqueues the 5378 * styles for both the editor and front-end. 5379 * 5380 * Design Notes: 5381 * This is not a public API, but rather an internal handler. 5382 * A future public Webfonts API will replace this stopgap code. 5383 * 5384 * This code design is intentional. 5385 * a. It hides the inner-workings. 5386 * b. It does not expose API ins or outs for consumption. 5387 * c. It only works with a theme's `theme.json`. 5388 * 5389 * Why? 5390 * a. To avoid backwards-compatibility issues when 5391 * the Webfonts API is introduced in Core. 5392 * b. To make `fontFace` declarations in `theme.json` work. 5393 * 5394 * @link https://github.com/WordPress/gutenberg/issues/40472 5395 * 5396 * @since 6.0.0 5397 * @deprecated 6.4.0 Use wp_print_font_faces() instead. 5398 * @access private 5399 */ 5400 function _wp_theme_json_webfonts_handler() { 5401 _deprecated_function( __FUNCTION__, '6.4.0', 'wp_print_font_faces' ); 5402 5403 // Block themes are unavailable during installation. 5404 if ( wp_installing() ) { 5405 return; 5406 } 5407 5408 if ( ! wp_theme_has_theme_json() ) { 5409 return; 5410 } 5411 5412 // Webfonts to be processed. 5413 $registered_webfonts = array(); 5414 5415 /** 5416 * Gets the webfonts from theme.json. 5417 * 5418 * @since 6.0.0 5419 * 5420 * @return array Array of defined webfonts. 5421 */ 5422 $fn_get_webfonts_from_theme_json = static function() { 5423 // Get settings from theme.json. 5424 $settings = WP_Theme_JSON_Resolver::get_merged_data()->get_settings(); 5425 5426 // If in the editor, add webfonts defined in variations. 5427 if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { 5428 $variations = WP_Theme_JSON_Resolver::get_style_variations(); 5429 foreach ( $variations as $variation ) { 5430 // Skip if fontFamilies are not defined in the variation. 5431 if ( empty( $variation['settings']['typography']['fontFamilies'] ) ) { 5432 continue; 5433 } 5434 5435 // Initialize the array structure. 5436 if ( empty( $settings['typography'] ) ) { 5437 $settings['typography'] = array(); 5438 } 5439 if ( empty( $settings['typography']['fontFamilies'] ) ) { 5440 $settings['typography']['fontFamilies'] = array(); 5441 } 5442 if ( empty( $settings['typography']['fontFamilies']['theme'] ) ) { 5443 $settings['typography']['fontFamilies']['theme'] = array(); 5444 } 5445 5446 // Combine variations with settings. Remove duplicates. 5447 $settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] ); 5448 $settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] ); 5449 } 5450 } 5451 5452 // Bail out early if there are no settings for webfonts. 5453 if ( empty( $settings['typography']['fontFamilies'] ) ) { 5454 return array(); 5455 } 5456 5457 $webfonts = array(); 5458 5459 // Look for fontFamilies. 5460 foreach ( $settings['typography']['fontFamilies'] as $font_families ) { 5461 foreach ( $font_families as $font_family ) { 5462 5463 // Skip if fontFace is not defined. 5464 if ( empty( $font_family['fontFace'] ) ) { 5465 continue; 5466 } 5467 5468 // Skip if fontFace is not an array of webfonts. 5469 if ( ! is_array( $font_family['fontFace'] ) ) { 5470 continue; 5471 } 5472 5473 $webfonts = array_merge( $webfonts, $font_family['fontFace'] ); 5474 } 5475 } 5476 5477 return $webfonts; 5478 }; 5479 5480 /** 5481 * Transforms each 'src' into an URI by replacing 'file:./' 5482 * placeholder from theme.json. 5483 * 5484 * The absolute path to the webfont file(s) cannot be defined in 5485 * theme.json. `file:./` is the placeholder which is replaced by 5486 * the theme's URL path to the theme's root. 5487 * 5488 * @since 6.0.0 5489 * 5490 * @param array $src Webfont file(s) `src`. 5491 * @return array Webfont's `src` in URI. 5492 */ 5493 $fn_transform_src_into_uri = static function( array $src ) { 5494 foreach ( $src as $key => $url ) { 5495 // Tweak the URL to be relative to the theme root. 5496 if ( ! str_starts_with( $url, 'file:./' ) ) { 5497 continue; 5498 } 5499 5500 $src[ $key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) ); 5501 } 5502 5503 return $src; 5504 }; 5505 5506 /** 5507 * Converts the font-face properties (i.e. keys) into kebab-case. 5508 * 5509 * @since 6.0.0 5510 * 5511 * @param array $font_face Font face to convert. 5512 * @return array Font faces with each property in kebab-case format. 5513 */ 5514 $fn_convert_keys_to_kebab_case = static function( array $font_face ) { 5515 foreach ( $font_face as $property => $value ) { 5516 $kebab_case = _wp_to_kebab_case( $property ); 5517 $font_face[ $kebab_case ] = $value; 5518 if ( $kebab_case !== $property ) { 5519 unset( $font_face[ $property ] ); 5520 } 5521 } 5522 5523 return $font_face; 5524 }; 5525 5526 /** 5527 * Validates a webfont. 5528 * 5529 * @since 6.0.0 5530 * 5531 * @param array $webfont The webfont arguments. 5532 * @return array|false The validated webfont arguments, or false if the webfont is invalid. 5533 */ 5534 $fn_validate_webfont = static function( $webfont ) { 5535 $webfont = wp_parse_args( 5536 $webfont, 5537 array( 5538 'font-family' => '', 5539 'font-style' => 'normal', 5540 'font-weight' => '400', 5541 'font-display' => 'fallback', 5542 'src' => array(), 5543 ) 5544 ); 5545 5546 // Check the font-family. 5547 if ( empty( $webfont['font-family'] ) || ! is_string( $webfont['font-family'] ) ) { 5548 trigger_error( __( 'Webfont font family must be a non-empty string.' ) ); 5549 5550 return false; 5551 } 5552 5553 // Check that the `src` property is defined and a valid type. 5554 if ( empty( $webfont['src'] ) || ( ! is_string( $webfont['src'] ) && ! is_array( $webfont['src'] ) ) ) { 5555 trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.' ) ); 5556 5557 return false; 5558 } 5559 5560 // Validate the `src` property. 5561 foreach ( (array) $webfont['src'] as $src ) { 5562 if ( ! is_string( $src ) || '' === trim( $src ) ) { 5563 trigger_error( __( 'Each webfont src must be a non-empty string.' ) ); 5564 5565 return false; 5566 } 5567 } 5568 5569 // Check the font-weight. 5570 if ( ! is_string( $webfont['font-weight'] ) && ! is_int( $webfont['font-weight'] ) ) { 5571 trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.' ) ); 5572 5573 return false; 5574 } 5575 5576 // Check the font-display. 5577 if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'optional', 'swap' ), true ) ) { 5578 $webfont['font-display'] = 'fallback'; 5579 } 5580 5581 $valid_props = array( 5582 'ascend-override', 5583 'descend-override', 5584 'font-display', 5585 'font-family', 5586 'font-stretch', 5587 'font-style', 5588 'font-weight', 5589 'font-variant', 5590 'font-feature-settings', 5591 'font-variation-settings', 5592 'line-gap-override', 5593 'size-adjust', 5594 'src', 5595 'unicode-range', 5596 ); 5597 5598 foreach ( $webfont as $prop => $value ) { 5599 if ( ! in_array( $prop, $valid_props, true ) ) { 5600 unset( $webfont[ $prop ] ); 5601 } 5602 } 5603 5604 return $webfont; 5605 }; 5606 5607 /** 5608 * Registers webfonts declared in theme.json. 5609 * 5610 * @since 6.0.0 5611 * 5612 * @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference). 5613 * @uses $fn_get_webfonts_from_theme_json To run the function that gets the webfonts from theme.json. 5614 * @uses $fn_convert_keys_to_kebab_case To run the function that converts keys into kebab-case. 5615 * @uses $fn_validate_webfont To run the function that validates each font-face (webfont) from theme.json. 5616 */ 5617 $fn_register_webfonts = static function() use ( &$registered_webfonts, $fn_get_webfonts_from_theme_json, $fn_convert_keys_to_kebab_case, $fn_validate_webfont, $fn_transform_src_into_uri ) { 5618 $registered_webfonts = array(); 5619 5620 foreach ( $fn_get_webfonts_from_theme_json() as $webfont ) { 5621 if ( ! is_array( $webfont ) ) { 5622 continue; 5623 } 5624 5625 $webfont = $fn_convert_keys_to_kebab_case( $webfont ); 5626 5627 $webfont = $fn_validate_webfont( $webfont ); 5628 5629 $webfont['src'] = $fn_transform_src_into_uri( (array) $webfont['src'] ); 5630 5631 // Skip if not valid. 5632 if ( empty( $webfont ) ) { 5633 continue; 5634 } 5635 5636 $registered_webfonts[] = $webfont; 5637 } 5638 }; 5639 5640 /** 5641 * Orders 'src' items to optimize for browser support. 5642 * 5643 * @since 6.0.0 5644 * 5645 * @param array $webfont Webfont to process. 5646 * @return array Ordered `src` items. 5647 */ 5648 $fn_order_src = static function( array $webfont ) { 5649 $src = array(); 5650 $src_ordered = array(); 5651 5652 foreach ( $webfont['src'] as $url ) { 5653 // Add data URIs first. 5654 if ( str_starts_with( trim( $url ), 'data:' ) ) { 5655 $src_ordered[] = array( 5656 'url' => $url, 5657 'format' => 'data', 5658 ); 5659 continue; 5660 } 5661 $format = pathinfo( $url, PATHINFO_EXTENSION ); 5662 $src[ $format ] = $url; 5663 } 5664 5665 // Add woff2. 5666 if ( ! empty( $src['woff2'] ) ) { 5667 $src_ordered[] = array( 5668 'url' => sanitize_url( $src['woff2'] ), 5669 'format' => 'woff2', 5670 ); 5671 } 5672 5673 // Add woff. 5674 if ( ! empty( $src['woff'] ) ) { 5675 $src_ordered[] = array( 5676 'url' => sanitize_url( $src['woff'] ), 5677 'format' => 'woff', 5678 ); 5679 } 5680 5681 // Add ttf. 5682 if ( ! empty( $src['ttf'] ) ) { 5683 $src_ordered[] = array( 5684 'url' => sanitize_url( $src['ttf'] ), 5685 'format' => 'truetype', 5686 ); 5687 } 5688 5689 // Add eot. 5690 if ( ! empty( $src['eot'] ) ) { 5691 $src_ordered[] = array( 5692 'url' => sanitize_url( $src['eot'] ), 5693 'format' => 'embedded-opentype', 5694 ); 5695 } 5696 5697 // Add otf. 5698 if ( ! empty( $src['otf'] ) ) { 5699 $src_ordered[] = array( 5700 'url' => sanitize_url( $src['otf'] ), 5701 'format' => 'opentype', 5702 ); 5703 } 5704 $webfont['src'] = $src_ordered; 5705 5706 return $webfont; 5707 }; 5708 5709 /** 5710 * Compiles the 'src' into valid CSS. 5711 * 5712 * @since 6.0.0 5713 * @since 6.2.0 Removed local() CSS. 5714 * 5715 * @param string $font_family Font family. 5716 * @param array $value Value to process. 5717 * @return string The CSS. 5718 */ 5719 $fn_compile_src = static function( $font_family, array $value ) { 5720 $src = ''; 5721 5722 foreach ( $value as $item ) { 5723 $src .= ( 'data' === $item['format'] ) 5724 ? ", url({$item['url']})" 5725 : ", url('{$item['url']}') format('{$item['format']}')"; 5726 } 5727 5728 $src = ltrim( $src, ', ' ); 5729 5730 return $src; 5731 }; 5732 5733 /** 5734 * Compiles the font variation settings. 5735 * 5736 * @since 6.0.0 5737 * 5738 * @param array $font_variation_settings Array of font variation settings. 5739 * @return string The CSS. 5740 */ 5741 $fn_compile_variations = static function( array $font_variation_settings ) { 5742 $variations = ''; 5743 5744 foreach ( $font_variation_settings as $key => $value ) { 5745 $variations .= "$key $value"; 5746 } 5747 5748 return $variations; 5749 }; 5750 5751 /** 5752 * Builds the font-family's CSS. 5753 * 5754 * @since 6.0.0 5755 * 5756 * @uses $fn_compile_src To run the function that compiles the src. 5757 * @uses $fn_compile_variations To run the function that compiles the variations. 5758 * 5759 * @param array $webfont Webfont to process. 5760 * @return string This font-family's CSS. 5761 */ 5762 $fn_build_font_face_css = static function( array $webfont ) use ( $fn_compile_src, $fn_compile_variations ) { 5763 $css = ''; 5764 5765 // Wrap font-family in quotes if it contains spaces. 5766 if ( 5767 str_contains( $webfont['font-family'], ' ' ) && 5768 ! str_contains( $webfont['font-family'], '"' ) && 5769 ! str_contains( $webfont['font-family'], "'" ) 5770 ) { 5771 $webfont['font-family'] = '"' . $webfont['font-family'] . '"'; 5772 } 5773 5774 foreach ( $webfont as $key => $value ) { 5775 /* 5776 * Skip "provider", since it's for internal API use, 5777 * and not a valid CSS property. 5778 */ 5779 if ( 'provider' === $key ) { 5780 continue; 5781 } 5782 5783 // Compile the "src" parameter. 5784 if ( 'src' === $key ) { 5785 $value = $fn_compile_src( $webfont['font-family'], $value ); 5786 } 5787 5788 // If font-variation-settings is an array, convert it to a string. 5789 if ( 'font-variation-settings' === $key && is_array( $value ) ) { 5790 $value = $fn_compile_variations( $value ); 5791 } 5792 5793 if ( ! empty( $value ) ) { 5794 $css .= "$key:$value;"; 5795 } 5796 } 5797 5798 return $css; 5799 }; 5800 5801 /** 5802 * Gets the '@font-face' CSS styles for locally-hosted font files. 5803 * 5804 * @since 6.0.0 5805 * 5806 * @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference). 5807 * @uses $fn_order_src To run the function that orders the src. 5808 * @uses $fn_build_font_face_css To run the function that builds the font-face CSS. 5809 * 5810 * @return string The `@font-face` CSS. 5811 */ 5812 $fn_get_css = static function() use ( &$registered_webfonts, $fn_order_src, $fn_build_font_face_css ) { 5813 $css = ''; 5814 5815 foreach ( $registered_webfonts as $webfont ) { 5816 // Order the webfont's `src` items to optimize for browser support. 5817 $webfont = $fn_order_src( $webfont ); 5818 5819 // Build the @font-face CSS for this webfont. 5820 $css .= '@font-face{' . $fn_build_font_face_css( $webfont ) . '}'; 5821 } 5822 5823 return $css; 5824 }; 5825 5826 /** 5827 * Generates and enqueues webfonts styles. 5828 * 5829 * @since 6.0.0 5830 * 5831 * @uses $fn_get_css To run the function that gets the CSS. 5832 */ 5833 $fn_generate_and_enqueue_styles = static function() use ( $fn_get_css ) { 5834 // Generate the styles. 5835 $styles = $fn_get_css(); 5836 5837 // Bail out if there are no styles to enqueue. 5838 if ( '' === $styles ) { 5839 return; 5840 } 5841 5842 // Enqueue the stylesheet. 5843 wp_register_style( 'wp-webfonts', '' ); 5844 wp_enqueue_style( 'wp-webfonts' ); 5845 5846 // Add the styles to the stylesheet. 5847 wp_add_inline_style( 'wp-webfonts', $styles ); 5848 }; 5849 5850 /** 5851 * Generates and enqueues editor styles. 5852 * 5853 * @since 6.0.0 5854 * 5855 * @uses $fn_get_css To run the function that gets the CSS. 5856 */ 5857 $fn_generate_and_enqueue_editor_styles = static function() use ( $fn_get_css ) { 5858 // Generate the styles. 5859 $styles = $fn_get_css(); 5860 5861 // Bail out if there are no styles to enqueue. 5862 if ( '' === $styles ) { 5863 return; 5864 } 5865 5866 wp_add_inline_style( 'wp-block-library', $styles ); 5867 }; 5868 5869 add_action( 'wp_loaded', $fn_register_webfonts ); 5870 add_action( 'wp_enqueue_scripts', $fn_generate_and_enqueue_styles ); 5871 add_action( 'admin_init', $fn_generate_and_enqueue_editor_styles ); 5872 } -
trunk/src/wp-includes/script-loader.php
r56496 r56500 3225 3225 3226 3226 /** 3227 * Runs the theme.json webfonts handler.3228 *3229 * Using `WP_Theme_JSON_Resolver`, it gets the fonts defined3230 * in the `theme.json` for the current selection and style3231 * variations, validates the font-face properties, generates3232 * the '@font-face' style declarations, and then enqueues the3233 * styles for both the editor and front-end.3234 *3235 * Design Notes:3236 * This is not a public API, but rather an internal handler.3237 * A future public Webfonts API will replace this stopgap code.3238 *3239 * This code design is intentional.3240 * a. It hides the inner-workings.3241 * b. It does not expose API ins or outs for consumption.3242 * c. It only works with a theme's `theme.json`.3243 *3244 * Why?3245 * a. To avoid backwards-compatibility issues when3246 * the Webfonts API is introduced in Core.3247 * b. To make `fontFace` declarations in `theme.json` work.3248 *3249 * @link https://github.com/WordPress/gutenberg/issues/404723250 *3251 * @since 6.0.03252 * @access private3253 */3254 function _wp_theme_json_webfonts_handler() {3255 // Block themes are unavailable during installation.3256 if ( wp_installing() ) {3257 return;3258 }3259 3260 if ( ! wp_theme_has_theme_json() ) {3261 return;3262 }3263 3264 // Webfonts to be processed.3265 $registered_webfonts = array();3266 3267 /**3268 * Gets the webfonts from theme.json.3269 *3270 * @since 6.0.03271 *3272 * @return array Array of defined webfonts.3273 */3274 $fn_get_webfonts_from_theme_json = static function() {3275 // Get settings from theme.json.3276 $settings = WP_Theme_JSON_Resolver::get_merged_data()->get_settings();3277 3278 // If in the editor, add webfonts defined in variations.3279 if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {3280 $variations = WP_Theme_JSON_Resolver::get_style_variations();3281 foreach ( $variations as $variation ) {3282 // Skip if fontFamilies are not defined in the variation.3283 if ( empty( $variation['settings']['typography']['fontFamilies'] ) ) {3284 continue;3285 }3286 3287 // Initialize the array structure.3288 if ( empty( $settings['typography'] ) ) {3289 $settings['typography'] = array();3290 }3291 if ( empty( $settings['typography']['fontFamilies'] ) ) {3292 $settings['typography']['fontFamilies'] = array();3293 }3294 if ( empty( $settings['typography']['fontFamilies']['theme'] ) ) {3295 $settings['typography']['fontFamilies']['theme'] = array();3296 }3297 3298 // Combine variations with settings. Remove duplicates.3299 $settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] );3300 $settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] );3301 }3302 }3303 3304 // Bail out early if there are no settings for webfonts.3305 if ( empty( $settings['typography']['fontFamilies'] ) ) {3306 return array();3307 }3308 3309 $webfonts = array();3310 3311 // Look for fontFamilies.3312 foreach ( $settings['typography']['fontFamilies'] as $font_families ) {3313 foreach ( $font_families as $font_family ) {3314 3315 // Skip if fontFace is not defined.3316 if ( empty( $font_family['fontFace'] ) ) {3317 continue;3318 }3319 3320 // Skip if fontFace is not an array of webfonts.3321 if ( ! is_array( $font_family['fontFace'] ) ) {3322 continue;3323 }3324 3325 $webfonts = array_merge( $webfonts, $font_family['fontFace'] );3326 }3327 }3328 3329 return $webfonts;3330 };3331 3332 /**3333 * Transforms each 'src' into an URI by replacing 'file:./'3334 * placeholder from theme.json.3335 *3336 * The absolute path to the webfont file(s) cannot be defined in3337 * theme.json. `file:./` is the placeholder which is replaced by3338 * the theme's URL path to the theme's root.3339 *3340 * @since 6.0.03341 *3342 * @param array $src Webfont file(s) `src`.3343 * @return array Webfont's `src` in URI.3344 */3345 $fn_transform_src_into_uri = static function( array $src ) {3346 foreach ( $src as $key => $url ) {3347 // Tweak the URL to be relative to the theme root.3348 if ( ! str_starts_with( $url, 'file:./' ) ) {3349 continue;3350 }3351 3352 $src[ $key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) );3353 }3354 3355 return $src;3356 };3357 3358 /**3359 * Converts the font-face properties (i.e. keys) into kebab-case.3360 *3361 * @since 6.0.03362 *3363 * @param array $font_face Font face to convert.3364 * @return array Font faces with each property in kebab-case format.3365 */3366 $fn_convert_keys_to_kebab_case = static function( array $font_face ) {3367 foreach ( $font_face as $property => $value ) {3368 $kebab_case = _wp_to_kebab_case( $property );3369 $font_face[ $kebab_case ] = $value;3370 if ( $kebab_case !== $property ) {3371 unset( $font_face[ $property ] );3372 }3373 }3374 3375 return $font_face;3376 };3377 3378 /**3379 * Validates a webfont.3380 *3381 * @since 6.0.03382 *3383 * @param array $webfont The webfont arguments.3384 * @return array|false The validated webfont arguments, or false if the webfont is invalid.3385 */3386 $fn_validate_webfont = static function( $webfont ) {3387 $webfont = wp_parse_args(3388 $webfont,3389 array(3390 'font-family' => '',3391 'font-style' => 'normal',3392 'font-weight' => '400',3393 'font-display' => 'fallback',3394 'src' => array(),3395 )3396 );3397 3398 // Check the font-family.3399 if ( empty( $webfont['font-family'] ) || ! is_string( $webfont['font-family'] ) ) {3400 trigger_error( __( 'Webfont font family must be a non-empty string.' ) );3401 3402 return false;3403 }3404 3405 // Check that the `src` property is defined and a valid type.3406 if ( empty( $webfont['src'] ) || ( ! is_string( $webfont['src'] ) && ! is_array( $webfont['src'] ) ) ) {3407 trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.' ) );3408 3409 return false;3410 }3411 3412 // Validate the `src` property.3413 foreach ( (array) $webfont['src'] as $src ) {3414 if ( ! is_string( $src ) || '' === trim( $src ) ) {3415 trigger_error( __( 'Each webfont src must be a non-empty string.' ) );3416 3417 return false;3418 }3419 }3420 3421 // Check the font-weight.3422 if ( ! is_string( $webfont['font-weight'] ) && ! is_int( $webfont['font-weight'] ) ) {3423 trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.' ) );3424 3425 return false;3426 }3427 3428 // Check the font-display.3429 if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'optional', 'swap' ), true ) ) {3430 $webfont['font-display'] = 'fallback';3431 }3432 3433 $valid_props = array(3434 'ascend-override',3435 'descend-override',3436 'font-display',3437 'font-family',3438 'font-stretch',3439 'font-style',3440 'font-weight',3441 'font-variant',3442 'font-feature-settings',3443 'font-variation-settings',3444 'line-gap-override',3445 'size-adjust',3446 'src',3447 'unicode-range',3448 );3449 3450 foreach ( $webfont as $prop => $value ) {3451 if ( ! in_array( $prop, $valid_props, true ) ) {3452 unset( $webfont[ $prop ] );3453 }3454 }3455 3456 return $webfont;3457 };3458 3459 /**3460 * Registers webfonts declared in theme.json.3461 *3462 * @since 6.0.03463 *3464 * @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference).3465 * @uses $fn_get_webfonts_from_theme_json To run the function that gets the webfonts from theme.json.3466 * @uses $fn_convert_keys_to_kebab_case To run the function that converts keys into kebab-case.3467 * @uses $fn_validate_webfont To run the function that validates each font-face (webfont) from theme.json.3468 */3469 $fn_register_webfonts = static function() use ( &$registered_webfonts, $fn_get_webfonts_from_theme_json, $fn_convert_keys_to_kebab_case, $fn_validate_webfont, $fn_transform_src_into_uri ) {3470 $registered_webfonts = array();3471 3472 foreach ( $fn_get_webfonts_from_theme_json() as $webfont ) {3473 if ( ! is_array( $webfont ) ) {3474 continue;3475 }3476 3477 $webfont = $fn_convert_keys_to_kebab_case( $webfont );3478 3479 $webfont = $fn_validate_webfont( $webfont );3480 3481 $webfont['src'] = $fn_transform_src_into_uri( (array) $webfont['src'] );3482 3483 // Skip if not valid.3484 if ( empty( $webfont ) ) {3485 continue;3486 }3487 3488 $registered_webfonts[] = $webfont;3489 }3490 };3491 3492 /**3493 * Orders 'src' items to optimize for browser support.3494 *3495 * @since 6.0.03496 *3497 * @param array $webfont Webfont to process.3498 * @return array Ordered `src` items.3499 */3500 $fn_order_src = static function( array $webfont ) {3501 $src = array();3502 $src_ordered = array();3503 3504 foreach ( $webfont['src'] as $url ) {3505 // Add data URIs first.3506 if ( str_starts_with( trim( $url ), 'data:' ) ) {3507 $src_ordered[] = array(3508 'url' => $url,3509 'format' => 'data',3510 );3511 continue;3512 }3513 $format = pathinfo( $url, PATHINFO_EXTENSION );3514 $src[ $format ] = $url;3515 }3516 3517 // Add woff2.3518 if ( ! empty( $src['woff2'] ) ) {3519 $src_ordered[] = array(3520 'url' => sanitize_url( $src['woff2'] ),3521 'format' => 'woff2',3522 );3523 }3524 3525 // Add woff.3526 if ( ! empty( $src['woff'] ) ) {3527 $src_ordered[] = array(3528 'url' => sanitize_url( $src['woff'] ),3529 'format' => 'woff',3530 );3531 }3532 3533 // Add ttf.3534 if ( ! empty( $src['ttf'] ) ) {3535 $src_ordered[] = array(3536 'url' => sanitize_url( $src['ttf'] ),3537 'format' => 'truetype',3538 );3539 }3540 3541 // Add eot.3542 if ( ! empty( $src['eot'] ) ) {3543 $src_ordered[] = array(3544 'url' => sanitize_url( $src['eot'] ),3545 'format' => 'embedded-opentype',3546 );3547 }3548 3549 // Add otf.3550 if ( ! empty( $src['otf'] ) ) {3551 $src_ordered[] = array(3552 'url' => sanitize_url( $src['otf'] ),3553 'format' => 'opentype',3554 );3555 }3556 $webfont['src'] = $src_ordered;3557 3558 return $webfont;3559 };3560 3561 /**3562 * Compiles the 'src' into valid CSS.3563 *3564 * @since 6.0.03565 * @since 6.2.0 Removed local() CSS.3566 *3567 * @param string $font_family Font family.3568 * @param array $value Value to process.3569 * @return string The CSS.3570 */3571 $fn_compile_src = static function( $font_family, array $value ) {3572 $src = '';3573 3574 foreach ( $value as $item ) {3575 $src .= ( 'data' === $item['format'] )3576 ? ", url({$item['url']})"3577 : ", url('{$item['url']}') format('{$item['format']}')";3578 }3579 3580 $src = ltrim( $src, ', ' );3581 3582 return $src;3583 };3584 3585 /**3586 * Compiles the font variation settings.3587 *3588 * @since 6.0.03589 *3590 * @param array $font_variation_settings Array of font variation settings.3591 * @return string The CSS.3592 */3593 $fn_compile_variations = static function( array $font_variation_settings ) {3594 $variations = '';3595 3596 foreach ( $font_variation_settings as $key => $value ) {3597 $variations .= "$key $value";3598 }3599 3600 return $variations;3601 };3602 3603 /**3604 * Builds the font-family's CSS.3605 *3606 * @since 6.0.03607 *3608 * @uses $fn_compile_src To run the function that compiles the src.3609 * @uses $fn_compile_variations To run the function that compiles the variations.3610 *3611 * @param array $webfont Webfont to process.3612 * @return string This font-family's CSS.3613 */3614 $fn_build_font_face_css = static function( array $webfont ) use ( $fn_compile_src, $fn_compile_variations ) {3615 $css = '';3616 3617 // Wrap font-family in quotes if it contains spaces.3618 if (3619 str_contains( $webfont['font-family'], ' ' ) &&3620 ! str_contains( $webfont['font-family'], '"' ) &&3621 ! str_contains( $webfont['font-family'], "'" )3622 ) {3623 $webfont['font-family'] = '"' . $webfont['font-family'] . '"';3624 }3625 3626 foreach ( $webfont as $key => $value ) {3627 /*3628 * Skip "provider", since it's for internal API use,3629 * and not a valid CSS property.3630 */3631 if ( 'provider' === $key ) {3632 continue;3633 }3634 3635 // Compile the "src" parameter.3636 if ( 'src' === $key ) {3637 $value = $fn_compile_src( $webfont['font-family'], $value );3638 }3639 3640 // If font-variation-settings is an array, convert it to a string.3641 if ( 'font-variation-settings' === $key && is_array( $value ) ) {3642 $value = $fn_compile_variations( $value );3643 }3644 3645 if ( ! empty( $value ) ) {3646 $css .= "$key:$value;";3647 }3648 }3649 3650 return $css;3651 };3652 3653 /**3654 * Gets the '@font-face' CSS styles for locally-hosted font files.3655 *3656 * @since 6.0.03657 *3658 * @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference).3659 * @uses $fn_order_src To run the function that orders the src.3660 * @uses $fn_build_font_face_css To run the function that builds the font-face CSS.3661 *3662 * @return string The `@font-face` CSS.3663 */3664 $fn_get_css = static function() use ( &$registered_webfonts, $fn_order_src, $fn_build_font_face_css ) {3665 $css = '';3666 3667 foreach ( $registered_webfonts as $webfont ) {3668 // Order the webfont's `src` items to optimize for browser support.3669 $webfont = $fn_order_src( $webfont );3670 3671 // Build the @font-face CSS for this webfont.3672 $css .= '@font-face{' . $fn_build_font_face_css( $webfont ) . '}';3673 }3674 3675 return $css;3676 };3677 3678 /**3679 * Generates and enqueues webfonts styles.3680 *3681 * @since 6.0.03682 *3683 * @uses $fn_get_css To run the function that gets the CSS.3684 */3685 $fn_generate_and_enqueue_styles = static function() use ( $fn_get_css ) {3686 // Generate the styles.3687 $styles = $fn_get_css();3688 3689 // Bail out if there are no styles to enqueue.3690 if ( '' === $styles ) {3691 return;3692 }3693 3694 // Enqueue the stylesheet.3695 wp_register_style( 'wp-webfonts', '' );3696 wp_enqueue_style( 'wp-webfonts' );3697 3698 // Add the styles to the stylesheet.3699 wp_add_inline_style( 'wp-webfonts', $styles );3700 };3701 3702 /**3703 * Generates and enqueues editor styles.3704 *3705 * @since 6.0.03706 *3707 * @uses $fn_get_css To run the function that gets the CSS.3708 */3709 $fn_generate_and_enqueue_editor_styles = static function() use ( $fn_get_css ) {3710 // Generate the styles.3711 $styles = $fn_get_css();3712 3713 // Bail out if there are no styles to enqueue.3714 if ( '' === $styles ) {3715 return;3716 }3717 3718 wp_add_inline_style( 'wp-block-library', $styles );3719 };3720 3721 add_action( 'wp_loaded', $fn_register_webfonts );3722 add_action( 'wp_enqueue_scripts', $fn_generate_and_enqueue_styles );3723 add_action( 'admin_init', $fn_generate_and_enqueue_editor_styles );3724 }3725 3726 /**3727 3227 * Loads classic theme styles on classic themes in the frontend. 3728 3228 * -
trunk/src/wp-settings.php
r56434 r56500 361 361 require ABSPATH . WPINC . '/style-engine/class-wp-style-engine-css-rules-store.php'; 362 362 require ABSPATH . WPINC . '/style-engine/class-wp-style-engine-processor.php'; 363 require ABSPATH . WPINC . '/fonts/class-wp-font-face-resolver.php'; 364 require ABSPATH . WPINC . '/fonts/class-wp-font-face.php'; 365 require ABSPATH . WPINC . '/fonts.php'; 363 366 364 367 $GLOBALS['wp_embed'] = new WP_Embed(); -
trunk/tests/phpunit/tests/theme/themeDir.php
r55294 r56500 186 186 'Block Theme [1.0.0] in subdirectory', 187 187 'Block Theme Deprecated Path', 188 ' Webfonts theme',188 'Block Theme with defined Typography Fonts', 189 189 'Empty `fontFace` in theme.json - no webfonts defined', 190 190 'A theme with the Update URI header',
Note: See TracChangeset
for help on using the changeset viewer.