mirror of
https://github.com/gosticks/wordpress-develop.git
synced 2025-10-16 12:05:38 +00:00
Introduce font-face styles generator and printer.
Introducing Font Face, a server-side `@font-face` styles generator and printer. tl;dr: * Introduces Font Face. * Deprecates `_wp_theme_json_webfonts_handler()`. **Introduce Font Face** From an array of fonts (i.e. each font-family and its font variations to be processed), it: 1. Validates each `font-face` declaration, i.e. the CSS property and value pairing. If validation fails, processing stops with no font-face styles printed. 3. Generates the `@font-face` CSS for each font-family. 4. Prints the CSS within a `<style id="wp-fonts-local">` element. The entry point into Font Face is through a new global function called `wp_print_font_faces()`, which is automatically called: * when the `'wp_head'` hook runs (for the front-end). * when the `'admin_print_styles'` hook runs (for the back-end). * when `_wp_get_iframed_editor_assets()` runs to inject the `@font-face` styles into the iframed editor. Once called, it gets the fonts from Theme_JSON merged data layer, which includes theme defined fonts and user activated fonts (once the Font Library #59166 is introduced into Core). For classic sites, themes and plugins can directly call `wp_print_font_faces()` and pass their fonts array to it for processing. **Deprecates `_wp_theme_json_webfonts_handler()`.** As Font Face is a direct replacement, the stopgap code in `_wp_theme_json_webfonts_handler()` (introduced in 6.0.0 via [53282]) is deprecated and unused in Core. **Props note:** There's a long multiple year history baked into Font Face, which dates back to the early versions of a web font API (see #46370 and [https://github.com/WordPress/gutenberg/issues/41479 roadmap]. The props list includes those who contributed from those early versions up to this commit. **References:** * #46370 original (Web)Fonts API proposal for registering and enqueuing web fonts. * [https://github.com/WordPress/gutenberg/issues/41479 Gutenberg tracking issue] which includes the evolution from Webfonts API to Fonts API to Font Face. * [53282] / #55567 Added the stopgap code `_wp_theme_json_webfonts_handler()` in 6.0. * [https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face @font-face on mdn web docs] * #59166 Font Library: Font manager for WordPress Follow-up to [53282]. Props aristath, jonoaldersonwp, hellofromTonya, andraganescu, annezazu, antonvlasenko, arena, askdesign, azaozz, bph, bradley2083, colorful-tones, costdev, davidbaumwald, desrosj, dingo_d, djcowan, domainsupport, dryanpress, elmastudio, flixos90, francina, garrett-eclipse, gigitux, grantmkin, grapplerulrich, gziolo, ironprogrammer, jb510, jeffpaul, jeremyyip, jffng, joostdevalk, jorgefilipecosta, juanmaguitar, mamaduka, matveb, mburridge, mitogh, ndiego, ntsekouras, oandregal, ocean90, oglekler, paaljoachim, pagelab, peterwilsoncc, poena, priethor, scruffian, SergeyBiryukov, shiloey, simison, skorasaurus, soean, westonruter, wildworks, zaguiini. Fixes #59165. git-svn-id: https://develop.svn.wordpress.org/trunk@56500 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
54a177910a
commit
c29b095e76
@ -259,6 +259,7 @@
|
||||
<element value="WP_Test_Adjacent_Image_Link_TestCase"/>
|
||||
<element value="WP_Tests_Image_Resize_UnitTestCase"/>
|
||||
<element value="WP_Theme_UnitTestCase"/>
|
||||
<element value="WP_Font_Face_UnitTestCase"/>
|
||||
|
||||
<!-- Mock classes. -->
|
||||
<element value="Spy_REST_Server"/>
|
||||
|
||||
@ -168,3 +168,6 @@ add_action( 'post_updated', array( 'WP_Privacy_Policy_Content', '_policy_page_up
|
||||
|
||||
// Append '(Draft)' to draft page titles in the privacy page dropdown.
|
||||
add_filter( 'list_pages', '_wp_privacy_settings_filter_draft_page_titles', 10, 2 );
|
||||
|
||||
// Font management.
|
||||
add_action( 'admin_print_styles', 'wp_print_font_faces', 50 );
|
||||
|
||||
@ -361,6 +361,7 @@ function _wp_get_iframed_editor_assets() {
|
||||
|
||||
ob_start();
|
||||
wp_print_styles();
|
||||
wp_print_font_faces();
|
||||
$styles = ob_get_clean();
|
||||
|
||||
ob_start();
|
||||
|
||||
@ -358,7 +358,6 @@ add_action( 'start_previewing_theme', 'wp_clean_theme_json_cache' );
|
||||
add_action( 'after_switch_theme', '_wp_menus_changed' );
|
||||
add_action( 'after_switch_theme', '_wp_sidebars_changed' );
|
||||
add_action( 'wp_print_styles', 'print_emoji_styles' );
|
||||
add_action( 'plugins_loaded', '_wp_theme_json_webfonts_handler' );
|
||||
|
||||
if ( isset( $_GET['replytocom'] ) ) {
|
||||
add_filter( 'wp_robots', 'wp_robots_no_robots' );
|
||||
@ -719,4 +718,7 @@ add_action( 'init', 'wp_register_persisted_preferences_meta' );
|
||||
// CPT wp_block custom postmeta field.
|
||||
add_action( 'init', 'wp_create_initial_post_meta' );
|
||||
|
||||
// Font management.
|
||||
add_action( 'wp_head', 'wp_print_font_faces', 50 );
|
||||
|
||||
unset( $filter, $action );
|
||||
|
||||
@ -5367,3 +5367,506 @@ function block_core_navigation_submenu_build_css_colors( $context, $attributes,
|
||||
|
||||
return $colors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the theme.json webfonts handler.
|
||||
*
|
||||
* Using `WP_Theme_JSON_Resolver`, it gets the fonts defined
|
||||
* in the `theme.json` for the current selection and style
|
||||
* variations, validates the font-face properties, generates
|
||||
* the '@font-face' style declarations, and then enqueues the
|
||||
* styles for both the editor and front-end.
|
||||
*
|
||||
* Design Notes:
|
||||
* This is not a public API, but rather an internal handler.
|
||||
* A future public Webfonts API will replace this stopgap code.
|
||||
*
|
||||
* This code design is intentional.
|
||||
* a. It hides the inner-workings.
|
||||
* b. It does not expose API ins or outs for consumption.
|
||||
* c. It only works with a theme's `theme.json`.
|
||||
*
|
||||
* Why?
|
||||
* a. To avoid backwards-compatibility issues when
|
||||
* the Webfonts API is introduced in Core.
|
||||
* b. To make `fontFace` declarations in `theme.json` work.
|
||||
*
|
||||
* @link https://github.com/WordPress/gutenberg/issues/40472
|
||||
*
|
||||
* @since 6.0.0
|
||||
* @deprecated 6.4.0 Use wp_print_font_faces() instead.
|
||||
* @access private
|
||||
*/
|
||||
function _wp_theme_json_webfonts_handler() {
|
||||
_deprecated_function( __FUNCTION__, '6.4.0', 'wp_print_font_faces' );
|
||||
|
||||
// Block themes are unavailable during installation.
|
||||
if ( wp_installing() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! wp_theme_has_theme_json() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Webfonts to be processed.
|
||||
$registered_webfonts = array();
|
||||
|
||||
/**
|
||||
* Gets the webfonts from theme.json.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @return array Array of defined webfonts.
|
||||
*/
|
||||
$fn_get_webfonts_from_theme_json = static function() {
|
||||
// Get settings from theme.json.
|
||||
$settings = WP_Theme_JSON_Resolver::get_merged_data()->get_settings();
|
||||
|
||||
// If in the editor, add webfonts defined in variations.
|
||||
if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
|
||||
$variations = WP_Theme_JSON_Resolver::get_style_variations();
|
||||
foreach ( $variations as $variation ) {
|
||||
// Skip if fontFamilies are not defined in the variation.
|
||||
if ( empty( $variation['settings']['typography']['fontFamilies'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Initialize the array structure.
|
||||
if ( empty( $settings['typography'] ) ) {
|
||||
$settings['typography'] = array();
|
||||
}
|
||||
if ( empty( $settings['typography']['fontFamilies'] ) ) {
|
||||
$settings['typography']['fontFamilies'] = array();
|
||||
}
|
||||
if ( empty( $settings['typography']['fontFamilies']['theme'] ) ) {
|
||||
$settings['typography']['fontFamilies']['theme'] = array();
|
||||
}
|
||||
|
||||
// Combine variations with settings. Remove duplicates.
|
||||
$settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] );
|
||||
$settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] );
|
||||
}
|
||||
}
|
||||
|
||||
// Bail out early if there are no settings for webfonts.
|
||||
if ( empty( $settings['typography']['fontFamilies'] ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$webfonts = array();
|
||||
|
||||
// Look for fontFamilies.
|
||||
foreach ( $settings['typography']['fontFamilies'] as $font_families ) {
|
||||
foreach ( $font_families as $font_family ) {
|
||||
|
||||
// Skip if fontFace is not defined.
|
||||
if ( empty( $font_family['fontFace'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if fontFace is not an array of webfonts.
|
||||
if ( ! is_array( $font_family['fontFace'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$webfonts = array_merge( $webfonts, $font_family['fontFace'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $webfonts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transforms each 'src' into an URI by replacing 'file:./'
|
||||
* placeholder from theme.json.
|
||||
*
|
||||
* The absolute path to the webfont file(s) cannot be defined in
|
||||
* theme.json. `file:./` is the placeholder which is replaced by
|
||||
* the theme's URL path to the theme's root.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param array $src Webfont file(s) `src`.
|
||||
* @return array Webfont's `src` in URI.
|
||||
*/
|
||||
$fn_transform_src_into_uri = static function( array $src ) {
|
||||
foreach ( $src as $key => $url ) {
|
||||
// Tweak the URL to be relative to the theme root.
|
||||
if ( ! str_starts_with( $url, 'file:./' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$src[ $key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) );
|
||||
}
|
||||
|
||||
return $src;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the font-face properties (i.e. keys) into kebab-case.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param array $font_face Font face to convert.
|
||||
* @return array Font faces with each property in kebab-case format.
|
||||
*/
|
||||
$fn_convert_keys_to_kebab_case = static function( array $font_face ) {
|
||||
foreach ( $font_face as $property => $value ) {
|
||||
$kebab_case = _wp_to_kebab_case( $property );
|
||||
$font_face[ $kebab_case ] = $value;
|
||||
if ( $kebab_case !== $property ) {
|
||||
unset( $font_face[ $property ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $font_face;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates a webfont.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param array $webfont The webfont arguments.
|
||||
* @return array|false The validated webfont arguments, or false if the webfont is invalid.
|
||||
*/
|
||||
$fn_validate_webfont = static function( $webfont ) {
|
||||
$webfont = wp_parse_args(
|
||||
$webfont,
|
||||
array(
|
||||
'font-family' => '',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '400',
|
||||
'font-display' => 'fallback',
|
||||
'src' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
// Check the font-family.
|
||||
if ( empty( $webfont['font-family'] ) || ! is_string( $webfont['font-family'] ) ) {
|
||||
trigger_error( __( 'Webfont font family must be a non-empty string.' ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the `src` property is defined and a valid type.
|
||||
if ( empty( $webfont['src'] ) || ( ! is_string( $webfont['src'] ) && ! is_array( $webfont['src'] ) ) ) {
|
||||
trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.' ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the `src` property.
|
||||
foreach ( (array) $webfont['src'] as $src ) {
|
||||
if ( ! is_string( $src ) || '' === trim( $src ) ) {
|
||||
trigger_error( __( 'Each webfont src must be a non-empty string.' ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the font-weight.
|
||||
if ( ! is_string( $webfont['font-weight'] ) && ! is_int( $webfont['font-weight'] ) ) {
|
||||
trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.' ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the font-display.
|
||||
if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'optional', 'swap' ), true ) ) {
|
||||
$webfont['font-display'] = 'fallback';
|
||||
}
|
||||
|
||||
$valid_props = array(
|
||||
'ascend-override',
|
||||
'descend-override',
|
||||
'font-display',
|
||||
'font-family',
|
||||
'font-stretch',
|
||||
'font-style',
|
||||
'font-weight',
|
||||
'font-variant',
|
||||
'font-feature-settings',
|
||||
'font-variation-settings',
|
||||
'line-gap-override',
|
||||
'size-adjust',
|
||||
'src',
|
||||
'unicode-range',
|
||||
);
|
||||
|
||||
foreach ( $webfont as $prop => $value ) {
|
||||
if ( ! in_array( $prop, $valid_props, true ) ) {
|
||||
unset( $webfont[ $prop ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $webfont;
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers webfonts declared in theme.json.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference).
|
||||
* @uses $fn_get_webfonts_from_theme_json To run the function that gets the webfonts from theme.json.
|
||||
* @uses $fn_convert_keys_to_kebab_case To run the function that converts keys into kebab-case.
|
||||
* @uses $fn_validate_webfont To run the function that validates each font-face (webfont) from theme.json.
|
||||
*/
|
||||
$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 ) {
|
||||
$registered_webfonts = array();
|
||||
|
||||
foreach ( $fn_get_webfonts_from_theme_json() as $webfont ) {
|
||||
if ( ! is_array( $webfont ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$webfont = $fn_convert_keys_to_kebab_case( $webfont );
|
||||
|
||||
$webfont = $fn_validate_webfont( $webfont );
|
||||
|
||||
$webfont['src'] = $fn_transform_src_into_uri( (array) $webfont['src'] );
|
||||
|
||||
// Skip if not valid.
|
||||
if ( empty( $webfont ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$registered_webfonts[] = $webfont;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Orders 'src' items to optimize for browser support.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param array $webfont Webfont to process.
|
||||
* @return array Ordered `src` items.
|
||||
*/
|
||||
$fn_order_src = static function( array $webfont ) {
|
||||
$src = array();
|
||||
$src_ordered = array();
|
||||
|
||||
foreach ( $webfont['src'] as $url ) {
|
||||
// Add data URIs first.
|
||||
if ( str_starts_with( trim( $url ), 'data:' ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => $url,
|
||||
'format' => 'data',
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$format = pathinfo( $url, PATHINFO_EXTENSION );
|
||||
$src[ $format ] = $url;
|
||||
}
|
||||
|
||||
// Add woff2.
|
||||
if ( ! empty( $src['woff2'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => sanitize_url( $src['woff2'] ),
|
||||
'format' => 'woff2',
|
||||
);
|
||||
}
|
||||
|
||||
// Add woff.
|
||||
if ( ! empty( $src['woff'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => sanitize_url( $src['woff'] ),
|
||||
'format' => 'woff',
|
||||
);
|
||||
}
|
||||
|
||||
// Add ttf.
|
||||
if ( ! empty( $src['ttf'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => sanitize_url( $src['ttf'] ),
|
||||
'format' => 'truetype',
|
||||
);
|
||||
}
|
||||
|
||||
// Add eot.
|
||||
if ( ! empty( $src['eot'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => sanitize_url( $src['eot'] ),
|
||||
'format' => 'embedded-opentype',
|
||||
);
|
||||
}
|
||||
|
||||
// Add otf.
|
||||
if ( ! empty( $src['otf'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => sanitize_url( $src['otf'] ),
|
||||
'format' => 'opentype',
|
||||
);
|
||||
}
|
||||
$webfont['src'] = $src_ordered;
|
||||
|
||||
return $webfont;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compiles the 'src' into valid CSS.
|
||||
*
|
||||
* @since 6.0.0
|
||||
* @since 6.2.0 Removed local() CSS.
|
||||
*
|
||||
* @param string $font_family Font family.
|
||||
* @param array $value Value to process.
|
||||
* @return string The CSS.
|
||||
*/
|
||||
$fn_compile_src = static function( $font_family, array $value ) {
|
||||
$src = '';
|
||||
|
||||
foreach ( $value as $item ) {
|
||||
$src .= ( 'data' === $item['format'] )
|
||||
? ", url({$item['url']})"
|
||||
: ", url('{$item['url']}') format('{$item['format']}')";
|
||||
}
|
||||
|
||||
$src = ltrim( $src, ', ' );
|
||||
|
||||
return $src;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compiles the font variation settings.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param array $font_variation_settings Array of font variation settings.
|
||||
* @return string The CSS.
|
||||
*/
|
||||
$fn_compile_variations = static function( array $font_variation_settings ) {
|
||||
$variations = '';
|
||||
|
||||
foreach ( $font_variation_settings as $key => $value ) {
|
||||
$variations .= "$key $value";
|
||||
}
|
||||
|
||||
return $variations;
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds the font-family's CSS.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @uses $fn_compile_src To run the function that compiles the src.
|
||||
* @uses $fn_compile_variations To run the function that compiles the variations.
|
||||
*
|
||||
* @param array $webfont Webfont to process.
|
||||
* @return string This font-family's CSS.
|
||||
*/
|
||||
$fn_build_font_face_css = static function( array $webfont ) use ( $fn_compile_src, $fn_compile_variations ) {
|
||||
$css = '';
|
||||
|
||||
// Wrap font-family in quotes if it contains spaces.
|
||||
if (
|
||||
str_contains( $webfont['font-family'], ' ' ) &&
|
||||
! str_contains( $webfont['font-family'], '"' ) &&
|
||||
! str_contains( $webfont['font-family'], "'" )
|
||||
) {
|
||||
$webfont['font-family'] = '"' . $webfont['font-family'] . '"';
|
||||
}
|
||||
|
||||
foreach ( $webfont as $key => $value ) {
|
||||
/*
|
||||
* Skip "provider", since it's for internal API use,
|
||||
* and not a valid CSS property.
|
||||
*/
|
||||
if ( 'provider' === $key ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compile the "src" parameter.
|
||||
if ( 'src' === $key ) {
|
||||
$value = $fn_compile_src( $webfont['font-family'], $value );
|
||||
}
|
||||
|
||||
// If font-variation-settings is an array, convert it to a string.
|
||||
if ( 'font-variation-settings' === $key && is_array( $value ) ) {
|
||||
$value = $fn_compile_variations( $value );
|
||||
}
|
||||
|
||||
if ( ! empty( $value ) ) {
|
||||
$css .= "$key:$value;";
|
||||
}
|
||||
}
|
||||
|
||||
return $css;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the '@font-face' CSS styles for locally-hosted font files.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference).
|
||||
* @uses $fn_order_src To run the function that orders the src.
|
||||
* @uses $fn_build_font_face_css To run the function that builds the font-face CSS.
|
||||
*
|
||||
* @return string The `@font-face` CSS.
|
||||
*/
|
||||
$fn_get_css = static function() use ( &$registered_webfonts, $fn_order_src, $fn_build_font_face_css ) {
|
||||
$css = '';
|
||||
|
||||
foreach ( $registered_webfonts as $webfont ) {
|
||||
// Order the webfont's `src` items to optimize for browser support.
|
||||
$webfont = $fn_order_src( $webfont );
|
||||
|
||||
// Build the @font-face CSS for this webfont.
|
||||
$css .= '@font-face{' . $fn_build_font_face_css( $webfont ) . '}';
|
||||
}
|
||||
|
||||
return $css;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates and enqueues webfonts styles.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @uses $fn_get_css To run the function that gets the CSS.
|
||||
*/
|
||||
$fn_generate_and_enqueue_styles = static function() use ( $fn_get_css ) {
|
||||
// Generate the styles.
|
||||
$styles = $fn_get_css();
|
||||
|
||||
// Bail out if there are no styles to enqueue.
|
||||
if ( '' === $styles ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Enqueue the stylesheet.
|
||||
wp_register_style( 'wp-webfonts', '' );
|
||||
wp_enqueue_style( 'wp-webfonts' );
|
||||
|
||||
// Add the styles to the stylesheet.
|
||||
wp_add_inline_style( 'wp-webfonts', $styles );
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates and enqueues editor styles.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @uses $fn_get_css To run the function that gets the CSS.
|
||||
*/
|
||||
$fn_generate_and_enqueue_editor_styles = static function() use ( $fn_get_css ) {
|
||||
// Generate the styles.
|
||||
$styles = $fn_get_css();
|
||||
|
||||
// Bail out if there are no styles to enqueue.
|
||||
if ( '' === $styles ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_add_inline_style( 'wp-block-library', $styles );
|
||||
};
|
||||
|
||||
add_action( 'wp_loaded', $fn_register_webfonts );
|
||||
add_action( 'wp_enqueue_scripts', $fn_generate_and_enqueue_styles );
|
||||
add_action( 'admin_init', $fn_generate_and_enqueue_editor_styles );
|
||||
}
|
||||
|
||||
57
src/wp-includes/fonts.php
Normal file
57
src/wp-includes/fonts.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* Fonts functions.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Fonts
|
||||
* @since 6.4.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generates and prints font-face styles for given fonts or theme.json fonts.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array[][] $fonts {
|
||||
* Optional. The font-families and their font variations. Default empty array.
|
||||
*
|
||||
* @type string $font-family => array[] $variations {
|
||||
* Optional. An associated array of font variations for this font-family.
|
||||
* Each variation has the following structure.
|
||||
*
|
||||
* @type array $font_variation {
|
||||
* @type string $font-family The font-family property.
|
||||
* @type string|string[] $src The URL(s) to each resource containing the font data.
|
||||
* @type string $font_style Optional. The font-style property. Default 'normal'.
|
||||
* @type string $font-weight Optional. The font-weight property. Default '400'.
|
||||
* @type string $font-display Optional. The font-display property. Default 'fallback'.
|
||||
* @type string $ascent-override Optional. The ascent-override property.
|
||||
* @type string $descent-override Optional. The descent-override property.
|
||||
* @type string $font-stretch Optional. The font-stretch property.
|
||||
* @type string $font-variant Optional. The font-variant property.
|
||||
* @type string $font-feature-settings Optional. The font-feature-settings property.
|
||||
* @type string $font-variation-settings Optional. The font-variation-settings property.
|
||||
* @type string $line-gap-override Optional. The line-gap-override property.
|
||||
* @type string $size-adjust Optional. The size-adjust property.
|
||||
* @type string $unicode-range Optional. The unicode-range property.
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
function wp_print_font_faces( $fonts = array() ) {
|
||||
static $wp_font_face = null;
|
||||
|
||||
if ( empty( $fonts ) ) {
|
||||
$fonts = WP_Font_Face_Resolver::get_fonts_from_theme_json();
|
||||
}
|
||||
|
||||
if ( empty( $fonts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( null === $wp_font_face ) {
|
||||
$wp_font_face = new WP_Font_Face();
|
||||
}
|
||||
|
||||
$wp_font_face->generate_and_print( $fonts );
|
||||
}
|
||||
154
src/wp-includes/fonts/class-wp-font-face-resolver.php
Normal file
154
src/wp-includes/fonts/class-wp-font-face-resolver.php
Normal file
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* WP_Font_Face_Resolver class.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Fonts
|
||||
* @since 6.4.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Font Face Resolver abstracts the processing of different data sources
|
||||
* (such as theme.json) for processing within the Font Face.
|
||||
*
|
||||
* This class is for internal core usage and is not supposed to be used by
|
||||
* extenders (plugins and/or themes).
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
class WP_Font_Face_Resolver {
|
||||
|
||||
/**
|
||||
* Gets fonts defined in theme.json.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @return array Returns the font-families, each with their font-face variations.
|
||||
*/
|
||||
public static function get_fonts_from_theme_json() {
|
||||
$settings = wp_get_global_settings();
|
||||
|
||||
// Bail out early if there are no font settings.
|
||||
if ( empty( $settings['typography']['fontFamilies'] ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return static::parse_settings( $settings );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse theme.json settings to extract font definitions with variations grouped by font-family.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array $settings Font settings to parse.
|
||||
* @return array Returns an array of fonts, grouped by font-family.
|
||||
*/
|
||||
private static function parse_settings( array $settings ) {
|
||||
$fonts = array();
|
||||
|
||||
foreach ( $settings['typography']['fontFamilies'] as $font_families ) {
|
||||
foreach ( $font_families as $definition ) {
|
||||
|
||||
// Skip if font-family "name" is not defined.
|
||||
if ( empty( $definition['name'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if "fontFace" is not defined, meaning there are no variations.
|
||||
if ( empty( $definition['fontFace'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$font_family = $definition['name'];
|
||||
|
||||
// Prepare the fonts array structure for this font-family.
|
||||
if ( ! array_key_exists( $font_family, $fonts ) ) {
|
||||
$fonts[ $font_family ] = array();
|
||||
}
|
||||
|
||||
$fonts[ $font_family ] = static::convert_font_face_properties( $definition['fontFace'], $font_family );
|
||||
}
|
||||
}
|
||||
|
||||
return $fonts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts font-face properties from theme.json format.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array $font_face_definition The font-face definitions to convert.
|
||||
* @param string $font_family_property The value to store in the font-face font-family property.
|
||||
* @return array Converted font-face properties.
|
||||
*/
|
||||
private static function convert_font_face_properties( array $font_face_definition, $font_family_property ) {
|
||||
$converted_font_faces = array();
|
||||
|
||||
foreach ( $font_face_definition as $font_face ) {
|
||||
// Add the font-family property to the font-face.
|
||||
$font_face['font-family'] = $font_family_property;
|
||||
|
||||
// Converts the "file:./" src placeholder into a theme font file URI.
|
||||
if ( ! empty( $font_face['src'] ) ) {
|
||||
$font_face['src'] = static::to_theme_file_uri( (array) $font_face['src'] );
|
||||
}
|
||||
|
||||
// Convert camelCase properties into kebab-case.
|
||||
$font_face = static::to_kebab_case( $font_face );
|
||||
|
||||
$converted_font_faces[] = $font_face;
|
||||
}
|
||||
|
||||
return $converted_font_faces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts each 'file:./' placeholder into a URI to the font file in the theme.
|
||||
*
|
||||
* The 'file:./' is specified in the theme's `theme.json` as a placeholder to be
|
||||
* replaced with the URI to the font file's location in the theme. When a "src"
|
||||
* beings with this placeholder, it is replaced, converting the src into a URI.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array $src An array of font file sources to process.
|
||||
* @return array An array of font file src URI(s).
|
||||
*/
|
||||
private static function to_theme_file_uri( array $src ) {
|
||||
$placeholder = 'file:./';
|
||||
|
||||
foreach ( $src as $src_key => $src_url ) {
|
||||
// Skip if the src doesn't start with the placeholder, as there's nothing to replace.
|
||||
if ( ! str_starts_with( $src_url, $placeholder ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$src_file = str_replace( $placeholder, '', $src_url );
|
||||
$src[ $src_key ] = get_theme_file_uri( $src_file );
|
||||
}
|
||||
|
||||
return $src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all first dimension keys into kebab-case.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array $data The array to process.
|
||||
* @return array Data with first dimension keys converted into kebab-case.
|
||||
*/
|
||||
private static function to_kebab_case( array $data ) {
|
||||
foreach ( $data as $key => $value ) {
|
||||
$kebab_case = _wp_to_kebab_case( $key );
|
||||
$data[ $kebab_case ] = $value;
|
||||
if ( $kebab_case !== $key ) {
|
||||
unset( $data[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
430
src/wp-includes/fonts/class-wp-font-face.php
Normal file
430
src/wp-includes/fonts/class-wp-font-face.php
Normal file
@ -0,0 +1,430 @@
|
||||
<?php
|
||||
/**
|
||||
* WP_Font_Face class.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Fonts
|
||||
* @since 6.4.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Font Face generates and prints `@font-face` styles for given fonts.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*/
|
||||
class WP_Font_Face {
|
||||
|
||||
/**
|
||||
* The font-face property defaults.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $font_face_property_defaults = array(
|
||||
'font-family' => '',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '400',
|
||||
'font-display' => 'fallback',
|
||||
);
|
||||
|
||||
/**
|
||||
* Valid font-face property names.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $valid_font_face_properties = array(
|
||||
'ascent-override',
|
||||
'descent-override',
|
||||
'font-display',
|
||||
'font-family',
|
||||
'font-stretch',
|
||||
'font-style',
|
||||
'font-weight',
|
||||
'font-variant',
|
||||
'font-feature-settings',
|
||||
'font-variation-settings',
|
||||
'line-gap-override',
|
||||
'size-adjust',
|
||||
'src',
|
||||
'unicode-range',
|
||||
);
|
||||
|
||||
/**
|
||||
* Valid font-display values.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $valid_font_display = array( 'auto', 'block', 'fallback', 'swap', 'optional' );
|
||||
|
||||
/**
|
||||
* Array of font-face style tag's attribute(s)
|
||||
* where the key is the attribute name and the
|
||||
* value is its value.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $style_tag_attrs = array();
|
||||
|
||||
/**
|
||||
* Creates and initializes an instance of WP_Font_Face.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*/
|
||||
public function __construct() {
|
||||
if (
|
||||
function_exists( 'is_admin' ) && ! is_admin()
|
||||
&&
|
||||
function_exists( 'current_theme_supports' ) && ! current_theme_supports( 'html5', 'style' )
|
||||
) {
|
||||
$this->style_tag_attrs = array( 'type' => 'text/css' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and prints the `@font-face` styles for the given fonts.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array[][] $fonts Optional. The font-families and their font variations.
|
||||
* See {@see wp_print_font_faces()} for the supported fields.
|
||||
* Default empty array.
|
||||
*/
|
||||
public function generate_and_print( array $fonts ) {
|
||||
$fonts = $this->validate_fonts( $fonts );
|
||||
|
||||
// Bail out if there are no fonts are given to process.
|
||||
if ( empty( $fonts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$css = $this->get_css( $fonts );
|
||||
|
||||
/*
|
||||
* The font-face CSS is contained within <style> tags and can only be interpreted
|
||||
* as CSS in the browser. Using wp_strip_all_tags() is sufficient escaping
|
||||
* to avoid malicious attempts to close </style> and open a <script>.
|
||||
*/
|
||||
$css = wp_strip_all_tags( $css );
|
||||
|
||||
// Bail out if there is no CSS to print.
|
||||
if ( empty( $css ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf( $this->get_style_element(), $css );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates each of the font-face properties.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array $fonts The fonts to valid.
|
||||
* @return array Prepared font-faces organized by provider and font-family.
|
||||
*/
|
||||
private function validate_fonts( array $fonts ) {
|
||||
$validated_fonts = array();
|
||||
|
||||
foreach ( $fonts as $font_faces ) {
|
||||
foreach ( $font_faces as $font_face ) {
|
||||
$font_face = $this->validate_font_face_declarations( $font_face );
|
||||
// Skip if failed validation.
|
||||
if ( false === $font_face ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$validated_fonts[] = $font_face;
|
||||
}
|
||||
}
|
||||
|
||||
return $validated_fonts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates each font-face declaration (property and value pairing).
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array $font_face Font face property and value pairings to validate.
|
||||
* @return array|false Validated font-face on success, or false on failure.
|
||||
*/
|
||||
private function validate_font_face_declarations( array $font_face ) {
|
||||
$font_face = wp_parse_args( $font_face, $this->font_face_property_defaults );
|
||||
|
||||
// Check the font-family.
|
||||
if ( empty( $font_face['font-family'] ) || ! is_string( $font_face['font-family'] ) ) {
|
||||
// @todo replace with `wp_trigger_error()`.
|
||||
_doing_it_wrong(
|
||||
__METHOD__,
|
||||
__( 'Font font-family must be a non-empty string.' ),
|
||||
'6.4.0'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure that local fonts have 'src' defined.
|
||||
if ( empty( $font_face['src'] ) || ( ! is_string( $font_face['src'] ) && ! is_array( $font_face['src'] ) ) ) {
|
||||
// @todo replace with `wp_trigger_error()`.
|
||||
_doing_it_wrong(
|
||||
__METHOD__,
|
||||
__( 'Font src must be a non-empty string or an array of strings.' ),
|
||||
'6.4.0'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the 'src' property.
|
||||
foreach ( (array) $font_face['src'] as $src ) {
|
||||
if ( empty( $src ) || ! is_string( $src ) ) {
|
||||
// @todo replace with `wp_trigger_error()`.
|
||||
_doing_it_wrong(
|
||||
__METHOD__,
|
||||
__( 'Each font src must be a non-empty string.' ),
|
||||
'6.4.0'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the font-weight.
|
||||
if ( ! is_string( $font_face['font-weight'] ) && ! is_int( $font_face['font-weight'] ) ) {
|
||||
// @todo replace with `wp_trigger_error()`.
|
||||
_doing_it_wrong(
|
||||
__METHOD__,
|
||||
__( 'Font font-weight must be a properly formatted string or integer.' ),
|
||||
'6.4.0'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the font-display.
|
||||
if ( ! in_array( $font_face['font-display'], $this->valid_font_display, true ) ) {
|
||||
$font_face['font-display'] = $this->font_face_property_defaults['font-display'];
|
||||
}
|
||||
|
||||
// Remove invalid properties.
|
||||
foreach ( $font_face as $property => $value ) {
|
||||
if ( ! in_array( $property, $this->valid_font_face_properties, true ) ) {
|
||||
unset( $font_face[ $property ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $font_face;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the style element for wrapping the `@font-face` CSS.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @return string The style element.
|
||||
*/
|
||||
private function get_style_element() {
|
||||
$attributes = $this->generate_style_element_attributes();
|
||||
|
||||
return "<style id='wp-fonts-local'{$attributes}>\n%s\n</style>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the defined <style> element's attributes.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @return string A string of attribute=value when defined, else, empty string.
|
||||
*/
|
||||
private function generate_style_element_attributes() {
|
||||
$attributes = '';
|
||||
foreach ( $this->style_tag_attrs as $name => $value ) {
|
||||
$attributes .= " {$name}='{$value}'";
|
||||
}
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the `@font-face` CSS styles for locally-hosted font files.
|
||||
*
|
||||
* This method does the following processing tasks:
|
||||
* 1. Orchestrates an optimized `src` (with format) for browser support.
|
||||
* 2. Generates the `@font-face` for all its fonts.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array $font_faces The font-faces to generate @font-face CSS styles.
|
||||
* @return string The `@font-face` CSS styles.
|
||||
*/
|
||||
private function get_css( $font_faces ) {
|
||||
$css = '';
|
||||
|
||||
foreach ( $font_faces as $font_face ) {
|
||||
// Order the font's `src` items to optimize for browser support.
|
||||
$font_face = $this->order_src( $font_face );
|
||||
|
||||
// Build the @font-face CSS for this font.
|
||||
$css .= '@font-face{' . $this->build_font_face_css( $font_face ) . '}' . "\n";
|
||||
}
|
||||
|
||||
// Don't print the last newline character.
|
||||
return rtrim( $css, "\n" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Orders `src` items to optimize for browser support.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array $font_face Font face to process.
|
||||
* @return array Font-face with ordered src items.
|
||||
*/
|
||||
private function order_src( array $font_face ) {
|
||||
if ( ! is_array( $font_face['src'] ) ) {
|
||||
$font_face['src'] = (array) $font_face['src'];
|
||||
}
|
||||
|
||||
$src = array();
|
||||
$src_ordered = array();
|
||||
|
||||
foreach ( $font_face['src'] as $url ) {
|
||||
// Add data URIs first.
|
||||
if ( str_starts_with( trim( $url ), 'data:' ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => $url,
|
||||
'format' => 'data',
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$format = pathinfo( $url, PATHINFO_EXTENSION );
|
||||
$src[ $format ] = $url;
|
||||
}
|
||||
|
||||
// Add woff2.
|
||||
if ( ! empty( $src['woff2'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => $src['woff2'],
|
||||
'format' => 'woff2',
|
||||
);
|
||||
}
|
||||
|
||||
// Add woff.
|
||||
if ( ! empty( $src['woff'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => $src['woff'],
|
||||
'format' => 'woff',
|
||||
);
|
||||
}
|
||||
|
||||
// Add ttf.
|
||||
if ( ! empty( $src['ttf'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => $src['ttf'],
|
||||
'format' => 'truetype',
|
||||
);
|
||||
}
|
||||
|
||||
// Add eot.
|
||||
if ( ! empty( $src['eot'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => $src['eot'],
|
||||
'format' => 'embedded-opentype',
|
||||
);
|
||||
}
|
||||
|
||||
// Add otf.
|
||||
if ( ! empty( $src['otf'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => $src['otf'],
|
||||
'format' => 'opentype',
|
||||
);
|
||||
}
|
||||
$font_face['src'] = $src_ordered;
|
||||
|
||||
return $font_face;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the font-family's CSS.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array $font_face Font face to process.
|
||||
* @return string This font-family's CSS.
|
||||
*/
|
||||
private function build_font_face_css( array $font_face ) {
|
||||
$css = '';
|
||||
|
||||
/*
|
||||
* Wrap font-family in quotes if it contains spaces
|
||||
* and is not already wrapped in quotes.
|
||||
*/
|
||||
if (
|
||||
str_contains( $font_face['font-family'], ' ' ) &&
|
||||
! str_contains( $font_face['font-family'], '"' ) &&
|
||||
! str_contains( $font_face['font-family'], "'" )
|
||||
) {
|
||||
$font_face['font-family'] = '"' . $font_face['font-family'] . '"';
|
||||
}
|
||||
|
||||
foreach ( $font_face as $key => $value ) {
|
||||
// Compile the "src" parameter.
|
||||
if ( 'src' === $key ) {
|
||||
$value = $this->compile_src( $value );
|
||||
}
|
||||
|
||||
// If font-variation-settings is an array, convert it to a string.
|
||||
if ( 'font-variation-settings' === $key && is_array( $value ) ) {
|
||||
$value = $this->compile_variations( $value );
|
||||
}
|
||||
|
||||
if ( ! empty( $value ) ) {
|
||||
$css .= "$key:$value;";
|
||||
}
|
||||
}
|
||||
|
||||
return $css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the `src` into valid CSS.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array $value Value to process.
|
||||
* @return string The CSS.
|
||||
*/
|
||||
private function compile_src( array $value ) {
|
||||
$src = '';
|
||||
|
||||
foreach ( $value as $item ) {
|
||||
$src .= ( 'data' === $item['format'] )
|
||||
? ", url({$item['url']})"
|
||||
: ", url('{$item['url']}') format('{$item['format']}')";
|
||||
}
|
||||
|
||||
$src = ltrim( $src, ', ' );
|
||||
return $src;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles the font variation settings.
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @param array $font_variation_settings Array of font variation settings.
|
||||
* @return string The CSS.
|
||||
*/
|
||||
private function compile_variations( array $font_variation_settings ) {
|
||||
$variations = '';
|
||||
|
||||
foreach ( $font_variation_settings as $key => $value ) {
|
||||
$variations .= "$key $value";
|
||||
}
|
||||
|
||||
return $variations;
|
||||
}
|
||||
}
|
||||
@ -3223,506 +3223,6 @@ function wp_enqueue_block_style( $block_name, $args ) {
|
||||
add_action( 'enqueue_block_assets', $callback );
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the theme.json webfonts handler.
|
||||
*
|
||||
* Using `WP_Theme_JSON_Resolver`, it gets the fonts defined
|
||||
* in the `theme.json` for the current selection and style
|
||||
* variations, validates the font-face properties, generates
|
||||
* the '@font-face' style declarations, and then enqueues the
|
||||
* styles for both the editor and front-end.
|
||||
*
|
||||
* Design Notes:
|
||||
* This is not a public API, but rather an internal handler.
|
||||
* A future public Webfonts API will replace this stopgap code.
|
||||
*
|
||||
* This code design is intentional.
|
||||
* a. It hides the inner-workings.
|
||||
* b. It does not expose API ins or outs for consumption.
|
||||
* c. It only works with a theme's `theme.json`.
|
||||
*
|
||||
* Why?
|
||||
* a. To avoid backwards-compatibility issues when
|
||||
* the Webfonts API is introduced in Core.
|
||||
* b. To make `fontFace` declarations in `theme.json` work.
|
||||
*
|
||||
* @link https://github.com/WordPress/gutenberg/issues/40472
|
||||
*
|
||||
* @since 6.0.0
|
||||
* @access private
|
||||
*/
|
||||
function _wp_theme_json_webfonts_handler() {
|
||||
// Block themes are unavailable during installation.
|
||||
if ( wp_installing() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! wp_theme_has_theme_json() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Webfonts to be processed.
|
||||
$registered_webfonts = array();
|
||||
|
||||
/**
|
||||
* Gets the webfonts from theme.json.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @return array Array of defined webfonts.
|
||||
*/
|
||||
$fn_get_webfonts_from_theme_json = static function() {
|
||||
// Get settings from theme.json.
|
||||
$settings = WP_Theme_JSON_Resolver::get_merged_data()->get_settings();
|
||||
|
||||
// If in the editor, add webfonts defined in variations.
|
||||
if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
|
||||
$variations = WP_Theme_JSON_Resolver::get_style_variations();
|
||||
foreach ( $variations as $variation ) {
|
||||
// Skip if fontFamilies are not defined in the variation.
|
||||
if ( empty( $variation['settings']['typography']['fontFamilies'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Initialize the array structure.
|
||||
if ( empty( $settings['typography'] ) ) {
|
||||
$settings['typography'] = array();
|
||||
}
|
||||
if ( empty( $settings['typography']['fontFamilies'] ) ) {
|
||||
$settings['typography']['fontFamilies'] = array();
|
||||
}
|
||||
if ( empty( $settings['typography']['fontFamilies']['theme'] ) ) {
|
||||
$settings['typography']['fontFamilies']['theme'] = array();
|
||||
}
|
||||
|
||||
// Combine variations with settings. Remove duplicates.
|
||||
$settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] );
|
||||
$settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] );
|
||||
}
|
||||
}
|
||||
|
||||
// Bail out early if there are no settings for webfonts.
|
||||
if ( empty( $settings['typography']['fontFamilies'] ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$webfonts = array();
|
||||
|
||||
// Look for fontFamilies.
|
||||
foreach ( $settings['typography']['fontFamilies'] as $font_families ) {
|
||||
foreach ( $font_families as $font_family ) {
|
||||
|
||||
// Skip if fontFace is not defined.
|
||||
if ( empty( $font_family['fontFace'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip if fontFace is not an array of webfonts.
|
||||
if ( ! is_array( $font_family['fontFace'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$webfonts = array_merge( $webfonts, $font_family['fontFace'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $webfonts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transforms each 'src' into an URI by replacing 'file:./'
|
||||
* placeholder from theme.json.
|
||||
*
|
||||
* The absolute path to the webfont file(s) cannot be defined in
|
||||
* theme.json. `file:./` is the placeholder which is replaced by
|
||||
* the theme's URL path to the theme's root.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param array $src Webfont file(s) `src`.
|
||||
* @return array Webfont's `src` in URI.
|
||||
*/
|
||||
$fn_transform_src_into_uri = static function( array $src ) {
|
||||
foreach ( $src as $key => $url ) {
|
||||
// Tweak the URL to be relative to the theme root.
|
||||
if ( ! str_starts_with( $url, 'file:./' ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$src[ $key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) );
|
||||
}
|
||||
|
||||
return $src;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the font-face properties (i.e. keys) into kebab-case.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param array $font_face Font face to convert.
|
||||
* @return array Font faces with each property in kebab-case format.
|
||||
*/
|
||||
$fn_convert_keys_to_kebab_case = static function( array $font_face ) {
|
||||
foreach ( $font_face as $property => $value ) {
|
||||
$kebab_case = _wp_to_kebab_case( $property );
|
||||
$font_face[ $kebab_case ] = $value;
|
||||
if ( $kebab_case !== $property ) {
|
||||
unset( $font_face[ $property ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $font_face;
|
||||
};
|
||||
|
||||
/**
|
||||
* Validates a webfont.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param array $webfont The webfont arguments.
|
||||
* @return array|false The validated webfont arguments, or false if the webfont is invalid.
|
||||
*/
|
||||
$fn_validate_webfont = static function( $webfont ) {
|
||||
$webfont = wp_parse_args(
|
||||
$webfont,
|
||||
array(
|
||||
'font-family' => '',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '400',
|
||||
'font-display' => 'fallback',
|
||||
'src' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
// Check the font-family.
|
||||
if ( empty( $webfont['font-family'] ) || ! is_string( $webfont['font-family'] ) ) {
|
||||
trigger_error( __( 'Webfont font family must be a non-empty string.' ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the `src` property is defined and a valid type.
|
||||
if ( empty( $webfont['src'] ) || ( ! is_string( $webfont['src'] ) && ! is_array( $webfont['src'] ) ) ) {
|
||||
trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.' ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate the `src` property.
|
||||
foreach ( (array) $webfont['src'] as $src ) {
|
||||
if ( ! is_string( $src ) || '' === trim( $src ) ) {
|
||||
trigger_error( __( 'Each webfont src must be a non-empty string.' ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the font-weight.
|
||||
if ( ! is_string( $webfont['font-weight'] ) && ! is_int( $webfont['font-weight'] ) ) {
|
||||
trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.' ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the font-display.
|
||||
if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'optional', 'swap' ), true ) ) {
|
||||
$webfont['font-display'] = 'fallback';
|
||||
}
|
||||
|
||||
$valid_props = array(
|
||||
'ascend-override',
|
||||
'descend-override',
|
||||
'font-display',
|
||||
'font-family',
|
||||
'font-stretch',
|
||||
'font-style',
|
||||
'font-weight',
|
||||
'font-variant',
|
||||
'font-feature-settings',
|
||||
'font-variation-settings',
|
||||
'line-gap-override',
|
||||
'size-adjust',
|
||||
'src',
|
||||
'unicode-range',
|
||||
);
|
||||
|
||||
foreach ( $webfont as $prop => $value ) {
|
||||
if ( ! in_array( $prop, $valid_props, true ) ) {
|
||||
unset( $webfont[ $prop ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $webfont;
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers webfonts declared in theme.json.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference).
|
||||
* @uses $fn_get_webfonts_from_theme_json To run the function that gets the webfonts from theme.json.
|
||||
* @uses $fn_convert_keys_to_kebab_case To run the function that converts keys into kebab-case.
|
||||
* @uses $fn_validate_webfont To run the function that validates each font-face (webfont) from theme.json.
|
||||
*/
|
||||
$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 ) {
|
||||
$registered_webfonts = array();
|
||||
|
||||
foreach ( $fn_get_webfonts_from_theme_json() as $webfont ) {
|
||||
if ( ! is_array( $webfont ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$webfont = $fn_convert_keys_to_kebab_case( $webfont );
|
||||
|
||||
$webfont = $fn_validate_webfont( $webfont );
|
||||
|
||||
$webfont['src'] = $fn_transform_src_into_uri( (array) $webfont['src'] );
|
||||
|
||||
// Skip if not valid.
|
||||
if ( empty( $webfont ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$registered_webfonts[] = $webfont;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Orders 'src' items to optimize for browser support.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param array $webfont Webfont to process.
|
||||
* @return array Ordered `src` items.
|
||||
*/
|
||||
$fn_order_src = static function( array $webfont ) {
|
||||
$src = array();
|
||||
$src_ordered = array();
|
||||
|
||||
foreach ( $webfont['src'] as $url ) {
|
||||
// Add data URIs first.
|
||||
if ( str_starts_with( trim( $url ), 'data:' ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => $url,
|
||||
'format' => 'data',
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$format = pathinfo( $url, PATHINFO_EXTENSION );
|
||||
$src[ $format ] = $url;
|
||||
}
|
||||
|
||||
// Add woff2.
|
||||
if ( ! empty( $src['woff2'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => sanitize_url( $src['woff2'] ),
|
||||
'format' => 'woff2',
|
||||
);
|
||||
}
|
||||
|
||||
// Add woff.
|
||||
if ( ! empty( $src['woff'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => sanitize_url( $src['woff'] ),
|
||||
'format' => 'woff',
|
||||
);
|
||||
}
|
||||
|
||||
// Add ttf.
|
||||
if ( ! empty( $src['ttf'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => sanitize_url( $src['ttf'] ),
|
||||
'format' => 'truetype',
|
||||
);
|
||||
}
|
||||
|
||||
// Add eot.
|
||||
if ( ! empty( $src['eot'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => sanitize_url( $src['eot'] ),
|
||||
'format' => 'embedded-opentype',
|
||||
);
|
||||
}
|
||||
|
||||
// Add otf.
|
||||
if ( ! empty( $src['otf'] ) ) {
|
||||
$src_ordered[] = array(
|
||||
'url' => sanitize_url( $src['otf'] ),
|
||||
'format' => 'opentype',
|
||||
);
|
||||
}
|
||||
$webfont['src'] = $src_ordered;
|
||||
|
||||
return $webfont;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compiles the 'src' into valid CSS.
|
||||
*
|
||||
* @since 6.0.0
|
||||
* @since 6.2.0 Removed local() CSS.
|
||||
*
|
||||
* @param string $font_family Font family.
|
||||
* @param array $value Value to process.
|
||||
* @return string The CSS.
|
||||
*/
|
||||
$fn_compile_src = static function( $font_family, array $value ) {
|
||||
$src = '';
|
||||
|
||||
foreach ( $value as $item ) {
|
||||
$src .= ( 'data' === $item['format'] )
|
||||
? ", url({$item['url']})"
|
||||
: ", url('{$item['url']}') format('{$item['format']}')";
|
||||
}
|
||||
|
||||
$src = ltrim( $src, ', ' );
|
||||
|
||||
return $src;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compiles the font variation settings.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param array $font_variation_settings Array of font variation settings.
|
||||
* @return string The CSS.
|
||||
*/
|
||||
$fn_compile_variations = static function( array $font_variation_settings ) {
|
||||
$variations = '';
|
||||
|
||||
foreach ( $font_variation_settings as $key => $value ) {
|
||||
$variations .= "$key $value";
|
||||
}
|
||||
|
||||
return $variations;
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds the font-family's CSS.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @uses $fn_compile_src To run the function that compiles the src.
|
||||
* @uses $fn_compile_variations To run the function that compiles the variations.
|
||||
*
|
||||
* @param array $webfont Webfont to process.
|
||||
* @return string This font-family's CSS.
|
||||
*/
|
||||
$fn_build_font_face_css = static function( array $webfont ) use ( $fn_compile_src, $fn_compile_variations ) {
|
||||
$css = '';
|
||||
|
||||
// Wrap font-family in quotes if it contains spaces.
|
||||
if (
|
||||
str_contains( $webfont['font-family'], ' ' ) &&
|
||||
! str_contains( $webfont['font-family'], '"' ) &&
|
||||
! str_contains( $webfont['font-family'], "'" )
|
||||
) {
|
||||
$webfont['font-family'] = '"' . $webfont['font-family'] . '"';
|
||||
}
|
||||
|
||||
foreach ( $webfont as $key => $value ) {
|
||||
/*
|
||||
* Skip "provider", since it's for internal API use,
|
||||
* and not a valid CSS property.
|
||||
*/
|
||||
if ( 'provider' === $key ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Compile the "src" parameter.
|
||||
if ( 'src' === $key ) {
|
||||
$value = $fn_compile_src( $webfont['font-family'], $value );
|
||||
}
|
||||
|
||||
// If font-variation-settings is an array, convert it to a string.
|
||||
if ( 'font-variation-settings' === $key && is_array( $value ) ) {
|
||||
$value = $fn_compile_variations( $value );
|
||||
}
|
||||
|
||||
if ( ! empty( $value ) ) {
|
||||
$css .= "$key:$value;";
|
||||
}
|
||||
}
|
||||
|
||||
return $css;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the '@font-face' CSS styles for locally-hosted font files.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference).
|
||||
* @uses $fn_order_src To run the function that orders the src.
|
||||
* @uses $fn_build_font_face_css To run the function that builds the font-face CSS.
|
||||
*
|
||||
* @return string The `@font-face` CSS.
|
||||
*/
|
||||
$fn_get_css = static function() use ( &$registered_webfonts, $fn_order_src, $fn_build_font_face_css ) {
|
||||
$css = '';
|
||||
|
||||
foreach ( $registered_webfonts as $webfont ) {
|
||||
// Order the webfont's `src` items to optimize for browser support.
|
||||
$webfont = $fn_order_src( $webfont );
|
||||
|
||||
// Build the @font-face CSS for this webfont.
|
||||
$css .= '@font-face{' . $fn_build_font_face_css( $webfont ) . '}';
|
||||
}
|
||||
|
||||
return $css;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates and enqueues webfonts styles.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @uses $fn_get_css To run the function that gets the CSS.
|
||||
*/
|
||||
$fn_generate_and_enqueue_styles = static function() use ( $fn_get_css ) {
|
||||
// Generate the styles.
|
||||
$styles = $fn_get_css();
|
||||
|
||||
// Bail out if there are no styles to enqueue.
|
||||
if ( '' === $styles ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Enqueue the stylesheet.
|
||||
wp_register_style( 'wp-webfonts', '' );
|
||||
wp_enqueue_style( 'wp-webfonts' );
|
||||
|
||||
// Add the styles to the stylesheet.
|
||||
wp_add_inline_style( 'wp-webfonts', $styles );
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates and enqueues editor styles.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @uses $fn_get_css To run the function that gets the CSS.
|
||||
*/
|
||||
$fn_generate_and_enqueue_editor_styles = static function() use ( $fn_get_css ) {
|
||||
// Generate the styles.
|
||||
$styles = $fn_get_css();
|
||||
|
||||
// Bail out if there are no styles to enqueue.
|
||||
if ( '' === $styles ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_add_inline_style( 'wp-block-library', $styles );
|
||||
};
|
||||
|
||||
add_action( 'wp_loaded', $fn_register_webfonts );
|
||||
add_action( 'wp_enqueue_scripts', $fn_generate_and_enqueue_styles );
|
||||
add_action( 'admin_init', $fn_generate_and_enqueue_editor_styles );
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads classic theme styles on classic themes in the frontend.
|
||||
*
|
||||
|
||||
@ -360,6 +360,9 @@ require ABSPATH . WPINC . '/style-engine/class-wp-style-engine-css-declarations.
|
||||
require ABSPATH . WPINC . '/style-engine/class-wp-style-engine-css-rule.php';
|
||||
require ABSPATH . WPINC . '/style-engine/class-wp-style-engine-css-rules-store.php';
|
||||
require ABSPATH . WPINC . '/style-engine/class-wp-style-engine-processor.php';
|
||||
require ABSPATH . WPINC . '/fonts/class-wp-font-face-resolver.php';
|
||||
require ABSPATH . WPINC . '/fonts/class-wp-font-face.php';
|
||||
require ABSPATH . WPINC . '/fonts.php';
|
||||
|
||||
$GLOBALS['wp_embed'] = new WP_Embed();
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,94 @@
|
||||
Copyright 2014-2017 Indian Type Foundry (info@indiantypefoundry.com). Copyright 2019 Google LLC.
|
||||
Copyright 2014-2018 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. Copyright 2019 Google LLC.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@ -0,0 +1,93 @@
|
||||
Copyright 2020 The Open Sans Project Authors (https://github.com/googlefonts/opensans)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,93 @@
|
||||
Copyright 2014 - 2021 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
|
||||
This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,7 +1,7 @@
|
||||
/*
|
||||
Theme Name: Webfonts theme
|
||||
Theme Name: Block Theme with defined Typography Fonts
|
||||
Theme URI: https://wordpress.org/
|
||||
Description: For testing purposes only.
|
||||
Version: 1.0.0
|
||||
Text Domain: webfonts-theme
|
||||
Text Domain: fonts-block-theme
|
||||
*/
|
||||
@ -0,0 +1,40 @@
|
||||
{
|
||||
"version": 2,
|
||||
"title": "Variation: duplicate fonts",
|
||||
"settings": {
|
||||
"typography": {
|
||||
"fontFamilies": [
|
||||
{
|
||||
"fontFamily": "\"DM Sans\", sans-serif",
|
||||
"name": "DM Sans",
|
||||
"slug": "dm-sans",
|
||||
"fontFace": [
|
||||
{
|
||||
"fontFamily": "DM Sans",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "normal",
|
||||
"fontWeight": "400",
|
||||
"src": [
|
||||
"file:./assets/fonts/dm-sans/DMSans-Regular.woff2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fontFamily": "DM Sans",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "normal",
|
||||
"fontWeight": "700",
|
||||
"src": [
|
||||
"file:./assets/fonts/dm-sans/DMSans-Bold.woff2"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"styles": {
|
||||
"typography": {
|
||||
"fontFamily": "var(--wp--preset--font-family--dm-sans)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
{
|
||||
"version": 2,
|
||||
"title": "Variation: new font family",
|
||||
"settings": {
|
||||
"typography": {
|
||||
"fontFamilies": [
|
||||
{
|
||||
"fontFamily": "\"Open Sans\", serif",
|
||||
"name": "Open Sans",
|
||||
"slug": "open-sans",
|
||||
"fontFace": [
|
||||
{
|
||||
"fontFamily": "Open Sans",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "normal",
|
||||
"fontWeight": "400",
|
||||
"src": [
|
||||
"file:./assets/fonts/open-sans/OpenSans-VariableFont_wdth,wght.tff"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fontFamily": "Open Sans",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "italic",
|
||||
"fontWeight": "400",
|
||||
"src": [
|
||||
"file:./assets/fonts/open-sans/OpenSans-Italic-VariableFont_wdth,wght.tff"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"styles": {
|
||||
"typography": {
|
||||
"fontFamily": "var(--wp--preset--font-family--open-sans)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
{
|
||||
"version": 2,
|
||||
"title": "Variation: new font variations",
|
||||
"settings": {
|
||||
"typography": {
|
||||
"fontFamilies": [
|
||||
{
|
||||
"fontFamily": "\"DM Sans\", sans-serif",
|
||||
"name": "DM Sans",
|
||||
"slug": "dm-sans",
|
||||
"fontFace": [
|
||||
{
|
||||
"fontFamily": "DM Sans",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "normal",
|
||||
"fontWeight": "500",
|
||||
"src": [
|
||||
"file:./assets/fonts/dm-sans/DMSans-Medium.woff2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fontFamily": "DM Sans",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "italic",
|
||||
"fontWeight": "500",
|
||||
"src": [
|
||||
"file:./assets/fonts/dm-sans/DMSans-Medium-Italic.woff2"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"styles": {
|
||||
"typography": {
|
||||
"fontFamily": "var(--wp--preset--font-family--dm-sans)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
{
|
||||
"version": 2,
|
||||
"title": "Variation - no fonts",
|
||||
"styles": {
|
||||
"typography": {
|
||||
"fontFamily": "var(--wp--preset--font-family--dm-sans)"
|
||||
}
|
||||
}
|
||||
}
|
||||
112
tests/phpunit/data/themedir1/fonts-block-theme/theme.json
Normal file
112
tests/phpunit/data/themedir1/fonts-block-theme/theme.json
Normal file
@ -0,0 +1,112 @@
|
||||
{
|
||||
"version": 2,
|
||||
"settings": {
|
||||
"appearanceTools": true,
|
||||
"color": {
|
||||
"palette": [
|
||||
{
|
||||
"slug": "light",
|
||||
"name": "Light",
|
||||
"color": "#f5f7f9"
|
||||
},
|
||||
{
|
||||
"slug": "dark",
|
||||
"name": "Dark",
|
||||
"color": "#000"
|
||||
}
|
||||
]
|
||||
},
|
||||
"typography": {
|
||||
"dropCap": false,
|
||||
"fluid": true,
|
||||
"fontFamilies": [
|
||||
{
|
||||
"fontFace": [
|
||||
{
|
||||
"fontFamily": "DM Sans",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "normal",
|
||||
"fontWeight": "400",
|
||||
"src": [
|
||||
"file:./assets/fonts/dm-sans/DMSans-Regular.woff2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fontFamily": "DM Sans",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "italic",
|
||||
"fontWeight": "400",
|
||||
"src": [
|
||||
"file:./assets/fonts/dm-sans/DMSans-Regular-Italic.woff2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fontFamily": "DM Sans",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "normal",
|
||||
"fontWeight": "700",
|
||||
"src": [
|
||||
"file:./assets/fonts/dm-sans/DMSans-Bold.woff2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fontFamily": "DM Sans",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "italic",
|
||||
"fontWeight": "700",
|
||||
"src": [
|
||||
"file:./assets/fonts/dm-sans/DMSans-Bold-Italic.woff2"
|
||||
]
|
||||
}
|
||||
],
|
||||
"fontFamily": "\"DM Sans\", sans-serif",
|
||||
"name": "DM Sans",
|
||||
"slug": "dm-sans"
|
||||
},
|
||||
{
|
||||
"fontFamily": "-apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif",
|
||||
"name": "System Font",
|
||||
"slug": "system-font"
|
||||
},
|
||||
{
|
||||
"fontFace": [
|
||||
{
|
||||
"fontFamily": "Source Serif Pro",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "normal",
|
||||
"fontWeight": "200 900",
|
||||
"src": [
|
||||
"file:./assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2"
|
||||
]
|
||||
},
|
||||
{
|
||||
"fontFamily": "Source Serif Pro",
|
||||
"fontStretch": "normal",
|
||||
"fontStyle": "italic",
|
||||
"fontWeight": "200 900",
|
||||
"src": [
|
||||
"file:./assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2"
|
||||
]
|
||||
}
|
||||
],
|
||||
"fontFamily": "\"Source Serif Pro\", serif",
|
||||
"name": "Source Serif Pro",
|
||||
"slug": "source-serif-pro"
|
||||
}
|
||||
]
|
||||
},
|
||||
"useRootPaddingAwareAlignments": true
|
||||
},
|
||||
"styles": {
|
||||
"typography": {
|
||||
"fontFamily": "var(--wp--preset--font-family--system-font)"
|
||||
}
|
||||
},
|
||||
"templateParts": [
|
||||
{
|
||||
"name": "small-header",
|
||||
"title": "Small Header",
|
||||
"area": "header"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
<?php
|
||||
@ -1,4 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Block theme.
|
||||
*/
|
||||
@ -1,103 +0,0 @@
|
||||
{
|
||||
"version": 2,
|
||||
"customTemplates": [
|
||||
{
|
||||
"name": "blank",
|
||||
"title": "Blank",
|
||||
"postTypes": [
|
||||
"page",
|
||||
"post"
|
||||
]
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
"appearanceTools": true,
|
||||
"color": {
|
||||
"duotone": [],
|
||||
"gradients": [],
|
||||
"palette": []
|
||||
},
|
||||
"custom": {},
|
||||
"spacing": {
|
||||
"units": [
|
||||
"%",
|
||||
"px",
|
||||
"em",
|
||||
"rem",
|
||||
"vh",
|
||||
"vw"
|
||||
]
|
||||
},
|
||||
"typography": {
|
||||
"dropCap": false,
|
||||
"fontFamilies": [
|
||||
{
|
||||
"fontFamily": "\"Source Serif Pro\", serif",
|
||||
"name": "Source Serif Pro",
|
||||
"slug": "source-serif-pro",
|
||||
"fontFace": [
|
||||
{
|
||||
"fontFamily": "Source Serif Pro",
|
||||
"fontWeight": "200 900",
|
||||
"fontStyle": "normal",
|
||||
"fontStretch": "normal",
|
||||
"src": [ "file:./assets/fonts/SourceSerif4Variable-Roman.ttf.woff2" ]
|
||||
},
|
||||
{
|
||||
"fontFamily": "Source Serif Pro",
|
||||
"fontWeight": "200 900",
|
||||
"fontStyle": "italic",
|
||||
"fontStretch": "normal",
|
||||
"src": [ "file:./assets/fonts/SourceSerif4Variable-Italic.ttf.woff2" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"fontSizes": [
|
||||
{
|
||||
"size": "1rem",
|
||||
"slug": "small"
|
||||
},
|
||||
{
|
||||
"size": "1.125rem",
|
||||
"slug": "medium"
|
||||
},
|
||||
{
|
||||
"size": "1.75rem",
|
||||
"slug": "large"
|
||||
},
|
||||
{
|
||||
"size": "clamp(1.75rem, 3vw, 2.25rem)",
|
||||
"slug": "x-large"
|
||||
}
|
||||
]
|
||||
},
|
||||
"layout": {
|
||||
"contentSize": "650px",
|
||||
"wideSize": "1000px"
|
||||
}
|
||||
},
|
||||
"styles": {
|
||||
"blocks": {},
|
||||
"color": {
|
||||
"background": "var(--wp--preset--color--background)",
|
||||
"text": "var(--wp--preset--color--foreground)"
|
||||
},
|
||||
"elements": {},
|
||||
"spacing": {
|
||||
"blockGap": "1.5rem"
|
||||
},
|
||||
"typography": {
|
||||
"fontFamily": "var(--wp--preset--font-family--system-font)",
|
||||
"lineHeight": "var(--wp--custom--typography--line-height--normal)",
|
||||
"fontSize": "var(--wp--preset--font-size--medium)"
|
||||
}
|
||||
},
|
||||
"templateParts": [
|
||||
{
|
||||
"name": "header",
|
||||
"title": "Header",
|
||||
"area": "header"
|
||||
}
|
||||
]
|
||||
}
|
||||
122
tests/phpunit/tests/fonts/font-face/base.php
Normal file
122
tests/phpunit/tests/fonts/font-face/base.php
Normal file
@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
* Test case for the Fonts tests.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Fonts
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/wp-font-face-tests-dataset.php';
|
||||
/**
|
||||
* Abstracts the common tasks for the Font Face tests.
|
||||
*/
|
||||
abstract class WP_Font_Face_UnitTestCase extends WP_UnitTestCase {
|
||||
use WP_Font_Face_Tests_Datasets;
|
||||
|
||||
/**
|
||||
* Current error reporting level (before a test changes it).
|
||||
*
|
||||
* @var null|int
|
||||
*/
|
||||
protected $error_reporting_level = null;
|
||||
|
||||
/**
|
||||
* Reflection data store for non-public property access.
|
||||
*
|
||||
* @var ReflectionProperty[]
|
||||
*/
|
||||
protected $property = array();
|
||||
|
||||
/**
|
||||
* Indicates the test class uses `switch_theme()` and requires
|
||||
* set_up and tear_down fixtures to set and reset hooks and memory.
|
||||
*
|
||||
* If a test class switches themes, set this property to `true`.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected static $requires_switch_theme_fixtures = false;
|
||||
|
||||
/**
|
||||
* Theme root directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $theme_root;
|
||||
|
||||
/**
|
||||
* Original theme directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $orig_theme_dir;
|
||||
|
||||
/**
|
||||
* Administrator ID.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected static $administrator_id = 0;
|
||||
|
||||
public static function set_up_before_class() {
|
||||
parent::set_up_before_class();
|
||||
|
||||
if ( self::$requires_switch_theme_fixtures ) {
|
||||
self::$theme_root = realpath( DIR_TESTDATA . '/themedir1' );
|
||||
}
|
||||
}
|
||||
|
||||
public static function tear_down_after_class() {
|
||||
// Reset static flags.
|
||||
self::$requires_switch_theme_fixtures = false;
|
||||
|
||||
parent::tear_down_after_class();
|
||||
}
|
||||
|
||||
public function set_up() {
|
||||
parent::set_up();
|
||||
|
||||
if ( self::$requires_switch_theme_fixtures ) {
|
||||
$this->orig_theme_dir = $GLOBALS['wp_theme_directories'];
|
||||
|
||||
// /themes is necessary as theme.php functions assume /themes is the root if there is only one root.
|
||||
$GLOBALS['wp_theme_directories'] = array( WP_CONTENT_DIR . '/themes', self::$theme_root );
|
||||
|
||||
// Set up the new root.
|
||||
add_filter( 'theme_root', array( $this, 'filter_set_theme_root' ) );
|
||||
add_filter( 'stylesheet_root', array( $this, 'filter_set_theme_root' ) );
|
||||
add_filter( 'template_root', array( $this, 'filter_set_theme_root' ) );
|
||||
|
||||
// Clear caches.
|
||||
wp_clean_themes_cache();
|
||||
unset( $GLOBALS['wp_themes'] );
|
||||
}
|
||||
}
|
||||
|
||||
public function tear_down() {
|
||||
$this->property = array();
|
||||
|
||||
// Reset the error reporting when modified within a test.
|
||||
if ( is_int( $this->error_reporting_level ) ) {
|
||||
error_reporting( $this->error_reporting_level );
|
||||
$this->error_reporting_level = null;
|
||||
}
|
||||
|
||||
// Restore themes.
|
||||
if ( self::$requires_switch_theme_fixtures ) {
|
||||
$GLOBALS['wp_theme_directories'] = $this->orig_theme_dir;
|
||||
remove_filter( 'theme_root', array( $this, 'filter_set_theme_root' ) );
|
||||
remove_filter( 'stylesheet_root', array( $this, 'filter_set_theme_root' ) );
|
||||
remove_filter( 'template_root', array( $this, 'filter_set_theme_root' ) );
|
||||
wp_clean_themes_cache();
|
||||
wp_clean_theme_json_cache();
|
||||
unset( $GLOBALS['wp_themes'] );
|
||||
}
|
||||
|
||||
parent::tear_down();
|
||||
}
|
||||
|
||||
public function filter_set_theme_root() {
|
||||
return self::$theme_root;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,274 @@
|
||||
<?php
|
||||
/**
|
||||
* Datasets for unit and integration tests.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Fonts
|
||||
*/
|
||||
|
||||
/**
|
||||
* Trait for reusing datasets within the Fonts tests.
|
||||
*/
|
||||
trait WP_Font_Face_Tests_Datasets {
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data_should_print_given_fonts() {
|
||||
return array(
|
||||
'single truetype format font' => array(
|
||||
'fonts' => array(
|
||||
'Inter' =>
|
||||
array(
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/inter/Inter-VariableFont_slnt,wght.ttf',
|
||||
),
|
||||
'font-family' => 'Inter',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '200',
|
||||
),
|
||||
),
|
||||
),
|
||||
'expected' => <<<CSS
|
||||
@font-face{font-family:Inter;font-style:normal;font-weight:200;font-display:fallback;src:url('https://example.org/assets/fonts/inter/Inter-VariableFont_slnt,wght.ttf') format('truetype');font-stretch:normal;}
|
||||
CSS
|
||||
,
|
||||
),
|
||||
'multiple truetype format fonts' => array(
|
||||
'fonts' => array(
|
||||
'Inter' =>
|
||||
array(
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/inter/Inter-VariableFont_slnt,wght.ttf',
|
||||
),
|
||||
'font-family' => 'Inter',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '200',
|
||||
),
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/inter/Inter-VariableFont_slnt-Italic,wght.ttf',
|
||||
),
|
||||
'font-family' => 'Inter',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'italic',
|
||||
'font-weight' => '900',
|
||||
),
|
||||
),
|
||||
),
|
||||
'expected' => <<<CSS
|
||||
@font-face{font-family:Inter;font-style:normal;font-weight:200;font-display:fallback;src:url('https://example.org/assets/fonts/inter/Inter-VariableFont_slnt,wght.ttf') format('truetype');font-stretch:normal;}
|
||||
@font-face{font-family:Inter;font-style:italic;font-weight:900;font-display:fallback;src:url('https://example.org/assets/fonts/inter/Inter-VariableFont_slnt-Italic,wght.ttf') format('truetype');font-stretch:normal;}
|
||||
CSS
|
||||
,
|
||||
),
|
||||
'single woff2 format font' => array(
|
||||
'fonts' => array(
|
||||
'DM Sans' =>
|
||||
array(
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/dm-sans/DMSans-Regular.woff2',
|
||||
),
|
||||
'font-family' => 'DM Sans',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '400',
|
||||
),
|
||||
),
|
||||
),
|
||||
'expected' => <<<CSS
|
||||
@font-face{font-family:"DM Sans";font-style:normal;font-weight:400;font-display:fallback;src:url('https://example.org/assets/fonts/dm-sans/DMSans-Regular.woff2') format('woff2');font-stretch:normal;}
|
||||
CSS
|
||||
,
|
||||
),
|
||||
'multiple woff2 format fonts' => array(
|
||||
'fonts' => array(
|
||||
'DM Sans' =>
|
||||
array(
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/dm-sans/DMSans-Regular.woff2',
|
||||
),
|
||||
'font-family' => 'DM Sans',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '400',
|
||||
),
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/dm-sans/DMSans-Regular-Italic.woff2',
|
||||
),
|
||||
'font-family' => 'DM Sans',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'italic',
|
||||
'font-weight' => '400',
|
||||
),
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/dm-sans/DMSans-Bold.woff2',
|
||||
),
|
||||
'font-family' => 'DM Sans',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '700',
|
||||
),
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/dm-sans/DMSans-Bold-Italic.woff2',
|
||||
),
|
||||
'font-family' => 'DM Sans',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'italic',
|
||||
'font-weight' => '700',
|
||||
),
|
||||
),
|
||||
'IBM Plex Mono' =>
|
||||
array(
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/ibm-plex-mono/IBMPlexMono-Light.woff2',
|
||||
),
|
||||
'font-family' => 'IBM Plex Mono',
|
||||
'font-display' => 'block',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '300',
|
||||
),
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2',
|
||||
),
|
||||
'font-family' => 'IBM Plex Mono',
|
||||
'font-display' => 'block',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '400',
|
||||
),
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/ibm-plex-mono/IBMPlexMono-Italic.woff2',
|
||||
),
|
||||
'font-family' => 'IBM Plex Mono',
|
||||
'font-display' => 'block',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'italic',
|
||||
'font-weight' => '400',
|
||||
),
|
||||
array(
|
||||
'src' =>
|
||||
array(
|
||||
'https://example.org/assets/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2',
|
||||
),
|
||||
'font-family' => 'IBM Plex Mono',
|
||||
'font-display' => 'block',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '700',
|
||||
),
|
||||
),
|
||||
),
|
||||
'expected' => <<<CSS
|
||||
@font-face{font-family:"DM Sans";font-style:normal;font-weight:400;font-display:fallback;src:url('https://example.org/assets/fonts/dm-sans/DMSans-Regular.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"DM Sans";font-style:italic;font-weight:400;font-display:fallback;src:url('https://example.org/assets/fonts/dm-sans/DMSans-Regular-Italic.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"DM Sans";font-style:normal;font-weight:700;font-display:fallback;src:url('https://example.org/assets/fonts/dm-sans/DMSans-Bold.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"DM Sans";font-style:italic;font-weight:700;font-display:fallback;src:url('https://example.org/assets/fonts/dm-sans/DMSans-Bold-Italic.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:300;font-display:block;src:url('https://example.org/assets/fonts/ibm-plex-mono/IBMPlexMono-Light.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:400;font-display:block;src:url('https://example.org/assets/fonts/ibm-plex-mono/IBMPlexMono-Regular.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"IBM Plex Mono";font-style:italic;font-weight:400;font-display:block;src:url('https://example.org/assets/fonts/ibm-plex-mono/IBMPlexMono-Italic.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"IBM Plex Mono";font-style:normal;font-weight:700;font-display:block;src:url('https://example.org/assets/fonts/ibm-plex-mono/IBMPlexMono-Bold.woff2') format('woff2');font-stretch:normal;}
|
||||
CSS
|
||||
,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function get_expected_fonts_for_fonts_block_theme( $key = '' ) {
|
||||
static $data = null;
|
||||
|
||||
if ( null === $data ) {
|
||||
$uri = get_stylesheet_directory_uri() . '/assets/fonts/';
|
||||
$data = array(
|
||||
'fonts' => array(
|
||||
'DM Sans' => array(
|
||||
array(
|
||||
'src' => array( $uri . 'dm-sans/DMSans-Regular.woff2' ),
|
||||
'font-family' => 'DM Sans',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '400',
|
||||
),
|
||||
array(
|
||||
'src' => array( $uri . 'dm-sans/DMSans-Regular-Italic.woff2' ),
|
||||
'font-family' => 'DM Sans',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'italic',
|
||||
'font-weight' => '400',
|
||||
),
|
||||
array(
|
||||
'src' => array( $uri . 'dm-sans/DMSans-Bold.woff2' ),
|
||||
'font-family' => 'DM Sans',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '700',
|
||||
),
|
||||
array(
|
||||
'src' => array( $uri . 'dm-sans/DMSans-Bold-Italic.woff2' ),
|
||||
'font-family' => 'DM Sans',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'italic',
|
||||
'font-weight' => '700',
|
||||
),
|
||||
),
|
||||
'Source Serif Pro' => array(
|
||||
array(
|
||||
'src' => array( $uri . 'source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2' ),
|
||||
'font-family' => 'Source Serif Pro',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '200 900',
|
||||
),
|
||||
array(
|
||||
'src' => array( $uri . 'source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2' ),
|
||||
'font-family' => 'Source Serif Pro',
|
||||
'font-stretch' => 'normal',
|
||||
'font-style' => 'italic',
|
||||
'font-weight' => '200 900',
|
||||
),
|
||||
),
|
||||
),
|
||||
'font_face_styles' => <<<CSS
|
||||
@font-face{font-family:"DM Sans";font-style:normal;font-weight:400;font-display:fallback;src:url('{$uri}dm-sans/DMSans-Regular.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"DM Sans";font-style:italic;font-weight:400;font-display:fallback;src:url('{$uri}dm-sans/DMSans-Regular-Italic.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"DM Sans";font-style:normal;font-weight:700;font-display:fallback;src:url('{$uri}dm-sans/DMSans-Bold.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"DM Sans";font-style:italic;font-weight:700;font-display:fallback;src:url('{$uri}dm-sans/DMSans-Bold-Italic.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"Source Serif Pro";font-style:normal;font-weight:200 900;font-display:fallback;src:url('{$uri}source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2') format('woff2');font-stretch:normal;}
|
||||
@font-face{font-family:"Source Serif Pro";font-style:italic;font-weight:200 900;font-display:fallback;src:url('{$uri}source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2') format('woff2');font-stretch:normal;}
|
||||
CSS
|
||||
,
|
||||
);
|
||||
}
|
||||
|
||||
if ( isset( $data[ $key ] ) ) {
|
||||
return $data[ $key ];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* Test case for WP_Font_Face::generate_and_print().
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Fonts
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @group fonts
|
||||
* @group fontface
|
||||
*
|
||||
* @covers WP_Font_Face::generate_and_print
|
||||
*/
|
||||
class Tests_Fonts_WPFontFace_GenerateAndPrint extends WP_UnitTestCase {
|
||||
use WP_Font_Face_Tests_Datasets;
|
||||
|
||||
public function test_should_not_generate_and_print_when_no_fonts() {
|
||||
$font_face = new WP_Font_Face();
|
||||
$fonts = array();
|
||||
|
||||
$this->expectOutputString( '' );
|
||||
$font_face->generate_and_print( $fonts );
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_should_print_given_fonts
|
||||
*
|
||||
* @param array $fonts Prepared fonts.
|
||||
* @param string $expected Expected CSS.
|
||||
*/
|
||||
public function test_should_generate_and_print_given_fonts( array $fonts, $expected ) {
|
||||
$font_face = new WP_Font_Face();
|
||||
$style_element = "<style id='wp-fonts-local' type='text/css'>\n%s\n</style>\n";
|
||||
$expected_output = sprintf( $style_element, $expected );
|
||||
|
||||
$this->expectOutputString( $expected_output );
|
||||
$font_face->generate_and_print( $fonts );
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* Test case for WP_Font_Face_Resolver::get_fonts_from_theme_json().
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Fonts
|
||||
*
|
||||
* @since 6.4.0
|
||||
*
|
||||
* @group fonts
|
||||
* @group fontface
|
||||
*
|
||||
* @covers WP_Font_Face_Resolver::get_fonts_from_theme_json
|
||||
*/
|
||||
class Tests_Fonts_WPFontFaceResolver_GetFontsFromThemeJson extends WP_Font_Face_UnitTestCase {
|
||||
const FONTS_THEME = 'fonts-block-theme';
|
||||
|
||||
public static function set_up_before_class() {
|
||||
self::$requires_switch_theme_fixtures = true;
|
||||
|
||||
parent::set_up_before_class();
|
||||
}
|
||||
|
||||
public function test_should_return_empty_array_when_no_fonts_defined_in_theme() {
|
||||
switch_theme( 'block-theme' );
|
||||
|
||||
$fonts = WP_Font_Face_Resolver::get_fonts_from_theme_json();
|
||||
$this->assertIsArray( $fonts, 'Should return an array data type' );
|
||||
$this->assertEmpty( $fonts, 'Should return an empty array' );
|
||||
}
|
||||
|
||||
public function test_should_return_all_fonts_from_theme() {
|
||||
switch_theme( static::FONTS_THEME );
|
||||
|
||||
$actual = WP_Font_Face_Resolver::get_fonts_from_theme_json();
|
||||
$expected = $this->get_expected_fonts_for_fonts_block_theme( 'fonts' );
|
||||
$this->assertSame( $expected, $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_should_replace_src_file_placeholder
|
||||
*
|
||||
* @param string $font_name Font's name.
|
||||
* @param string $font_index Font's index in the $fonts array.
|
||||
* @param string $expected Expected src.
|
||||
*/
|
||||
public function test_should_replace_src_file_placeholder( $font_name, $font_index, $expected ) {
|
||||
switch_theme( static::FONTS_THEME );
|
||||
|
||||
$fonts = WP_Font_Face_Resolver::get_fonts_from_theme_json();
|
||||
|
||||
$actual = $fonts[ $font_name ][ $font_index ]['src'][0];
|
||||
$expected = get_stylesheet_directory_uri() . $expected;
|
||||
|
||||
$this->assertStringNotContainsString( 'file:./', $actual, 'Font src should not contain the "file:./" placeholder' );
|
||||
$this->assertSame( $expected, $actual, 'Font src should be an URL to its file' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data_should_replace_src_file_placeholder() {
|
||||
return array(
|
||||
// Theme's theme.json.
|
||||
'DM Sans: 400 normal' => array(
|
||||
'font_name' => 'DM Sans',
|
||||
'font_index' => 0,
|
||||
'expected' => '/assets/fonts/dm-sans/DMSans-Regular.woff2',
|
||||
),
|
||||
'DM Sans: 400 italic' => array(
|
||||
'font_name' => 'DM Sans',
|
||||
'font_index' => 1,
|
||||
'expected' => '/assets/fonts/dm-sans/DMSans-Regular-Italic.woff2',
|
||||
),
|
||||
'DM Sans: 700 normal' => array(
|
||||
'font_name' => 'DM Sans',
|
||||
'font_index' => 2,
|
||||
'expected' => '/assets/fonts/dm-sans/DMSans-Bold.woff2',
|
||||
),
|
||||
'DM Sans: 700 italic' => array(
|
||||
'font_name' => 'DM Sans',
|
||||
'font_index' => 3,
|
||||
'expected' => '/assets/fonts/dm-sans/DMSans-Bold-Italic.woff2',
|
||||
),
|
||||
'Source Serif Pro: 200-900 normal' => array(
|
||||
'font_name' => 'Source Serif Pro',
|
||||
'font_index' => 0,
|
||||
'expected' => '/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2',
|
||||
),
|
||||
'Source Serif Pro: 200-900 italic' => array(
|
||||
'font_name' => 'Source Serif Pro',
|
||||
'font_index' => 1,
|
||||
'expected' => '/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
88
tests/phpunit/tests/fonts/font-face/wpPrintFontFaces.php
Normal file
88
tests/phpunit/tests/fonts/font-face/wpPrintFontFaces.php
Normal file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* Test case for wp_print_font_faces().
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage Fonts
|
||||
*
|
||||
* @since 6.4.0
|
||||
*/
|
||||
require_once __DIR__ . '/base.php';
|
||||
|
||||
/**
|
||||
* @group fonts
|
||||
* @group fontface
|
||||
*
|
||||
* @covers wp_print_font_faces
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
*/
|
||||
class Tests_Fonts_WpPrintFontFaces extends WP_Font_Face_UnitTestCase {
|
||||
const FONTS_THEME = 'fonts-block-theme';
|
||||
|
||||
public static function set_up_before_class() {
|
||||
self::$requires_switch_theme_fixtures = true;
|
||||
|
||||
parent::set_up_before_class();
|
||||
}
|
||||
|
||||
public function test_should_not_print_when_no_fonts() {
|
||||
switch_theme( 'block-theme' );
|
||||
|
||||
$this->expectOutputString( '' );
|
||||
wp_print_font_faces();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_should_print_given_fonts
|
||||
*
|
||||
* @param array $fonts Fonts to process.
|
||||
* @param string $expected Expected CSS.
|
||||
*/
|
||||
public function test_should_print_given_fonts( array $fonts, $expected ) {
|
||||
$expected_output = $this->get_expected_styles_output( $expected );
|
||||
|
||||
$this->expectOutputString( $expected_output );
|
||||
wp_print_font_faces( $fonts );
|
||||
}
|
||||
|
||||
public function test_should_escape_tags() {
|
||||
$fonts = array(
|
||||
'Source Serif Pro' => array(
|
||||
array(
|
||||
'src' => array( 'http://example.com/assets/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2' ),
|
||||
'font-family' => 'Source Serif Pro',
|
||||
'font-style' => 'normal',
|
||||
'font-weight' => '200 900',
|
||||
'font-stretch' => '</style><script>console.log("Hello")</script><style>',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$expected_output = <<<CSS
|
||||
<style id='wp-fonts-local' type='text/css'>
|
||||
@font-face{font-family:"Source Serif Pro";font-style:normal;font-weight:200 900;font-display:fallback;src:url('http://example.com/assets/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2') format('woff2');font-stretch:;}
|
||||
</style>
|
||||
|
||||
CSS;
|
||||
$this->expectOutputString( $expected_output );
|
||||
|
||||
wp_print_font_faces( $fonts );
|
||||
}
|
||||
|
||||
public function test_should_print_fonts_in_merged_data() {
|
||||
switch_theme( static::FONTS_THEME );
|
||||
|
||||
$expected = $this->get_expected_fonts_for_fonts_block_theme( 'font_face_styles' );
|
||||
$expected_output = $this->get_expected_styles_output( $expected );
|
||||
|
||||
$this->expectOutputString( $expected_output );
|
||||
wp_print_font_faces();
|
||||
}
|
||||
|
||||
private function get_expected_styles_output( $styles ) {
|
||||
$style_element = "<style id='wp-fonts-local' type='text/css'>\n%s\n</style>\n";
|
||||
return sprintf( $style_element, $styles );
|
||||
}
|
||||
}
|
||||
@ -185,7 +185,7 @@ class Tests_Theme_ThemeDir extends WP_UnitTestCase {
|
||||
'Block Theme [0.4.0]',
|
||||
'Block Theme [1.0.0] in subdirectory',
|
||||
'Block Theme Deprecated Path',
|
||||
'Webfonts theme',
|
||||
'Block Theme with defined Typography Fonts',
|
||||
'Empty `fontFace` in theme.json - no webfonts defined',
|
||||
'A theme with the Update URI header',
|
||||
);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user