Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webfonts API #37140

Merged
merged 35 commits into from
Feb 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
325d4d2
rebase - combining 46 commits to 1 and resolving lots of conflicts
aristath Jan 24, 2022
c513718
Revert changes to resolver class
oandregal Feb 8, 2022
c335778
Override the parts we need
oandregal Feb 8, 2022
f9cc7d2
Rename file for a better description
oandregal Feb 8, 2022
32193e4
Add webfonts to the parent theme
aristath Feb 9, 2022
bfe756b
indentation fix
aristath Feb 9, 2022
699ab2f
Update Global Styles endpoint to use Gutenberg callback and theme jso…
creativecoder Feb 9, 2022
c8144fd
rebase - combining 46 commits to 1 and resolving lots of conflicts
aristath Jan 24, 2022
a51d2af
Add missing textdomain
aristath Feb 10, 2022
2e56ef5
add missing inline docs
aristath Feb 10, 2022
42fd092
inline doc (copy from 5.9 class)
aristath Feb 10, 2022
6fe2971
Remove extra blank line
aristath Feb 10, 2022
fc44a08
Remove non-applicable docs
aristath Feb 10, 2022
ddb51ce
This already exists in the parent
aristath Feb 10, 2022
524d8af
add full item
aristath Feb 15, 2022
32770bc
add missing global styles
aristath Feb 15, 2022
151effe
remove multiples
aristath Feb 15, 2022
bbd3d27
update test
aristath Feb 15, 2022
938771d
remove extra comma
aristath Feb 15, 2022
5aa2217
Missed this in previous commit
aristath Feb 15, 2022
0112e50
Remove old docs (no longer applicable)
aristath Feb 17, 2022
51bcf85
doc
aristath Feb 18, 2022
38d9cb3
revert 5.9 changes
aristath Feb 18, 2022
33bcfd6
get_merged_data no longer needs to be overriden
aristath Feb 18, 2022
9d3dd5d
use static instead of self
aristath Feb 18, 2022
447daac
simplify
aristath Feb 18, 2022
8a6dec7
add an explanation for when porting to wp-core
aristath Feb 18, 2022
f6e58dd
Revert adding fonts to the webfonts stylesheet
oandregal Feb 21, 2022
19248d2
Update test
oandregal Feb 21, 2022
af8eb3d
explain why we skip the provider
aristath Feb 28, 2022
5ed7aa1
Move webfonts-API files to the compat/wordpress-6.0 folder
aristath Feb 28, 2022
0376a3e
Remove out-of-date comment
aristath Feb 28, 2022
2f865fc
Trigger a notice when an unregistered provider is used.
aristath Feb 28, 2022
8b63574
use error_log instead of trigger_error
aristath Feb 28, 2022
88f86de
typo
aristath Feb 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*
* @access private
*/
class WP_Theme_JSON_Resolver_Gutenberg {
class WP_Theme_JSON_Resolver_5_9 {

/**
* Container for data coming from core.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php
/**
* WP_Theme_JSON_Resolver_Gutenberg class
*
* @package gutenberg
*/

/**
* Class that abstracts the processing of the different data sources
* for site-level config and offers an API to work with them.
*
* This class is for internal core usage and is not supposed to be used by extenders (plugins and/or themes).
* This is a low-level API that may need to do breaking changes. Please,
* use get_global_settings, get_global_styles, and get_global_stylesheet instead.
*
* @access private
*/
class WP_Theme_JSON_Resolver_Gutenberg extends WP_Theme_JSON_Resolver_5_9 {
aristath marked this conversation as resolved.
Show resolved Hide resolved

/**
* Returns the theme's data.
*
* Data from theme.json will be backfilled from existing
* theme supports, if any. Note that if the same data
* is present in theme.json and in theme supports,
* the theme.json takes precedence.
*
* @param array $deprecated Deprecated argument.
* @return WP_Theme_JSON_Gutenberg Entity that holds theme data.
*/
public static function get_theme_data( $deprecated = array() ) {
if ( ! empty( $deprecated ) ) {
_deprecated_argument( __METHOD__, '5.9' );
}
if ( null === static::$theme ) {
$theme_json_data = static::read_json_file( static::get_file_path_from_theme( 'theme.json' ) );
$theme_json_data = static::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) );
$theme_json_data = gutenberg_add_registered_webfonts_to_theme_json( $theme_json_data );
aristath marked this conversation as resolved.
Show resolved Hide resolved
static::$theme = new WP_Theme_JSON_Gutenberg( $theme_json_data );

if ( wp_get_theme()->parent() ) {
// Get parent theme.json.
$parent_theme_json_data = static::read_json_file( static::get_file_path_from_theme( 'theme.json', true ) );
$parent_theme_json_data = static::translate( $parent_theme_json_data, wp_get_theme()->parent()->get( 'TextDomain' ) );
$parent_theme_json_data = gutenberg_add_registered_webfonts_to_theme_json( $parent_theme_json_data );
$parent_theme = new WP_Theme_JSON_Gutenberg( $parent_theme_json_data );

// Merge the child theme.json into the parent theme.json.
// The child theme takes precedence over the parent.
$parent_theme->merge( static::$theme );
static::$theme = $parent_theme;
}
}

/*
* We want the presets and settings declared in theme.json
* to override the ones declared via theme supports.
* So we take theme supports, transform it to theme.json shape
* and merge the static::$theme upon that.
*/
$theme_support_data = WP_Theme_JSON_Gutenberg::get_from_editor_settings( get_default_block_editor_settings() );
if ( ! static::theme_has_support() ) {
if ( ! isset( $theme_support_data['settings']['color'] ) ) {
$theme_support_data['settings']['color'] = array();
}

$default_palette = false;
if ( current_theme_supports( 'default-color-palette' ) ) {
$default_palette = true;
}
if ( ! isset( $theme_support_data['settings']['color']['palette'] ) ) {
// If the theme does not have any palette, we still want to show the core one.
$default_palette = true;
}
$theme_support_data['settings']['color']['defaultPalette'] = $default_palette;

$default_gradients = false;
if ( current_theme_supports( 'default-gradient-presets' ) ) {
$default_gradients = true;
}
if ( ! isset( $theme_support_data['settings']['color']['gradients'] ) ) {
// If the theme does not have any gradients, we still want to show the core ones.
$default_gradients = true;
}
$theme_support_data['settings']['color']['defaultGradients'] = $default_gradients;
}
$with_theme_supports = new WP_Theme_JSON_Gutenberg( $theme_support_data );
$with_theme_supports->merge( static::$theme );

return $with_theme_supports;
}
}
259 changes: 259 additions & 0 deletions lib/compat/wordpress-6.0/class-wp-webfonts-provider-local.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
<?php
/**
* Webfonts API: Provider for locally-hosted fonts.
*
* @package WordPress
* @subpackage WebFonts
* @since 6.0.0
*/

/**
* A core bundled provider for generating `@font-face` styles
* from locally-hosted font files.
*
* This provider builds an optimized `src` (for browser support)
* and then generates the `@font-face` styles.
*
* All know-how (business logic) for how to interact with and
* generate styles from locally-hosted font files is contained
* in this provider.
*
* @since 6.0.0
*/
class WP_Webfonts_Provider_Local extends WP_Webfonts_Provider {

/**
* The provider's unique ID.
*
* @since 6.0.0
*
* @var string
*/
protected $id = 'local';

/**
* 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 webfonts.
*
* For example, when given these webfonts:
* <code>
* array(
* 'source-serif-pro.normal.200 900' => array(
* 'provider' => 'local',
* 'font_family' => 'Source Serif Pro',
* 'font_weight' => '200 900',
* 'font_style' => 'normal',
* 'src' => 'https://example.com/wp-content/themes/twentytwentytwo/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2' ),
* ),
* 'source-serif-pro.italic.400 900' => array(
* 'provider' => 'local',
* 'font_family' => 'Source Serif Pro',
* 'font_weight' => '200 900',
* 'font_style' => 'italic',
* 'src' => 'https://example.com/wp-content/themes/twentytwentytwo/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2' ),
* ),
* )
* </code>
*
* the following `@font-face` styles are generated and returned:
* <code>
*
* @font-face{
* font-family:"Source Serif Pro";
* font-style:normal;
* font-weight:200 900;
* font-stretch:normal;
* src:local("Source Serif Pro"), url('/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2') format('woff2');
* }
* @font-face{
* font-family:"Source Serif Pro";
* font-style:italic;
* font-weight:200 900;
* font-stretch:normal;
* src:local("Source Serif Pro"), url('/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2') format('woff2');
* }
* </code>
*
* @since 6.0.0
*
* @return string The `@font-face` CSS.
*/
public function get_css() {
$css = '';

foreach ( $this->webfonts as $webfont ) {
// Order the webfont's `src` items to optimize for browser support.
$webfont = $this->order_src( $webfont );

// Build the @font-face CSS for this webfont.
$css .= '@font-face{' . $this->build_font_face_css( $webfont ) . '}';
}

return $css;
}

/**
* Order `src` items to optimize for browser support.
*
* @since 6.0.0
*
* @param array $webfont Webfont to process.
* @return array
*/
private function order_src( array $webfont ) {
if ( ! is_array( $webfont['src'] ) ) {
$webfont['src'] = (array) $webfont['src'];
}

$src = array();
$src_ordered = array();

foreach ( $webfont['src'] as $url ) {
// Add data URIs first.
if ( 0 === strpos( 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',
);
}
$webfont['src'] = $src_ordered;

return $webfont;
}

/**
* Builds the font-family's CSS.
*
* @since 6.0.0
*
* @param array $webfont Webfont to process.
* @return string This font-family's CSS.
*/
private function build_font_face_css( array $webfont ) {
$css = '';

// Wrap font-family in quotes if it contains spaces.
if (
false !== strpos( $webfont['font-family'], ' ' ) &&
false === strpos( $webfont['font-family'], '"' ) &&
false === strpos( $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 = $this->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 = $this->compile_variations( $value );
}

if ( ! empty( $value ) ) {
$css .= "$key:$value;";
}
}

return $css;
}

/**
* 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.
*/
private function compile_src( $font_family, array $value ) {
$src = "local($font_family)";

foreach ( $value as $item ) {

if ( 0 === strpos( $item['url'], get_site_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.
*/
private function compile_variations( array $font_variation_settings ) {
$variations = '';

foreach ( $font_variation_settings as $key => $value ) {
$variations .= "$key $value";
}

return $variations;
}
}
Loading