From 6dddb53ceef843d6ddd504faef7666564486049e Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini Date: Mon, 4 Apr 2022 12:25:19 -0500 Subject: [PATCH 01/37] Register webfonts declared in theme.json --- ...class-wp-theme-json-resolver-gutenberg.php | 9 +- .../register-webfonts-from-theme-json.php | 123 +++++++++++------- 2 files changed, 86 insertions(+), 46 deletions(-) diff --git a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php index 960ea659e8d2ee..587e61dc32f381 100644 --- a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php @@ -36,6 +36,10 @@ public static function get_theme_data( $deprecated = array(), $settings = array( 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' ) ); + + $original_theme_json = new WP_Theme_JSON_Gutenberg( $theme_json_data ); + gutenberg_register_webfonts_from_theme_json( $original_theme_json->get_settings() ); + $theme_json_data = gutenberg_add_registered_webfonts_to_theme_json( $theme_json_data ); static::$theme = new WP_Theme_JSON_Gutenberg( $theme_json_data ); @@ -43,8 +47,9 @@ public static function get_theme_data( $deprecated = array(), $settings = array( // 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 ); + + $parent_theme = new WP_Theme_JSON_Gutenberg( $parent_theme_json_data ); + gutenberg_register_webfonts_from_theme_json( $parent_theme->get_settings() ); // Merge the child theme.json into the parent theme.json. // The child theme takes precedence over the parent. diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 071d88e325bc81..d382f45236cabc 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -6,12 +6,54 @@ */ /** - * Register webfonts defined in theme.json. + * Transforms the keys of the webfont defined in theme.json into + * kebab case, so the Webfonts API can handle it. + * + * @param array $webfont The webfont to be tranformed. + * + * @return array The kebab-case version of the webfont. */ -function gutenberg_register_webfonts_from_theme_json() { - // Get settings. - $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings(); +function gutenberg_webfont_to_kebab_case( $webfont ) { + $kebab_cased_webfont = array(); + + foreach ( $webfont as $key => $value ) { + $kebab_cased_webfont[ _wp_to_kebab_case( $key ) ] = $value; + } + + return $kebab_cased_webfont; +} +/** + * Transforms the source of the font face from `file.:/` into an actual URI. + * + * @param array $font_face The font face. + * + * @return array The URI-resolved font face. + */ +function gutenberg_resolve_font_face_uri( $font_face ) { + if ( empty( $font_face['src'] ) ) { + return $font_face; + } + + $font_face['src'] = (array) $font_face['src']; + + foreach ( $font_face['src'] as $src_key => $url ) { + // Tweak the URL to be relative to the theme root. + if ( ! str_starts_with( $url, 'file:./' ) ) { + continue; + } + $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) ); + } + + return $font_face; +} + +/** + * Register webfonts defined in theme.json + * + * @param array $settings The theme.json file. + */ +function gutenberg_register_webfonts_from_theme_json( $settings ) { // If in the editor, add webfonts defined in variations. if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { $variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations(); @@ -43,55 +85,50 @@ function gutenberg_register_webfonts_from_theme_json() { return; } - $webfonts = array(); - - // Look for fontFamilies. - foreach ( $settings['typography']['fontFamilies'] as $font_families ) { - foreach ( $font_families as $font_family ) { + $font_faces_to_register = array(); - // Skip if fontFace is not defined. - if ( empty( $font_family['fontFace'] ) ) { - continue; - } + foreach ( $settings['typography']['fontFamilies'] as $font_families_by_origin ) { + foreach ( $font_families_by_origin as $font_family ) { + if ( isset( $font_family['provider'] ) ) { + if ( empty( $font_family['fontFaces'] ) ) { + trigger_error( + sprintf( + /* translators: %s: font family name */ + esc_html__( 'The "%s" font family specifies a provider, but no font faces.', 'gutenberg' ), + esc_html( $font_family['fontFamily'] ) + ) + ); - $font_family['fontFace'] = (array) $font_family['fontFace']; - - foreach ( $font_family['fontFace'] as $font_face ) { - // Skip if the webfont was registered through the Webfonts API. - if ( isset( $font_face['origin'] ) && 'gutenberg_wp_webfonts_api' === $font_face['origin'] ) { continue; } - // Check if webfonts have a "src" param, and if they do account for the use of "file:./". - if ( ! empty( $font_face['src'] ) ) { - $font_face['src'] = (array) $font_face['src']; - - foreach ( $font_face['src'] as $src_key => $url ) { - // Tweak the URL to be relative to the theme root. - if ( ! str_starts_with( $url, 'file:./' ) ) { - continue; - } - $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) ); - } - } + foreach ( $font_family['fontFaces'] as $font_face ) { + $font_face['provider'] = $font_family['provider']; + $font_face = gutenberg_resolve_font_face_uri( $font_face ); + $font_face = gutenberg_webfont_to_kebab_case( $font_face ); - // Convert keys to kebab-case. - 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 ] ); - } + $font_faces_to_register[] = $font_face; } - $webfonts[] = $font_face; + continue; + } + + if ( ! isset( $font_family['fontFaces'] ) ) { + continue; + } + + foreach ( $font_family['fontFaces'] as $font_face ) { + if ( isset( $font_face['provider'] ) ) { + $font_face = gutenberg_resolve_font_face_uri( $font_face ); + $font_face = gutenberg_webfont_to_kebab_case( $font_face ); + + $font_faces_to_register[] = $font_face; + } } } } - foreach ( $webfonts as $webfont ) { - wp_webfonts()->register_webfont( $webfont ); - wp_webfonts()->enqueue_webfont( $webfont['font-family'] ); - } + + wp_register_webfonts( $font_faces_to_register ); } /** @@ -171,5 +208,3 @@ function gutenberg_add_registered_webfonts_to_theme_json( $data ) { return $data; } - -add_action( 'init', 'gutenberg_register_webfonts_from_theme_json' ); From d80dba4da3877dc74ab1e41237065c5807d95956 Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini Date: Mon, 4 Apr 2022 22:02:28 -0500 Subject: [PATCH 02/37] Add registered webfonts to theme.json --- .../add-registered-webfonts-to-theme-json.php | 130 ++++++++++++++++++ .../register-webfonts-from-theme-json.php | 78 ----------- lib/load.php | 1 + 3 files changed, 131 insertions(+), 78 deletions(-) create mode 100644 lib/experimental/add-registered-webfonts-to-theme-json.php diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php new file mode 100644 index 00000000000000..778501eb1fdaf5 --- /dev/null +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -0,0 +1,130 @@ + $webfont ) { + if ( gutenberg_is_webfont_equal( $webfont, $webfont_to_find ) ) { + return $index; + } + } + + return false; +} + +function gutenberg_webfont_to_camel_case( $webfont ) { + $camel_cased_webfont = array(); + + foreach ( $webfont as $key => $value ) { + $camel_cased_webfont[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value; + } + + return $camel_cased_webfont; +} + +function gutenberg_get_font_family_indexes( $families ) { + $indexes = array(); + + foreach ( $families as $index => $family ) { + $indexes[ wp_webfonts()->get_font_slug( $family ) ] = $index; + } + + return $indexes; +} + +/** + * Add missing fonts data to the global styles. + * + * @param array $data The global styles. + * @return array The global styles with missing fonts data. + */ +function gutenberg_add_registered_webfonts_to_theme_json( $data ) { + $registered_font_families = wp_webfonts()->get_all_webfonts(); + + if ( empty( $registered_font_families ) ) { + return $data; + } + + // Make sure the path to settings.typography.fontFamilies.theme exists + // before adding missing fonts. + if ( empty( $data['settings'] ) ) { + $data['settings'] = array(); + } + if ( empty( $data['settings']['typography'] ) ) { + $data['settings']['typography'] = array(); + } + if ( empty( $data['settings']['typography']['fontFamilies'] ) ) { + $data['settings']['typography']['fontFamilies'] = array(); + } + + $font_family_indexes_in_theme_json = gutenberg_get_font_family_indexes( $data['settings']['typography']['fontFamilies'] ); + + foreach ( $registered_font_families as $slug => $registered_font_faces ) { + // Font family not in theme.json, so let's add it. + if ( ! isset( $font_family_indexes_in_theme_json[ $slug ] ) ) { + $family_name = $registered_font_faces[0]['font-family']; + + $data['settings']['typography']['fontFamilies'][] = array( + 'origin' => 'gutenberg_wp_webfonts_api', + 'fontFamily' => str_contains( $family_name, ' ' ) ? "'{$family_name}'" : $family_name, + 'name' => $family_name, + 'slug' => $slug, + 'fontFaces' => array_map( + function( $font_face ) { + $font_face['origin'] = 'gutenberg_wp_webfonts_api'; + + return gutenberg_webfont_to_camel_case( $font_face ); + }, + $registered_font_faces + ), + ); + + continue; + } + + $font_family_index_in_theme_json = $font_family_indexes_in_theme_json[ $slug ]; + $font_family_in_theme_json = $data['settings']['typography']['fontFamilies'][ $font_family_index_in_theme_json ]; + + if ( ! isset( $font_family_in_theme_json['fontFaces'] ) ) { + // Font family exists, but it's not declaring any font face + // Let's not get in their way. + continue; + } + + $font_faces_in_theme_json = $font_family_in_theme_json['fontFaces']; + + foreach ( $registered_font_faces as $registered_font_face ) { + $registered_font_face = gutenberg_webfont_to_camel_case( $registered_font_face ); + + if ( false !== gutenberg_find_webfont( $font_faces_in_theme_json, $registered_font_face ) ) { + // Webfont is already there, so let's not add it. + continue; + } + + $registered_font_face['origin'] = 'gutenberg_wp_webfonts_api'; + + $data['settings']['typography']['fontFamilies'][ $font_family_index_in_theme_json ]['fontFaces'][] = $registered_font_face; + } + } + + return $data; +} diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index d382f45236cabc..336456c7a52976 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -130,81 +130,3 @@ function gutenberg_register_webfonts_from_theme_json( $settings ) { wp_register_webfonts( $font_faces_to_register ); } - -/** - * Add missing fonts data to the global styles. - * - * @param array $data The global styles. - * @return array The global styles with missing fonts data. - */ -function gutenberg_add_registered_webfonts_to_theme_json( $data ) { - $font_families_registered = wp_webfonts()->get_all_webfonts(); - $font_families_from_theme = array(); - if ( ! empty( $data['settings'] ) && ! empty( $data['settings']['typography'] ) && ! empty( $data['settings']['typography']['fontFamilies'] ) ) { - $font_families_from_theme = $data['settings']['typography']['fontFamilies']; - } - - /** - * Helper to get an array of the font-families. - * - * @param array $families_data The font-families data. - * @return array The font-families array. - */ - $get_families = static function( $families_data ) { - $families = array(); - foreach ( $families_data as $family ) { - $families[] = WP_Webfonts::get_font_slug( $family ); - } - - // Micro-optimization: Use array_flip( array_flip( $array ) ) - // instead of array_unique( $array ) because it's faster. - // The result is the same. - return array_flip( array_flip( $families ) ); - }; - - // Diff the arrays to find the missing fonts. - $to_add = array_diff( - array_keys( $font_families_registered ), - $get_families( $font_families_from_theme ) - ); - - // Bail out early if there are no missing fonts. - if ( empty( $to_add ) ) { - return $data; - } - - // Make sure the path to settings.typography.fontFamilies.theme exists - // before adding missing fonts. - if ( empty( $data['settings'] ) ) { - $data['settings'] = array(); - } - if ( empty( $data['settings']['typography'] ) ) { - $data['settings']['typography'] = array(); - } - if ( empty( $data['settings']['typography']['fontFamilies'] ) ) { - $data['settings']['typography']['fontFamilies'] = array(); - } - - foreach ( $to_add as $slug ) { - $font_faces_for_family = $font_families_registered[ $slug ]; - $family_name = $font_faces_for_family[0]['font-family']; - $font_faces = array(); - - foreach ( $font_faces_for_family as $font_face ) { - $camel_cased = array( 'origin' => 'gutenberg_wp_webfonts_api' ); - foreach ( $font_face as $key => $value ) { - $camel_cased[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value; - } - $font_faces[] = $camel_cased; - } - - $data['settings']['typography']['fontFamilies'][] = array( - 'fontFamily' => str_contains( $family_name, ' ' ) ? "'{$family_name}'" : $family_name, - 'name' => $family_name, - 'slug' => $slug, - 'fontFace' => $font_faces, - ); - } - - return $data; -} diff --git a/lib/load.php b/lib/load.php index 5d9969c409ffa1..6679d95000631d 100644 --- a/lib/load.php +++ b/lib/load.php @@ -115,6 +115,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.0/block-template.php'; require __DIR__ . '/compat/wordpress-6.0/edit-form-blocks.php'; require __DIR__ . '/experimental/register-webfonts-from-theme-json.php'; +require __DIR__ . '/experimental/add-registered-webfonts-to-theme-json.php'; require __DIR__ . '/experimental/class-wp-theme-json-resolver-gutenberg.php'; require __DIR__ . '/experimental/class-wp-webfonts.php'; require __DIR__ . '/experimental/class-wp-webfonts-provider.php'; From 0d64aab2d516981031e59a88c39543cee94ab2ab Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini Date: Mon, 4 Apr 2022 22:29:57 -0500 Subject: [PATCH 03/37] Enqueue webfonts listed in theme.json --- .../add-registered-webfonts-to-theme-json.php | 16 ++- lib/experimental/class-wp-webfonts.php | 113 ++++++++++++++++-- .../enqueue-webfonts-listed-in-theme-json.php | 73 +++++++++++ lib/load.php | 1 + 4 files changed, 193 insertions(+), 10 deletions(-) create mode 100644 lib/experimental/enqueue-webfonts-listed-in-theme-json.php diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index 778501eb1fdaf5..07185b6efc978b 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -5,11 +5,15 @@ * @package gutenberg */ -function gutenberg_is_webfont_equal( $a, $b ) { - $equality_attrs = array( +function gutenberg_is_webfont_equal( $a, $b, $is_camel_case = true ) { + $equality_attrs = $is_camel_case ? array( 'fontFamily', 'fontStyle', 'fontWeight', + ) : array( + 'font-family', + 'font-style', + 'font-weight', ); foreach ( $equality_attrs as $attr ) { @@ -22,8 +26,14 @@ function gutenberg_is_webfont_equal( $a, $b ) { } function gutenberg_find_webfont( $webfonts, $webfont_to_find ) { + if ( ! count( $webfonts ) ) { + return false; + } + + $is_camel_case = isset( $webfonts[0]['fontFamily'] ); + foreach ( $webfonts as $index => $webfont ) { - if ( gutenberg_is_webfont_equal( $webfont, $webfont_to_find ) ) { + if ( gutenberg_is_webfont_equal( $webfont, $webfont_to_find, $is_camel_case ) ) { return $index; } } diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index e422f51658befb..56273673e8aae2 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -145,28 +145,80 @@ public function register_webfont( array $webfont ) { /** * Enqueue a font-family that has been already registered. * - * @param string $font_family_name The font family name to be enqueued. + * @param string $font_family_name The font family name to be enqueued. + * @param array|null $font_face The font face to selectively enqueue. * @return bool True if successfully enqueued, else false. */ - public function enqueue_webfont( $font_family_name ) { + public function enqueue_webfont( $font_family_name, $font_face = null ) { $slug = $this->get_font_slug( $font_family_name ); - if ( isset( $this->enqueued_webfonts[ $slug ] ) ) { + // The font family is already enqueued and there are none left to enqueue. + if ( isset( $this->enqueued_webfonts[ $slug ] ) && ! isset( $this->registered_webfonts[ $slug ] ) ) { return true; } if ( ! isset( $this->registered_webfonts[ $slug ] ) ) { - /* translators: %s unique slug to identify the font family of the webfont */ - _doing_it_wrong( __METHOD__, sprintf( __( 'The "%s" font family is not registered.', 'gutenberg' ), $slug ), '6.0.0' ); + _doing_it_wrong( + __METHOD__, + sprintf( + /* translators: %s unique slug to identify the font family of the webfont */ + esc_html__( 'The "%s" font family is not registered.', 'gutenberg' ), + esc_html( $slug ) + ), + '6.0.0' + ); return false; } - $this->enqueued_webfonts[ $slug ] = $this->registered_webfonts[ $slug ]; - unset( $this->registered_webfonts[ $slug ] ); + // Enqueueing the font family completely. + if ( ! $font_face ) { + $font_family_to_enqueue = $this->unregister_font_family( $font_family_name ); + $this->enqueued_webfonts[ $slug ] = $font_family_to_enqueue; + + return true; + } + + // Enqueueing a single font face. + + $font_face = gutenberg_webfont_to_kebab_case( $font_face ); + $font_face_to_enqueue = $this->unregister_font_face( $font_face ); + + if ( ! $font_face_to_enqueue ) { + trigger_error( + sprintf( + /* translators: %1$s: font family, %2$s: font weight, %3$s: font style */ + esc_html__( 'The "%1$s:%2$s:%3$s" font face is not registered.', 'gutenberg' ), + esc_html( $font_face['font-family'] ), + esc_html( $font_face['font-weight'] ), + esc_html( $font_face['font-style'] ) + ) + ); + + return false; + } + + if ( ! isset( $this->enqueued_webfonts[ $slug ] ) ) { + $this->enqueued_webfonts[ $slug ] = array(); + } + + $this->enqueued_webfonts[ $slug ][] = $font_face_to_enqueue; + return true; } + /** + * Checks if a font family is registered. + * + * @param string $font_family_name The font family name to check in the registry. + * @return bool True if found, else false. + */ + public function is_font_family_registered( $font_family_name ) { + $slug = $this->get_font_slug( $font_family_name ); + + return isset( $this->registered_webfonts[ $slug ] ); + } + /** * Get the font slug. * @@ -191,6 +243,53 @@ public static function get_font_slug( $to_convert ) { return sanitize_title( $to_convert ); } + /** + * Unregisters a font family. + * + * @param string $font_family_name The font family, by name, to unregister. + * @return array[]|false The font face objects of the family if unregistered, false otherwise. + */ + private function unregister_font_family( $font_family_name ) { + $slug = $this->get_font_slug( $font_family_name ); + + if ( ! isset( $this->registered_webfonts[ $slug ] ) ) { + return false; + } + + $font_family = $this->registered_webfonts[ $slug ]; + unset( $this->registered_webfonts[ $slug ] ); + + return $font_family; + } + + /** + * Unregisters a font face. + * + * @param array $font_face_to_unregister The font face object, to unregister. + * @return array|false The font face object if unregistered, false otherwise. + */ + private function unregister_font_face( $font_face_to_unregister ) { + $font_family_slug = $this->get_font_slug( $font_face_to_unregister ); + + $font_family = $this->registered_webfonts[ $font_family_slug ]; + $index = gutenberg_find_webfont( $font_family, $font_face_to_unregister ); + + // Font face not found. + if ( false === $index ) { + return false; + } + + $font_face = $this->registered_webfonts[ $font_family_slug ][ $index ]; + unset( $this->registered_webfonts[ $font_family_slug ][ $index ] ); + + // No font faces left, let's remove the font family entry. + if ( 0 === count( $this->registered_webfonts[ $font_family_slug ] ) ) { + unset( $this->registered_webfonts[ $font_family_slug ] ); + } + + return $font_face; + } + /** * Validate a webfont. * diff --git a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php new file mode 100644 index 00000000000000..024574fba57f8a --- /dev/null +++ b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php @@ -0,0 +1,73 @@ +get_settings(); + + // Bail out early if there are no settings for webfonts. + if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) { + return; + } + + // Look for fontFamilies. + foreach ( $settings['typography']['fontFamilies'] as $font_families ) { + foreach ( $font_families as $font_family ) { + // Skip dynamically included font families. We only want to enqueue explicitly added fonts. + if ( gutenberg_is_externally_registered_webfont( $font_family ) ) { + continue; + } + + // If no font faces defined. + if ( ! isset( $font_family['fontFaces'] ) ) { + // And the font family is registered. + if ( ! wp_webfonts()->is_font_family_registered( $font_family['fontFamily'] ) ) { + continue; + } + + // Enqueue the entire family. + wp_webfonts()->enqueue_webfont( $font_family ); + continue; + } + + // Loop through all the font faces, enqueueing each one of them. + foreach ( $font_family['fontFaces'] as $font_face ) { + // Skip dynamically included font faces. We only want to enqueue the font faces listed in theme.json. + if ( gutenberg_is_externally_registered_webfont( $font_face ) ) { + continue; + } + + wp_webfonts()->enqueue_webfont( $font_family, $font_face ); + } + } + } +} + +add_filter( 'wp_loaded', 'gutenberg_enqueue_webfonts_listed_in_theme_json' ); + +// No need to run this -- opening the admin interface enqueues all the webfonts. +add_action( + 'admin_init', + function() { + remove_filter( 'wp_loaded', 'gutenberg_enqueue_webfonts_listed_in_theme_json' ); + } +); diff --git a/lib/load.php b/lib/load.php index 6679d95000631d..cb797612870a80 100644 --- a/lib/load.php +++ b/lib/load.php @@ -116,6 +116,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.0/edit-form-blocks.php'; require __DIR__ . '/experimental/register-webfonts-from-theme-json.php'; require __DIR__ . '/experimental/add-registered-webfonts-to-theme-json.php'; +require __DIR__ . '/experimental/enqueue-webfonts-listed-in-theme-json.php'; require __DIR__ . '/experimental/class-wp-theme-json-resolver-gutenberg.php'; require __DIR__ . '/experimental/class-wp-webfonts.php'; require __DIR__ . '/experimental/class-wp-webfonts-provider.php'; From b527cd7d5f40937bd4cfdc6b564c86e014e1b95c Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini Date: Wed, 6 Apr 2022 19:31:20 -0500 Subject: [PATCH 04/37] Do not run gutenberg_add_registered_webfonts_to_theme_json unless opening the admin interface --- .../class-wp-theme-json-resolver-gutenberg.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php index 587e61dc32f381..fb2416c7aa62fd 100644 --- a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php @@ -40,8 +40,11 @@ public static function get_theme_data( $deprecated = array(), $settings = array( $original_theme_json = new WP_Theme_JSON_Gutenberg( $theme_json_data ); gutenberg_register_webfonts_from_theme_json( $original_theme_json->get_settings() ); - $theme_json_data = gutenberg_add_registered_webfonts_to_theme_json( $theme_json_data ); - static::$theme = new WP_Theme_JSON_Gutenberg( $theme_json_data ); + if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { + $theme_json_data = gutenberg_add_registered_webfonts_to_theme_json( $theme_json_data ); + } + + static::$theme = new WP_Theme_JSON_Gutenberg( $theme_json_data ); if ( wp_get_theme()->parent() ) { // Get parent theme.json. From 62e0e6d8641b24a3642bbce098b7e0b0f530396a Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini Date: Wed, 6 Apr 2022 19:41:45 -0500 Subject: [PATCH 05/37] Extract utility functions into their own help files --- .../add-registered-webfonts-to-theme-json.php | 58 +------- .../register-webfonts-from-theme-json.php | 43 ------ lib/experimental/webfonts-utils.php | 136 ++++++++++++++++++ lib/load.php | 1 + 4 files changed, 138 insertions(+), 100 deletions(-) create mode 100644 lib/experimental/webfonts-utils.php diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index 07185b6efc978b..c413e6f6011a2c 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -5,62 +5,6 @@ * @package gutenberg */ -function gutenberg_is_webfont_equal( $a, $b, $is_camel_case = true ) { - $equality_attrs = $is_camel_case ? array( - 'fontFamily', - 'fontStyle', - 'fontWeight', - ) : array( - 'font-family', - 'font-style', - 'font-weight', - ); - - foreach ( $equality_attrs as $attr ) { - if ( $a[ $attr ] !== $b[ $attr ] ) { - return false; - } - } - - return true; -} - -function gutenberg_find_webfont( $webfonts, $webfont_to_find ) { - if ( ! count( $webfonts ) ) { - return false; - } - - $is_camel_case = isset( $webfonts[0]['fontFamily'] ); - - foreach ( $webfonts as $index => $webfont ) { - if ( gutenberg_is_webfont_equal( $webfont, $webfont_to_find, $is_camel_case ) ) { - return $index; - } - } - - return false; -} - -function gutenberg_webfont_to_camel_case( $webfont ) { - $camel_cased_webfont = array(); - - foreach ( $webfont as $key => $value ) { - $camel_cased_webfont[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value; - } - - return $camel_cased_webfont; -} - -function gutenberg_get_font_family_indexes( $families ) { - $indexes = array(); - - foreach ( $families as $index => $family ) { - $indexes[ wp_webfonts()->get_font_slug( $family ) ] = $index; - } - - return $indexes; -} - /** * Add missing fonts data to the global styles. * @@ -86,7 +30,7 @@ function gutenberg_add_registered_webfonts_to_theme_json( $data ) { $data['settings']['typography']['fontFamilies'] = array(); } - $font_family_indexes_in_theme_json = gutenberg_get_font_family_indexes( $data['settings']['typography']['fontFamilies'] ); + $font_family_indexes_in_theme_json = gutenberg_map_font_family_indexes( $data['settings']['typography']['fontFamilies'] ); foreach ( $registered_font_families as $slug => $registered_font_faces ) { // Font family not in theme.json, so let's add it. diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 336456c7a52976..81602c7c9edf67 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -5,49 +5,6 @@ * @package gutenberg */ -/** - * Transforms the keys of the webfont defined in theme.json into - * kebab case, so the Webfonts API can handle it. - * - * @param array $webfont The webfont to be tranformed. - * - * @return array The kebab-case version of the webfont. - */ -function gutenberg_webfont_to_kebab_case( $webfont ) { - $kebab_cased_webfont = array(); - - foreach ( $webfont as $key => $value ) { - $kebab_cased_webfont[ _wp_to_kebab_case( $key ) ] = $value; - } - - return $kebab_cased_webfont; -} - -/** - * Transforms the source of the font face from `file.:/` into an actual URI. - * - * @param array $font_face The font face. - * - * @return array The URI-resolved font face. - */ -function gutenberg_resolve_font_face_uri( $font_face ) { - if ( empty( $font_face['src'] ) ) { - return $font_face; - } - - $font_face['src'] = (array) $font_face['src']; - - foreach ( $font_face['src'] as $src_key => $url ) { - // Tweak the URL to be relative to the theme root. - if ( ! str_starts_with( $url, 'file:./' ) ) { - continue; - } - $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) ); - } - - return $font_face; -} - /** * Register webfonts defined in theme.json * diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php new file mode 100644 index 00000000000000..1a43052c626cd4 --- /dev/null +++ b/lib/experimental/webfonts-utils.php @@ -0,0 +1,136 @@ + $value ) { + $kebab_cased_webfont[ _wp_to_kebab_case( $key ) ] = $value; + } + + return $kebab_cased_webfont; +} + +/** + * Transforms the source of the font face from `file.:/` into an actual URI. + * + * @param array $font_face The font face. + * + * @return array The URI-resolved font face. + */ +function gutenberg_resolve_font_face_uri( $font_face ) { + if ( empty( $font_face['src'] ) ) { + return $font_face; + } + + $font_face['src'] = (array) $font_face['src']; + + foreach ( $font_face['src'] as $src_key => $url ) { + // Tweak the URL to be relative to the theme root. + if ( ! str_starts_with( $url, 'file:./' ) ) { + continue; + } + $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) ); + } + + return $font_face; +} + +/** + * Compares two webfonts. + * + * @param array $a The first webfont. + * @param array $b The second webfont. + * @param boolean $is_camel_case If the font attributes are in camel case or kebab case. Defaults to camel case. + * + * @return boolean True if they're equal, false otherwise. + */ +function gutenberg_is_webfont_equal( $a, $b, $is_camel_case = true ) { + $equality_attrs = $is_camel_case ? array( + 'fontFamily', + 'fontStyle', + 'fontWeight', + ) : array( + 'font-family', + 'font-style', + 'font-weight', + ); + + foreach ( $equality_attrs as $attr ) { + if ( $a[ $attr ] !== $b[ $attr ] ) { + return false; + } + } + + return true; +} + +/** + * Finds $webfont_to_find in $webfonts. + * + * @param array[] $webfonts The webfonts array. + * @param array $webfont_to_find The webfont to find. + * + * @return integer|false The index of $webfont in $webfonts if found. False otherwise. + */ +function gutenberg_find_webfont( $webfonts, $webfont_to_find ) { + if ( ! count( $webfonts ) ) { + return false; + } + + $is_camel_case = isset( $webfonts[0]['fontFamily'] ); + + foreach ( $webfonts as $index => $webfont ) { + if ( gutenberg_is_webfont_equal( $webfont, $webfont_to_find, $is_camel_case ) ) { + return $index; + } + } + + return false; +} + +/** + * Converts webfont attributes from kebab case to camel case. + * + * @param array $webfont The kebab-cased webfont. + * + * @return array The camel-cased webfont. + */ +function gutenberg_webfont_to_camel_case( $webfont ) { + $camel_cased_webfont = array(); + + foreach ( $webfont as $key => $value ) { + $camel_cased_webfont[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value; + } + + return $camel_cased_webfont; +} + +/** + * Map the font families by slug and their corresponding indexes in $families. + * + * @param array[] $families The font families array. + * + * @return array An array in array( [slug] => [index]) format. + */ +function gutenberg_map_font_family_indexes( $families ) { + $indexes = array(); + + foreach ( $families as $index => $family ) { + $indexes[ wp_webfonts()->get_font_slug( $family ) ] = $index; + } + + return $indexes; +} diff --git a/lib/load.php b/lib/load.php index cb797612870a80..1b1354c7d929e8 100644 --- a/lib/load.php +++ b/lib/load.php @@ -122,6 +122,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/experimental/class-wp-webfonts-provider.php'; require __DIR__ . '/experimental/class-wp-webfonts-provider-local.php'; require __DIR__ . '/experimental/webfonts.php'; +require __DIR__ . '/experimental/webfonts-utils.php'; require __DIR__ . '/experimental/blocks.php'; require __DIR__ . '/blocks.php'; From 9c2c42bd48e97678e8d1c8a5d725cf807e08b779 Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini Date: Thu, 7 Apr 2022 16:00:10 -0500 Subject: [PATCH 06/37] Escape font face attributes when echoing errors --- lib/experimental/class-wp-webfonts.php | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 56273673e8aae2..cc0b691a10a372 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -455,8 +455,14 @@ private function generate_styles( array $webfonts_by_provider ) { // Bail out if the provider class does not exist. if ( ! class_exists( $provider_class ) ) { - /* translators: %s is the provider name. */ - trigger_error( sprintf( __( 'Webfont provider "%s" is not registered.', 'gutenberg' ), $provider_id ) ); + trigger_error( + sprintf( + /* translators: %s is the provider name. */ + esc_html__( 'Webfont provider "%s" is not registered.', 'gutenberg' ), + esc_html( $provider_id ) + ) + ); + continue; } @@ -498,8 +504,13 @@ private function get_webfonts_by_provider( array $font_families ) { // Skip if the provider is not registered. if ( ! isset( $providers[ $provider ] ) ) { - /* translators: %s is the provider name. */ - trigger_error( sprintf( __( 'Webfont provider "%s" is not registered.', 'gutenberg' ), $provider ) ); + trigger_error( + sprintf( + /* translators: %s is the provider name. */ + esc_html__( 'Webfont provider "%s" is not registered.', 'gutenberg' ), + esc_html( $provider ) + ) + ); continue; } From 1f637226d095744010eeb7ae82d97b0493ddd425 Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini Date: Thu, 7 Apr 2022 19:31:48 -0500 Subject: [PATCH 07/37] Add tests --- phpunit/class-wp-webfonts-mock-provider.php | 21 ++ .../enqueue-font-family/functions.php | 31 +++ .../themedir1/enqueue-font-family/style.css | 7 + .../themedir1/enqueue-font-family/theme.json | 14 ++ .../enqueue-only-one-font-face/functions.php | 31 +++ .../enqueue-only-one-font-face/style.css | 7 + .../enqueue-only-one-font-face/theme.json | 21 ++ .../style.css | 7 + .../theme.json | 30 +++ .../style.css | 7 + .../theme.json | 29 +++ ...nly-webfonts-listed-in-theme-json-test.php | 212 ++++++++++++++++++ 12 files changed, 417 insertions(+) create mode 100644 phpunit/class-wp-webfonts-mock-provider.php create mode 100644 phpunit/data/themedir1/enqueue-font-family/functions.php create mode 100644 phpunit/data/themedir1/enqueue-font-family/style.css create mode 100644 phpunit/data/themedir1/enqueue-font-family/theme.json create mode 100644 phpunit/data/themedir1/enqueue-only-one-font-face/functions.php create mode 100644 phpunit/data/themedir1/enqueue-only-one-font-face/style.css create mode 100644 phpunit/data/themedir1/enqueue-only-one-font-face/theme.json create mode 100644 phpunit/data/themedir1/register-and-enqueue-through-different-providers/style.css create mode 100644 phpunit/data/themedir1/register-and-enqueue-through-different-providers/theme.json create mode 100644 phpunit/data/themedir1/register-and-enqueue-to-the-same-provider/style.css create mode 100644 phpunit/data/themedir1/register-and-enqueue-to-the-same-provider/theme.json create mode 100644 phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php diff --git a/phpunit/class-wp-webfonts-mock-provider.php b/phpunit/class-wp-webfonts-mock-provider.php new file mode 100644 index 00000000000000..820de8d2f9b241 --- /dev/null +++ b/phpunit/class-wp-webfonts-mock-provider.php @@ -0,0 +1,21 @@ + 'Roboto', + 'font-style' => 'normal', + 'font-stretch' => 'normal', + 'font-weight' => '400', + 'src' => get_theme_file_uri( '/assets/fonts/Roboto-regular.ttf' ), + ) + ); + + wp_register_webfont( + array( + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-stretch' => 'normal', + 'font-weight' => '400', + 'src' => get_theme_file_uri( '/assets/fonts/Source-Serif-Pro-Regular.ttf' ), + ) + ); + } +); diff --git a/phpunit/data/themedir1/enqueue-font-family/style.css b/phpunit/data/themedir1/enqueue-font-family/style.css new file mode 100644 index 00000000000000..eb132a0ce97bcb --- /dev/null +++ b/phpunit/data/themedir1/enqueue-font-family/style.css @@ -0,0 +1,7 @@ +/* +Theme Name: Test theme +Theme URI: https://wordpress.org/ +Description: For testing purposes only. +Version: 1.0.0 +Text Domain: block-theme +*/ diff --git a/phpunit/data/themedir1/enqueue-font-family/theme.json b/phpunit/data/themedir1/enqueue-font-family/theme.json new file mode 100644 index 00000000000000..76c09ad7959620 --- /dev/null +++ b/phpunit/data/themedir1/enqueue-font-family/theme.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "settings": { + "typography": { + "fontFamilies": [ + { + "fontFamily": "Roboto", + "slug": "roboto", + "name": "Roboto" + } + ] + } + } +} diff --git a/phpunit/data/themedir1/enqueue-only-one-font-face/functions.php b/phpunit/data/themedir1/enqueue-only-one-font-face/functions.php new file mode 100644 index 00000000000000..2c5c2b825967e3 --- /dev/null +++ b/phpunit/data/themedir1/enqueue-only-one-font-face/functions.php @@ -0,0 +1,31 @@ + 'Roboto', + 'font-style' => 'normal', + 'font-stretch' => 'normal', + 'font-weight' => '400', + 'src' => get_theme_file_uri( '/assets/fonts/Roboto-Regular.ttf' ), + ) + ); + + wp_register_webfont( + array( + 'font-family' => 'Roboto', + 'font-style' => 'bold', + 'font-stretch' => 'normal', + 'font-weight' => '900', + 'src' => get_theme_file_uri( '/assets/fonts/Roboto-Bold.ttf' ), + ) + ); + } +); diff --git a/phpunit/data/themedir1/enqueue-only-one-font-face/style.css b/phpunit/data/themedir1/enqueue-only-one-font-face/style.css new file mode 100644 index 00000000000000..eb132a0ce97bcb --- /dev/null +++ b/phpunit/data/themedir1/enqueue-only-one-font-face/style.css @@ -0,0 +1,7 @@ +/* +Theme Name: Test theme +Theme URI: https://wordpress.org/ +Description: For testing purposes only. +Version: 1.0.0 +Text Domain: block-theme +*/ diff --git a/phpunit/data/themedir1/enqueue-only-one-font-face/theme.json b/phpunit/data/themedir1/enqueue-only-one-font-face/theme.json new file mode 100644 index 00000000000000..c009e413c64a35 --- /dev/null +++ b/phpunit/data/themedir1/enqueue-only-one-font-face/theme.json @@ -0,0 +1,21 @@ +{ + "version": 1, + "settings": { + "typography": { + "fontFamilies": [ + { + "fontFamily": "Roboto", + "slug": "roboto", + "name": "Roboto", + "fontFaces": [ + { + "fontFamily": "Roboto", + "fontWeight": "900", + "fontStyle": "bold" + } + ] + } + ] + } + } +} diff --git a/phpunit/data/themedir1/register-and-enqueue-through-different-providers/style.css b/phpunit/data/themedir1/register-and-enqueue-through-different-providers/style.css new file mode 100644 index 00000000000000..eb132a0ce97bcb --- /dev/null +++ b/phpunit/data/themedir1/register-and-enqueue-through-different-providers/style.css @@ -0,0 +1,7 @@ +/* +Theme Name: Test theme +Theme URI: https://wordpress.org/ +Description: For testing purposes only. +Version: 1.0.0 +Text Domain: block-theme +*/ diff --git a/phpunit/data/themedir1/register-and-enqueue-through-different-providers/theme.json b/phpunit/data/themedir1/register-and-enqueue-through-different-providers/theme.json new file mode 100644 index 00000000000000..307013a664e7e8 --- /dev/null +++ b/phpunit/data/themedir1/register-and-enqueue-through-different-providers/theme.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "settings": { + "typography": { + "fontFamilies": [ + { + "fontFamily": "Roboto", + "slug": "roboto", + "name": "Roboto", + "fontFaces": [ + { + "provider": "mock", + "fontFamily": "Roboto", + "fontWeight": "400", + "fontStyle": "regular", + "src": "file:./assets/fonts/Roboto-Regular.ttf" + }, + { + "provider": "local", + "fontFamily": "Roboto", + "fontWeight": "900", + "fontStyle": "bold", + "src": "file:./assets/fonts/Roboto-Bold.ttf" + } + ] + } + ] + } + } +} diff --git a/phpunit/data/themedir1/register-and-enqueue-to-the-same-provider/style.css b/phpunit/data/themedir1/register-and-enqueue-to-the-same-provider/style.css new file mode 100644 index 00000000000000..eb132a0ce97bcb --- /dev/null +++ b/phpunit/data/themedir1/register-and-enqueue-to-the-same-provider/style.css @@ -0,0 +1,7 @@ +/* +Theme Name: Test theme +Theme URI: https://wordpress.org/ +Description: For testing purposes only. +Version: 1.0.0 +Text Domain: block-theme +*/ diff --git a/phpunit/data/themedir1/register-and-enqueue-to-the-same-provider/theme.json b/phpunit/data/themedir1/register-and-enqueue-to-the-same-provider/theme.json new file mode 100644 index 00000000000000..167796c585fbd7 --- /dev/null +++ b/phpunit/data/themedir1/register-and-enqueue-to-the-same-provider/theme.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "settings": { + "typography": { + "fontFamilies": [ + { + "fontFamily": "Roboto", + "slug": "roboto", + "name": "Roboto", + "provider": "local", + "fontFaces": [ + { + "fontFamily": "Roboto", + "fontWeight": "400", + "fontStyle": "regular", + "src": "file:./assets/fonts/Roboto-Regular.ttf" + }, + { + "fontFamily": "Roboto", + "fontWeight": "900", + "fontStyle": "bold", + "src": "file:./assets/fonts/Roboto-Bold.ttf" + } + ] + } + ] + } + } +} diff --git a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php new file mode 100644 index 00000000000000..5dbb91d9ef26e0 --- /dev/null +++ b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php @@ -0,0 +1,212 @@ +old_wp_styles = $wp_styles; + + $wp_styles = null; + + global $wp_webfonts; + $this->old_wp_webfonts = $wp_webfonts; + + $wp_webfonts = null; + + $this->theme_root = realpath( __DIR__ . '/data/themedir1' ); + + $this->old_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 ); + $this->queries = array(); + // Clear caches. + wp_clean_themes_cache(); + unset( $GLOBALS['wp_themes'] ); + } + + /** + * Restores the original theme root and WP_Webfonts instance. + */ + public function tearDown() { + global $wp_webfonts; + global $wp_styles; + + $wp_webfonts = $this->old_wp_webfonts; + $wp_styles = $this->old_wp_styles; + + // Restore the original theme directory setup. + $GLOBALS['wp_theme_directories'] = $this->old_theme_dir; + wp_clean_themes_cache(); + unset( $GLOBALS['wp_themes'] ); + + parent::tearDown(); + } + + /** + * Switches to $theme_name, runs the necessary hooks + * and generates the styles for it. + * + * The styles will hold the webfonts that will get loaded + * in the front-end, and that's what this test suite is asserting. + * + * @param string $theme_name The theme name. Themes are located in phpunited/data/themedir1. + */ + private function generate_styles_for_theme( $theme_name ) { + switch_theme( $theme_name ); + + if ( file_exists( get_stylesheet_directory() . '/functions.php' ) ) { + require_once get_stylesheet_directory() . '/functions.php'; + } + + do_action( 'after_setup_theme' ); + WP_Theme_JSON_Resolver_Gutenberg::clean_cached_data(); + do_action( 'wp_loaded' ); + + wp_webfonts()->generate_and_enqueue_styles(); + } + + /** + * Enqueue an externally registered font family. + * + * The `enqueue-font-family` theme registers two font families + * but only one is listed in theme.json. + */ + public function test_enqueue_an_externally_registered_font_family() { + $this->generate_styles_for_theme( 'enqueue-font-family' ); + + $expected = << +@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:fallback;font-stretch:normal;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/enqueue-font-family/assets/fonts/Roboto-regular.ttf') format('truetype');} + +EOF; + + $this->assertContains( + $expected, + get_echo( 'wp_print_styles' ) + ); + } + + /** + * Enqueue only one of all externally registered font faces. + * + * The `enqueue-only-one-font-face` theme registers two font faces + * for Roboto, but only one is listed in theme.json. + */ + public function test_enqueue_only_one_of_all_externally_registered_font_faces() { + $this->generate_styles_for_theme( 'enqueue-only-one-font-face' ); + + $expected = << +@font-face{font-family:Roboto;font-style:bold;font-weight:900;font-display:fallback;font-stretch:normal;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/enqueue-only-one-font-face/assets/fonts/Roboto-Bold.ttf') format('truetype');} + +EOF; + + $this->assertContains( + $expected, + get_echo( 'wp_print_styles' ) + ); + } + + /** + * Register (and enqueue) a collection of font faces to the same provider. + * + * The `register-and-enqueue-to-the-same-provider` theme registers and + * enqueue a font family listed in theme.json through the same provider, declared + * at top level. + */ + public function test_register_and_enqueue_font_faces_to_same_provider() { + $this->generate_styles_for_theme( 'register-and-enqueue-to-the-same-provider' ); + + $expected = << +@font-face{font-family:Roboto;font-style:regular;font-weight:400;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-to-the-same-provider/assets/fonts/Roboto-Regular.ttf') format('truetype');}@font-face{font-family:Roboto;font-style:bold;font-weight:900;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-to-the-same-provider/assets/fonts/Roboto-Bold.ttf') format('truetype');} + +EOF; + + $this->assertContains( + $expected, + get_echo( 'wp_print_styles' ) + ); + } + + /** + * Register (and enqueue) a collection of font faces through different providers. + * + * The `register-and-enqueue-through-different-providers` theme registers and + * enqueue a font family listed in theme.json through different providers, + * declared at font face level. + */ + public function test_register_and_enqueue_font_faces_through_different_providers() { + wp_register_webfont_provider( 'mock', 'WP_Webfonts_Mock_Provider' ); + $this->generate_styles_for_theme( 'register-and-enqueue-through-different-providers' ); + + $expected = << +@font-face{font-family:Roboto;font-style:bold;font-weight:900;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-through-different-providers/assets/fonts/Roboto-Bold.ttf') format('truetype');}@font-face{font-family:Roboto;font-style:regular;font-weight:400;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-through-different-providers/assets/fonts/Roboto-Regular.ttf') format('truetype');} + +EOF; + + $this->assertContains( + $expected, + get_echo( 'wp_print_styles' ) + ); + } +} From c89e70db83c6d65b44fc1ba4d68142c48dcb9454 Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini Date: Wed, 13 Apr 2022 09:46:33 -0500 Subject: [PATCH 08/37] Inline gutenberg_map_font_family_indexes --- .../add-registered-webfonts-to-theme-json.php | 11 ++++++++++- lib/experimental/webfonts-utils.php | 17 ----------------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index c413e6f6011a2c..f482bb99687781 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -30,7 +30,16 @@ function gutenberg_add_registered_webfonts_to_theme_json( $data ) { $data['settings']['typography']['fontFamilies'] = array(); } - $font_family_indexes_in_theme_json = gutenberg_map_font_family_indexes( $data['settings']['typography']['fontFamilies'] ); + /** + * Map the font families by slug to their corresponding index + * in theme.json, so we can avoid looping theme.json looking for + * font families every time we want to register a face. + */ + $font_family_indexes_in_theme_json = array(); + + foreach ( $data['settings']['typography']['fontFamilies'] as $index => $family ) { + $font_family_indexes_in_theme_json[ wp_webfonts()->get_font_slug( $family ) ] = $index; + } foreach ( $registered_font_families as $slug => $registered_font_faces ) { // Font family not in theme.json, so let's add it. diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index 1a43052c626cd4..b3028fc9ccc6c6 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -117,20 +117,3 @@ function gutenberg_webfont_to_camel_case( $webfont ) { return $camel_cased_webfont; } - -/** - * Map the font families by slug and their corresponding indexes in $families. - * - * @param array[] $families The font families array. - * - * @return array An array in array( [slug] => [index]) format. - */ -function gutenberg_map_font_family_indexes( $families ) { - $indexes = array(); - - foreach ( $families as $index => $family ) { - $indexes[ wp_webfonts()->get_font_slug( $family ) ] = $index; - } - - return $indexes; -} From de27be02826d942fef50f0e2eac4671afa3bd7f4 Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini Date: Wed, 13 Apr 2022 09:56:25 -0500 Subject: [PATCH 09/37] Make array key transformation functions more generic --- .../add-registered-webfonts-to-theme-json.php | 4 +- lib/experimental/class-wp-webfonts.php | 2 +- .../register-webfonts-from-theme-json.php | 4 +- lib/experimental/webfonts-utils.php | 57 ++++++++++--------- 4 files changed, 35 insertions(+), 32 deletions(-) diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index f482bb99687781..f297f33bf59a59 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -55,7 +55,7 @@ function gutenberg_add_registered_webfonts_to_theme_json( $data ) { function( $font_face ) { $font_face['origin'] = 'gutenberg_wp_webfonts_api'; - return gutenberg_webfont_to_camel_case( $font_face ); + return _wp_array_keys_to_camel_case( $font_face ); }, $registered_font_faces ), @@ -76,7 +76,7 @@ function( $font_face ) { $font_faces_in_theme_json = $font_family_in_theme_json['fontFaces']; foreach ( $registered_font_faces as $registered_font_face ) { - $registered_font_face = gutenberg_webfont_to_camel_case( $registered_font_face ); + $registered_font_face = _wp_array_keys_to_camel_case( $registered_font_face ); if ( false !== gutenberg_find_webfont( $font_faces_in_theme_json, $registered_font_face ) ) { // Webfont is already there, so let's not add it. diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index cc0b691a10a372..97ae523d93bd54 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -181,7 +181,7 @@ public function enqueue_webfont( $font_family_name, $font_face = null ) { // Enqueueing a single font face. - $font_face = gutenberg_webfont_to_kebab_case( $font_face ); + $font_face = _wp_array_keys_to_kebab_case( $font_face ); $font_face_to_enqueue = $this->unregister_font_face( $font_face ); if ( ! $font_face_to_enqueue ) { diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 81602c7c9edf67..d00f3ad7b319a4 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -62,7 +62,7 @@ function gutenberg_register_webfonts_from_theme_json( $settings ) { foreach ( $font_family['fontFaces'] as $font_face ) { $font_face['provider'] = $font_family['provider']; $font_face = gutenberg_resolve_font_face_uri( $font_face ); - $font_face = gutenberg_webfont_to_kebab_case( $font_face ); + $font_face = _wp_array_keys_to_kebab_case( $font_face ); $font_faces_to_register[] = $font_face; } @@ -77,7 +77,7 @@ function gutenberg_register_webfonts_from_theme_json( $settings ) { foreach ( $font_family['fontFaces'] as $font_face ) { if ( isset( $font_face['provider'] ) ) { $font_face = gutenberg_resolve_font_face_uri( $font_face ); - $font_face = gutenberg_webfont_to_kebab_case( $font_face ); + $font_face = _wp_array_keys_to_kebab_case( $font_face ); $font_faces_to_register[] = $font_face; } diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index b3028fc9ccc6c6..8fda17d46f6932 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -5,22 +5,23 @@ * @package gutenberg */ -/** - * Transforms the keys of the webfont defined in theme.json into - * kebab case, so the Webfonts API can handle it. - * - * @param array $webfont The webfont to be tranformed. - * - * @return array The kebab-case version of the webfont. - */ -function gutenberg_webfont_to_kebab_case( $webfont ) { - $kebab_cased_webfont = array(); +if ( ! function_exists( '_wp_array_keys_to_kebab_case' ) ) { + /** + * Transforms the keys of the array to kebab-case. + * + * @param array $array The array to be tranformed. + * + * @return array The kebab-cased array. + */ + function _wp_array_keys_to_kebab_case( $array ) { + $kebab_cased_array = array(); + + foreach ( $array as $key => $value ) { + $kebab_cased_array[ _wp_to_kebab_case( $key ) ] = $value; + } - foreach ( $webfont as $key => $value ) { - $kebab_cased_webfont[ _wp_to_kebab_case( $key ) ] = $value; + return $kebab_cased_array; } - - return $kebab_cased_webfont; } /** @@ -101,19 +102,21 @@ function gutenberg_find_webfont( $webfonts, $webfont_to_find ) { return false; } -/** - * Converts webfont attributes from kebab case to camel case. - * - * @param array $webfont The kebab-cased webfont. - * - * @return array The camel-cased webfont. - */ -function gutenberg_webfont_to_camel_case( $webfont ) { - $camel_cased_webfont = array(); +if ( ! function_exists( '_wp_array_keys_to_camel_case' ) ) { + /** + * Transforms the keys of the array from kebab-case to camel-case. + * + * @param array $array The kebab-cased array. + * + * @return array The camel-cased array. + */ + function _wp_array_keys_to_camel_case( $array ) { + $camel_cased_array = array(); + + foreach ( $array as $key => $value ) { + $camel_cased_array[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value; + } - foreach ( $webfont as $key => $value ) { - $camel_cased_webfont[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value; + return $camel_cased_array; } - - return $camel_cased_webfont; } From 3c1c444e50e1dcd78484f1a30835958569b50ca4 Mon Sep 17 00:00:00 2001 From: Luis Felipe Zaguini Date: Wed, 13 Apr 2022 10:03:18 -0500 Subject: [PATCH 10/37] Make helper functions used in Webfonts API private --- .../add-registered-webfonts-to-theme-json.php | 4 ++-- .../class-wp-theme-json-resolver-gutenberg.php | 6 +++--- lib/experimental/class-wp-webfonts.php | 2 +- .../enqueue-webfonts-listed-in-theme-json.php | 12 ++++++------ .../register-webfonts-from-theme-json.php | 6 +++--- lib/experimental/webfonts-utils.php | 8 ++++---- ...queue-only-webfonts-listed-in-theme-json-test.php | 6 +++--- 7 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index f297f33bf59a59..78f36419de19aa 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -11,7 +11,7 @@ * @param array $data The global styles. * @return array The global styles with missing fonts data. */ -function gutenberg_add_registered_webfonts_to_theme_json( $data ) { +function _gutenberg_add_registered_webfonts_to_theme_json( $data ) { $registered_font_families = wp_webfonts()->get_all_webfonts(); if ( empty( $registered_font_families ) ) { @@ -78,7 +78,7 @@ function( $font_face ) { foreach ( $registered_font_faces as $registered_font_face ) { $registered_font_face = _wp_array_keys_to_camel_case( $registered_font_face ); - if ( false !== gutenberg_find_webfont( $font_faces_in_theme_json, $registered_font_face ) ) { + if ( false !== _gutenberg_find_webfont( $font_faces_in_theme_json, $registered_font_face ) ) { // Webfont is already there, so let's not add it. continue; } diff --git a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php index fb2416c7aa62fd..8e49bc7e87c808 100644 --- a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php @@ -38,10 +38,10 @@ public static function get_theme_data( $deprecated = array(), $settings = array( $theme_json_data = static::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) ); $original_theme_json = new WP_Theme_JSON_Gutenberg( $theme_json_data ); - gutenberg_register_webfonts_from_theme_json( $original_theme_json->get_settings() ); + _gutenberg_register_webfonts_from_theme_json( $original_theme_json->get_settings() ); if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { - $theme_json_data = gutenberg_add_registered_webfonts_to_theme_json( $theme_json_data ); + $theme_json_data = _gutenberg_add_registered_webfonts_to_theme_json( $theme_json_data ); } static::$theme = new WP_Theme_JSON_Gutenberg( $theme_json_data ); @@ -52,7 +52,7 @@ public static function get_theme_data( $deprecated = array(), $settings = array( $parent_theme_json_data = static::translate( $parent_theme_json_data, wp_get_theme()->parent()->get( 'TextDomain' ) ); $parent_theme = new WP_Theme_JSON_Gutenberg( $parent_theme_json_data ); - gutenberg_register_webfonts_from_theme_json( $parent_theme->get_settings() ); + _gutenberg_register_webfonts_from_theme_json( $parent_theme->get_settings() ); // Merge the child theme.json into the parent theme.json. // The child theme takes precedence over the parent. diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 97ae523d93bd54..87b1f7b293bede 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -272,7 +272,7 @@ private function unregister_font_face( $font_face_to_unregister ) { $font_family_slug = $this->get_font_slug( $font_face_to_unregister ); $font_family = $this->registered_webfonts[ $font_family_slug ]; - $index = gutenberg_find_webfont( $font_family, $font_face_to_unregister ); + $index = _gutenberg_find_webfont( $font_family, $font_face_to_unregister ); // Font face not found. if ( false === $index ) { diff --git a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php index 024574fba57f8a..28baea3dcbfebe 100644 --- a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php +++ b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php @@ -12,7 +12,7 @@ * * @return boolean True if registered programmatically, false otherwise. */ -function gutenberg_is_externally_registered_webfont( $webfont ) { +function _gutenberg_is_externally_registered_webfont( $webfont ) { return isset( $webfont['origin'] ) && 'gutenberg_wp_webfonts_api' === $webfont['origin']; } @@ -21,7 +21,7 @@ function gutenberg_is_externally_registered_webfont( $webfont ) { * * Enqueued webfonts will end up in the front-end as inlined CSS. */ -function gutenberg_enqueue_webfonts_listed_in_theme_json() { +function _gutenberg_enqueue_webfonts_listed_in_theme_json() { $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings(); // Bail out early if there are no settings for webfonts. @@ -33,7 +33,7 @@ function gutenberg_enqueue_webfonts_listed_in_theme_json() { foreach ( $settings['typography']['fontFamilies'] as $font_families ) { foreach ( $font_families as $font_family ) { // Skip dynamically included font families. We only want to enqueue explicitly added fonts. - if ( gutenberg_is_externally_registered_webfont( $font_family ) ) { + if ( _gutenberg_is_externally_registered_webfont( $font_family ) ) { continue; } @@ -52,7 +52,7 @@ function gutenberg_enqueue_webfonts_listed_in_theme_json() { // Loop through all the font faces, enqueueing each one of them. foreach ( $font_family['fontFaces'] as $font_face ) { // Skip dynamically included font faces. We only want to enqueue the font faces listed in theme.json. - if ( gutenberg_is_externally_registered_webfont( $font_face ) ) { + if ( _gutenberg_is_externally_registered_webfont( $font_face ) ) { continue; } @@ -62,12 +62,12 @@ function gutenberg_enqueue_webfonts_listed_in_theme_json() { } } -add_filter( 'wp_loaded', 'gutenberg_enqueue_webfonts_listed_in_theme_json' ); +add_filter( 'wp_loaded', '_gutenberg_enqueue_webfonts_listed_in_theme_json' ); // No need to run this -- opening the admin interface enqueues all the webfonts. add_action( 'admin_init', function() { - remove_filter( 'wp_loaded', 'gutenberg_enqueue_webfonts_listed_in_theme_json' ); + remove_filter( 'wp_loaded', '_gutenberg_enqueue_webfonts_listed_in_theme_json' ); } ); diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index d00f3ad7b319a4..2d3dda251a12b0 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -10,7 +10,7 @@ * * @param array $settings The theme.json file. */ -function gutenberg_register_webfonts_from_theme_json( $settings ) { +function _gutenberg_register_webfonts_from_theme_json( $settings ) { // If in the editor, add webfonts defined in variations. if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { $variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations(); @@ -61,7 +61,7 @@ function gutenberg_register_webfonts_from_theme_json( $settings ) { foreach ( $font_family['fontFaces'] as $font_face ) { $font_face['provider'] = $font_family['provider']; - $font_face = gutenberg_resolve_font_face_uri( $font_face ); + $font_face = _gutenberg_resolve_font_face_uri( $font_face ); $font_face = _wp_array_keys_to_kebab_case( $font_face ); $font_faces_to_register[] = $font_face; @@ -76,7 +76,7 @@ function gutenberg_register_webfonts_from_theme_json( $settings ) { foreach ( $font_family['fontFaces'] as $font_face ) { if ( isset( $font_face['provider'] ) ) { - $font_face = gutenberg_resolve_font_face_uri( $font_face ); + $font_face = _gutenberg_resolve_font_face_uri( $font_face ); $font_face = _wp_array_keys_to_kebab_case( $font_face ); $font_faces_to_register[] = $font_face; diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index 8fda17d46f6932..fd514af20107b3 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -31,7 +31,7 @@ function _wp_array_keys_to_kebab_case( $array ) { * * @return array The URI-resolved font face. */ -function gutenberg_resolve_font_face_uri( $font_face ) { +function _gutenberg_resolve_font_face_uri( $font_face ) { if ( empty( $font_face['src'] ) ) { return $font_face; } @@ -58,7 +58,7 @@ function gutenberg_resolve_font_face_uri( $font_face ) { * * @return boolean True if they're equal, false otherwise. */ -function gutenberg_is_webfont_equal( $a, $b, $is_camel_case = true ) { +function _gutenberg_is_webfont_equal( $a, $b, $is_camel_case = true ) { $equality_attrs = $is_camel_case ? array( 'fontFamily', 'fontStyle', @@ -86,7 +86,7 @@ function gutenberg_is_webfont_equal( $a, $b, $is_camel_case = true ) { * * @return integer|false The index of $webfont in $webfonts if found. False otherwise. */ -function gutenberg_find_webfont( $webfonts, $webfont_to_find ) { +function _gutenberg_find_webfont( $webfonts, $webfont_to_find ) { if ( ! count( $webfonts ) ) { return false; } @@ -94,7 +94,7 @@ function gutenberg_find_webfont( $webfonts, $webfont_to_find ) { $is_camel_case = isset( $webfonts[0]['fontFamily'] ); foreach ( $webfonts as $index => $webfont ) { - if ( gutenberg_is_webfont_equal( $webfont, $webfont_to_find, $is_camel_case ) ) { + if ( _gutenberg_is_webfont_equal( $webfont, $webfont_to_find, $is_camel_case ) ) { return $index; } } diff --git a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php index 5dbb91d9ef26e0..516be0361c3951 100644 --- a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php +++ b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php @@ -12,9 +12,9 @@ * Tests the enqueueing of webfonts listed in theme.json * * @group webfonts - * @covers gutenberg_register_webfonts_from_theme_json - * gutenberg_add_registered_webfonts_to_theme_json - * gutenberg_enqueue_webfonts_listed_in_theme_json + * @covers _gutenberg_register_webfonts_from_theme_json + * _gutenberg_add_registered_webfonts_to_theme_json + * _gutenberg_enqueue_webfonts_listed_in_theme_json */ class Enqueue_Only_Webfonts_Listed_In_Theme_JSON_Test extends WP_UnitTestCase { /** From ed7e81c8354e2bf64629db9f75f0a5492b824b47 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 18 Apr 2022 10:39:17 +0300 Subject: [PATCH 11/37] Rename _gutenberg_register_webfonts_from_theme_json function --- lib/experimental/class-wp-theme-json-resolver-gutenberg.php | 4 ++-- lib/experimental/register-webfonts-from-theme-json.php | 2 +- phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php index 8e49bc7e87c808..653ab8c5dbc5d8 100644 --- a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php @@ -38,7 +38,7 @@ public static function get_theme_data( $deprecated = array(), $settings = array( $theme_json_data = static::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) ); $original_theme_json = new WP_Theme_JSON_Gutenberg( $theme_json_data ); - _gutenberg_register_webfonts_from_theme_json( $original_theme_json->get_settings() ); + _wp_register_webfonts_from_theme_json( $original_theme_json->get_settings() ); if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { $theme_json_data = _gutenberg_add_registered_webfonts_to_theme_json( $theme_json_data ); @@ -52,7 +52,7 @@ public static function get_theme_data( $deprecated = array(), $settings = array( $parent_theme_json_data = static::translate( $parent_theme_json_data, wp_get_theme()->parent()->get( 'TextDomain' ) ); $parent_theme = new WP_Theme_JSON_Gutenberg( $parent_theme_json_data ); - _gutenberg_register_webfonts_from_theme_json( $parent_theme->get_settings() ); + _wp_register_webfonts_from_theme_json( $parent_theme->get_settings() ); // Merge the child theme.json into the parent theme.json. // The child theme takes precedence over the parent. diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 2d3dda251a12b0..07b2736807858d 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -10,7 +10,7 @@ * * @param array $settings The theme.json file. */ -function _gutenberg_register_webfonts_from_theme_json( $settings ) { +function _wp_register_webfonts_from_theme_json( $settings ) { // If in the editor, add webfonts defined in variations. if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { $variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations(); diff --git a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php index 516be0361c3951..2c23bd1fde2106 100644 --- a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php +++ b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php @@ -12,7 +12,7 @@ * Tests the enqueueing of webfonts listed in theme.json * * @group webfonts - * @covers _gutenberg_register_webfonts_from_theme_json + * @covers _wp_register_webfonts_from_theme_json * _gutenberg_add_registered_webfonts_to_theme_json * _gutenberg_enqueue_webfonts_listed_in_theme_json */ From a7d7c51fcc5dffd4af223641fd9058de3c7597b2 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 18 Apr 2022 10:39:51 +0300 Subject: [PATCH 12/37] function_exists condition for _wp_register_webfonts_from_theme_json --- .../register-webfonts-from-theme-json.php | 130 +++++++++--------- 1 file changed, 66 insertions(+), 64 deletions(-) diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 07b2736807858d..55bb0b9cbd59c9 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -5,85 +5,87 @@ * @package gutenberg */ -/** - * Register webfonts defined in theme.json - * - * @param array $settings The theme.json file. - */ -function _wp_register_webfonts_from_theme_json( $settings ) { - // If in the editor, add webfonts defined in variations. - if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { - $variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations(); - - foreach ( $variations as $variation ) { - - // Sanity check: Skip if fontFamilies are not defined in the variation. - if ( - empty( $variation['settings'] ) || - empty( $variation['settings']['typography'] ) || - empty( $variation['settings']['typography']['fontFamilies'] ) - ) { - continue; - } +if ( ! function_exists( '_wp_register_webfonts_from_theme_json' ) ) { + /** + * Register webfonts defined in theme.json + * + * @param array $settings The theme.json file. + */ + function _wp_register_webfonts_from_theme_json( $settings ) { + // If in the editor, add webfonts defined in variations. + if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { + $variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations(); + + foreach ( $variations as $variation ) { + + // Sanity check: Skip if fontFamilies are not defined in the variation. + if ( + empty( $variation['settings'] ) || + empty( $variation['settings']['typography'] ) || + empty( $variation['settings']['typography']['fontFamilies'] ) + ) { + continue; + } - // Merge the variation settings with the global settings. - $settings['typography'] = empty( $settings['typography'] ) ? array() : $settings['typography']; - $settings['typography']['fontFamilies'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']; - $settings['typography']['fontFamilies']['theme'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']['theme']; - $settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] ); + // Merge the variation settings with the global settings. + $settings['typography'] = empty( $settings['typography'] ) ? array() : $settings['typography']; + $settings['typography']['fontFamilies'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']; + $settings['typography']['fontFamilies']['theme'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']['theme']; + $settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] ); - // Make sure there are no duplicates. - $settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] ); + // Make sure there are no duplicates. + $settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] ); + } } - } - // Bail out early if there are no settings for webfonts. - if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) { - return; - } + // Bail out early if there are no settings for webfonts. + if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) { + return; + } - $font_faces_to_register = array(); + $font_faces_to_register = array(); - foreach ( $settings['typography']['fontFamilies'] as $font_families_by_origin ) { - foreach ( $font_families_by_origin as $font_family ) { - if ( isset( $font_family['provider'] ) ) { - if ( empty( $font_family['fontFaces'] ) ) { - trigger_error( - sprintf( - /* translators: %s: font family name */ - esc_html__( 'The "%s" font family specifies a provider, but no font faces.', 'gutenberg' ), - esc_html( $font_family['fontFamily'] ) - ) - ); + foreach ( $settings['typography']['fontFamilies'] as $font_families_by_origin ) { + foreach ( $font_families_by_origin as $font_family ) { + if ( isset( $font_family['provider'] ) ) { + if ( empty( $font_family['fontFaces'] ) ) { + trigger_error( + sprintf( + /* translators: %s: font family name */ + esc_html__( 'The "%s" font family specifies a provider, but no font faces.', 'gutenberg' ), + esc_html( $font_family['fontFamily'] ) + ) + ); - continue; - } + continue; + } - foreach ( $font_family['fontFaces'] as $font_face ) { - $font_face['provider'] = $font_family['provider']; - $font_face = _gutenberg_resolve_font_face_uri( $font_face ); - $font_face = _wp_array_keys_to_kebab_case( $font_face ); + foreach ( $font_family['fontFaces'] as $font_face ) { + $font_face['provider'] = $font_family['provider']; + $font_face = _gutenberg_resolve_font_face_uri( $font_face ); + $font_face = _wp_array_keys_to_kebab_case( $font_face ); - $font_faces_to_register[] = $font_face; - } + $font_faces_to_register[] = $font_face; + } - continue; - } + continue; + } - if ( ! isset( $font_family['fontFaces'] ) ) { - continue; - } + if ( ! isset( $font_family['fontFaces'] ) ) { + continue; + } - foreach ( $font_family['fontFaces'] as $font_face ) { - if ( isset( $font_face['provider'] ) ) { - $font_face = _gutenberg_resolve_font_face_uri( $font_face ); - $font_face = _wp_array_keys_to_kebab_case( $font_face ); + foreach ( $font_family['fontFaces'] as $font_face ) { + if ( isset( $font_face['provider'] ) ) { + $font_face = _gutenberg_resolve_font_face_uri( $font_face ); + $font_face = _wp_array_keys_to_kebab_case( $font_face ); - $font_faces_to_register[] = $font_face; + $font_faces_to_register[] = $font_face; + } } } } - } - wp_register_webfonts( $font_faces_to_register ); + wp_register_webfonts( $font_faces_to_register ); + } } From 5caadad204119bba494800cd31aa311e9e75c4c2 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 18 Apr 2022 10:41:28 +0300 Subject: [PATCH 13/37] Rename _gutenberg_enqueue_webfonts_listed_in_theme_json function --- lib/experimental/enqueue-webfonts-listed-in-theme-json.php | 6 +++--- phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php index 28baea3dcbfebe..17b4ea24514c1c 100644 --- a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php +++ b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php @@ -21,7 +21,7 @@ function _gutenberg_is_externally_registered_webfont( $webfont ) { * * Enqueued webfonts will end up in the front-end as inlined CSS. */ -function _gutenberg_enqueue_webfonts_listed_in_theme_json() { +function _wp_enqueue_webfonts_listed_in_theme_json() { $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings(); // Bail out early if there are no settings for webfonts. @@ -62,12 +62,12 @@ function _gutenberg_enqueue_webfonts_listed_in_theme_json() { } } -add_filter( 'wp_loaded', '_gutenberg_enqueue_webfonts_listed_in_theme_json' ); +add_filter( 'wp_loaded', '_wp_enqueue_webfonts_listed_in_theme_json' ); // No need to run this -- opening the admin interface enqueues all the webfonts. add_action( 'admin_init', function() { - remove_filter( 'wp_loaded', '_gutenberg_enqueue_webfonts_listed_in_theme_json' ); + remove_filter( 'wp_loaded', '_wp_enqueue_webfonts_listed_in_theme_json' ); } ); diff --git a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php index 2c23bd1fde2106..bb5819846eef53 100644 --- a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php +++ b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php @@ -14,7 +14,7 @@ * @group webfonts * @covers _wp_register_webfonts_from_theme_json * _gutenberg_add_registered_webfonts_to_theme_json - * _gutenberg_enqueue_webfonts_listed_in_theme_json + * _wp_enqueue_webfonts_listed_in_theme_json */ class Enqueue_Only_Webfonts_Listed_In_Theme_JSON_Test extends WP_UnitTestCase { /** From c5a5b2b5444afca833fe493b214ab980792eac0e Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 18 Apr 2022 10:42:58 +0300 Subject: [PATCH 14/37] Add function_exists check for _wp_enqueue_webfonts_listed_in_theme_json --- .../enqueue-webfonts-listed-in-theme-json.php | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php index 17b4ea24514c1c..eb6b40b281fe59 100644 --- a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php +++ b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php @@ -16,47 +16,49 @@ function _gutenberg_is_externally_registered_webfont( $webfont ) { return isset( $webfont['origin'] ) && 'gutenberg_wp_webfonts_api' === $webfont['origin']; } -/** - * Enqueue webfonts listed in theme.json. - * - * Enqueued webfonts will end up in the front-end as inlined CSS. - */ -function _wp_enqueue_webfonts_listed_in_theme_json() { - $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings(); - - // Bail out early if there are no settings for webfonts. - if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) { - return; - } +if ( ! function_exists( '_wp_enqueue_webfonts_listed_in_theme_json' ) ) { + /** + * Enqueue webfonts listed in theme.json. + * + * Enqueued webfonts will end up in the front-end as inlined CSS. + */ + function _wp_enqueue_webfonts_listed_in_theme_json() { + $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings(); - // Look for fontFamilies. - foreach ( $settings['typography']['fontFamilies'] as $font_families ) { - foreach ( $font_families as $font_family ) { - // Skip dynamically included font families. We only want to enqueue explicitly added fonts. - if ( _gutenberg_is_externally_registered_webfont( $font_family ) ) { - continue; - } + // Bail out early if there are no settings for webfonts. + if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) { + return; + } - // If no font faces defined. - if ( ! isset( $font_family['fontFaces'] ) ) { - // And the font family is registered. - if ( ! wp_webfonts()->is_font_family_registered( $font_family['fontFamily'] ) ) { + // Look for fontFamilies. + foreach ( $settings['typography']['fontFamilies'] as $font_families ) { + foreach ( $font_families as $font_family ) { + // Skip dynamically included font families. We only want to enqueue explicitly added fonts. + if ( _gutenberg_is_externally_registered_webfont( $font_family ) ) { continue; } - // Enqueue the entire family. - wp_webfonts()->enqueue_webfont( $font_family ); - continue; - } + // If no font faces defined. + if ( ! isset( $font_family['fontFaces'] ) ) { + // And the font family is registered. + if ( ! wp_webfonts()->is_font_family_registered( $font_family['fontFamily'] ) ) { + continue; + } - // Loop through all the font faces, enqueueing each one of them. - foreach ( $font_family['fontFaces'] as $font_face ) { - // Skip dynamically included font faces. We only want to enqueue the font faces listed in theme.json. - if ( _gutenberg_is_externally_registered_webfont( $font_face ) ) { + // Enqueue the entire family. + wp_webfonts()->enqueue_webfont( $font_family ); continue; } - wp_webfonts()->enqueue_webfont( $font_family, $font_face ); + // Loop through all the font faces, enqueueing each one of them. + foreach ( $font_family['fontFaces'] as $font_face ) { + // Skip dynamically included font faces. We only want to enqueue the font faces listed in theme.json. + if ( _gutenberg_is_externally_registered_webfont( $font_face ) ) { + continue; + } + + wp_webfonts()->enqueue_webfont( $font_family, $font_face ); + } } } } From 6a59c6cd9b26cbd2f52d385891aebcc563d817c2 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 18 Apr 2022 10:44:38 +0300 Subject: [PATCH 15/37] Rename _gutenberg_add_registered_webfonts_to_theme_json function --- lib/experimental/add-registered-webfonts-to-theme-json.php | 2 +- lib/experimental/class-wp-theme-json-resolver-gutenberg.php | 2 +- phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index 78f36419de19aa..b9bec557ff2025 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -11,7 +11,7 @@ * @param array $data The global styles. * @return array The global styles with missing fonts data. */ -function _gutenberg_add_registered_webfonts_to_theme_json( $data ) { +function _wp_add_registered_webfonts_to_theme_json( $data ) { $registered_font_families = wp_webfonts()->get_all_webfonts(); if ( empty( $registered_font_families ) ) { diff --git a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php index 653ab8c5dbc5d8..0dfd8e895a3094 100644 --- a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php @@ -41,7 +41,7 @@ public static function get_theme_data( $deprecated = array(), $settings = array( _wp_register_webfonts_from_theme_json( $original_theme_json->get_settings() ); if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { - $theme_json_data = _gutenberg_add_registered_webfonts_to_theme_json( $theme_json_data ); + $theme_json_data = _wp_add_registered_webfonts_to_theme_json( $theme_json_data ); } static::$theme = new WP_Theme_JSON_Gutenberg( $theme_json_data ); diff --git a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php index bb5819846eef53..a425744a72428d 100644 --- a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php +++ b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php @@ -13,7 +13,7 @@ * * @group webfonts * @covers _wp_register_webfonts_from_theme_json - * _gutenberg_add_registered_webfonts_to_theme_json + * _wp_add_registered_webfonts_to_theme_json * _wp_enqueue_webfonts_listed_in_theme_json */ class Enqueue_Only_Webfonts_Listed_In_Theme_JSON_Test extends WP_UnitTestCase { From 182507b59a8bf12c60d58113a915aa8aa11f4b07 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 18 Apr 2022 10:45:38 +0300 Subject: [PATCH 16/37] Add function_exists check for _wp_add_registered_webfonts_to_theme_json --- .../add-registered-webfonts-to-theme-json.php | 138 +++++++++--------- 1 file changed, 70 insertions(+), 68 deletions(-) diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index b9bec557ff2025..3c4b0910b09a52 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -5,89 +5,91 @@ * @package gutenberg */ -/** - * Add missing fonts data to the global styles. - * - * @param array $data The global styles. - * @return array The global styles with missing fonts data. - */ -function _wp_add_registered_webfonts_to_theme_json( $data ) { - $registered_font_families = wp_webfonts()->get_all_webfonts(); - - if ( empty( $registered_font_families ) ) { - return $data; - } - - // Make sure the path to settings.typography.fontFamilies.theme exists - // before adding missing fonts. - if ( empty( $data['settings'] ) ) { - $data['settings'] = array(); - } - if ( empty( $data['settings']['typography'] ) ) { - $data['settings']['typography'] = array(); - } - if ( empty( $data['settings']['typography']['fontFamilies'] ) ) { - $data['settings']['typography']['fontFamilies'] = array(); - } - +if ( ! function_exists( '_wp_add_registered_webfonts_to_theme_json' ) ) { /** - * Map the font families by slug to their corresponding index - * in theme.json, so we can avoid looping theme.json looking for - * font families every time we want to register a face. + * Add missing fonts data to the global styles. + * + * @param array $data The global styles. + * @return array The global styles with missing fonts data. */ - $font_family_indexes_in_theme_json = array(); + function _wp_add_registered_webfonts_to_theme_json( $data ) { + $registered_font_families = wp_webfonts()->get_all_webfonts(); - foreach ( $data['settings']['typography']['fontFamilies'] as $index => $family ) { - $font_family_indexes_in_theme_json[ wp_webfonts()->get_font_slug( $family ) ] = $index; - } + if ( empty( $registered_font_families ) ) { + return $data; + } - foreach ( $registered_font_families as $slug => $registered_font_faces ) { - // Font family not in theme.json, so let's add it. - if ( ! isset( $font_family_indexes_in_theme_json[ $slug ] ) ) { - $family_name = $registered_font_faces[0]['font-family']; - - $data['settings']['typography']['fontFamilies'][] = array( - 'origin' => 'gutenberg_wp_webfonts_api', - 'fontFamily' => str_contains( $family_name, ' ' ) ? "'{$family_name}'" : $family_name, - 'name' => $family_name, - 'slug' => $slug, - 'fontFaces' => array_map( - function( $font_face ) { - $font_face['origin'] = 'gutenberg_wp_webfonts_api'; - - return _wp_array_keys_to_camel_case( $font_face ); - }, - $registered_font_faces - ), - ); - - continue; + // Make sure the path to settings.typography.fontFamilies.theme exists + // before adding missing fonts. + if ( empty( $data['settings'] ) ) { + $data['settings'] = array(); + } + if ( empty( $data['settings']['typography'] ) ) { + $data['settings']['typography'] = array(); + } + if ( empty( $data['settings']['typography']['fontFamilies'] ) ) { + $data['settings']['typography']['fontFamilies'] = array(); } - $font_family_index_in_theme_json = $font_family_indexes_in_theme_json[ $slug ]; - $font_family_in_theme_json = $data['settings']['typography']['fontFamilies'][ $font_family_index_in_theme_json ]; + /** + * Map the font families by slug to their corresponding index + * in theme.json, so we can avoid looping theme.json looking for + * font families every time we want to register a face. + */ + $font_family_indexes_in_theme_json = array(); - if ( ! isset( $font_family_in_theme_json['fontFaces'] ) ) { - // Font family exists, but it's not declaring any font face - // Let's not get in their way. - continue; + foreach ( $data['settings']['typography']['fontFamilies'] as $index => $family ) { + $font_family_indexes_in_theme_json[ wp_webfonts()->get_font_slug( $family ) ] = $index; } - $font_faces_in_theme_json = $font_family_in_theme_json['fontFaces']; + foreach ( $registered_font_families as $slug => $registered_font_faces ) { + // Font family not in theme.json, so let's add it. + if ( ! isset( $font_family_indexes_in_theme_json[ $slug ] ) ) { + $family_name = $registered_font_faces[0]['font-family']; + + $data['settings']['typography']['fontFamilies'][] = array( + 'origin' => 'gutenberg_wp_webfonts_api', + 'fontFamily' => str_contains( $family_name, ' ' ) ? "'{$family_name}'" : $family_name, + 'name' => $family_name, + 'slug' => $slug, + 'fontFaces' => array_map( + function( $font_face ) { + $font_face['origin'] = 'gutenberg_wp_webfonts_api'; + + return _wp_array_keys_to_camel_case( $font_face ); + }, + $registered_font_faces + ), + ); + + continue; + } - foreach ( $registered_font_faces as $registered_font_face ) { - $registered_font_face = _wp_array_keys_to_camel_case( $registered_font_face ); + $font_family_index_in_theme_json = $font_family_indexes_in_theme_json[ $slug ]; + $font_family_in_theme_json = $data['settings']['typography']['fontFamilies'][ $font_family_index_in_theme_json ]; - if ( false !== _gutenberg_find_webfont( $font_faces_in_theme_json, $registered_font_face ) ) { - // Webfont is already there, so let's not add it. + if ( ! isset( $font_family_in_theme_json['fontFaces'] ) ) { + // Font family exists, but it's not declaring any font face + // Let's not get in their way. continue; } - $registered_font_face['origin'] = 'gutenberg_wp_webfonts_api'; + $font_faces_in_theme_json = $font_family_in_theme_json['fontFaces']; + + foreach ( $registered_font_faces as $registered_font_face ) { + $registered_font_face = _wp_array_keys_to_camel_case( $registered_font_face ); - $data['settings']['typography']['fontFamilies'][ $font_family_index_in_theme_json ]['fontFaces'][] = $registered_font_face; + if ( false !== _gutenberg_find_webfont( $font_faces_in_theme_json, $registered_font_face ) ) { + // Webfont is already there, so let's not add it. + continue; + } + + $registered_font_face['origin'] = 'gutenberg_wp_webfonts_api'; + + $data['settings']['typography']['fontFamilies'][ $font_family_index_in_theme_json ]['fontFaces'][] = $registered_font_face; + } } - } - return $data; + return $data; + } } From 7f13181006420b71c797ca498223b7770f0d9a29 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 18 Apr 2022 11:35:21 +0300 Subject: [PATCH 17/37] Fix registering webfonts from styles variations --- ...class-wp-theme-json-resolver-gutenberg.php | 27 +++++++++++++ .../register-webfonts-from-theme-json.php | 38 +++++-------------- 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php index 0dfd8e895a3094..d2a9935d83f442 100644 --- a/lib/experimental/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/experimental/class-wp-theme-json-resolver-gutenberg.php @@ -106,4 +106,31 @@ public static function get_theme_data( $deprecated = array(), $settings = array( return $with_theme_supports; } + /** + * There are three sources of data (origins) for a site: + * default, theme, and custom. The custom's has higher priority + * than the theme's, and the theme's higher than defaults's. + * + * Unlike the getters {@link get_core_data}, + * {@link get_theme_data}, and {@link get_user_data}, + * this method returns data after it has been merged + * with the previous origins. This means that if the same piece of data + * is declared in different origins (user, theme, and core), + * the last origin overrides the previous. + * + * For example, if the user has set a background color + * for the paragraph block, and the theme has done it as well, + * the user preference wins. + * + * @param string $origin Optional. To what level should we merge data. + * Valid values are 'theme' or 'custom'. + * Default is 'custom'. + * @return WP_Theme_JSON_Gutenberg + */ + public static function get_merged_data( $origin = 'custom' ) { + $result = parent::get_merged_data( $origin ); + _wp_register_webfonts_from_theme_json( $result->get_settings() ); + + return $result; + } } diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 55bb0b9cbd59c9..3479d8b075296a 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -47,45 +47,25 @@ function _wp_register_webfonts_from_theme_json( $settings ) { foreach ( $settings['typography']['fontFamilies'] as $font_families_by_origin ) { foreach ( $font_families_by_origin as $font_family ) { - if ( isset( $font_family['provider'] ) ) { - if ( empty( $font_family['fontFaces'] ) ) { - trigger_error( - sprintf( - /* translators: %s: font family name */ - esc_html__( 'The "%s" font family specifies a provider, but no font faces.', 'gutenberg' ), - esc_html( $font_family['fontFamily'] ) - ) - ); - - continue; - } - - foreach ( $font_family['fontFaces'] as $font_face ) { - $font_face['provider'] = $font_family['provider']; - $font_face = _gutenberg_resolve_font_face_uri( $font_face ); - $font_face = _wp_array_keys_to_kebab_case( $font_face ); - - $font_faces_to_register[] = $font_face; - } - + // Skip if no `fontFaces` are defined. + if ( empty( $font_family['fontFaces'] ) ) { continue; } - if ( ! isset( $font_family['fontFaces'] ) ) { - continue; + // Fallback to the `local` provider if no `provider` is defined. + if ( ! isset( $font_family['provider'] ) ) { + $font_family['provider'] = 'local'; } foreach ( $font_family['fontFaces'] as $font_face ) { - if ( isset( $font_face['provider'] ) ) { - $font_face = _gutenberg_resolve_font_face_uri( $font_face ); - $font_face = _wp_array_keys_to_kebab_case( $font_face ); + $font_face['provider'] = $font_family['provider']; + $font_face = _gutenberg_resolve_font_face_uri( $font_face ); + $font_face = _wp_array_keys_to_kebab_case( $font_face ); - $font_faces_to_register[] = $font_face; - } + $font_faces_to_register[] = $font_face; } } } - wp_register_webfonts( $font_faces_to_register ); } } From 0319d5b5cb7b474ab84e0c423bb9d4c77c6f7fb9 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Tue, 19 Apr 2022 09:53:22 +0300 Subject: [PATCH 18/37] Update lib/experimental/register-webfonts-from-theme-json.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- lib/experimental/register-webfonts-from-theme-json.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 3479d8b075296a..444da8738b66e0 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -19,11 +19,7 @@ function _wp_register_webfonts_from_theme_json( $settings ) { foreach ( $variations as $variation ) { // Sanity check: Skip if fontFamilies are not defined in the variation. - if ( - empty( $variation['settings'] ) || - empty( $variation['settings']['typography'] ) || - empty( $variation['settings']['typography']['fontFamilies'] ) - ) { + if ( empty( $variation['settings']['typography']['fontFamilies'] ) ) { continue; } From ef407bd68034a1424caf7597f0e694b195c1c65d Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Tue, 19 Apr 2022 09:53:31 +0300 Subject: [PATCH 19/37] Update lib/experimental/add-registered-webfonts-to-theme-json.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- lib/experimental/add-registered-webfonts-to-theme-json.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index 3c4b0910b09a52..965ec6e0a17ffc 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -31,7 +31,7 @@ function _wp_add_registered_webfonts_to_theme_json( $data ) { $data['settings']['typography']['fontFamilies'] = array(); } - /** + /* * Map the font families by slug to their corresponding index * in theme.json, so we can avoid looping theme.json looking for * font families every time we want to register a face. From 658b6ee4b3823761bbf1ee44aff0a77d3640862f Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Tue, 19 Apr 2022 09:55:37 +0300 Subject: [PATCH 20/37] Rename unregister_font_family to remove_font_family --- lib/experimental/class-wp-webfonts.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 87b1f7b293bede..b7ccffecf636da 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -173,7 +173,7 @@ public function enqueue_webfont( $font_family_name, $font_face = null ) { // Enqueueing the font family completely. if ( ! $font_face ) { - $font_family_to_enqueue = $this->unregister_font_family( $font_family_name ); + $font_family_to_enqueue = $this->remove_font_family( $font_family_name ); $this->enqueued_webfonts[ $slug ] = $font_family_to_enqueue; return true; @@ -249,7 +249,7 @@ public static function get_font_slug( $to_convert ) { * @param string $font_family_name The font family, by name, to unregister. * @return array[]|false The font face objects of the family if unregistered, false otherwise. */ - private function unregister_font_family( $font_family_name ) { + private function remove_font_family( $font_family_name ) { $slug = $this->get_font_slug( $font_family_name ); if ( ! isset( $this->registered_webfonts[ $slug ] ) ) { From bea59decf868f803902ac0cb9b58b4c075d1a21d Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Tue, 19 Apr 2022 09:56:53 +0300 Subject: [PATCH 21/37] Update lib/experimental/webfonts-utils.php Co-authored-by: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> --- lib/experimental/webfonts-utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index fd514af20107b3..495f06d0e0fac9 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -114,7 +114,7 @@ function _wp_array_keys_to_camel_case( $array ) { $camel_cased_array = array(); foreach ( $array as $key => $value ) { - $camel_cased_array[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value; + $camel_cased_array[ _wp_to_kebab_case( $key ) ] = $value; } return $camel_cased_array; From f55f4da52a7b94fe4d27f121fd9bcb3061b76bff Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Tue, 19 Apr 2022 11:40:48 +0300 Subject: [PATCH 22/37] This has changed --- phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php index a425744a72428d..64333e9e593b0b 100644 --- a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php +++ b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php @@ -200,7 +200,7 @@ public function test_register_and_enqueue_font_faces_through_different_providers $expected = << -@font-face{font-family:Roboto;font-style:bold;font-weight:900;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-through-different-providers/assets/fonts/Roboto-Bold.ttf') format('truetype');}@font-face{font-family:Roboto;font-style:regular;font-weight:400;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-through-different-providers/assets/fonts/Roboto-Regular.ttf') format('truetype');} +@font-face{font-family:Roboto;font-style:regular;font-weight:400;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-through-different-providers/assets/fonts/Roboto-Regular.ttf') format('truetype');}@font-face{font-family:Roboto;font-style:bold;font-weight:900;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-through-different-providers/assets/fonts/Roboto-Bold.ttf') format('truetype');}\n EOF; From ae4238f713f55d24ebfedc888c54aa55ee853cf1 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Tue, 19 Apr 2022 12:08:42 +0300 Subject: [PATCH 23/37] fix indentation --- lib/experimental/register-webfonts-from-theme-json.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 444da8738b66e0..9a25c4188cfda1 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -23,11 +23,11 @@ function _wp_register_webfonts_from_theme_json( $settings ) { continue; } - // Merge the variation settings with the global settings. - $settings['typography'] = empty( $settings['typography'] ) ? array() : $settings['typography']; - $settings['typography']['fontFamilies'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']; - $settings['typography']['fontFamilies']['theme'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']['theme']; - $settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] ); + // Merge the variation settings with the global settings. + $settings['typography'] = empty( $settings['typography'] ) ? array() : $settings['typography']; + $settings['typography']['fontFamilies'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']; + $settings['typography']['fontFamilies']['theme'] = empty( $settings['typography']['fontFamilies'] ) ? array() : $settings['typography']['fontFamilies']['theme']; + $settings['typography']['fontFamilies']['theme'] = array_merge( $settings['typography']['fontFamilies']['theme'], $variation['settings']['typography']['fontFamilies']['theme'] ); // Make sure there are no duplicates. $settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] ); From dc148440f85ca08e3dbf4d5cf25bf83d111ce7de Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Tue, 19 Apr 2022 11:30:43 -0500 Subject: [PATCH 24/37] Fixes undefined index notice in _gutenberg_is_webfont_equal(). Adds a guard clause to check if the attribute exists in each webfont before the comparison happens. If no, it bails out, returning false, as there's nothing to compare. Some girl scouting: * Renames the function's properties to be more readable. * Adds `array` type declaration as only arrays are accepted. * A wee bit of alignment for consistency in Core. --- lib/experimental/webfonts-utils.php | 41 +++++++++++++++++------------ 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index 495f06d0e0fac9..2320062d097c9c 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -50,27 +50,34 @@ function _gutenberg_resolve_font_face_uri( $font_face ) { } /** - * Compares two webfonts. + * Compares if the two given webfonts are the equal. * - * @param array $a The first webfont. - * @param array $b The second webfont. - * @param boolean $is_camel_case If the font attributes are in camel case or kebab case. Defaults to camel case. - * - * @return boolean True if they're equal, false otherwise. + * @param array $webfont1 The first webfont. + * @param array $webfont2 The second webfont. + * @param boolean $is_camel_case True if the font attributes are in camel case; else false for kebab case. + * Defaults to camel case. + * @return boolean True if the webfonts are equal, false otherwise. */ -function _gutenberg_is_webfont_equal( $a, $b, $is_camel_case = true ) { - $equality_attrs = $is_camel_case ? array( - 'fontFamily', - 'fontStyle', - 'fontWeight', - ) : array( - 'font-family', - 'font-style', - 'font-weight', - ); +function _gutenberg_is_webfont_equal( array $webfont1, array $webfont2, $is_camel_case = true ) { + $equality_attrs = $is_camel_case + ? array( + 'fontFamily', + 'fontStyle', + 'fontWeight', + ) + : array( + 'font-family', + 'font-style', + 'font-weight', + ); foreach ( $equality_attrs as $attr ) { - if ( $a[ $attr ] !== $b[ $attr ] ) { + // Bail out if the attribute does not exist. + if ( ! isset( $webfont1[ $attr ] ) || ! isset( $webfont2[ $attr ] ) ) { + return false; + } + + if ( $webfont1[ $attr ] !== $webfont2[ $attr ] ) { return false; } } From bd4259e45d78b61d615ad4d4cba27302797f87c8 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Tue, 19 Apr 2022 12:10:00 -0500 Subject: [PATCH 25/37] Uses each `fontFaces` font-family for enqueuing. The font-family in each `fontFaces` may be different than its parent. For example, the parent may have a fallback defined such as "fontFamily": "\"Source Serif Pro\", serif",`. --- .../enqueue-webfonts-listed-in-theme-json.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php index eb6b40b281fe59..68d734d8dc8480 100644 --- a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php +++ b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php @@ -57,7 +57,17 @@ function _wp_enqueue_webfonts_listed_in_theme_json() { continue; } - wp_webfonts()->enqueue_webfont( $font_family, $font_face ); + /* + * Skip if this font-face's font-family is not defined. Why? + * Its font-family may be different from its parent (i.e. `$font_family`). + * For example, the parent may define a fallback such as "serif", + * whereas this font-face may define only the font-family. + */ + if ( ! isset( $font_face['fontFamily'] ) ) { + continue; + } + + wp_webfonts()->enqueue_webfont( $font_face['fontFamily'], $font_face ); } } } From 01abcde0567a3457f377e7cb4a56fbfabd00cbee Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Tue, 19 Apr 2022 13:29:13 -0500 Subject: [PATCH 26/37] Fixes failing test and updates test for Core coding standards. --- .../enqueue-webfonts-listed-in-theme-json.php | 3 +- ...nly-webfonts-listed-in-theme-json-test.php | 76 +++++++++---------- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php index 68d734d8dc8480..a5e5df292ac8c5 100644 --- a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php +++ b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php @@ -59,7 +59,8 @@ function _wp_enqueue_webfonts_listed_in_theme_json() { /* * Skip if this font-face's font-family is not defined. Why? - * Its font-family may be different from its parent (i.e. `$font_family`). + * The font-face's font-family is the key used during the registration + * process. Its font-family may be different from its parent `$font_family`. * For example, the parent may define a fallback such as "serif", * whereas this font-face may define only the font-family. */ diff --git a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php index 64333e9e593b0b..0b11e5d5e4069e 100644 --- a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php +++ b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php @@ -9,14 +9,14 @@ require __DIR__ . '/class-wp-webfonts-mock-provider.php'; /** - * Tests the enqueueing of webfonts listed in theme.json + * Integration tests for the enqueueing of webfonts listed in theme.json. * * @group webfonts * @covers _wp_register_webfonts_from_theme_json - * _wp_add_registered_webfonts_to_theme_json - * _wp_enqueue_webfonts_listed_in_theme_json + * @covers _wp_add_registered_webfonts_to_theme_json + * @covers _wp_enqueue_webfonts_listed_in_theme_json */ -class Enqueue_Only_Webfonts_Listed_In_Theme_JSON_Test extends WP_UnitTestCase { +class Test_WebfontsApi_EnqueueWebfontsListedInThemeJSON extends WP_UnitTestCase { /** * WP_Webfonts instance reference * @@ -48,8 +48,8 @@ class Enqueue_Only_Webfonts_Listed_In_Theme_JSON_Test extends WP_UnitTestCase { /** * Set up the new theme root directory and throw away the WP_Webfonts class. */ - public function setUp() { - parent::setUp(); + public function set_up() { + parent::set_up(); global $wp_styles; @@ -69,14 +69,14 @@ public function setUp() { // /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 () { + $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 ); - $this->queries = array(); + // Clear caches. wp_clean_themes_cache(); unset( $GLOBALS['wp_themes'] ); @@ -85,7 +85,7 @@ public function setUp() { /** * Restores the original theme root and WP_Webfonts instance. */ - public function tearDown() { + public function tear_down() { global $wp_webfonts; global $wp_styles; @@ -97,30 +97,7 @@ public function tearDown() { wp_clean_themes_cache(); unset( $GLOBALS['wp_themes'] ); - parent::tearDown(); - } - - /** - * Switches to $theme_name, runs the necessary hooks - * and generates the styles for it. - * - * The styles will hold the webfonts that will get loaded - * in the front-end, and that's what this test suite is asserting. - * - * @param string $theme_name The theme name. Themes are located in phpunited/data/themedir1. - */ - private function generate_styles_for_theme( $theme_name ) { - switch_theme( $theme_name ); - - if ( file_exists( get_stylesheet_directory() . '/functions.php' ) ) { - require_once get_stylesheet_directory() . '/functions.php'; - } - - do_action( 'after_setup_theme' ); - WP_Theme_JSON_Resolver_Gutenberg::clean_cached_data(); - do_action( 'wp_loaded' ); - - wp_webfonts()->generate_and_enqueue_styles(); + parent::tear_down(); } /** @@ -138,7 +115,7 @@ public function test_enqueue_an_externally_registered_font_family() { EOF; - $this->assertContains( + $this->assertStringContainsString( $expected, get_echo( 'wp_print_styles' ) ); @@ -159,7 +136,7 @@ public function test_enqueue_only_one_of_all_externally_registered_font_faces() EOF; - $this->assertContains( + $this->assertStringContainsString( $expected, get_echo( 'wp_print_styles' ) ); @@ -181,7 +158,7 @@ public function test_register_and_enqueue_font_faces_to_same_provider() { EOF; - $this->assertContains( + $this->assertStringContainsString( $expected, get_echo( 'wp_print_styles' ) ); @@ -200,13 +177,36 @@ public function test_register_and_enqueue_font_faces_through_different_providers $expected = << -@font-face{font-family:Roboto;font-style:regular;font-weight:400;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-through-different-providers/assets/fonts/Roboto-Regular.ttf') format('truetype');}@font-face{font-family:Roboto;font-style:bold;font-weight:900;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-through-different-providers/assets/fonts/Roboto-Bold.ttf') format('truetype');}\n +@font-face{font-family:Roboto;font-style:regular;font-weight:400;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-through-different-providers/assets/fonts/Roboto-Regular.ttf') format('truetype');}@font-face{font-family:Roboto;font-style:bold;font-weight:900;font-display:fallback;src:local(Roboto), url('/wp-content/plugins/gutenberg/phpunit/data/themedir1/register-and-enqueue-through-different-providers/assets/fonts/Roboto-Bold.ttf') format('truetype');} EOF; - $this->assertContains( + $this->assertStringContainsString( $expected, get_echo( 'wp_print_styles' ) ); } + + /** + * Switches to $theme_name, runs the necessary hooks + * and generates the styles for it. + * + * The styles will hold the webfonts that will get loaded + * in the front-end, and that's what this test suite is asserting. + * + * @param string $theme_name The theme name. Themes are located in phpunited/data/themedir1. + */ + private function generate_styles_for_theme( $theme_name ) { + switch_theme( $theme_name ); + + if ( file_exists( get_stylesheet_directory() . '/functions.php' ) ) { + require_once get_stylesheet_directory() . '/functions.php'; + } + + do_action( 'after_setup_theme' ); + WP_Theme_JSON_Resolver_Gutenberg::clean_cached_data(); + do_action( 'wp_loaded' ); + + wp_webfonts()->generate_and_enqueue_styles(); + } } From 39d88e59b4bffa6317d8ae0b97e2f0ecc833739b Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Tue, 19 Apr 2022 14:26:48 -0500 Subject: [PATCH 27/37] Prepped to WP Core coding standards. 1. Added @since annotations. 2. Removed empty line between last @param and @return in DocBlock. 3. Renamed variables that were using PHP reserved key words, such as `$array`. Required to avoid PHP 8.x deprecation notices and PHP 9 fatal errors. 4. Used `empty()` instead of `count()` for readability and consistency. 5. Moved `_wp_array_keys_to_kebab_case()` to group the array key transformation functions. 6. A wee bit of girl scouting in the DocBlocks for readability and consistency. --- .../add-registered-webfonts-to-theme-json.php | 8 ++- lib/experimental/class-wp-webfonts.php | 20 ++++-- .../enqueue-webfonts-listed-in-theme-json.php | 7 +- lib/experimental/webfonts-utils.php | 64 ++++++++++--------- 4 files changed, 58 insertions(+), 41 deletions(-) diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index 965ec6e0a17ffc..7e1aa522591d05 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -7,12 +7,14 @@ if ( ! function_exists( '_wp_add_registered_webfonts_to_theme_json' ) ) { /** - * Add missing fonts data to the global styles. + * Add missing webfonts data to the global styles. + * + * @since 6.0.0 * * @param array $data The global styles. - * @return array The global styles with missing fonts data. + * @return array The global styles with missing webfonts data. */ - function _wp_add_registered_webfonts_to_theme_json( $data ) { + function _wp_add_registered_webfonts_to_theme_json( array $data ) { $registered_font_families = wp_webfonts()->get_all_webfonts(); if ( empty( $registered_font_families ) ) { diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index b7ccffecf636da..9a06134c136551 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -180,7 +180,6 @@ public function enqueue_webfont( $font_family_name, $font_face = null ) { } // Enqueueing a single font face. - $font_face = _wp_array_keys_to_kebab_case( $font_face ); $font_face_to_enqueue = $this->unregister_font_face( $font_face ); @@ -210,6 +209,8 @@ public function enqueue_webfont( $font_family_name, $font_face = null ) { /** * Checks if a font family is registered. * + * @since 6.0.0 + * * @param string $font_family_name The font family name to check in the registry. * @return bool True if found, else false. */ @@ -265,12 +266,18 @@ private function remove_font_family( $font_family_name ) { /** * Unregisters a font face. * - * @param array $font_face_to_unregister The font face object, to unregister. - * @return array|false The font face object if unregistered, false otherwise. + * @since 6.0.0 + * + * @param array $font_face_to_unregister The font face to unregister. + * @return array|false The font face if unregistered, false otherwise. */ - private function unregister_font_face( $font_face_to_unregister ) { + private function unregister_font_face( array $font_face_to_unregister ) { $font_family_slug = $this->get_font_slug( $font_face_to_unregister ); + if ( false === $font_family_slug || ! isset( $this->registered_webfonts[ $font_family_slug ] ) ) { + return false; + } + $font_family = $this->registered_webfonts[ $font_family_slug ]; $index = _gutenberg_find_webfont( $font_family, $font_face_to_unregister ); @@ -283,7 +290,7 @@ private function unregister_font_face( $font_face_to_unregister ) { unset( $this->registered_webfonts[ $font_family_slug ][ $index ] ); // No font faces left, let's remove the font family entry. - if ( 0 === count( $this->registered_webfonts[ $font_family_slug ] ) ) { + if ( empty( $this->registered_webfonts[ $font_family_slug ] ) ) { unset( $this->registered_webfonts[ $font_family_slug ] ); } @@ -296,10 +303,9 @@ private function unregister_font_face( $font_face_to_unregister ) { * @since 6.0.0 * * @param array $webfont The webfont arguments. - * * @return array|false The validated webfont arguments, or false if the webfont is invalid. */ - public function validate_webfont( $webfont ) { + public function validate_webfont( array $webfont ) { $webfont = wp_parse_args( $webfont, array( diff --git a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php index a5e5df292ac8c5..845e20038d73a6 100644 --- a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php +++ b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php @@ -8,11 +8,12 @@ /** * Check if the webfont was registered programmatically. * - * @param array $webfont The webfont that'll have their origin checked. + * @since 6.0.0 * + * @param array $webfont The webfont to check. * @return boolean True if registered programmatically, false otherwise. */ -function _gutenberg_is_externally_registered_webfont( $webfont ) { +function _gutenberg_is_externally_registered_webfont( array $webfont ) { return isset( $webfont['origin'] ) && 'gutenberg_wp_webfonts_api' === $webfont['origin']; } @@ -21,6 +22,8 @@ function _gutenberg_is_externally_registered_webfont( $webfont ) { * Enqueue webfonts listed in theme.json. * * Enqueued webfonts will end up in the front-end as inlined CSS. + * + * @since 6.0.0 */ function _wp_enqueue_webfonts_listed_in_theme_json() { $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings(); diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index 2320062d097c9c..87a11581124c37 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -5,33 +5,15 @@ * @package gutenberg */ -if ( ! function_exists( '_wp_array_keys_to_kebab_case' ) ) { - /** - * Transforms the keys of the array to kebab-case. - * - * @param array $array The array to be tranformed. - * - * @return array The kebab-cased array. - */ - function _wp_array_keys_to_kebab_case( $array ) { - $kebab_cased_array = array(); - - foreach ( $array as $key => $value ) { - $kebab_cased_array[ _wp_to_kebab_case( $key ) ] = $value; - } - - return $kebab_cased_array; - } -} - /** * Transforms the source of the font face from `file.:/` into an actual URI. * - * @param array $font_face The font face. + * @since 6.0.0 * + * @param array $font_face The font face. * @return array The URI-resolved font face. */ -function _gutenberg_resolve_font_face_uri( $font_face ) { +function _gutenberg_resolve_font_face_uri( array $font_face ) { if ( empty( $font_face['src'] ) ) { return $font_face; } @@ -52,6 +34,8 @@ function _gutenberg_resolve_font_face_uri( $font_face ) { /** * Compares if the two given webfonts are the equal. * + * @since 6.0.0 + * * @param array $webfont1 The first webfont. * @param array $webfont2 The second webfont. * @param boolean $is_camel_case True if the font attributes are in camel case; else false for kebab case. @@ -88,13 +72,14 @@ function _gutenberg_is_webfont_equal( array $webfont1, array $webfont2, $is_came /** * Finds $webfont_to_find in $webfonts. * + * @since 6.0.0 + * * @param array[] $webfonts The webfonts array. * @param array $webfont_to_find The webfont to find. - * * @return integer|false The index of $webfont in $webfonts if found. False otherwise. */ -function _gutenberg_find_webfont( $webfonts, $webfont_to_find ) { - if ( ! count( $webfonts ) ) { +function _gutenberg_find_webfont( array $webfonts, $webfont_to_find ) { + if ( empty( $webfonts ) ) { return false; } @@ -111,19 +96,40 @@ function _gutenberg_find_webfont( $webfonts, $webfont_to_find ) { if ( ! function_exists( '_wp_array_keys_to_camel_case' ) ) { /** - * Transforms the keys of the array from kebab-case to camel-case. + * Transforms the keys in the given array to camelCase. * - * @param array $array The kebab-cased array. + * @since 6.0.0 * - * @return array The camel-cased array. + * @param array $to_transform The array to transform. + * @return array Given array with camelCase keys. */ - function _wp_array_keys_to_camel_case( $array ) { + function _wp_array_keys_to_camel_case( array $to_transform ) { $camel_cased_array = array(); - foreach ( $array as $key => $value ) { + foreach ( $to_transform as $key => $value ) { $camel_cased_array[ _wp_to_kebab_case( $key ) ] = $value; } return $camel_cased_array; } } + +if ( ! function_exists( '_wp_array_keys_to_kebab_case' ) ) { + /** + * Transforms the keys in the given array to kebab-case. + * + * @since 6.0.0 + * + * @param array $to_transform The array to be transformed. + * @return array Given array with kebab-case keys. + */ + function _wp_array_keys_to_kebab_case( array $to_transform ) { + $kebab_cased_array = array(); + + foreach ( $to_transform as $key => $value ) { + $kebab_cased_array[ _wp_to_kebab_case( $key ) ] = $value; + } + + return $kebab_cased_array; + } +} From b36c64777b5c28fb1e7e801e6fb770106d731d78 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 20 Apr 2022 08:42:25 +0300 Subject: [PATCH 28/37] Revert "Update lib/experimental/webfonts-utils.php" This reverts commit bea59decf868f803902ac0cb9b58b4c075d1a21d. --- lib/experimental/webfonts-utils.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index 87a11581124c37..cf0bf0053cacc9 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -107,7 +107,7 @@ function _wp_array_keys_to_camel_case( array $to_transform ) { $camel_cased_array = array(); foreach ( $to_transform as $key => $value ) { - $camel_cased_array[ _wp_to_kebab_case( $key ) ] = $value; + $camel_cased_array[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value; } return $camel_cased_array; From d6bbb43c1a3b09a7227c940ac90310a806baedd2 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 20 Apr 2022 09:38:54 +0300 Subject: [PATCH 29/37] Mark functions as private --- lib/experimental/register-webfonts-from-theme-json.php | 2 ++ lib/experimental/webfonts-utils.php | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 9a25c4188cfda1..651fc497753329 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -9,6 +9,8 @@ /** * Register webfonts defined in theme.json * + * @private + * * @param array $settings The theme.json file. */ function _wp_register_webfonts_from_theme_json( $settings ) { diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index cf0bf0053cacc9..b77cb31bec62d5 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -9,6 +9,7 @@ * Transforms the source of the font face from `file.:/` into an actual URI. * * @since 6.0.0 + * @private * * @param array $font_face The font face. * @return array The URI-resolved font face. @@ -35,6 +36,7 @@ function _gutenberg_resolve_font_face_uri( array $font_face ) { * Compares if the two given webfonts are the equal. * * @since 6.0.0 + * @private * * @param array $webfont1 The first webfont. * @param array $webfont2 The second webfont. @@ -73,6 +75,7 @@ function _gutenberg_is_webfont_equal( array $webfont1, array $webfont2, $is_came * Finds $webfont_to_find in $webfonts. * * @since 6.0.0 + * @private * * @param array[] $webfonts The webfonts array. * @param array $webfont_to_find The webfont to find. @@ -99,6 +102,7 @@ function _gutenberg_find_webfont( array $webfonts, $webfont_to_find ) { * Transforms the keys in the given array to camelCase. * * @since 6.0.0 + * @private * * @param array $to_transform The array to transform. * @return array Given array with camelCase keys. @@ -119,6 +123,7 @@ function _wp_array_keys_to_camel_case( array $to_transform ) { * Transforms the keys in the given array to kebab-case. * * @since 6.0.0 + * @private * * @param array $to_transform The array to be transformed. * @return array Given array with kebab-case keys. From 779cece8071fa06e7144e7078ec730f95a5954e3 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 20 Apr 2022 09:41:48 +0300 Subject: [PATCH 30/37] missed this one --- lib/experimental/add-registered-webfonts-to-theme-json.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index 7e1aa522591d05..90312823dd5b4e 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -10,6 +10,7 @@ * Add missing webfonts data to the global styles. * * @since 6.0.0 + * @private * * @param array $data The global styles. * @return array The global styles with missing webfonts data. From 606373bed1170914d6fdb85e68174149384ae78f Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 20 Apr 2022 09:46:42 +0300 Subject: [PATCH 31/37] prefix stylesheet handles with 'wp-' --- lib/experimental/class-wp-webfonts.php | 4 ++-- .../enqueue-only-webfonts-listed-in-theme-json-test.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 9a06134c136551..fb4a7e04dd9be2 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -63,10 +63,10 @@ public function init() { // Register callback to generate and enqueue styles. if ( did_action( 'wp_enqueue_scripts' ) ) { - $this->stylesheet_handle = 'webfonts-footer'; + $this->stylesheet_handle = 'wp-webfonts-footer'; $hook = 'wp_print_footer_scripts'; } else { - $this->stylesheet_handle = 'webfonts'; + $this->stylesheet_handle = 'wp-webfonts'; $hook = 'wp_enqueue_scripts'; } add_action( $hook, array( $this, 'generate_and_enqueue_styles' ) ); diff --git a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php index 0b11e5d5e4069e..6f2afe34563f75 100644 --- a/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php +++ b/phpunit/enqueue-only-webfonts-listed-in-theme-json-test.php @@ -110,7 +110,7 @@ public function test_enqueue_an_externally_registered_font_family() { $this->generate_styles_for_theme( 'enqueue-font-family' ); $expected = << + EOF; @@ -131,7 +131,7 @@ public function test_enqueue_only_one_of_all_externally_registered_font_faces() $this->generate_styles_for_theme( 'enqueue-only-one-font-face' ); $expected = << + EOF; @@ -153,7 +153,7 @@ public function test_register_and_enqueue_font_faces_to_same_provider() { $this->generate_styles_for_theme( 'register-and-enqueue-to-the-same-provider' ); $expected = << + EOF; @@ -176,7 +176,7 @@ public function test_register_and_enqueue_font_faces_through_different_providers $this->generate_styles_for_theme( 'register-and-enqueue-through-different-providers' ); $expected = << + EOF; From 1c0e508c80db0bf1b67672606bc2fffdf24f99a1 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 20 Apr 2022 12:14:44 +0300 Subject: [PATCH 32/37] Rename function to _wp_resolve_font_face_uri --- .../register-webfonts-from-theme-json.php | 2 +- lib/experimental/webfonts-utils.php | 44 ++++++++++--------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 651fc497753329..8d2c2622c49481 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -57,7 +57,7 @@ function _wp_register_webfonts_from_theme_json( $settings ) { foreach ( $font_family['fontFaces'] as $font_face ) { $font_face['provider'] = $font_family['provider']; - $font_face = _gutenberg_resolve_font_face_uri( $font_face ); + $font_face = _wp_resolve_font_face_uri( $font_face ); $font_face = _wp_array_keys_to_kebab_case( $font_face ); $font_faces_to_register[] = $font_face; diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index b77cb31bec62d5..bfb1b335201857 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -5,31 +5,33 @@ * @package gutenberg */ -/** - * Transforms the source of the font face from `file.:/` into an actual URI. - * - * @since 6.0.0 - * @private - * - * @param array $font_face The font face. - * @return array The URI-resolved font face. - */ -function _gutenberg_resolve_font_face_uri( array $font_face ) { - if ( empty( $font_face['src'] ) ) { - return $font_face; - } +if ( ! function_exists( '_wp_resolve_font_face_uri' ) ) { + /** + * Transforms the source of the font face from `file.:/` into an actual URI. + * + * @since 6.0.0 + * @private + * + * @param array $font_face The font face. + * @return array The URI-resolved font face. + */ + function _wp_resolve_font_face_uri( array $font_face ) { + if ( empty( $font_face['src'] ) ) { + return $font_face; + } - $font_face['src'] = (array) $font_face['src']; + $font_face['src'] = (array) $font_face['src']; - foreach ( $font_face['src'] as $src_key => $url ) { - // Tweak the URL to be relative to the theme root. - if ( ! str_starts_with( $url, 'file:./' ) ) { - continue; + foreach ( $font_face['src'] as $src_key => $url ) { + // Tweak the URL to be relative to the theme root. + if ( ! str_starts_with( $url, 'file:./' ) ) { + continue; + } + $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) ); } - $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) ); - } - return $font_face; + return $font_face; + } } /** From 260156a08b723254c58a3fe640946742036e1247 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 20 Apr 2022 12:21:34 +0300 Subject: [PATCH 33/37] we don't need a separate function is_webfont_equal --- lib/experimental/webfonts-utils.php | 59 +++++++++-------------------- 1 file changed, 18 insertions(+), 41 deletions(-) diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index bfb1b335201857..9f64f7ff599221 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -34,45 +34,6 @@ function _wp_resolve_font_face_uri( array $font_face ) { } } -/** - * Compares if the two given webfonts are the equal. - * - * @since 6.0.0 - * @private - * - * @param array $webfont1 The first webfont. - * @param array $webfont2 The second webfont. - * @param boolean $is_camel_case True if the font attributes are in camel case; else false for kebab case. - * Defaults to camel case. - * @return boolean True if the webfonts are equal, false otherwise. - */ -function _gutenberg_is_webfont_equal( array $webfont1, array $webfont2, $is_camel_case = true ) { - $equality_attrs = $is_camel_case - ? array( - 'fontFamily', - 'fontStyle', - 'fontWeight', - ) - : array( - 'font-family', - 'font-style', - 'font-weight', - ); - - foreach ( $equality_attrs as $attr ) { - // Bail out if the attribute does not exist. - if ( ! isset( $webfont1[ $attr ] ) || ! isset( $webfont2[ $attr ] ) ) { - return false; - } - - if ( $webfont1[ $attr ] !== $webfont2[ $attr ] ) { - return false; - } - } - - return true; -} - /** * Finds $webfont_to_find in $webfonts. * @@ -91,8 +52,24 @@ function _gutenberg_find_webfont( array $webfonts, $webfont_to_find ) { $is_camel_case = isset( $webfonts[0]['fontFamily'] ); foreach ( $webfonts as $index => $webfont ) { - if ( _gutenberg_is_webfont_equal( $webfont, $webfont_to_find, $is_camel_case ) ) { - return $index; + $equality_attrs = $is_camel_case + ? array( 'fontFamily', 'fontStyle', 'fontWeight' ) + : array( 'font-family', 'font-style', 'font-weight' ); + + $found = $index; + foreach ( $equality_attrs as $attr ) { + // Bail out if the attribute does not exist, or if the values are not equal. + if ( + empty( $webfont[ $attr ] ) || + empty( $webfont_to_find[ $attr ] ) || + $webfont[ $attr ] !== $webfont_to_find[ $attr ] + ) { + $found = false; + break; + } + } + if ( false !== $found ) { + return $found; } } From b2eb078097bb29f56d53ad0b5e393b1650417932 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 20 Apr 2022 12:59:57 +0300 Subject: [PATCH 34/37] move find_webfont function to the WP_Webfonts class --- .../add-registered-webfonts-to-theme-json.php | 2 +- lib/experimental/class-wp-webfonts.php | 43 ++++++++++++++++++- lib/experimental/webfonts-utils.php | 42 ------------------ 3 files changed, 43 insertions(+), 44 deletions(-) diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index 90312823dd5b4e..beb1649d02dd42 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -82,7 +82,7 @@ function( $font_face ) { foreach ( $registered_font_faces as $registered_font_face ) { $registered_font_face = _wp_array_keys_to_camel_case( $registered_font_face ); - if ( false !== _gutenberg_find_webfont( $font_faces_in_theme_json, $registered_font_face ) ) { + if ( false !== wp_webfonts()->find_webfont( $font_faces_in_theme_json, $registered_font_face ) ) { // Webfont is already there, so let's not add it. continue; } diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index fb4a7e04dd9be2..ea2bd1456845d8 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -279,7 +279,7 @@ private function unregister_font_face( array $font_face_to_unregister ) { } $font_family = $this->registered_webfonts[ $font_family_slug ]; - $index = _gutenberg_find_webfont( $font_family, $font_face_to_unregister ); + $index = $this->find_webfont( $font_family, $font_face_to_unregister ); // Font face not found. if ( false === $index ) { @@ -530,4 +530,45 @@ private function get_webfonts_by_provider( array $font_families ) { return $webfonts_by_provider; } + + /** + * Finds $webfont_to_find in $webfonts. + * + * @since 6.0.0 + * + * @param array[] $webfonts The webfonts array. + * @param array $webfont_to_find The webfont to find. + * @return integer|false The index of $webfont in $webfonts if found. False otherwise. + */ + public function find_webfont( array $webfonts, $webfont_to_find ) { + if ( empty( $webfonts ) ) { + return false; + } + + $is_camel_case = isset( $webfonts[0]['fontFamily'] ); + + foreach ( $webfonts as $index => $webfont ) { + $equality_attrs = $is_camel_case + ? array( 'fontFamily', 'fontStyle', 'fontWeight' ) + : array( 'font-family', 'font-style', 'font-weight' ); + + $found = $index; + foreach ( $equality_attrs as $attr ) { + // Bail out if the attribute does not exist, or if the values are not equal. + if ( + empty( $webfont[ $attr ] ) || + empty( $webfont_to_find[ $attr ] ) || + $webfont[ $attr ] !== $webfont_to_find[ $attr ] + ) { + $found = false; + break; + } + } + if ( false !== $found ) { + return $found; + } + } + + return false; + } } diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index 9f64f7ff599221..1afa6933cc74f6 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -34,48 +34,6 @@ function _wp_resolve_font_face_uri( array $font_face ) { } } -/** - * Finds $webfont_to_find in $webfonts. - * - * @since 6.0.0 - * @private - * - * @param array[] $webfonts The webfonts array. - * @param array $webfont_to_find The webfont to find. - * @return integer|false The index of $webfont in $webfonts if found. False otherwise. - */ -function _gutenberg_find_webfont( array $webfonts, $webfont_to_find ) { - if ( empty( $webfonts ) ) { - return false; - } - - $is_camel_case = isset( $webfonts[0]['fontFamily'] ); - - foreach ( $webfonts as $index => $webfont ) { - $equality_attrs = $is_camel_case - ? array( 'fontFamily', 'fontStyle', 'fontWeight' ) - : array( 'font-family', 'font-style', 'font-weight' ); - - $found = $index; - foreach ( $equality_attrs as $attr ) { - // Bail out if the attribute does not exist, or if the values are not equal. - if ( - empty( $webfont[ $attr ] ) || - empty( $webfont_to_find[ $attr ] ) || - $webfont[ $attr ] !== $webfont_to_find[ $attr ] - ) { - $found = false; - break; - } - } - if ( false !== $found ) { - return $found; - } - } - - return false; -} - if ( ! function_exists( '_wp_array_keys_to_camel_case' ) ) { /** * Transforms the keys in the given array to camelCase. From 0de111734c1a155d161841218e527a3906f3fd16 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 20 Apr 2022 13:04:56 +0300 Subject: [PATCH 35/37] The _wp_resolve_font_face_uri function is only used once. Can be removed --- .../register-webfonts-from-theme-json.php | 13 ++++++++- lib/experimental/webfonts-utils.php | 29 ------------------- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 8d2c2622c49481..c678960b348916 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -56,8 +56,19 @@ function _wp_register_webfonts_from_theme_json( $settings ) { } foreach ( $font_family['fontFaces'] as $font_face ) { + + // Transforms the source of the font face from `file.:/` into an actual URI. + if ( ! empty( $font_face['src'] ) ) { + $font_face['src'] = (array) $font_face['src']; + foreach ( $font_face['src'] as $src_key => $url ) { + // Tweak the URL to be relative to the theme root. + if ( ! str_starts_with( $url, 'file:./' ) ) { + continue; + } + $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) ); + } + } $font_face['provider'] = $font_family['provider']; - $font_face = _wp_resolve_font_face_uri( $font_face ); $font_face = _wp_array_keys_to_kebab_case( $font_face ); $font_faces_to_register[] = $font_face; diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index 1afa6933cc74f6..7963b6ee721581 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -5,35 +5,6 @@ * @package gutenberg */ -if ( ! function_exists( '_wp_resolve_font_face_uri' ) ) { - /** - * Transforms the source of the font face from `file.:/` into an actual URI. - * - * @since 6.0.0 - * @private - * - * @param array $font_face The font face. - * @return array The URI-resolved font face. - */ - function _wp_resolve_font_face_uri( array $font_face ) { - if ( empty( $font_face['src'] ) ) { - return $font_face; - } - - $font_face['src'] = (array) $font_face['src']; - - foreach ( $font_face['src'] as $src_key => $url ) { - // Tweak the URL to be relative to the theme root. - if ( ! str_starts_with( $url, 'file:./' ) ) { - continue; - } - $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) ); - } - - return $font_face; - } -} - if ( ! function_exists( '_wp_array_keys_to_camel_case' ) ) { /** * Transforms the keys in the given array to camelCase. From e2fe01c1ce2902b0b21fb21cbf9ace829e9dace3 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 20 Apr 2022 13:22:54 +0300 Subject: [PATCH 36/37] The array_keys_to_camel_case function can be removed --- .../add-registered-webfonts-to-theme-json.php | 22 ++++++++++++++++--- lib/experimental/webfonts-utils.php | 21 ------------------ 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/lib/experimental/add-registered-webfonts-to-theme-json.php b/lib/experimental/add-registered-webfonts-to-theme-json.php index beb1649d02dd42..e7d0297fdaaf83 100644 --- a/lib/experimental/add-registered-webfonts-to-theme-json.php +++ b/lib/experimental/add-registered-webfonts-to-theme-json.php @@ -45,6 +45,22 @@ function _wp_add_registered_webfonts_to_theme_json( array $data ) { $font_family_indexes_in_theme_json[ wp_webfonts()->get_font_slug( $family ) ] = $index; } + /** + * Transforms the keys in the given array to camelCase. + * + * @param array $to_transform The array to transform. + * @return array Given array with camelCase keys. + */ + $array_keys_to_camel_case = function( array $to_transform ) { + $camel_cased_array = array(); + + foreach ( $to_transform as $key => $value ) { + $camel_cased_array[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value; + } + + return $camel_cased_array; + }; + foreach ( $registered_font_families as $slug => $registered_font_faces ) { // Font family not in theme.json, so let's add it. if ( ! isset( $font_family_indexes_in_theme_json[ $slug ] ) ) { @@ -56,10 +72,10 @@ function _wp_add_registered_webfonts_to_theme_json( array $data ) { 'name' => $family_name, 'slug' => $slug, 'fontFaces' => array_map( - function( $font_face ) { + function( $font_face ) use ( $array_keys_to_camel_case ) { $font_face['origin'] = 'gutenberg_wp_webfonts_api'; - return _wp_array_keys_to_camel_case( $font_face ); + return $array_keys_to_camel_case( $font_face ); }, $registered_font_faces ), @@ -80,7 +96,7 @@ function( $font_face ) { $font_faces_in_theme_json = $font_family_in_theme_json['fontFaces']; foreach ( $registered_font_faces as $registered_font_face ) { - $registered_font_face = _wp_array_keys_to_camel_case( $registered_font_face ); + $registered_font_face = $array_keys_to_camel_case( $registered_font_face ); if ( false !== wp_webfonts()->find_webfont( $font_faces_in_theme_json, $registered_font_face ) ) { // Webfont is already there, so let's not add it. diff --git a/lib/experimental/webfonts-utils.php b/lib/experimental/webfonts-utils.php index 7963b6ee721581..e8250b0cfddc07 100644 --- a/lib/experimental/webfonts-utils.php +++ b/lib/experimental/webfonts-utils.php @@ -5,27 +5,6 @@ * @package gutenberg */ -if ( ! function_exists( '_wp_array_keys_to_camel_case' ) ) { - /** - * Transforms the keys in the given array to camelCase. - * - * @since 6.0.0 - * @private - * - * @param array $to_transform The array to transform. - * @return array Given array with camelCase keys. - */ - function _wp_array_keys_to_camel_case( array $to_transform ) { - $camel_cased_array = array(); - - foreach ( $to_transform as $key => $value ) { - $camel_cased_array[ lcfirst( str_replace( '-', '', ucwords( $key, '-' ) ) ) ] = $value; - } - - return $camel_cased_array; - } -} - if ( ! function_exists( '_wp_array_keys_to_kebab_case' ) ) { /** * Transforms the keys in the given array to kebab-case. From e94fffae0684aa5a6dc370ce3eba262cb77071d9 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 20 Apr 2022 14:33:12 +0300 Subject: [PATCH 37/37] Remove the _gutenberg_is_externally_registered_webfont function --- .../enqueue-webfonts-listed-in-theme-json.php | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php index 845e20038d73a6..b214d856b0b7d6 100644 --- a/lib/experimental/enqueue-webfonts-listed-in-theme-json.php +++ b/lib/experimental/enqueue-webfonts-listed-in-theme-json.php @@ -5,18 +5,6 @@ * @package gutenberg */ -/** - * Check if the webfont was registered programmatically. - * - * @since 6.0.0 - * - * @param array $webfont The webfont to check. - * @return boolean True if registered programmatically, false otherwise. - */ -function _gutenberg_is_externally_registered_webfont( array $webfont ) { - return isset( $webfont['origin'] ) && 'gutenberg_wp_webfonts_api' === $webfont['origin']; -} - if ( ! function_exists( '_wp_enqueue_webfonts_listed_in_theme_json' ) ) { /** * Enqueue webfonts listed in theme.json. @@ -37,7 +25,7 @@ function _wp_enqueue_webfonts_listed_in_theme_json() { foreach ( $settings['typography']['fontFamilies'] as $font_families ) { foreach ( $font_families as $font_family ) { // Skip dynamically included font families. We only want to enqueue explicitly added fonts. - if ( _gutenberg_is_externally_registered_webfont( $font_family ) ) { + if ( isset( $font_family['origin'] ) && 'gutenberg_wp_webfonts_api' === $font_family['origin'] ) { continue; } @@ -56,7 +44,7 @@ function _wp_enqueue_webfonts_listed_in_theme_json() { // Loop through all the font faces, enqueueing each one of them. foreach ( $font_family['fontFaces'] as $font_face ) { // Skip dynamically included font faces. We only want to enqueue the font faces listed in theme.json. - if ( _gutenberg_is_externally_registered_webfont( $font_face ) ) { + if ( isset( $font_face['origin'] ) && 'gutenberg_wp_webfonts_api' === $font_face['origin'] ) { continue; }