mirror of
https://github.com/gosticks/wordpress-develop.git
synced 2025-10-16 12:05:38 +00:00
Themes: Add internal-only theme.json's webfonts handler (stopgap).
Adds `_wp_theme_json_webfonts_handler()` for handling `fontFace` declarations in a theme's `theme.json` file to generate the `@font-face` styles for both the editor and front-end. Design notes: * It is not a public API, but rather an internal, Core-only handler. * It is a stopgap implementation that will be replaced when the public Webfonts API is introduced in Core. * The code design is intentional, albeit funky, with the purpose of avoiding backwards-compatibility issues when the public Webfonts API is introduced in Core. * It hides the inter-workings. * Does not exposing API ins and outs for external consumption. * Only works for `theme.json`. * Does not provide registration or enqueuing access for plugins. For more context on the decision to include this stopgap and the Webfonts API, see: * Core's PR 40493 https://github.com/WordPress/gutenberg/pull/40493 * Gutenberg's tracking issue 40472 https://github.com/WordPress/gutenberg/issues/40472 Props aristath, hellofromTonya, peterwilsoncc, costdev, jffng, zieladam, gziolo, bph, jonoaldersonwp, desrosj. See #55567, #46370. git-svn-id: https://develop.svn.wordpress.org/trunk@53282 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
60cb20c4cc
commit
02414638ce
@ -351,6 +351,7 @@ add_action( 'start_previewing_theme', array( 'WP_Theme_JSON_Resolver', 'clean_ca
|
||||
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' );
|
||||
|
||||
@ -3027,3 +3027,499 @@ function wp_enqueue_block_style( $block_name, $args ) {
|
||||
// Enqueue assets in the editor.
|
||||
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() {
|
||||
// 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.', 'gutenberg' ) );
|
||||
|
||||
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.', 'gutenberg' ) );
|
||||
|
||||
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.', 'gutenberg' ) );
|
||||
|
||||
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.', 'gutenberg' ) );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the font-display.
|
||||
if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', '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
|
||||
*
|
||||
* @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 = "local($font_family)";
|
||||
|
||||
foreach ( $value as $item ) {
|
||||
|
||||
if (
|
||||
str_starts_with( $item['url'], site_url() ) ||
|
||||
str_starts_with( $item['url'], home_url() )
|
||||
) {
|
||||
$item['url'] = wp_make_link_relative( $item['url'] );
|
||||
}
|
||||
|
||||
$src .= ( 'data' === $item['format'] )
|
||||
? ", url({$item['url']})"
|
||||
: ", url('{$item['url']}') format('{$item['format']}')";
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
@ -0,0 +1 @@
|
||||
<?php
|
||||
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Block theme.
|
||||
*/
|
||||
@ -0,0 +1,7 @@
|
||||
/*
|
||||
Theme Name: Empty `fontFace` in theme.json - no webfonts defined
|
||||
Theme URI: https://wordpress.org/
|
||||
Description: For testing purposes only.
|
||||
Version: 1.0.0
|
||||
Text Domain: empty-fontface-theme
|
||||
*/
|
||||
@ -0,0 +1,3 @@
|
||||
<!-- wp:paragraph -->
|
||||
<p>Index Template</p>
|
||||
<!-- /wp:paragraph -->
|
||||
88
tests/phpunit/data/themedir1/empty-fontface-theme/theme.json
Normal file
88
tests/phpunit/data/themedir1/empty-fontface-theme/theme.json
Normal file
@ -0,0 +1,88 @@
|
||||
{
|
||||
"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": "Roboto",
|
||||
"name": "Roboto",
|
||||
"slug": "roboto",
|
||||
"fontFace": []
|
||||
}
|
||||
],
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
<?php
|
||||
4
tests/phpunit/data/themedir1/webfonts-theme/index.php
Normal file
4
tests/phpunit/data/themedir1/webfonts-theme/index.php
Normal file
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Block theme.
|
||||
*/
|
||||
7
tests/phpunit/data/themedir1/webfonts-theme/style.css
Normal file
7
tests/phpunit/data/themedir1/webfonts-theme/style.css
Normal file
@ -0,0 +1,7 @@
|
||||
/*
|
||||
Theme Name: Webfonts theme
|
||||
Theme URI: https://wordpress.org/
|
||||
Description: For testing purposes only.
|
||||
Version: 1.0.0
|
||||
Text Domain: webfonts-theme
|
||||
*/
|
||||
@ -0,0 +1,3 @@
|
||||
<!-- wp:paragraph -->
|
||||
<p>Index Template</p>
|
||||
<!-- /wp:paragraph -->
|
||||
103
tests/phpunit/data/themedir1/webfonts-theme/theme.json
Normal file
103
tests/phpunit/data/themedir1/webfonts-theme/theme.json
Normal file
@ -0,0 +1,103 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -165,6 +165,8 @@ class Tests_Theme_ThemeDir extends WP_UnitTestCase {
|
||||
'Block Theme Child Theme',
|
||||
'Block Theme [0.4.0]',
|
||||
'Block Theme [1.0.0] in subdirectory',
|
||||
'Webfonts theme',
|
||||
'Empty `fontFace` in theme.json - no webfonts defined',
|
||||
);
|
||||
|
||||
sort( $theme_names );
|
||||
|
||||
135
tests/phpunit/tests/webfonts/wpThemeJsonWebfontsHandler.php
Normal file
135
tests/phpunit/tests/webfonts/wpThemeJsonWebfontsHandler.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* Enqueue only webfonts listed in theme.json
|
||||
*
|
||||
* @package WordPress
|
||||
*/
|
||||
|
||||
/**
|
||||
* Integration tests for the theme.json webfonts handler.
|
||||
*
|
||||
* @group webfonts
|
||||
* @group themes
|
||||
* @covers _wp_theme_json_webfonts_handler
|
||||
*/
|
||||
class Test_WebfontsApi_WpThemeJsonWebfontsHandler extends WP_UnitTestCase {
|
||||
|
||||
/**
|
||||
* WP_Styles instance reference
|
||||
*
|
||||
* @var WP_Styles
|
||||
*/
|
||||
private $orig_wp_styles;
|
||||
|
||||
/**
|
||||
* Theme root path.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $theme_root;
|
||||
|
||||
/**
|
||||
* The old theme root path.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $orig_theme_dir;
|
||||
|
||||
public function set_up() {
|
||||
parent::set_up();
|
||||
|
||||
global $wp_styles;
|
||||
$this->orig_wp_styles = $wp_styles;
|
||||
$wp_styles = null;
|
||||
|
||||
$this->theme_root = realpath( DIR_TESTDATA . '/themedir1' );
|
||||
$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', $this->theme_root );
|
||||
|
||||
$theme_root_callback = function () {
|
||||
return $this->theme_root;
|
||||
};
|
||||
|
||||
add_filter( 'theme_root', $theme_root_callback );
|
||||
add_filter( 'stylesheet_root', $theme_root_callback );
|
||||
add_filter( 'template_root', $theme_root_callback );
|
||||
|
||||
// Clear caches.
|
||||
wp_clean_themes_cache();
|
||||
unset( $GLOBALS['wp_themes'] );
|
||||
}
|
||||
|
||||
public function tear_down() {
|
||||
global $wp_styles;
|
||||
$wp_styles = $this->orig_wp_styles;
|
||||
|
||||
// Restore the original theme directory setup.
|
||||
$GLOBALS['wp_theme_directories'] = $this->orig_theme_dir;
|
||||
wp_clean_themes_cache();
|
||||
unset( $GLOBALS['wp_themes'] );
|
||||
|
||||
parent::tear_down();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 55567
|
||||
* @ticket 46370
|
||||
*/
|
||||
public function test_font_face_generated_from_themejson() {
|
||||
$this->setup_theme_and_test( 'webfonts-theme' );
|
||||
|
||||
$expected = <<<EOF
|
||||
<style id='wp-webfonts-inline-css' type='text/css'>
|
||||
@font-face{font-family:"Source Serif Pro";font-style:normal;font-weight:200 900;font-display:fallback;src:local("Source Serif Pro"), url('THEME_ROOT_URL/assets/fonts/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:local("Source Serif Pro"), url('THEME_ROOT_URL/assets/fonts/SourceSerif4Variable-Italic.ttf.woff2') format('woff2');font-stretch:normal;}
|
||||
</style>
|
||||
EOF;
|
||||
$expected = str_replace( 'THEME_ROOT_URL', get_stylesheet_directory_uri(), $expected );
|
||||
|
||||
$this->assertStringContainsString(
|
||||
$expected,
|
||||
get_echo( 'wp_print_styles' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_font_face_not_generated
|
||||
*
|
||||
* @ticket 55567
|
||||
* @ticket 46370
|
||||
*/
|
||||
public function test_font_face_not_generated( $theme_name ) {
|
||||
$this->setup_theme_and_test( $theme_name );
|
||||
|
||||
$actual = get_echo( 'wp_print_styles' );
|
||||
$this->assertStringNotContainsString( "<style id='wp-webfonts-inline-css", $actual );
|
||||
$this->assertStringNotContainsString( '@font-face', $actual );
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for unhappy paths.
|
||||
*
|
||||
* @return string[][]
|
||||
*/
|
||||
public function data_font_face_not_generated() {
|
||||
return array(
|
||||
'classic theme with no theme.json' => array( 'default' ),
|
||||
'no "fontFace" in theme.json' => array( 'block-theme' ),
|
||||
'empty "fontFace" in theme.json' => array( 'empty-fontface-theme' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the theme and test.
|
||||
*
|
||||
* @param string $theme_name Name of the theme to switch to for the test.
|
||||
*/
|
||||
private function setup_theme_and_test( $theme_name ) {
|
||||
switch_theme( $theme_name );
|
||||
do_action( 'after_setup_theme' );
|
||||
WP_Theme_JSON_Resolver::clean_cached_data();
|
||||
do_action( 'wp_loaded' );
|
||||
do_action( 'wp_enqueue_scripts' );
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user