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

Font Face: Adds a GB specific resolver to capture changes not yet in Core #54990

Open
wants to merge 2 commits into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
@@ -0,0 +1,177 @@
<?php
/**
* Gutenberg_Font_Face_Resolver_6_4 class.
*
* @package Gutenberg
* @subpackage Fonts
*/

/**
* 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 Gutenberg_Font_Face_Resolver_6_4 {

/**
* 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 = gutenberg_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 "fontFace" is not defined, meaning there are no variations.
if ( empty( $definition['fontFace'] ) ) {
continue;
}

// Skip if "fontFamily" is not defined.
if ( empty( $definition['fontFamily'] ) ) {
continue;
}

$font_family_name = static::maybe_parse_name_from_comma_separated_list( $definition['fontFamily'] );

// Skip if no font family is defined.
if ( empty( $font_family_name ) ) {
continue;
}

// Prepare the fonts array structure for this font-family.
if ( ! array_key_exists( $font_family_name, $fonts ) ) {
$fonts[ $font_family_name ] = array();
}

$fonts[ $font_family_name ] = static::convert_font_face_properties( $definition['fontFace'], $font_family_name );
}
}

return $fonts;
}

/**
* Parse font-family name from comma-separated lists.
*
* If the given `fontFamily` is a comma-separated lists (example: "Inter, sans-serif" ),
* parse and return the fist font from the list.
*
* @since 6.4.0
*
* @param string $font_family Font family `fontFamily' to parse.
* @return string Font-family name.
*/
private static function maybe_parse_name_from_comma_separated_list( $font_family ) {
if ( str_contains( $font_family, ',' ) ) {
$font_family = explode( ',', $font_family )[0];
}

return trim( $font_family, "\"'" );
}

/**
* 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public static function get_fonts_from_theme_json() {
* @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 ) {
protected static function parse_settings( array $settings ) {
$fonts = array();

foreach ( $settings['typography']['fontFamilies'] as $font_families ) {
Expand Down
25 changes: 25 additions & 0 deletions lib/compat/wordpress-6.4/fonts/fonts.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,31 @@ function wp_print_font_faces( $fonts = array() ) {
$wp_font_face = new WP_Font_Face();
$wp_font_face->generate_and_print( $fonts );
}
} else {
// @core-merge: do not merge this code into Core.

// Remove Core's hooked callback to replace with the plugin's callback.
remove_action( 'wp_head', 'wp_print_font_faces', 50 );
remove_action( 'admin_print_styles', 'wp_print_font_faces', 50 );
add_action( 'wp_head', '_gutenberg_print_font_faces', 50 );
add_action( 'admin_print_styles', '_gutenberg_print_font_faces', 50 );

/**
* Generates and prints font-face styles for given fonts or theme.json fonts.
*
* @access private
*/
function _gutenberg_print_font_faces() {
// Uses the plugin's resolver, i.e. that includes changes not yet merged
// that may not yet be merged into WP Core.
$fonts = Gutenberg_Font_Face_Resolver_6_4::get_fonts_from_theme_json();

if ( empty( $fonts ) ) {
return;
}

wp_print_font_faces( $fonts );
}
}

// @core-merge: do not merge this code into Core.
Expand Down
1 change: 1 addition & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/compat/wordpress-6.4/fonts/font-face/class-wp-font-face.php';
require __DIR__ . '/compat/wordpress-6.4/fonts/font-face/class-wp-font-face-resolver.php';
}
require __DIR__ . '/compat/wordpress-6.4/fonts/font-face/class-gutenberg-font-face-resolver-6-4.php';

/*
* As _gutenberg_get_iframed_editor_assets_6_4() overrides Core's _wp_get_iframed_editor_assets(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ public static function 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();
$fonts = Gutenberg_Font_Face_Resolver_6_4::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();
$actual = Gutenberg_Font_Face_Resolver_6_4::get_fonts_from_theme_json();
$expected = $this->get_expected_fonts_for_fonts_block_theme( 'fonts' );
$this->assertSame( $expected, $actual );
}
Expand All @@ -52,7 +52,7 @@ public function test_should_return_all_fonts_from_theme() {
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();
$fonts = Gutenberg_Font_Face_Resolver_6_4::get_fonts_from_theme_json();

$actual = $fonts[ $font_name ][ $font_index ]['src'][0];
$expected = get_stylesheet_directory_uri() . $expected;
Expand Down