From 0dd01bd2d0ddff6da78cc26cdda49c735cc1c367 Mon Sep 17 00:00:00 2001 From: Jon Desrosiers Date: Mon, 25 Apr 2022 11:44:25 -0400 Subject: [PATCH 01/63] First pass at proof of concept extending `WP_Dependencies`. --- lib/experimental/class-NEW-web-fonts.php | 193 +++++++++++++++++++ lib/experimental/web-fonts.php | 210 +++++++++++++++++++++ lib/experimental/webfonts.php | 229 ----------------------- lib/load.php | 5 +- 4 files changed, 406 insertions(+), 231 deletions(-) create mode 100644 lib/experimental/class-NEW-web-fonts.php create mode 100644 lib/experimental/web-fonts.php delete mode 100644 lib/experimental/webfonts.php diff --git a/lib/experimental/class-NEW-web-fonts.php b/lib/experimental/class-NEW-web-fonts.php new file mode 100644 index 00000000000000..4d84b582dd0d4d --- /dev/null +++ b/lib/experimental/class-NEW-web-fonts.php @@ -0,0 +1,193 @@ +providers; + } + + public function __contstruct() { + /** + * Fires when the WP_Web_Fonts instance is initialized. + * + * @since X.X.X + * + * @param WP_Web_Fonts $wp_web_fonts WP_Web_Fonts instance (passed by reference). + */ + do_action_ref_array( 'wp_default_web_fonts', array( &$this ) ); + } + + /** + * Removes a font family and all registered variations. + * + * @param mixed|string|string[] $font_family + */ + function remove_family( $font_family ) { + $font_family_handle = sanitize_title( $font_family ); + + if ( ! isset( $this->registered[ $font_family_handle ] ) ) { + return; + } + + $variations = $this->registered[ $font_family_handle ]->deps; + + foreach ( $variations as $variation ) { + $this->remove( $variation ); + } + + $this->remove( $font_family_handle ); + } + + /** + * Removes a variation. + * + * @param $font_family + * @param $variation_handle + */ + function remove_variation( $font_family, $variation_handle ) { + $font_family_handle = sanitize_title( $font_family ); + + $this->remove( $variation_handle ); + + if ( ! isset( $this->registered[ $font_family_handle ] ) ) { + return; + } + + // Remove the variation as a dependency. + $this->registered[ $font_family_handle ]->deps = array_values( array_diff( + $this->registered[ $font_family_handle ]->deps, + array( $variation_handle ) + ) ); + } + + /** + * Registers a variation for a font family. + * + * @param string $font_family + * @param string $variation_handle + * @param array $variation + */ + public function add_variation( $font_family, $variation_handle, $variation ) { + $font_family_handle = sanitize_title( $font_family ); + + // Register the font family when it does not yet exist. + if ( ! isset( $this->registered[ $font_family ] ) ) { + $this->add( $font_family_handle, false ); + } + + $variation = $this->validate_variation( $font_family, $variation ); + + if ( $variation['src'] ) { + return $this->add( $variation_handle, $variation['src'] ); + } else { + return $this->add( $variation_handle, false ); + } + } + + /** + * Adds a variation as a dependency for the main font alias. + * + * @param $font_family_handle + * @param $variation_handle + */ + public function add_dependency( $font_family_handle, $variation_handle ) { + $dependencies = $this->registered[ $font_family_handle ]; + $dependencies[] = $variation_handle; + $this->registered[ $font_family_handle ] = $dependencies; + } + + /** + * Validates and sanitizes a variation. + * + * @param $font_family + * @param $variation + * @return array|false|object + */ + function validate_variation( $font_family, $variation ) { + $defaults = array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '400', + 'font-display' => 'fallback', + ); + + $defaults = apply_filters( 'wp_web_font_variation_defaults', $defaults ); + + $defaults['font-family'] = $font_family; + $variation = wp_parse_args( $variation, $defaults ); + + // Local fonts need a "src". + if ( 'local' === $variation['provider'] ) { + // Make sure that local fonts have 'src' defined. + if ( empty( $variation['src'] ) || ( ! is_string( $variation['src'] ) && ! is_array( $variation['src'] ) ) ) { + trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.', 'gutenberg' ) ); + return false; + } + } + + // Validate the 'src' property. + if ( ! empty( $variation['src'] ) ) { + foreach ( (array) $variation['src'] as $src ) { + if ( empty( $src ) || ! is_string( $src ) ) { + trigger_error( __( 'Each webfont src must be a non-empty string.', 'gutenberg' ) ); + return false; + } + } + } + + // Check the font-weight. + if ( ! is_string( $variation['font-weight'] ) && ! is_int( $variation['font-weight'] ) ) { + trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.', 'gutenberg' ) ); + return false; + } + + // Check the font-display. + if ( ! in_array( $variation['font-display'], array( 'auto', 'block', 'fallback', 'swap' ), true ) ) { + $variation['font-display'] = 'fallback'; + } + + $valid_props = array( + 'ascend-override', + 'descend-override', + 'font-display', + 'font-family', + 'font-stretch', + 'font-style', + 'font-weight', + 'font-variant', + 'font-feature-settings', + 'font-variation-settings', + 'line-gap-override', + 'size-adjust', + 'src', + 'unicode-range', + + // Exceptions. + 'provider', + ); + + foreach ( $variation as $prop => $value ) { + if ( ! in_array( $prop, $valid_props, true ) ) { + unset( $variation[ $prop ] ); + } + } + + return $variation; + } +} diff --git a/lib/experimental/web-fonts.php b/lib/experimental/web-fonts.php new file mode 100644 index 00000000000000..347b6ff9c27668 --- /dev/null +++ b/lib/experimental/web-fonts.php @@ -0,0 +1,210 @@ +add( $font_family, false ); + } +} + +if ( ! function_exists( 'wp_register_web_font_variation' ) ) { + /** + * Registers a font variation. + * + * @param $font_family + * @return mixed + */ + function wp_register_web_font_variation( $font_family, $variation_handle, $variation ) { + return wp_web_fonts()->add_variation( $font_family, $variation_handle, $variation ); + } +} + +if ( ! function_exists( 'wp_register_web_fonts' ) ) { + /** + * Registers a list of web fonts and variations. + * + * @param $web_fonts + * @return array + */ + function wp_register_web_fonts( $web_fonts, $enqueue = false ) { + $registered = array(); + + foreach ( $web_fonts as $font_family => $variations ) { + wp_register_web_font_family( $font_family ); + + foreach ( $variations as $variation_handle => $variation ) { + $registered[] = wp_register_web_font_variation( $font_family, $variation_handle, $variation ); + + if ( $enqueue ) { + wp_enqueue_web_font( $variation_handle ); + } + } + } + + return $registered; + } +} + +if ( ! function_exists( 'wp_enqueue_web_font' ) ) { + /** + * Enqueues a web font family and all variations. + */ + function wp_enqueue_web_font( $handle ) { + $wp_web_fonts = wp_web_fonts(); + $wp_web_fonts->enqueue( $handle ); + } +} + +if ( ! function_exists( 'wp_enqueue_web_font_variations' ) ) { + /** + * Enqueues a specific set of web font variations. + */ + function wp_enqueue_web_font_variations( $variations ) { + $wp_web_fonts = wp_web_fonts(); + + // Looking to enqueue all variations of a font family. + foreach ( $variations as $variation ) { + $wp_web_fonts->enqueue( $variation ); + } + } +} + +if ( ! function_exists( 'wp_deregister_web_font_family' ) ) { + /** + * Unregisters an entire font family and all vcariations. + */ + function wp_deregister_web_font_family( $font_family ) { + wp_web_fonts()->remove_family( $font_family ); + } +} + +if ( ! function_exists( 'wp_deregister_web_font_variation' ) ) { + /** + * @param $variation_handle + */ + function wp_deregister_web_font_variation( $font_family, $variation_handle ) { + wp_web_fonts()->remove_variation( $font_family, $variation_handle ); + } +} + + + + + + + + + + + + + +/** Unaltered so far. */ + + + + +if ( ! function_exists( 'wp_register_webfont_provider' ) ) { + /** + * Registers a custom font service provider. + * + * A webfont provider contains the business logic for how to + * interact with a remote font service and how to generate + * the `@font-face` styles for that remote service. + * + * How to register a custom font service provider: + * 1. Load its class file into memory before registration. + * 2. Pass the class' name to this function. + * + * For example, for a class named `My_Custom_Font_Service_Provider`: + * ``` + * wp_register_webfont_provider( My_Custom_Font_Service_Provider::class ); + * ``` + * + * @since 6.0.0 + * + * @param string $name The provider's name. + * @param string $classname The provider's class name. + * The class should be a child of `WP_Webfonts_Provider`. + * See {@see WP_Webfonts_Provider}. + * + * @return bool True if successfully registered, else false. + */ + function wp_register_webfont_provider( $name, $classname ) { + return wp_webfonts()->register_provider( $name, $classname ); + } +} + +if ( ! function_exists( 'wp_get_webfont_providers' ) ) { + /** + * Gets all registered providers. + * + * Return an array of providers, each keyed by their unique + * ID (i.e. the `$id` property in the provider's object) with + * an instance of the provider (object): + * ID => provider instance + * + * Each provider contains the business logic for how to + * process its specific font service (i.e. local or remote) + * and how to generate the `@font-face` styles for its service. + * + * @since 6.0.0 + * + * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. + */ + function wp_get_webfont_providers() { + return wp_webfonts()->get_providers(); + } +} + +/** + * Add webfonts mime types. + */ +add_filter( + 'mime_types', + function( $mime_types ) { + // Webfonts formats. + $mime_types['woff2'] = 'font/woff2'; + $mime_types['woff'] = 'font/woff'; + $mime_types['ttf'] = 'font/ttf'; + $mime_types['eot'] = 'application/vnd.ms-fontobject'; + $mime_types['otf'] = 'application/x-font-opentype'; + + return $mime_types; + } +); diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php deleted file mode 100644 index 201101d1d7093e..00000000000000 --- a/lib/experimental/webfonts.php +++ /dev/null @@ -1,229 +0,0 @@ -init(); - } - - return $wp_webfonts; - } -} - -if ( ! function_exists( 'wp_register_webfonts' ) ) { - /** - * Registers a collection of webfonts. - * - * Example of how to register Source Serif Pro font with font-weight range of 200-900 - * and font-style of normal and italic: - * - * If the font files are contained within the theme: - * - * wp_register_webfonts( - * array( - * array( - * 'provider' => 'local', - * 'font-family' => 'Source Serif Pro', - * 'font-weight' => '200 900', - * 'font-style' => 'normal', - * 'src' => get_theme_file_uri( 'assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2' ), - * ), - * array( - * 'provider' => 'local', - * 'font-family' => 'Source Serif Pro', - * 'font-weight' => '200 900', - * 'font-style' => 'italic', - * 'src' => get_theme_file_uri( 'assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2' ), - * ), - * ) - * ); - * - * - * Webfonts should be registered in the `after_setup_theme` hook. - * - * @since 6.0.0 - * - * @param array[] $webfonts Webfonts to be registered. - * This contains an array of webfonts to be registered. - * Each webfont is an array. - * @return string[] The font family slug of the registered webfonts. - */ - function wp_register_webfonts( array $webfonts ) { - $registered_webfont_slugs = array(); - - foreach ( $webfonts as $webfont ) { - $slug = wp_register_webfont( $webfont ); - - if ( is_string( $slug ) ) { - $registered_webfont_slugs[ $slug ] = true; - } - } - - return array_keys( $registered_webfont_slugs ); - } -} - -if ( ! function_exists( 'wp_register_webfont' ) ) { - /** - * Registers a single webfont. - * - * Example of how to register Source Serif Pro font with font-weight range of 200-900: - * - * If the font file is contained within the theme: - * - * - * wp_register_webfont( - * array( - * 'provider' => 'local', - * 'font-family' => 'Source Serif Pro', - * 'font-weight' => '200 900', - * 'font-style' => 'normal', - * 'src' => get_theme_file_uri( 'assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2' ), - * ) - * ); - * - * - * @since 6.0.0 - * - * @param array $webfont Webfont to be registered. - * @return string|false The font family slug if successfully registered, else false. - */ - function wp_register_webfont( array $webfont ) { - return wp_webfonts()->register_webfont( $webfont ); - } -} - -if ( ! function_exists( 'wp_enqueue_webfonts' ) ) { - /** - * Enqueues a collection of font families. - * - * Example of how to enqueue Source Serif Pro and Roboto font families, both registered beforehand. - * - * - * wp_enqueue_webfonts( - * 'Roboto', - * 'Sans Serif Pro' - * ); - * - * - * Font families should be enqueued from the `init` hook or later. - * - * @since 6.0.0 - * - * @param string[] $webfonts Font families to be enqueued. - */ - function wp_enqueue_webfonts( array $webfonts ) { - foreach ( $webfonts as $webfont ) { - wp_enqueue_webfont( $webfont ); - } - } -} - -if ( ! function_exists( 'wp_enqueue_webfont' ) ) { - /** - * Enqueue a single font family that has been registered beforehand. - * - * Example of how to enqueue Source Serif Pro font: - * - * - * wp_enqueue_webfont( 'Source Serif Pro' ); - * - * - * Font families should be enqueued from the `init` hook or later. - * - * @since 6.0.0 - * - * @param string $font_family_name The font family name to be enqueued. - * @return bool True if successfully enqueued, else false. - */ - function wp_enqueue_webfont( $font_family_name ) { - return wp_webfonts()->enqueue_webfont( $font_family_name ); - } -} - -if ( ! function_exists( 'wp_register_webfont_provider' ) ) { - /** - * Registers a custom font service provider. - * - * A webfont provider contains the business logic for how to - * interact with a remote font service and how to generate - * the `@font-face` styles for that remote service. - * - * How to register a custom font service provider: - * 1. Load its class file into memory before registration. - * 2. Pass the class' name to this function. - * - * For example, for a class named `My_Custom_Font_Service_Provider`: - * ``` - * wp_register_webfont_provider( My_Custom_Font_Service_Provider::class ); - * ``` - * - * @since 6.0.0 - * - * @param string $name The provider's name. - * @param string $classname The provider's class name. - * The class should be a child of `WP_Webfonts_Provider`. - * See {@see WP_Webfonts_Provider}. - * - * @return bool True if successfully registered, else false. - */ - function wp_register_webfont_provider( $name, $classname ) { - return wp_webfonts()->register_provider( $name, $classname ); - } -} - -if ( ! function_exists( 'wp_get_webfont_providers' ) ) { - /** - * Gets all registered providers. - * - * Return an array of providers, each keyed by their unique - * ID (i.e. the `$id` property in the provider's object) with - * an instance of the provider (object): - * ID => provider instance - * - * Each provider contains the business logic for how to - * process its specific font service (i.e. local or remote) - * and how to generate the `@font-face` styles for its service. - * - * @since 6.0.0 - * - * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. - */ - function wp_get_webfont_providers() { - return wp_webfonts()->get_providers(); - } -} - -/** - * Add webfonts mime types. - */ -add_filter( - 'mime_types', - function( $mime_types ) { - // Webfonts formats. - $mime_types['woff2'] = 'font/woff2'; - $mime_types['woff'] = 'font/woff'; - $mime_types['ttf'] = 'font/ttf'; - $mime_types['eot'] = 'application/vnd.ms-fontobject'; - $mime_types['otf'] = 'application/x-font-opentype'; - - return $mime_types; - } -); diff --git a/lib/load.php b/lib/load.php index 11830fb9a0c4d3..f198e1b85b3b07 100644 --- a/lib/load.php +++ b/lib/load.php @@ -118,10 +118,11 @@ function gutenberg_is_experiment_enabled( $name ) { } require __DIR__ . '/experimental/class-wp-theme-json-gutenberg.php'; require __DIR__ . '/experimental/class-wp-theme-json-resolver-gutenberg.php'; -require __DIR__ . '/experimental/class-wp-webfonts.php'; +require __DIR__ . '/experimental/class-NEW-web-fonts.php'; 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/web-fonts.php'; +require __DIR__ . '/experimental/blocks.php'; require __DIR__ . '/experimental/navigation-theme-opt-in.php'; require __DIR__ . '/experimental/navigation-page.php'; From 60be65bf24e9c2cbbf23bdc44ba186ba46f4d6ec Mon Sep 17 00:00:00 2001 From: Jon Desrosiers Date: Mon, 25 Apr 2022 11:45:16 -0400 Subject: [PATCH 02/63] Keep the old file names to show an actual diff. --- lib/experimental/class-NEW-web-fonts.php | 193 -------- lib/experimental/class-old-wp-webfonts.php | 417 ++++++++++++++++++ lib/experimental/class-wp-webfonts.php | 392 ++++------------ .../{web-fonts.php => webfonts.php} | 0 lib/load.php | 4 +- 5 files changed, 503 insertions(+), 503 deletions(-) delete mode 100644 lib/experimental/class-NEW-web-fonts.php create mode 100644 lib/experimental/class-old-wp-webfonts.php rename lib/experimental/{web-fonts.php => webfonts.php} (100%) diff --git a/lib/experimental/class-NEW-web-fonts.php b/lib/experimental/class-NEW-web-fonts.php deleted file mode 100644 index 4d84b582dd0d4d..00000000000000 --- a/lib/experimental/class-NEW-web-fonts.php +++ /dev/null @@ -1,193 +0,0 @@ -providers; - } - - public function __contstruct() { - /** - * Fires when the WP_Web_Fonts instance is initialized. - * - * @since X.X.X - * - * @param WP_Web_Fonts $wp_web_fonts WP_Web_Fonts instance (passed by reference). - */ - do_action_ref_array( 'wp_default_web_fonts', array( &$this ) ); - } - - /** - * Removes a font family and all registered variations. - * - * @param mixed|string|string[] $font_family - */ - function remove_family( $font_family ) { - $font_family_handle = sanitize_title( $font_family ); - - if ( ! isset( $this->registered[ $font_family_handle ] ) ) { - return; - } - - $variations = $this->registered[ $font_family_handle ]->deps; - - foreach ( $variations as $variation ) { - $this->remove( $variation ); - } - - $this->remove( $font_family_handle ); - } - - /** - * Removes a variation. - * - * @param $font_family - * @param $variation_handle - */ - function remove_variation( $font_family, $variation_handle ) { - $font_family_handle = sanitize_title( $font_family ); - - $this->remove( $variation_handle ); - - if ( ! isset( $this->registered[ $font_family_handle ] ) ) { - return; - } - - // Remove the variation as a dependency. - $this->registered[ $font_family_handle ]->deps = array_values( array_diff( - $this->registered[ $font_family_handle ]->deps, - array( $variation_handle ) - ) ); - } - - /** - * Registers a variation for a font family. - * - * @param string $font_family - * @param string $variation_handle - * @param array $variation - */ - public function add_variation( $font_family, $variation_handle, $variation ) { - $font_family_handle = sanitize_title( $font_family ); - - // Register the font family when it does not yet exist. - if ( ! isset( $this->registered[ $font_family ] ) ) { - $this->add( $font_family_handle, false ); - } - - $variation = $this->validate_variation( $font_family, $variation ); - - if ( $variation['src'] ) { - return $this->add( $variation_handle, $variation['src'] ); - } else { - return $this->add( $variation_handle, false ); - } - } - - /** - * Adds a variation as a dependency for the main font alias. - * - * @param $font_family_handle - * @param $variation_handle - */ - public function add_dependency( $font_family_handle, $variation_handle ) { - $dependencies = $this->registered[ $font_family_handle ]; - $dependencies[] = $variation_handle; - $this->registered[ $font_family_handle ] = $dependencies; - } - - /** - * Validates and sanitizes a variation. - * - * @param $font_family - * @param $variation - * @return array|false|object - */ - function validate_variation( $font_family, $variation ) { - $defaults = array( - 'provider' => 'local', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ); - - $defaults = apply_filters( 'wp_web_font_variation_defaults', $defaults ); - - $defaults['font-family'] = $font_family; - $variation = wp_parse_args( $variation, $defaults ); - - // Local fonts need a "src". - if ( 'local' === $variation['provider'] ) { - // Make sure that local fonts have 'src' defined. - if ( empty( $variation['src'] ) || ( ! is_string( $variation['src'] ) && ! is_array( $variation['src'] ) ) ) { - trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.', 'gutenberg' ) ); - return false; - } - } - - // Validate the 'src' property. - if ( ! empty( $variation['src'] ) ) { - foreach ( (array) $variation['src'] as $src ) { - if ( empty( $src ) || ! is_string( $src ) ) { - trigger_error( __( 'Each webfont src must be a non-empty string.', 'gutenberg' ) ); - return false; - } - } - } - - // Check the font-weight. - if ( ! is_string( $variation['font-weight'] ) && ! is_int( $variation['font-weight'] ) ) { - trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.', 'gutenberg' ) ); - return false; - } - - // Check the font-display. - if ( ! in_array( $variation['font-display'], array( 'auto', 'block', 'fallback', 'swap' ), true ) ) { - $variation['font-display'] = 'fallback'; - } - - $valid_props = array( - 'ascend-override', - 'descend-override', - 'font-display', - 'font-family', - 'font-stretch', - 'font-style', - 'font-weight', - 'font-variant', - 'font-feature-settings', - 'font-variation-settings', - 'line-gap-override', - 'size-adjust', - 'src', - 'unicode-range', - - // Exceptions. - 'provider', - ); - - foreach ( $variation as $prop => $value ) { - if ( ! in_array( $prop, $valid_props, true ) ) { - unset( $variation[ $prop ] ); - } - } - - return $variation; - } -} diff --git a/lib/experimental/class-old-wp-webfonts.php b/lib/experimental/class-old-wp-webfonts.php new file mode 100644 index 00000000000000..e422f51658befb --- /dev/null +++ b/lib/experimental/class-old-wp-webfonts.php @@ -0,0 +1,417 @@ +register_provider( 'local', 'WP_Webfonts_Provider_Local' ); + + // Register callback to generate and enqueue styles. + if ( did_action( 'wp_enqueue_scripts' ) ) { + $this->stylesheet_handle = 'webfonts-footer'; + $hook = 'wp_print_footer_scripts'; + } else { + $this->stylesheet_handle = 'webfonts'; + $hook = 'wp_enqueue_scripts'; + } + add_action( $hook, array( $this, 'generate_and_enqueue_styles' ) ); + + // Enqueue webfonts in the block editor. + add_action( 'admin_init', array( $this, 'generate_and_enqueue_editor_styles' ) ); + } + + /** + * Get the list of registered fonts. + * + * @since 6.0.0 + * + * @return array[] + */ + public function get_registered_webfonts() { + return $this->registered_webfonts; + } + + /** + * Get the list of enqueued fonts. + * + * @return array[] + */ + public function get_enqueued_webfonts() { + return $this->enqueued_webfonts; + } + + /** + * Get the list of all fonts. + * + * @return array[] + */ + public function get_all_webfonts() { + return array_merge( $this->get_registered_webfonts(), $this->get_enqueued_webfonts() ); + } + + /** + * Get the list of providers. + * + * @since 6.0.0 + * + * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. + */ + public function get_providers() { + return $this->providers; + } + + /** + * Register a webfont. + * + * @since 6.0.0 + * + * @param array $webfont Webfont to be registered. + * @return string|false The font family slug if successfully registered, else false. + */ + public function register_webfont( array $webfont ) { + $webfont = $this->validate_webfont( $webfont ); + + // If not valid, bail out. + if ( ! $webfont ) { + return false; + } + + $slug = $this->get_font_slug( $webfont ); + + // Initialize a new font-family collection. + if ( ! isset( $this->registered_webfonts[ $slug ] ) ) { + $this->registered_webfonts[ $slug ] = array(); + } + + $this->registered_webfonts[ $slug ][] = $webfont; + return $slug; + } + + /** + * Enqueue a font-family that has been already registered. + * + * @param string $font_family_name The font family name to be enqueued. + * @return bool True if successfully enqueued, else false. + */ + public function enqueue_webfont( $font_family_name ) { + $slug = $this->get_font_slug( $font_family_name ); + + if ( isset( $this->enqueued_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' ); + + return false; + } + + $this->enqueued_webfonts[ $slug ] = $this->registered_webfonts[ $slug ]; + unset( $this->registered_webfonts[ $slug ] ); + return true; + } + + /** + * Get the font slug. + * + * @since 6.0.0 + * + * @param array|string $to_convert The value to convert into a slug. Expected as the web font's array + * or a font-family as a string. + * @return string|false The font slug on success, or false if the font-family cannot be determined. + */ + public static function get_font_slug( $to_convert ) { + if ( is_array( $to_convert ) ) { + if ( isset( $to_convert['font-family'] ) ) { + $to_convert = $to_convert['font-family']; + } elseif ( isset( $to_convert['fontFamily'] ) ) { + $to_convert = $to_convert['fontFamily']; + } else { + _doing_it_wrong( __METHOD__, __( 'Could not determine the font family name.', 'gutenberg' ), '6.0.0' ); + return false; + } + } + + return sanitize_title( $to_convert ); + } + + /** + * Validate a webfont. + * + * @since 6.0.0 + * + * @param array $webfont The webfont arguments. + * + * @return array|false The validated webfont arguments, or false if the webfont is invalid. + */ + public function validate_webfont( $webfont ) { + $webfont = wp_parse_args( + $webfont, + array( + 'provider' => 'local', + 'font-family' => '', + 'font-style' => 'normal', + 'font-weight' => '400', + 'font-display' => 'fallback', + ) + ); + + // Check the font-family. + if ( empty( $webfont['font-family'] ) || ! is_string( $webfont['font-family'] ) ) { + trigger_error( __( 'Webfont font family must be a non-empty string.', 'gutenberg' ) ); + return false; + } + + // Local fonts need a "src". + if ( 'local' === $webfont['provider'] ) { + // Make sure that local fonts have 'src' defined. + if ( empty( $webfont['src'] ) || ( ! is_string( $webfont['src'] ) && ! is_array( $webfont['src'] ) ) ) { + trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.', 'gutenberg' ) ); + return false; + } + } + + // Validate the 'src' property. + if ( ! empty( $webfont['src'] ) ) { + foreach ( (array) $webfont['src'] as $src ) { + if ( empty( $src ) || ! is_string( $src ) ) { + trigger_error( __( 'Each webfont src must be a non-empty string.', 'gutenberg' ) ); + return false; + } + } + } + + // Check the font-weight. + if ( ! is_string( $webfont['font-weight'] ) && ! is_int( $webfont['font-weight'] ) ) { + trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.', 'gutenberg' ) ); + return false; + } + + // Check the font-display. + if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'swap' ), true ) ) { + $webfont['font-display'] = 'fallback'; + } + + $valid_props = array( + 'ascend-override', + 'descend-override', + 'font-display', + 'font-family', + 'font-stretch', + 'font-style', + 'font-weight', + 'font-variant', + 'font-feature-settings', + 'font-variation-settings', + 'line-gap-override', + 'size-adjust', + 'src', + 'unicode-range', + + // Exceptions. + 'provider', + ); + + foreach ( $webfont as $prop => $value ) { + if ( ! in_array( $prop, $valid_props, true ) ) { + unset( $webfont[ $prop ] ); + } + } + + return $webfont; + } + + /** + * Register a provider. + * + * @since 6.0.0 + * + * @param string $provider The provider name. + * @param string $class The provider class name. + * @return bool True if successfully registered, else false. + */ + public function register_provider( $provider, $class ) { + if ( empty( $provider ) || empty( $class ) ) { + return false; + } + $this->providers[ $provider ] = $class; + return true; + } + + /** + * Generate and enqueue webfonts styles. + * + * @since 6.0.0 + */ + public function generate_and_enqueue_styles() { + // Generate the styles. + $webfonts = $this->get_webfonts_by_provider( $this->get_enqueued_webfonts() ); + $styles = $this->generate_styles( $webfonts ); + + // Bail out if there are no styles to enqueue. + if ( '' === $styles ) { + return; + } + + // Enqueue the stylesheet. + wp_register_style( $this->stylesheet_handle, '' ); + wp_enqueue_style( $this->stylesheet_handle ); + + // Add the styles to the stylesheet. + wp_add_inline_style( $this->stylesheet_handle, $styles ); + } + + /** + * Generate and enqueue editor styles. + * + * @since 6.0.0 + */ + public function generate_and_enqueue_editor_styles() { + // Generate the styles. + $webfonts = $this->get_webfonts_by_provider( $this->get_all_webfonts() ); + $styles = $this->generate_styles( $webfonts ); + + // Bail out if there are no styles to enqueue. + if ( '' === $styles ) { + return; + } + + wp_enqueue_style( 'wp-block-library' ); + wp_add_inline_style( 'wp-block-library', $styles ); + } + + /** + * Generate styles for webfonts. + * + * @since 6.0.0 + * + * @param array[] $webfonts_by_provider Webfonts organized by provider. + * @return string $styles Generated styles. + */ + private function generate_styles( array $webfonts_by_provider ) { + $styles = ''; + $providers = $this->get_providers(); + + /* + * Loop through each of the providers to get the CSS for their respective webfonts + * to incrementally generate the collective styles for all of them. + */ + foreach ( $providers as $provider_id => $provider_class ) { + + // 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 ) ); + continue; + } + + $provider_webfonts = isset( $webfonts_by_provider[ $provider_id ] ) + ? $webfonts_by_provider[ $provider_id ] + : array(); + + // If there are no registered webfonts for this provider, skip it. + if ( empty( $provider_webfonts ) ) { + continue; + } + + /* + * Process the webfonts by first passing them to the provider via `set_webfonts()` + * and then getting the CSS from the provider. + */ + $provider = new $provider_class(); + $provider->set_webfonts( $provider_webfonts ); + $styles .= $provider->get_css(); + } + + return $styles; + } + + + /** + * Reorganizes webfonts grouped by font-family into grouped by provider. + * + * @param array[] $font_families Font families and each of their webfonts. + * @return array[] Webfonts organized by providers. + */ + private function get_webfonts_by_provider( array $font_families ) { + $providers = $this->get_providers(); + $webfonts_by_provider = array(); + + foreach ( $font_families as $webfonts ) { + foreach ( $webfonts as $webfont ) { + $provider = $webfont['provider']; + + // 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 ) ); + continue; + } + + // Initialize a new provider collection. + if ( ! isset( $webfonts_by_provider[ $provider ] ) ) { + $webfonts_by_provider[ $provider ] = array(); + } + $webfonts_by_provider[ $provider ][] = $webfont; + } + } + + return $webfonts_by_provider; + } +} diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index e40aca9e8671f8..dd670fcdc61f12 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -1,38 +1,6 @@ register_provider( 'local', 'WP_Webfonts_Provider_Local' ); - - // Register callback to generate and enqueue styles. - if ( did_action( 'wp_enqueue_scripts' ) ) { - $this->stylesheet_handle = 'webfonts-footer'; - $hook = 'wp_print_footer_scripts'; - } else { - $this->stylesheet_handle = 'webfonts'; - $hook = 'wp_enqueue_scripts'; - } - add_action( $hook, array( $this, 'generate_and_enqueue_styles' ) ); - - // Enqueue webfonts in the block editor. - add_action( 'admin_init', array( $this, 'generate_and_enqueue_editor_styles' ) ); + public function get_providers() { + return $this->providers; } - /** - * Get the list of registered fonts. - * - * @since 6.0.0 - * - * @return array[] - */ - public function get_registered_webfonts() { - return $this->registered_webfonts; + public function __contstruct() { + /** + * Fires when the WP_Web_Fonts instance is initialized. + * + * @since X.X.X + * + * @param WP_Web_Fonts $wp_web_fonts WP_Web_Fonts instance (passed by reference). + */ + do_action_ref_array( 'wp_default_web_fonts', array( &$this ) ); } /** - * Get the list of enqueued fonts. + * Removes a font family and all registered variations. * - * @return array[] + * @param mixed|string|string[] $font_family */ - public function get_enqueued_webfonts() { - return $this->enqueued_webfonts; - } + function remove_family( $font_family ) { + $font_family_handle = sanitize_title( $font_family ); - /** - * Get the list of all fonts. - * - * @return array[] - */ - public function get_all_webfonts() { - return array_merge( $this->get_registered_webfonts(), $this->get_enqueued_webfonts() ); - } + if ( ! isset( $this->registered[ $font_family_handle ] ) ) { + return; + } - /** - * Get the list of providers. - * - * @since 6.0.0 - * - * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. - */ - public function get_providers() { - return $this->providers; + $variations = $this->registered[ $font_family_handle ]->deps; + + foreach ( $variations as $variation ) { + $this->remove( $variation ); + } + + $this->remove( $font_family_handle ); } /** - * Register a webfont. - * - * @since 6.0.0 + * Removes a variation. * - * @param array $webfont Webfont to be registered. - * @return string|false The font family slug if successfully registered, else false. + * @param $font_family + * @param $variation_handle */ - public function register_webfont( array $webfont ) { - $webfont = $this->validate_webfont( $webfont ); - - // If not valid, bail out. - if ( ! $webfont ) { - return false; - } + function remove_variation( $font_family, $variation_handle ) { + $font_family_handle = sanitize_title( $font_family ); - $slug = $this->get_font_slug( $webfont ); + $this->remove( $variation_handle ); - // Initialize a new font-family collection. - if ( ! isset( $this->registered_webfonts[ $slug ] ) ) { - $this->registered_webfonts[ $slug ] = array(); + if ( ! isset( $this->registered[ $font_family_handle ] ) ) { + return; } - $this->registered_webfonts[ $slug ][] = $webfont; - return $slug; + // Remove the variation as a dependency. + $this->registered[ $font_family_handle ]->deps = array_values( array_diff( + $this->registered[ $font_family_handle ]->deps, + array( $variation_handle ) + ) ); } /** - * Enqueue a font-family that has been already registered. + * Registers a variation for a font family. * - * @param string $font_family_name The font family name to be enqueued. - * @return bool True if successfully enqueued, else false. + * @param string $font_family + * @param string $variation_handle + * @param array $variation */ - public function enqueue_webfont( $font_family_name ) { - $slug = $this->get_font_slug( $font_family_name ); + public function add_variation( $font_family, $variation_handle, $variation ) { + $font_family_handle = sanitize_title( $font_family ); - if ( isset( $this->enqueued_webfonts[ $slug ] ) ) { - return true; + // Register the font family when it does not yet exist. + if ( ! isset( $this->registered[ $font_family ] ) ) { + $this->add( $font_family_handle, false ); } - 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' ); + $variation = $this->validate_variation( $font_family, $variation ); - return false; + if ( $variation['src'] ) { + return $this->add( $variation_handle, $variation['src'] ); + } else { + return $this->add( $variation_handle, false ); } - - $this->enqueued_webfonts[ $slug ] = $this->registered_webfonts[ $slug ]; - unset( $this->registered_webfonts[ $slug ] ); - return true; } /** - * Get the font slug. + * Adds a variation as a dependency for the main font alias. * - * @since 6.0.0 - * - * @param array|string $to_convert The value to convert into a slug. Expected as the web font's array - * or a font-family as a string. - * @return string|false The font slug on success, or false if the font-family cannot be determined. + * @param $font_family_handle + * @param $variation_handle */ - public static function get_font_slug( $to_convert ) { - if ( is_array( $to_convert ) ) { - if ( isset( $to_convert['font-family'] ) ) { - $to_convert = $to_convert['font-family']; - } elseif ( isset( $to_convert['fontFamily'] ) ) { - $to_convert = $to_convert['fontFamily']; - } else { - _doing_it_wrong( __METHOD__, __( 'Could not determine the font family name.', 'gutenberg' ), '6.0.0' ); - return false; - } - } - - return sanitize_title( $to_convert ); + public function add_dependency( $font_family_handle, $variation_handle ) { + $dependencies = $this->registered[ $font_family_handle ]; + $dependencies[] = $variation_handle; + $this->registered[ $font_family_handle ] = $dependencies; } /** - * Validate a webfont. - * - * @since 6.0.0 + * Validates and sanitizes a variation. * - * @param array $webfont The webfont arguments. - * - * @return array|false The validated webfont arguments, or false if the webfont is invalid. + * @param $font_family + * @param $variation + * @return array|false|object */ - public function validate_webfont( $webfont ) { - $webfont = wp_parse_args( - $webfont, - array( - 'provider' => 'local', - 'font-family' => '', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ) + function validate_variation( $font_family, $variation ) { + $defaults = array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '400', + 'font-display' => 'fallback', ); - // Check the font-family. - if ( empty( $webfont['font-family'] ) || ! is_string( $webfont['font-family'] ) ) { - trigger_error( __( 'Webfont font family must be a non-empty string.', 'gutenberg' ) ); - return false; - } + $defaults = apply_filters( 'wp_web_font_variation_defaults', $defaults ); + + $defaults['font-family'] = $font_family; + $variation = wp_parse_args( $variation, $defaults ); // Local fonts need a "src". - if ( 'local' === $webfont['provider'] ) { + if ( 'local' === $variation['provider'] ) { // Make sure that local fonts have 'src' defined. - if ( empty( $webfont['src'] ) || ( ! is_string( $webfont['src'] ) && ! is_array( $webfont['src'] ) ) ) { + if ( empty( $variation['src'] ) || ( ! is_string( $variation['src'] ) && ! is_array( $variation['src'] ) ) ) { trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.', 'gutenberg' ) ); return false; } } // Validate the 'src' property. - if ( ! empty( $webfont['src'] ) ) { - foreach ( (array) $webfont['src'] as $src ) { + if ( ! empty( $variation['src'] ) ) { + foreach ( (array) $variation['src'] as $src ) { if ( empty( $src ) || ! is_string( $src ) ) { trigger_error( __( 'Each webfont src must be a non-empty string.', 'gutenberg' ) ); return false; @@ -238,7 +152,7 @@ public function validate_webfont( $webfont ) { } // Check the font-weight. - if ( ! is_string( $webfont['font-weight'] ) && ! is_int( $webfont['font-weight'] ) ) { + if ( ! is_string( $variation['font-weight'] ) && ! is_int( $variation['font-weight'] ) ) { trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.', 'gutenberg' ) ); return false; } @@ -268,150 +182,12 @@ public function validate_webfont( $webfont ) { 'provider', ); - foreach ( $webfont as $prop => $value ) { + foreach ( $variation as $prop => $value ) { if ( ! in_array( $prop, $valid_props, true ) ) { - unset( $webfont[ $prop ] ); - } - } - - return $webfont; - } - - /** - * Register a provider. - * - * @since 6.0.0 - * - * @param string $provider The provider name. - * @param string $class The provider class name. - * @return bool True if successfully registered, else false. - */ - public function register_provider( $provider, $class ) { - if ( empty( $provider ) || empty( $class ) ) { - return false; - } - $this->providers[ $provider ] = $class; - return true; - } - - /** - * Generate and enqueue webfonts styles. - * - * @since 6.0.0 - */ - public function generate_and_enqueue_styles() { - // Generate the styles. - $webfonts = $this->get_webfonts_by_provider( $this->get_enqueued_webfonts() ); - $styles = $this->generate_styles( $webfonts ); - - // Bail out if there are no styles to enqueue. - if ( '' === $styles ) { - return; - } - - // Enqueue the stylesheet. - wp_register_style( $this->stylesheet_handle, '' ); - wp_enqueue_style( $this->stylesheet_handle ); - - // Add the styles to the stylesheet. - wp_add_inline_style( $this->stylesheet_handle, $styles ); - } - - /** - * Generate and enqueue editor styles. - * - * @since 6.0.0 - */ - public function generate_and_enqueue_editor_styles() { - // Generate the styles. - $webfonts = $this->get_webfonts_by_provider( $this->get_all_webfonts() ); - $styles = $this->generate_styles( $webfonts ); - - // Bail out if there are no styles to enqueue. - if ( '' === $styles ) { - return; - } - - wp_enqueue_style( 'wp-block-library' ); - wp_add_inline_style( 'wp-block-library', $styles ); - } - - /** - * Generate styles for webfonts. - * - * @since 6.0.0 - * - * @param array[] $webfonts_by_provider Webfonts organized by provider. - * @return string $styles Generated styles. - */ - private function generate_styles( array $webfonts_by_provider ) { - $styles = ''; - $providers = $this->get_providers(); - - /* - * Loop through each of the providers to get the CSS for their respective webfonts - * to incrementally generate the collective styles for all of them. - */ - foreach ( $providers as $provider_id => $provider_class ) { - - // 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 ) ); - continue; - } - - $provider_webfonts = isset( $webfonts_by_provider[ $provider_id ] ) - ? $webfonts_by_provider[ $provider_id ] - : array(); - - // If there are no registered webfonts for this provider, skip it. - if ( empty( $provider_webfonts ) ) { - continue; - } - - /* - * Process the webfonts by first passing them to the provider via `set_webfonts()` - * and then getting the CSS from the provider. - */ - $provider = new $provider_class(); - $provider->set_webfonts( $provider_webfonts ); - $styles .= $provider->get_css(); - } - - return $styles; - } - - - /** - * Reorganizes webfonts grouped by font-family into grouped by provider. - * - * @param array[] $font_families Font families and each of their webfonts. - * @return array[] Webfonts organized by providers. - */ - private function get_webfonts_by_provider( array $font_families ) { - $providers = $this->get_providers(); - $webfonts_by_provider = array(); - - foreach ( $font_families as $webfonts ) { - foreach ( $webfonts as $webfont ) { - $provider = $webfont['provider']; - - // 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 ) ); - continue; - } - - // Initialize a new provider collection. - if ( ! isset( $webfonts_by_provider[ $provider ] ) ) { - $webfonts_by_provider[ $provider ] = array(); - } - $webfonts_by_provider[ $provider ][] = $webfont; + unset( $variation[ $prop ] ); } } - return $webfonts_by_provider; + return $variation; } } diff --git a/lib/experimental/web-fonts.php b/lib/experimental/webfonts.php similarity index 100% rename from lib/experimental/web-fonts.php rename to lib/experimental/webfonts.php diff --git a/lib/load.php b/lib/load.php index f198e1b85b3b07..2bb50bd50e0fc2 100644 --- a/lib/load.php +++ b/lib/load.php @@ -118,10 +118,10 @@ function gutenberg_is_experiment_enabled( $name ) { } require __DIR__ . '/experimental/class-wp-theme-json-gutenberg.php'; require __DIR__ . '/experimental/class-wp-theme-json-resolver-gutenberg.php'; -require __DIR__ . '/experimental/class-NEW-web-fonts.php'; +require __DIR__ . '/experimental/class-wp-webfonts.php'; require __DIR__ . '/experimental/class-wp-webfonts-provider.php'; require __DIR__ . '/experimental/class-wp-webfonts-provider-local.php'; -require __DIR__ . '/experimental/web-fonts.php'; +require __DIR__ . '/experimental/webfonts.php'; require __DIR__ . '/experimental/blocks.php'; require __DIR__ . '/experimental/navigation-theme-opt-in.php'; require __DIR__ . '/experimental/navigation-page.php'; From d3dfdf98a1e245cc2f45fee9c00d8ac8ec644ae2 Mon Sep 17 00:00:00 2001 From: Jon Desrosiers Date: Mon, 25 Apr 2022 11:45:58 -0400 Subject: [PATCH 03/63] Move more methods into the new class. --- lib/experimental/class-wp-webfonts.php | 140 +++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 11 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index dd670fcdc61f12..55bf63a2d040e7 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -12,17 +12,9 @@ class WP_Web_Fonts extends WP_Dependencies { private $providers = array(); /** - * Get the list of providers. - * - * @since 6.0.0 * - * @return WP_Web_Fonts_Provider[] All registered providers, each keyed by their unique ID. */ - public function get_providers() { - return $this->providers; - } - - public function __contstruct() { + public function __construct() { /** * Fires when the WP_Web_Fonts instance is initialized. * @@ -33,6 +25,42 @@ public function __contstruct() { do_action_ref_array( 'wp_default_web_fonts', array( &$this ) ); } + /** + * Get the list of all registered web fonts and variations. + * + * @since 6.0.0 + * + * @return array[] + */ + public function get_registered() { + return array_keys( $this->registered ); + } + + /** + * Get the list of enqueued web fonts and variations. + * + * @return array[] + */ + public function get_enqueued() { + return $this->queue; + } + + /** + * Gets a list of all variations registered for a font family. + * + * @param $font_family + * @return array + */ + public function get_variations( $font_family ) { + $font_family_handle = sanitize_title( $font_family ); + + if ( ! isset( $this->registered[ $font_family_handle ] ) ) { + return array(); + } + + return $this->registered[ $font_family_handle ]->deps; + } + /** * Removes a font family and all registered variations. * @@ -93,10 +121,15 @@ public function add_variation( $font_family, $variation_handle, $variation ) { $variation = $this->validate_variation( $font_family, $variation ); + // Variation validation failed. + if ( ! $variation ) { + return false; + } + if ( $variation['src'] ) { - return $this->add( $variation_handle, $variation['src'] ); + return $this->add( $variation_handle, $variation['src'], array(), false, $variation ); } else { - return $this->add( $variation_handle, false ); + return $this->add( $variation_handle, false, array(), false, $variation ); } } @@ -157,6 +190,12 @@ function validate_variation( $font_family, $variation ) { return false; } + //Verify provider. + if ( ! class_exists( $variation['provider'] ) ) { + trigger_error( __( 'The provider class specified does not exist.', 'gutenberg' ) ); + return false; + } + // Check the font-display. if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'swap', 'optional' ), true ) ) { $webfont['font-display'] = 'fallback'; @@ -190,4 +229,83 @@ function validate_variation( $font_family, $variation ) { return $variation; } + + /** + * Generate styles for webfonts. + * + * @since 6.0.0 + * + * @param array[] $webfonts_by_provider Webfonts organized by provider. + * @return string $styles Generated styles. + */ + public function do_item( $handle, $group = false ) { + if ( ! parent::do_item( $handle ) ) { + return false; + } + + $styles = ''; + $providers = $this->get_providers(); + + /* + * Loop through each of the providers to get the CSS for their respective webfonts + * to incrementally generate the collective styles for all of them. + */ + foreach ( $providers as $provider_id => $provider_class ) { + + // 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 ) ); + continue; + } + + $provider_webfonts = isset( $webfonts_by_provider[ $provider_id ] ) + ? $webfonts_by_provider[ $provider_id ] + : array(); + + // If there are no registered webfonts for this provider, skip it. + if ( empty( $provider_webfonts ) ) { + continue; + } + + /* + * Process the webfonts by first passing them to the provider via `set_webfonts()` + * and then getting the CSS from the provider. + */ + $provider = new $provider_class(); + $provider->set_webfonts( $provider_webfonts ); + $styles .= $provider->get_css(); + } + + return $styles; + } + + /** + * Register a provider. + * + * @since 6.0.0 + * + * @param string $provider The provider name. + * @param string $class The provider class name. + * @return bool True if successfully registered, else false. + */ + public function register_provider( $provider, $class ) { + if ( empty( $provider ) || empty( $class ) || ! class_exists( $class ) ) { + return false; + } + $this->providers[ $provider ] = $class; + return true; + } + + /** + * Get the list of providers. + * + * @since 6.0.0 + * + * @return WP_Web_Fonts_Provider[] All registered providers, each keyed by their unique ID. + */ + public function get_providers() { + return $this->providers; + } + } From ee531b1b7cacefc94c5d2e16f35524cf4ed23edc Mon Sep 17 00:00:00 2001 From: Jon Desrosiers Date: Mon, 25 Apr 2022 11:46:20 -0400 Subject: [PATCH 04/63] Working on getting `do_item()` to work correctly. --- lib/experimental/class-wp-webfonts.php | 58 ++++++++++++++++++++------ 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 55bf63a2d040e7..b26c754a8b612d 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -127,10 +127,16 @@ public function add_variation( $font_family, $variation_handle, $variation ) { } if ( $variation['src'] ) { - return $this->add( $variation_handle, $variation['src'], array(), false, $variation ); + $result = $this->add( $variation_handle, $variation['src'], array(), false, array( 'font-properties' => $variation ) ); } else { - return $this->add( $variation_handle, false, array(), false, $variation ); + $result = $this->add( $variation_handle, false, array(), false, array( 'font-properties' => $variation ) ); } + + if ( $result ) { + $this->providers[ $variation['provider'] ]['fonts'][] = $variation_handle; + } + + return $result; } /** @@ -246,34 +252,39 @@ public function do_item( $handle, $group = false ) { $styles = ''; $providers = $this->get_providers(); + $obj = $this->registered[ $handle ]; + /* * Loop through each of the providers to get the CSS for their respective webfonts * to incrementally generate the collective styles for all of them. */ - foreach ( $providers as $provider_id => $provider_class ) { - + foreach ( $providers as $provider_id => $provider ) { // Bail out if the provider class does not exist. - if ( ! class_exists( $provider_class ) ) { + if ( ! class_exists( $provider['class'] ) ) { /* translators: %s is the provider name. */ trigger_error( sprintf( __( 'Webfont provider "%s" is not registered.', 'gutenberg' ), $provider_id ) ); continue; } - $provider_webfonts = isset( $webfonts_by_provider[ $provider_id ] ) - ? $webfonts_by_provider[ $provider_id ] - : array(); + $fonts = $this->get_enqueued_fonts_for_provider( $provider_id ); // If there are no registered webfonts for this provider, skip it. - if ( empty( $provider_webfonts ) ) { + if ( empty( $fonts ) ) { continue; } + $provider_fonts = array(); + + foreach ( $fonts as $font_handle ) { + $provider_fonts[ $font_handle ] = $this->get_data( $font_handle, 'font-properties' ); + } + /* * Process the webfonts by first passing them to the provider via `set_webfonts()` * and then getting the CSS from the provider. */ - $provider = new $provider_class(); - $provider->set_webfonts( $provider_webfonts ); + $provider = new $provider['class'](); + $provider->set_webfonts( $provider_fonts ); $styles .= $provider->get_css(); } @@ -293,7 +304,10 @@ public function register_provider( $provider, $class ) { if ( empty( $provider ) || empty( $class ) || ! class_exists( $class ) ) { return false; } - $this->providers[ $provider ] = $class; + $this->providers[ $provider ] = array( + 'class' => $class, + 'fonts' => array(), + ); return true; } @@ -302,10 +316,28 @@ public function register_provider( $provider, $class ) { * * @since 6.0.0 * - * @return WP_Web_Fonts_Provider[] All registered providers, each keyed by their unique ID. + * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. */ public function get_providers() { return $this->providers; } + /** + * Retrieves a list of enqueued web font variations for a provider. + * + * @return array[] Webfonts organized by providers. + */ + private function get_enqueued_fonts_for_provider( $provider ) { + $providers = $this->get_providers(); + + if ( empty( $providers[ $provider ] ) ) { + return array(); + } + + return array_intersect( + $providers[ $provider ]['fonts'], + $this->get_enqueued() + ); + } + } From 3680ad2a40f7880915b317c0e651a0c6f71d3316 Mon Sep 17 00:00:00 2001 From: Jon Desrosiers Date: Mon, 25 Apr 2022 11:46:46 -0400 Subject: [PATCH 05/63] Continuing to work on changing the underlying Webfont class. --- lib/experimental/class-old-wp-webfonts.php | 20 -- lib/experimental/class-wp-webfonts.php | 26 +- .../register-webfonts-from-theme-json.php | 269 +++++++++--------- lib/experimental/webfonts.php | 99 ++++--- 4 files changed, 210 insertions(+), 204 deletions(-) diff --git a/lib/experimental/class-old-wp-webfonts.php b/lib/experimental/class-old-wp-webfonts.php index e422f51658befb..4c66383765db9f 100644 --- a/lib/experimental/class-old-wp-webfonts.php +++ b/lib/experimental/class-old-wp-webfonts.php @@ -75,26 +75,6 @@ public function init() { add_action( 'admin_init', array( $this, 'generate_and_enqueue_editor_styles' ) ); } - /** - * Get the list of registered fonts. - * - * @since 6.0.0 - * - * @return array[] - */ - public function get_registered_webfonts() { - return $this->registered_webfonts; - } - - /** - * Get the list of enqueued fonts. - * - * @return array[] - */ - public function get_enqueued_webfonts() { - return $this->enqueued_webfonts; - } - /** * Get the list of all fonts. * diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index b26c754a8b612d..c44f7aa88e0ca3 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -1,6 +1,6 @@ registered ); @@ -126,6 +126,8 @@ public function add_variation( $font_family, $variation_handle, $variation ) { return false; } + $variation_handle = $font_family_handle . '-' . $variation_handle; + if ( $variation['src'] ) { $result = $this->add( $variation_handle, $variation['src'], array(), false, array( 'font-properties' => $variation ) ); } else { @@ -146,9 +148,9 @@ public function add_variation( $font_family, $variation_handle, $variation ) { * @param $variation_handle */ public function add_dependency( $font_family_handle, $variation_handle ) { - $dependencies = $this->registered[ $font_family_handle ]; + $dependencies = $this->registered[ $font_family_handle ]->deps; $dependencies[] = $variation_handle; - $this->registered[ $font_family_handle ] = $dependencies; + $this->registered[ $font_family_handle ]->deps = $dependencies; } /** @@ -178,6 +180,9 @@ function validate_variation( $font_family, $variation ) { trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.', 'gutenberg' ) ); return false; } + } elseif ( ! class_exists( $variation['provider'] ) ) { + trigger_error( __( 'The provider class specified does not exist.', 'gutenberg' ) ); + return false; } // Validate the 'src' property. @@ -196,12 +201,6 @@ function validate_variation( $font_family, $variation ) { return false; } - //Verify provider. - if ( ! class_exists( $variation['provider'] ) ) { - trigger_error( __( 'The provider class specified does not exist.', 'gutenberg' ) ); - return false; - } - // Check the font-display. if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'swap', 'optional' ), true ) ) { $webfont['font-display'] = 'fallback'; @@ -304,6 +303,7 @@ public function register_provider( $provider, $class ) { if ( empty( $provider ) || empty( $class ) || ! class_exists( $class ) ) { return false; } + $this->providers[ $provider ] = array( 'class' => $class, 'fonts' => array(), diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index f0a37677eb0637..bb9d9a2ee64df9 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -5,173 +5,180 @@ * @package gutenberg */ -/** - * Register webfonts defined in theme.json. - */ -function gutenberg_register_webfonts_from_theme_json() { - // Get settings. - $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings(); - - // If in the editor, add webfonts defined in variations. - if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { - $variations = WP_Theme_JSON_Resolver_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( 'gutenberg_register_webfonts_from_theme_json' ) ) { + /** + * Register webfonts defined in theme.json. + */ + function gutenberg_register_webfonts_from_theme_json() { + // Get settings. + $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings(); - // 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'] ); + // 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(); - // Make sure there are no duplicates. - $settings['typography']['fontFamilies'] = array_unique( $settings['typography']['fontFamilies'] ); - } - } + foreach ( $variations as $variation ) { - // Bail out early if there are no settings for webfonts. - if ( empty( $settings['typography'] ) || empty( $settings['typography']['fontFamilies'] ) ) { - return; - } - - $webfonts = array(); + // 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; + } - // Look for fontFamilies. - foreach ( $settings['typography']['fontFamilies'] as $font_families ) { - foreach ( $font_families as $font_family ) { + // 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'] ); - // Skip if fontFace is not defined. - if ( empty( $font_family['fontFace'] ) ) { - continue; + // 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; + } + + $webfonts = array(); - $font_family['fontFace'] = (array) $font_family['fontFace']; + // Look for fontFamilies. + foreach ( $settings['typography']['fontFamilies'] as $font_families ) { + foreach ( $font_families as $font_family ) { - 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'] ) { + // Skip if fontFace is not defined. + if ( empty( $font_family['fontFace'] ) ) { 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']; + $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; + } - 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; + // 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 ) ); } - $font_face['src'][ $src_key ] = get_theme_file_uri( str_replace( 'file:./', '', $url ) ); } - } - // 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 ] ); + // 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 ] ); + } } - } - $webfonts[] = $font_face; + $webfonts[] = $font_face; + } } } - } - foreach ( $webfonts as $webfont ) { - wp_webfonts()->register_webfont( $webfont ); - } - foreach ( $webfonts as $webfont ) { - wp_webfonts()->enqueue_webfont( $webfont['font-family'] ); - } -} -/** - * 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']; + $to_enqueue = array(); + + foreach ( $webfonts as $webfont ) { + $font_family_handle = sanitize_title( $webfont['font-family'] ); + + wp_register_web_font_family( $font_family_handle ); + + $variation_handle = sanitize_title( implode( ' ', array( $webfont['font-weight'], $webfont['font-style'] ) ) ); + wp_register_web_font_variation( $font_family_handle, $variation_handle, $webfont ); + $to_enqueue[] = $font_family_handle; + } + + foreach ( $to_enqueue as $font_family ) { + wp_webfonts()->enqueue( $font_family ); + } } +} +if ( ! function_exists( 'gutenberg_add_registered_webfonts_to_theme_json' ) ) { /** - * Helper to get an array of the font-families. + * Add missing fonts data to the global styles. * - * @param array $families_data The font-families data. - * @return array The font-families array. + * @param array $data The global styles. + * @return array The global styles with missing fonts data. */ - $get_families = static function( $families_data ) { - $families = array(); - foreach ( $families_data as $family ) { - $families[] = WP_Webfonts::get_font_slug( $family ); + 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']; } - // 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 ) ); - }; + /** + * 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 ); + } - // Diff the arrays to find the missing fonts. - $to_add = array_diff( - array_keys( $font_families_registered ), - $get_families( $font_families_from_theme ) - ); + // 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 ) ); + }; - // Bail out early if there are no missing fonts. - if ( empty( $to_add ) ) { - return $data; - } + // Diff the arrays to find the missing fonts. + $to_add = array_diff( array_keys( $font_families_registered ), $get_families( $font_families_from_theme ) ); - // 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(); - } + // 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 ( $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; + 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; } - $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, + ); } - $data['settings']['typography']['fontFamilies'][] = array( - 'fontFamily' => str_contains( $family_name, ' ' ) ? "'{$family_name}'" : $family_name, - 'name' => $family_name, - 'slug' => $slug, - 'fontFace' => $font_faces, - ); + return $data; } - - return $data; } // `gutenberg_register_webfonts_from_theme_json()` calls `WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()`, which instantiates `WP_Theme_JSON_Gutenberg()`; diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index 347b6ff9c27668..0bbf0b8f405091 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -7,24 +7,24 @@ * @since 6.0.0 */ -if ( ! function_exists( 'wp_web_fonts' ) ) { +if ( ! function_exists( 'wp_webfonts' ) ) { /** - * Initialize $wp_web_fonts if it has not been set. + * Initialize $wp_webfonts if it has not been set. * * @since X.X.X * - * @global WP_Web_Fonts $wp_web_fonts + * @global WP_Webfonts $wp_webfonts * - * @return WP_Web_Fonts WP_Web_Fonts instance. + * @return WP_Webfonts WP_Webfonts instance. */ - function wp_web_fonts() { - global $wp_web_fonts; + function wp_webfonts() { + global $wp_webfonts; - if ( ! ( $wp_web_fonts instanceof WP_Web_Fonts ) ) { - $wp_web_fonts = new WP_Web_Fonts(); + if ( ! ( $wp_webfonts instanceof WP_Webfonts ) ) { + $wp_webfonts = new WP_Webfonts(); } - return $wp_web_fonts; + return $wp_webfonts; } } @@ -36,9 +36,9 @@ function wp_web_fonts() { * @return array|bool */ function wp_register_web_font_family( $font_family ) { - $wp_web_fonts = wp_web_fonts(); + $wp_webfonts = wp_webfonts(); - return $wp_web_fonts->add( $font_family, false ); + return $wp_webfonts->add( sanitize_title( $font_family ), false ); } } @@ -50,21 +50,21 @@ function wp_register_web_font_family( $font_family ) { * @return mixed */ function wp_register_web_font_variation( $font_family, $variation_handle, $variation ) { - return wp_web_fonts()->add_variation( $font_family, $variation_handle, $variation ); + return wp_webfonts()->add_variation( $font_family, $variation_handle, $variation ); } } -if ( ! function_exists( 'wp_register_web_fonts' ) ) { +if ( ! function_exists( 'wp_register_webfonts' ) ) { /** * Registers a list of web fonts and variations. * - * @param $web_fonts + * @param $webfonts * @return array */ - function wp_register_web_fonts( $web_fonts, $enqueue = false ) { + function wp_register_webfonts( $webfonts, $enqueue = false ) { $registered = array(); - foreach ( $web_fonts as $font_family => $variations ) { + foreach ( $webfonts as $font_family => $variations ) { wp_register_web_font_family( $font_family ); foreach ( $variations as $variation_handle => $variation ) { @@ -85,8 +85,8 @@ function wp_register_web_fonts( $web_fonts, $enqueue = false ) { * Enqueues a web font family and all variations. */ function wp_enqueue_web_font( $handle ) { - $wp_web_fonts = wp_web_fonts(); - $wp_web_fonts->enqueue( $handle ); + $wp_webfonts = wp_webfonts(); + $wp_webfonts->enqueue( $handle ); } } @@ -95,21 +95,21 @@ function wp_enqueue_web_font( $handle ) { * Enqueues a specific set of web font variations. */ function wp_enqueue_web_font_variations( $variations ) { - $wp_web_fonts = wp_web_fonts(); + $wp_webfonts = wp_webfonts(); // Looking to enqueue all variations of a font family. foreach ( $variations as $variation ) { - $wp_web_fonts->enqueue( $variation ); + $wp_webfonts->enqueue( $variation ); } } } if ( ! function_exists( 'wp_deregister_web_font_family' ) ) { /** - * Unregisters an entire font family and all vcariations. + * Unregisters an entire font family and all variations. */ function wp_deregister_web_font_family( $font_family ) { - wp_web_fonts()->remove_family( $font_family ); + wp_webfonts()->remove_family( $font_family ); } } @@ -118,27 +118,10 @@ function wp_deregister_web_font_family( $font_family ) { * @param $variation_handle */ function wp_deregister_web_font_variation( $font_family, $variation_handle ) { - wp_web_fonts()->remove_variation( $font_family, $variation_handle ); + wp_webfonts()->remove_variation( $font_family, $variation_handle ); } } - - - - - - - - - - - - -/** Unaltered so far. */ - - - - if ( ! function_exists( 'wp_register_webfont_provider' ) ) { /** * Registers a custom font service provider. @@ -192,6 +175,42 @@ function wp_get_webfont_providers() { } } +if ( ! function_exists( 'wp_print_webfonts' ) ) { + function wp_print_webfonts( $handles = false ) { + global $wp_webfonts; + + /** + * Fires before webfonts in the $handles queue are printed. + * + * @since X.X.X + */ + do_action( 'wp_print_webfonts' ); + + if ( '' === $handles ) { // For 'wp_head'. + $handles = false; + } + + _wp_scripts_maybe_doing_it_wrong( __FUNCTION__ ); + + if ( ! ( $wp_webfonts instanceof WP_Webfonts ) ) { + if ( ! $handles ) { + return array(); // No need to instantiate if nothing is there. + } + } + + return wp_webfonts()->do_items( $handles ); + } +} + + + + + + + + + + /** * Add webfonts mime types. */ From db1487aa9657ce41b7cbed77d90ef7e3fe504ef9 Mon Sep 17 00:00:00 2001 From: Jon Desrosiers Date: Tue, 26 Apr 2022 10:11:54 -0400 Subject: [PATCH 06/63] Simplify `add_dependency()` method. --- lib/experimental/class-wp-webfonts.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index c44f7aa88e0ca3..5f20794da48512 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -148,9 +148,7 @@ public function add_variation( $font_family, $variation_handle, $variation ) { * @param $variation_handle */ public function add_dependency( $font_family_handle, $variation_handle ) { - $dependencies = $this->registered[ $font_family_handle ]->deps; - $dependencies[] = $variation_handle; - $this->registered[ $font_family_handle ]->deps = $dependencies; + $this->registered[ $font_family_handle ]->deps[] = $variation_handle; } /** From 83730819bb34d26b912044d2470deebcb3e22377 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Thu, 18 Aug 2022 16:24:37 -0500 Subject: [PATCH 07/63] Prep the unit tests --- phpunit/class-wp-webfonts-test.php | 453 ---------------- phpunit/fixtures/mock-provider.php | 21 + phpunit/webfonts/wp-webfonts-testcase.php | 137 +++++ .../webfonts/wp-webfonts-tests-dataset.php | 513 ++++++++++++++++++ .../wpWebfontsProviderLocal-test.php} | 59 +- 5 files changed, 706 insertions(+), 477 deletions(-) delete mode 100644 phpunit/class-wp-webfonts-test.php create mode 100644 phpunit/fixtures/mock-provider.php create mode 100644 phpunit/webfonts/wp-webfonts-testcase.php create mode 100644 phpunit/webfonts/wp-webfonts-tests-dataset.php rename phpunit/{class-wp-webfonts-local-provider-test.php => webfonts/wpWebfontsProviderLocal-test.php} (94%) diff --git a/phpunit/class-wp-webfonts-test.php b/phpunit/class-wp-webfonts-test.php deleted file mode 100644 index 45732c6a265b4c..00000000000000 --- a/phpunit/class-wp-webfonts-test.php +++ /dev/null @@ -1,453 +0,0 @@ -old_wp_webfonts = $wp_webfonts; - - $wp_webfonts = null; - } - - public function tear_down() { - global $wp_webfonts; - - $wp_webfonts = $this->old_wp_webfonts; - parent::tear_down(); - } - - /** - * Test wp_register_webfonts() bulk register webfonts. - * - * @covers wp_register_webfonts - * @covers WP_Webfonts::register_font - * @covers WP_Webfonts::get_registered_fonts - * @covers WP_Webfonts::get_enqueued_fonts - */ - public function test_wp_register_webfonts() { - $font_family_name = 'Source Serif Pro'; - - $fonts = array( - array( - 'provider' => 'local', - 'font-family' => $font_family_name, - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ), - array( - 'provider' => 'local', - 'font-family' => $font_family_name, - 'font-style' => 'italic', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2', - 'font-display' => 'fallback', - ), - ); - - $expected = array( - wp_webfonts()->get_font_slug( $font_family_name ) => $fonts, - ); - - wp_register_webfonts( $fonts ); - $this->assertEquals( $expected, wp_webfonts()->get_registered_webfonts() ); - $this->assertEquals( array(), wp_webfonts()->get_enqueued_webfonts() ); - } - - /** - * Test wp_register_webfont() register a single webfont. - * - * @covers wp_register_webfont - * @covers WP_Webfonts::register_font - * @covers WP_Webfonts::get_registered_fonts - * @covers WP_Webfonts::get_enqueued_fonts - */ - public function test_wp_register_webfont() { - $font_family_name = 'Source Serif Pro'; - - $font = array( - 'provider' => 'local', - 'font-family' => $font_family_name, - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ); - - $expected = array( - wp_webfonts()->get_font_slug( $font_family_name ) => array( $font ), - ); - - wp_register_webfont( $font ); - $this->assertEquals( $expected, wp_webfonts()->get_registered_webfonts() ); - $this->assertEquals( array(), wp_webfonts()->get_enqueued_webfonts() ); - } - - /** - * Test wp_register_webfont() does not enqueue the webfont on registration. - * - * @covers wp_register_webfont - * @covers WP_Webfonts::register_font - * @covers WP_Webfonts::get_registered_fonts - * @covers WP_Webfonts::get_enqueued_fonts - */ - public function test_wp_register_webfont_does_not_enqueue_on_registration() { - $font_family_name = 'Source Serif Pro'; - - $font = array( - 'provider' => 'local', - 'font-family' => $font_family_name, - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ); - - $expected = array( - wp_webfonts()->get_font_slug( $font_family_name ) => array( $font ), - ); - - wp_register_webfont( $font ); - $this->assertEquals( $expected, wp_webfonts()->get_registered_webfonts() ); - $this->assertEquals( array(), wp_webfonts()->get_enqueued_webfonts() ); - } - - /** - * Test wp_enqueue_webfonts() bulk enqueue webfonts. - * - * @covers wp_enqueue_webfonts - * @covers WP_Webfonts::enqueue_font - * @covers WP_Webfonts::get_enqueued_fonts - * @covers WP_Webfonts::get_registered_fonts - */ - public function test_wp_enqueue_webfonts() { - $source_serif_pro = array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ); - - wp_register_webfont( $source_serif_pro ); - - $roboto = array( - 'provider' => 'local', - 'font-family' => 'Roboto', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/roboto/Roboto.ttf.woff2', - 'font-display' => 'fallback', - ); - - wp_register_webfont( $roboto ); - - $expected = array( - wp_webfonts()->get_font_slug( $source_serif_pro['font-family'] ) => array( $source_serif_pro ), - wp_webfonts()->get_font_slug( $roboto['font-family'] ) => array( $roboto ), - ); - - wp_enqueue_webfonts( - array( - $source_serif_pro['font-family'], - $roboto['font-family'], - ) - ); - - $this->assertEquals( $expected, wp_webfonts()->get_enqueued_webfonts() ); - $this->assertEquals( array(), wp_webfonts()->get_registered_webfonts() ); - } - - /** - * Test wp_enqueue_font() enqueues a registered webfont. - * - * @covers wp_enqueue_webfont - * @covers WP_Webfonts::enqueued_font - * @covers WP_Webfonts::get_enqueued_fonts - * @covers WP_Webfonts::get_registered_fonts - */ - public function test_wp_enqueue_webfont_enqueues_registered_webfont() { - $font_family_name = 'Source Serif Pro'; - - $font = array( - 'provider' => 'local', - 'font-family' => $font_family_name, - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ); - - $expected = array( - wp_webfonts()->get_font_slug( $font_family_name ) => array( $font ), - ); - - wp_register_webfont( $font ); - wp_enqueue_webfont( $font_family_name ); - - $this->assertEquals( array(), wp_webfonts()->get_registered_webfonts() ); - $this->assertEquals( $expected, wp_webfonts()->get_enqueued_webfonts() ); - } - - /** - * Test wp_enqueue_font() does not enqueue a webfont that was not registered. - * - * @covers wp_enqueue_webfont - * @covers WP_Webfonts::enqueued_font - * @covers WP_Webfonts::get_enqueued_fonts - * @covers WP_Webfonts::get_registered_fonts - * - * @expectedIncorrectUsage WP_Webfonts::enqueue_webfont - */ - public function test_wp_enqueue_webfont_does_not_enqueue_unregistered_webfont() { - $font_family_name = 'Source Serif Pro'; - - wp_enqueue_webfont( $font_family_name ); - - $this->assertSame( array(), wp_webfonts()->get_registered_webfonts(), 'WP_Webfonts::get_registered_webfonts should return an empty array' ); - $this->assertSame( array(), wp_webfonts()->get_enqueued_webfonts(), 'WP_Webfonts::get_enqueued_webfonts should return an empty array' ); - } - - /** - * @covers wp_register_webfont - * @covers WP_Webfonts::register_provider - * @covers WP_Webfonts::get_providers - */ - public function test_get_providers() { - wp_register_webfont_provider( 'test-provider', 'Test_Provider' ); - $this->assertEquals( - array( - 'local' => 'WP_Webfonts_Provider_Local', - 'test-provider' => 'Test_Provider', - ), - wp_get_webfont_providers() - ); - } - - /** - * @dataProvider data_get_font_slug_when_cannot_determine_fontfamily - * @covers WP_Webfonts::get_font_slug - * - * @expectedIncorrectUsage WP_Webfonts::get_font_slug - */ - public function test_get_font_slug_when_cannot_determine_fontfamily( $to_convert ) { - $this->assertFalse( wp_webfonts()->get_font_slug( $to_convert ) ); - } - - /** - * Data provider. - * - * @return array[] - */ - public function data_get_font_slug_when_cannot_determine_fontfamily() { - return array( - 'empty array' => array( array() ), - 'array without a font-family key' => array( - array( - 'provider' => 'local', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-display' => 'fallback', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - ), - ), - "array with 'font family' key" => array( - array( 'font family' => 'Source Serif Pro' ), - ), - "array with 'Font-Family' key" => array( - array( 'Font-Family' => 'Source Serif Pro' ), - ), - "array with 'FontFamily' key" => array( - array( 'FontFamily' => 'Source Serif Pro' ), - ), - ); - } - - /** - * @dataProvider data_get_font_slug - * @covers WP_Webfonts::get_font_slug - */ - public function test_get_font_slug( $to_convert, $expected ) { - $this->assertSame( $expected, wp_webfonts()->get_font_slug( $to_convert ) ); - } - - /** - * Data provider. - * - * @return array[] - */ - public function data_get_font_slug() { - return array( - "array using 'fontFamily' format" => array( - 'to_convert' => array( 'fontFamily' => 'Source Serif Pro' ), - 'expected' => 'source-serif-pro', - ), - "array using 'font-family' format" => array( - 'to_convert' => array( 'font-family' => 'Source Serif Pro' ), - 'expected' => 'source-serif-pro', - ), - 'string with font family name' => array( - 'to_convert' => 'Source Serif Pro', - 'expected' => 'source-serif-pro', - ), - 'empty string' => array( - 'to_convert' => '', - 'expected' => '', - ), - ); - } - - /** - * @covers WP_Webfonts::validate_webfont - */ - public function test_validate_webfont() { - $this->expectNotice(); - - // Test empty array. - $this->assertFalse( wp_webfonts()->validate_webfont( array() ) ); - - $font = array( - 'font-family' => 'Test Font 1', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - ); - - // Test missing provider fallback to local. - $this->assertEquals( 'local', wp_webfonts()->validate_webfont( $font )['provider'] ); - - // Test missing font-weight fallback to 400. - $this->assertEquals( '400', wp_webfonts()->validate_webfont( $font )['font-weight'] ); - - // Test missing font-style fallback to normal. - $this->assertEquals( 'normal', wp_webfonts()->validate_webfont( $font )['font-style'] ); - - // Test missing font-display fallback to fallback. - $this->assertEquals( 'fallback', wp_webfonts()->validate_webfont( $font )['font-display'] ); - - // Test local font with missing "src". - $this->assertFalse( wp_webfonts()->validate_webfont( array( 'font-family' => 'Test Font 2' ) ) ); - - // Test valid src URL, without a protocol. - $font['src'] = '//example.com/SourceSerif4Variable-Roman.ttf.woff2'; - $this->assertEquals( wp_webfonts()->validate_webfont( $font )['src'], $font['src'] ); - - // Test font-weight. - $font_weights = array( 100, '100', '100 900', 'normal' ); - foreach ( $font_weights as $value ) { - $font['font-weight'] = $value; - $this->assertEquals( wp_webfonts()->validate_webfont( $font )['font-weight'], $value ); - } - - // Test that invalid keys get removed from the font. - $font['invalid-key'] = 'invalid'; - $this->assertArrayNotHasKey( 'invalid-key', wp_webfonts()->validate_webfont( $font ) ); - } - - /** - * Test generate_and_enqueue_styles outputs only enqueued webfonts. - * - * @covers WP_Webfonts::generate_and_enqueue_styles - */ - public function test_generate_and_enqueue_styles() { - wp_register_webfonts( - array( - array( - 'provider' => 'local', - 'font-family' => 'Roboto', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/roboto/Roboto-Regular.ttf', - 'font-display' => 'fallback', - ), - array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ), - ) - ); - - wp_enqueue_webfont( 'Source Serif Pro' ); - - wp_webfonts()->generate_and_enqueue_styles(); - - $expected = <<assertStringContainsString( - $expected, - get_echo( 'wp_print_styles' ) - ); - } - - /** - * Test generate_and_enqueue_editor_styles outputs registered and enqueued webfonts. - * Both are necessary so the editor correctly loads webfonts picked while in the editor. - * - * @covers WP_Webfonts::generate_and_enqueue_editor_styles - */ - public function test_generate_and_enqueue_editor_styles() { - wp_register_webfonts( - array( - array( - 'provider' => 'local', - 'font-family' => 'Roboto', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/roboto/Roboto-Regular.ttf', - 'font-display' => 'fallback', - ), - array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ), - ) - ); - - wp_enqueue_webfont( 'Source Serif Pro' ); - - wp_webfonts()->generate_and_enqueue_editor_styles(); - - $expected = <<assertStringContainsString( - $expected, - get_echo( 'wp_print_styles' ) - ); - } -} diff --git a/phpunit/fixtures/mock-provider.php b/phpunit/fixtures/mock-provider.php new file mode 100644 index 00000000000000..152badb1ce266c --- /dev/null +++ b/phpunit/fixtures/mock-provider.php @@ -0,0 +1,21 @@ +'; + + public function get_css() { + return $this->css; + } +} diff --git a/phpunit/webfonts/wp-webfonts-testcase.php b/phpunit/webfonts/wp-webfonts-testcase.php new file mode 100644 index 00000000000000..495ef996a7e51b --- /dev/null +++ b/phpunit/webfonts/wp-webfonts-testcase.php @@ -0,0 +1,137 @@ +old_wp_webfonts = $GLOBALS['wp_webfonts']; + $GLOBALS['wp_webfonts'] = null; + } + + public function tear_down() { + $GLOBALS['wp_webfonts'] = $this->old_wp_webfonts; + parent::tear_down(); + } + + protected function set_up_mock( $method ) { + if ( is_string( $method ) ) { + $method = array( $method ); + } + $mock = $this->getMockBuilder( WP_Webfonts::class )->setMethods( $method )->getMock(); + + // Set the global. + $GLOBALS['wp_webfonts'] = $mock; + + return $mock; + } + + protected function get_registered_handles() { + return array_keys( $this->get_registered() ); + } + + protected function get_registered() { + return wp_webfonts()->registered; + } + + protected function get_variations( $font_family, $wp_webfonts = null ) { + if ( ! ( $wp_webfonts instanceof WP_Webfonts ) ) { + $wp_webfonts = wp_webfonts(); + } + return $wp_webfonts->registered[ $font_family ]->deps; + } + + protected function get_enqueued_handles() { + return wp_webfonts()->queue; + } + + protected function get_queued_before_register( $wp_webfonts = null ) { + return $this->get_property_value( 'queued_before_register', WP_Dependencies::class, $wp_webfonts ); + } + + protected function get_property_value( $property_name, $class, $wp_webfonts = null ) { + $property = new ReflectionProperty( $class, $property_name ); + $property->setAccessible( true ); + + if ( ! $wp_webfonts ) { + $wp_webfonts = wp_webfonts(); + } + return $property->getValue( $wp_webfonts ); + } + + /** + * Sets up multiple font family and variation mocks. + * + * @param array $inputs Array of array( font-family => variations ) to setup. + * @param WP_Webfonts $wp_webfonts Instance of WP_Webfonts. + * @return stdClass[] Array of registered mocks. + */ + protected function setup_registration_mocks( array $inputs, WP_Webfonts $wp_webfonts ) { + $mocks = array(); + + $build_mock = function( $handle ) use ( &$mocks, $wp_webfonts ) { + $mock = new stdClass(); + $mock->deps = array(); + // Add to each queue. + $mocks[ $handle ] = $mock; + $wp_webfonts->registered[ $handle ] = $mock; + + return $mock; + }; + + foreach ( $inputs as $font_family => $variations ) { + $font_mock = $build_mock( $font_family ); + + foreach ( $variations as $variation_handle => $variation ) { + if ( ! is_string( $variation_handle ) ) { + $variation_handle = $variation; + } + $build_mock( $variation_handle ); + $font_mock->deps[] = $variation_handle; + } + } + + return $mocks; + } + + /** + * Register one or more font-family and its variations to set up a test. + * + * @param string $font_family Font family to test. + * @param array $variations Variations. + * @param WP_Webfonts|null $wp_webfonts Optional. Instance of the WP_Webfonts. + */ + protected function setup_register( $font_family, $variations, $wp_webfonts = null ) { + if ( ! ( $wp_webfonts instanceof WP_Webfonts ) ) { + $wp_webfonts = wp_webfonts(); + } + + $wp_webfonts->add( $font_family, false ); + + foreach ( $variations as $variation_handle => $variation ) { + if ( ! is_string( $variation_handle ) ) { + $variation_handle = ''; + } + $wp_webfonts->add_variation( $font_family, $variation, $variation_handle ); + } + } +} diff --git a/phpunit/webfonts/wp-webfonts-tests-dataset.php b/phpunit/webfonts/wp-webfonts-tests-dataset.php new file mode 100644 index 00000000000000..33de17c13580ff --- /dev/null +++ b/phpunit/webfonts/wp-webfonts-tests-dataset.php @@ -0,0 +1,513 @@ + array( + 'expected' => 'lato-400-normal', + 'font_family_handle' => 'lato', + 'variation' => array( + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + ), + ), + + 'font-weight and font-style not defined; with variation handle' => array( + 'expected' => 'my-custom-handle', + 'font_family_handle' => 'lato', + 'variation' => array( + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + ), + 'variation_handle' => 'my-custom-handle', + ), + + 'font-weight defined; without variation handle' => array( + 'expected' => 'source-serif-pro-200-900-normal', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'font-family' => 'Source Serif Pro', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + ), + ), + + 'font-weight defined; with variation handle' => array( + 'expected' => 'my_custom_handle', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'font-family' => 'Source Serif Pro', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + ), + 'variation_handle' => 'my_custom_handle', + ), + + 'font-weight defined; without variation handle' => array( + 'expected' => 'source-serif-pro-200-900-normal', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'font-family' => 'Source Serif Pro', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + ), + ), + + 'font-weight defined; with variation handle' => array( + 'expected' => 'my_custom_handle', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'font-family' => 'Source Serif Pro', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + ), + 'variation_handle' => 'my_custom_handle', + ), + + 'font-weight defined; without variation handle' => array( + 'expected' => 'source-serif-pro-200-900-normal', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + + 'more variation properties; with variation handle' => array( + 'expected' => 'my-custom-handle', + 'font_family_handle' => 'source-serif-pro', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'variation_handle' => 'my-custom-handle', + ), + ); + } + + /** + * Data provider for testing registration of variations where the font family is not defined. + * + * @return array + */ + public function data_font_family_not_define_in_variation() { + return array( + 'empty string font family handle' => array( + 'font_family_handle' => '', + 'variation' => array( + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + ), + 'expected_message' => 'Font family handle must be a non-empty string', + ), + 'empty string font family handle with font-family defined in variant' => array( + 'font_family_handle' => '', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Lato', + 'font-weight' => '200', + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + ), + 'expected_message' => 'Font family handle must be a non-empty string', + ), + 'non string font family handle' => array( + 'font_family_handle' => 10, + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family handle must be a non-empty string', + ), + ); + } + + /** + * Data provider for testing when the variation's handle can't be determine from the given input. + * + * @return array + */ + public function data_unable_determine_variation_handle() { + return array( + 'integer values' => array( + 'font_family_handle' => 'lato', + 'variation' => array( + 'font-weight' => 400, + 'font-style' => 0, + 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require', + ), + 'with empty string font-weight and font-style' => array( + 'font_family_handle' => 'merriweather', + 'variation' => array( + 'font-weight' => '', + 'font-style' => '', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require', + ), + 'integer font-weight, empty string font-style' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-weight' => 400, + 'font-style' => '', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require', + ), + 'empty string font-weight, integer font-style' => array( + 'font_family' => 'lato', + 'variation' => array( + 'font-weight' => '', + 'font-style' => 400, + 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + 'expected_message' => 'Variant handle could not be determined as font-weight and/or font-style are require', + ), + ); + } + + /** + * Data provider for testing an invalid variation. + * + * @return array + */ + public function data_invalid_variation() { + return array( + 'src: undefined' => array( + 'expected' => 'Webfont src must be a non-empty string or an array of strings.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Some font', + 'font-weight' => '200', + ), + ), + 'src: null' => array( + 'expected' => 'Webfont src must be a non-empty string or an array of strings.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Some font', + 'font-weight' => '200', + 'src' => null, + ), + ), + 'src: empty string' => array( + 'expected' => 'Webfont src must be a non-empty string or an array of strings.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Some font', + 'font-weight' => '200', + 'src' => '', + ), + ), + 'src: empty array' => array( + 'expected' => 'Webfont src must be a non-empty string or an array of strings.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-weight' => '200', + 'src' => array(), + ), + ), + 'src: array of an empty string' => array( + 'expected' => 'Each webfont src must be a non-empty string.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-weight' => '200', + 'src' => array( '' ), + ), + ), + 'src: array of a non-string' => array( + 'expected' => 'Each webfont src must be a non-empty string.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-weight' => '200', + 'src' => array( null ), + ), + ), + 'src: array with an empty string' => array( + 'expected' => 'Each webfont src must be a non-empty string.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-weight' => '200', + 'src' => array( + 'https://example.com/assets/fonts/merriweather.ttf.woff2', + '', + 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + ), + ), + 'src: array with a non-string' => array( + 'expected' => 'Each webfont src must be a non-empty string.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'provider' => 'local', + 'font-weight' => '200', + 'src' => array( + 'https://example.com/assets/fonts/merriweather.ttf.woff2', + null, + 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + ), + ), + 'provider does not exist' => array( + 'expected' => 'The provider class specified does not exist.', + 'font_family_handle' => 'merriweather', + 'variation' => array( + 'provider' => 'doesnotexit', + 'font-weight' => '200 900', + ), + ), + 'font-weight: null' => array( + 'expected' => 'Webfont font-weight must be a properly formatted string or integer.', + 'font_family_handle' => 'merriweather', + 'variation' => array( + 'font-weight' => null, + 'font-style' => 'normal', + 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + ), + ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_deregister() { + return array( + 'one family family no variations' => array( + 'font_family' => 'lato', + 'inputs' => array( + 'lato' => array(), + ), + 'handles' => array( 'lato' ), + 'expected' => array(), + ), + 'one family family with 1 variation' => array( + 'font_family' => 'merriweather', + 'inputs' => array( + 'merriweather' => array( + 'merriweather-200-900-normal' => array( + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + ), + ), + 'handles' => array( 'merriweather', 'merriweather-200-900-normal' ), + 'expected' => array(), + ), + 'font family with multiple variations' => array( + 'font_family' => 'Source Serif Pro', + 'inputs' => array( + 'Source Serif Pro' => array( + 'Source Serif Pro-300-normal' => array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '300', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'Source Serif Pro-900-italic' => array( + 'provider' => 'local', + 'font-style' => 'italic', + 'font-weight' => '900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + ), + 'handles' => array( 'Source Serif Pro', 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic' ), + 'expected' => array(), + ), + 'multiple font families without variations' => array( + 'font_family' => 'Source Serif Pro', + 'inputs' => array( + 'lato' => array(), + 'my-font' => array(), + 'Source Serif Pro' => array(), + 'some other font' => array(), + ), + 'handles' => array( 'lato', 'my-font', 'Source Serif Pro', 'some other font' ), + 'expected' => array( 'lato', 'my-font', 'some other font' ), + ), + 'multiple font families with variations' => array( + 'font_family' => 'my-font', + 'inputs' => array( + 'merriweather' => array( + 'merriweather-200-900-normal' => array( + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + ), + 'Source Serif Pro' => array( + 'Source Serif Pro-300-normal' => array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '300', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'Source Serif Pro-900-italic' => array( + 'provider' => 'local', + 'font-style' => 'italic', + 'font-weight' => '900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + 'my-font' => array( + 'my-font-300-italic' => array( + 'font-weight' => '300', + 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2', + ), + ), + ), + 'handles' => array( + 'merriweather', + 'merriweather-200-900-normal', + 'Source Serif Pro', + 'Source Serif Pro-300-normal', + 'Source Serif Pro-900-italic', + 'my-font', + 'my-font-300-italic', + ), + 'expected' => array( + 'merriweather', + 'merriweather-200-900-normal', + 'Source Serif Pro', + 'Source Serif Pro-300-normal', + 'Source Serif Pro-900-italic', + ), + ), + ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_font_family_handles() { + return array( + 'single word handle' => array( 'lato' ), + 'multiple word handle' => array( 'source-sans-pro' ), + 'single word name' => array( 'Merriweather' ), + 'multiple word name' => array( 'My Cool Font' ), + ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_enqueue() { + return array( + '1 font-family' => array( + 'font_family' => 'lato', + 'expected_queue' => array( 'lato' ), + 'expected_queued_before_register' => array( + 'lato' => null, + ), + ), + '2 font families' => array( + 'font_family' => array( 'merriweather', 'my-font' ), + 'expected_queue' => array( 'merriweather', 'my-font' ), + 'expected_queued_before_register' => array( + 'merriweather' => null, + 'my-font' => null, + ), + ), + '3 font families' => array( + 'font_family' => array( 'merriweather', 'my-font', 'Source Serif Pro' ), + 'expected_queue' => array( 'merriweather', 'my-font', 'Source Serif Pro' ), + 'expected_queued_before_register' => array( + 'merriweather' => null, + 'my-font' => null, + 'Source Serif Pro' => null, + ), + ), + ); + } + + protected function get_data_registry() { + return array( + 'lato' => array(), + 'merriweather' => array( + 'merriweather-200-900-normal' => array( + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + ), + 'Source Serif Pro' => array( + 'Source Serif Pro-300-normal' => array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '300', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'Source Serif Pro-900-italic' => array( + 'provider' => 'local', + 'font-style' => 'italic', + 'font-weight' => '900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + 'my-font' => array( + 'my-font-300-normal' => array( + 'font-weight' => '300', + 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2', + ), + 'my-font-300-italic' => array( + 'font-weight' => '300', + 'font-style' => 'italic', + 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2', + ), + 'my-font-900-normal' => array( + 'font-weight' => '900', + 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2', + ), + ), + ); + } +} diff --git a/phpunit/class-wp-webfonts-local-provider-test.php b/phpunit/webfonts/wpWebfontsProviderLocal-test.php similarity index 94% rename from phpunit/class-wp-webfonts-local-provider-test.php rename to phpunit/webfonts/wpWebfontsProviderLocal-test.php index 43ef4a84951c84..9b60283fce9642 100644 --- a/phpunit/class-wp-webfonts-local-provider-test.php +++ b/phpunit/webfonts/wpWebfontsProviderLocal-test.php @@ -1,10 +1,15 @@ set_up_theme(); } - /** - * Local `src` paths to need to be relative to the theme. This method sets up the - * `wp-content/themes/` directory to ensure consistency when running tests. - */ - private function set_up_theme() { - $this->theme_root = realpath( DIR_TESTDATA . '/themedir1' ); - $this->orig_theme_dir = $GLOBALS['wp_theme_directories']; - $GLOBALS['wp_theme_directories'] = array( $this->theme_root ); - - $theme_root_callback = function () { - return $this->theme_root; - }; - add_filter( 'theme_root', $theme_root_callback ); - add_filter( 'stylesheet_root', $theme_root_callback ); - add_filter( 'template_root', $theme_root_callback ); - - // Clear caches. - wp_clean_themes_cache(); - unset( $GLOBALS['wp_themes'] ); - } - - public function tear_down() { + function tear_down() { // Restore the original theme directory setup. $GLOBALS['wp_theme_directories'] = $this->orig_theme_dir; wp_clean_themes_cache(); @@ -109,7 +93,10 @@ public function data_get_css() { ), ), 'expected' => << @font-face{font-family:"Open Sans";font-style:italic;font-weight:bold;src:local("Open Sans"), url('http://example.org/assets/fonts/OpenSans-Italic-VariableFont_wdth,wght.ttf') format('truetype');} + + CSS , ), @@ -133,13 +120,37 @@ public function data_get_css() { ), ), 'expected' => << @font-face{font-family:"Source Serif Pro";font-style:normal;font-weight:200 900;font-stretch:normal;src:local("Source Serif Pro"), url('http://example.org/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2') format('woff2');}@font-face{font-family:"Source Serif Pro";font-style:italic;font-weight:200 900;font-stretch:normal;src:local("Source Serif Pro"), url('http://example.org/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2') format('woff2');} + + CSS , ), ); } + /** + * Local `src` paths to need to be relative to the theme. This method sets up the + * `wp-content/themes/` directory to ensure consistency when running tests. + */ + private function set_up_theme() { + $this->theme_root = realpath( DIR_TESTDATA . '/themedir1' ); + $this->orig_theme_dir = $GLOBALS['wp_theme_directories']; + $GLOBALS['wp_theme_directories'] = array( $this->theme_root ); + + $theme_root_callback = function () { + return $this->theme_root; + }; + add_filter( 'theme_root', $theme_root_callback ); + add_filter( 'stylesheet_root', $theme_root_callback ); + add_filter( 'template_root', $theme_root_callback ); + + // Clear caches. + wp_clean_themes_cache(); + unset( $GLOBALS['wp_themes'] ); + } + private function get_webfonts_property() { $property = new ReflectionProperty( $this->provider, 'webfonts' ); $property->setAccessible( true ); From 63494010aaa6521e7996a62c15f03912b9334f18 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Thu, 18 Aug 2022 16:29:16 -0500 Subject: [PATCH 08/63] wp_webfonts() plus tests --- lib/experimental/class-wp-webfonts.php | 8 ++++-- lib/experimental/webfonts.php | 3 +- phpunit/webfonts/wpWebfonts-test.php | 38 ++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 phpunit/webfonts/wpWebfonts-test.php diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 5f20794da48512..aafcf0505526a7 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -5,14 +5,16 @@ class WP_Webfonts extends WP_Dependencies { /** * An array of registered providers. * - * @since 6.0.0 + * @since X.X.X * * @var array */ private $providers = array(); /** + * Constructor. * + * @since X.X.X */ public function __construct() { /** @@ -28,7 +30,7 @@ public function __construct() { /** * Get the list of all registered web fonts and variations. * - * @since 6.0.0 + * @since X.X.X * * @return strings[] */ @@ -39,6 +41,8 @@ public function get_registered() { /** * Get the list of enqueued web fonts and variations. * + * @since X.X.X + * * @return array[] */ public function get_enqueued() { diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index 0bbf0b8f405091..fca6aadca1f876 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -4,7 +4,7 @@ * * @package WordPress * @subpackage WebFonts - * @since 6.0.0 + * @since X.X.X */ if ( ! function_exists( 'wp_webfonts' ) ) { @@ -22,6 +22,7 @@ function wp_webfonts() { if ( ! ( $wp_webfonts instanceof WP_Webfonts ) ) { $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->register_provider( 'local', 'WP_Webfonts_Provider_Local' ); } return $wp_webfonts; diff --git a/phpunit/webfonts/wpWebfonts-test.php b/phpunit/webfonts/wpWebfonts-test.php new file mode 100644 index 00000000000000..32067a9fa61c9a --- /dev/null +++ b/phpunit/webfonts/wpWebfonts-test.php @@ -0,0 +1,38 @@ +assertInstanceOf( WP_Webfonts::class, wp_webfonts() ); + } + + public function test_global_set() { + global $wp_webfonts; + $this->assertNull( $wp_webfonts ); + $instance = wp_webfonts(); + $this->assertInstanceOf( WP_Webfonts::class, $wp_webfonts ); + $this->assertSame( $instance, $wp_webfonts ); + } + + public function test_local_provider_is_automatically_registered() { + $expected = array( + 'local' => array( + 'class' => 'WP_Webfonts_Provider_Local', + 'fonts' => array(), + ), + ); + $this->assertSame( $expected, wp_webfonts()->get_providers() ); + } +} From fb5eb265452dfcfee5eb30d7e8085dc6d473b1e5 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Thu, 18 Aug 2022 16:38:14 -0500 Subject: [PATCH 09/63] wp_register_font_family() plus tests --- lib/experimental/class-wp-webfonts-utils.php | 36 +++++ .../register-webfonts-from-theme-json.php | 2 +- lib/experimental/webfonts.php | 22 +-- lib/load.php | 1 + .../webfonts/wpRegisterFontFamily-test.php | 133 ++++++++++++++++++ phpunit/webfonts/wpWebfonts/add-test.php | 45 ++++++ .../convertFontFamilyIntoHandle-test.php | 84 +++++++++++ 7 files changed, 314 insertions(+), 9 deletions(-) create mode 100644 lib/experimental/class-wp-webfonts-utils.php create mode 100644 phpunit/webfonts/wpRegisterFontFamily-test.php create mode 100644 phpunit/webfonts/wpWebfonts/add-test.php create mode 100644 phpunit/webfonts/wpWebfontsUtils/convertFontFamilyIntoHandle-test.php diff --git a/lib/experimental/class-wp-webfonts-utils.php b/lib/experimental/class-wp-webfonts-utils.php new file mode 100644 index 00000000000000..eae8c1e7866ce7 --- /dev/null +++ b/lib/experimental/class-wp-webfonts-utils.php @@ -0,0 +1,36 @@ +add( sanitize_title( $font_family ), false ); + $result = wp_webfonts()->add( $handle, false ) ? $handle : null; + return $result ? $handle : null; } } @@ -66,7 +72,7 @@ function wp_register_webfonts( $webfonts, $enqueue = false ) { $registered = array(); foreach ( $webfonts as $font_family => $variations ) { - wp_register_web_font_family( $font_family ); + wp_register_font_family( $font_family ); foreach ( $variations as $variation_handle => $variation ) { $registered[] = wp_register_web_font_variation( $font_family, $variation_handle, $variation ); diff --git a/lib/load.php b/lib/load.php index 2bb50bd50e0fc2..471552e102ffe3 100644 --- a/lib/load.php +++ b/lib/load.php @@ -112,6 +112,7 @@ function gutenberg_is_experiment_enabled( $name ) { // Experimental features. remove_action( 'plugins_loaded', '_wp_theme_json_webfonts_handler' ); // Turns off WP 6.0's stopgap handler for Webfonts API. require __DIR__ . '/experimental/block-editor-settings-mobile.php'; +require __DIR__ . '/experimental/class-wp-webfonts-utils.php'; require __DIR__ . '/experimental/register-webfonts-from-theme-json.php'; if ( ! class_exists( 'WP_HTML_Tag_Processor' ) ) { require __DIR__ . '/experimental/html/index.php'; diff --git a/phpunit/webfonts/wpRegisterFontFamily-test.php b/phpunit/webfonts/wpRegisterFontFamily-test.php new file mode 100644 index 00000000000000..6064fbac37c761 --- /dev/null +++ b/phpunit/webfonts/wpRegisterFontFamily-test.php @@ -0,0 +1,133 @@ +set_up_mock( 'add' ); + $mock->expects( $this->once() ) + ->method( 'add' ) + ->with( + $this->identicalTo( $expected_handle ), + $this->identicalTo( false ) + ) + ->will( $this->returnValue( $expected_handle ) ); + + $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family should return true after registering' ); + } + + /** + * Integration test for registering a font family. + * + * @dataProvider data_font_family + * + * @covers WP_Webfonts::add + * + * @param string $font_family Font family to test. + * @param string $expected_handle Expected registered handle. + */ + public function test_register( $font_family, $expected_handle ) { + $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family should return true after registering' ); + $this->assertSame( array( $expected_handle ), $this->get_registered_handles(), 'After registering, the registry should contain the font family handle' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_font_family() { + return array( + 'single word name' => array( + 'font_family' => 'Lato', + 'expected_handle' => 'lato', + ), + 'multiple word name' => array( + 'font_family' => 'Source Sans Pro', + 'expected_handle' => 'source-sans-pro', + ), + 'handle' => array( + 'font_family' => 'source-serif-pro', + 'expected_handle' => 'source-serif-pro', + ), + ); + } + + /** + * Unit test for registering a font-family that mocks WP_Webfonts. + * + * @dataProvider data_invalid_font_family + * + * @param string $invalid_input Invalid input to test. + */ + public function test_unit_register_fails( $invalid_input ) { + $mock = $this->set_up_mock( 'add' ); + $mock->expects( $this->never() )->method( 'add' ); + + $this->assertNull( wp_register_font_family( $invalid_input ), 'Registering an invalid input should return null' ); + } + + /** + * Integration test for registering a font family. + * + * @dataProvider data_invalid_font_family + * + * @covers WP_Webfonts::add + * + * @param string $invalid_input Invalid input to test. + */ + public function test_register_fails( $invalid_input ) { + $this->assertNull( wp_register_font_family( $invalid_input ), 'Registering an invalid input should return null' ); + $this->assertEmpty( $this->get_registered(), 'Invalid input should not register' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_invalid_font_family() { + return array( + 'non-string' => array( null ), + 'empty string' => array( '' ), + ); + } + + /** + * Integration test for attempting to re-register a font family. + * + * @dataProvider data_font_family + * + * @covers WP_Webfonts::add + * + * @param string $font_family Font family to test. + * @param string $expected_handle Expected registered handle. + */ + public function test_re_register( $font_family, $expected_handle ) { + // Register the font family. + wp_register_font_family( $font_family ); + + // Attempt to re-register it. + $this->assertNull( wp_register_font_family( $font_family ), 'Font family should return true after registering' ); + $this->assertSame( array( $expected_handle ), $this->get_registered_handles(), 'The font family should only be registered once' ); + } +} diff --git a/phpunit/webfonts/wpWebfonts/add-test.php b/phpunit/webfonts/wpWebfonts/add-test.php new file mode 100644 index 00000000000000..91c79bf1542a6f --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/add-test.php @@ -0,0 +1,45 @@ +assertTrue( $wp_webfonts->add( $handle, false ), 'Registering a handle should return true' ); + $this->assertCount( 1, $wp_webfonts->registered ); + $this->assertArrayHasKey( $handle, $wp_webfonts->registered, 'Font family handle should be in the registry after registration' ); + + } + + /** + * Data provider. + * + * @return array + */ + public function data_handles() { + return array( + 'name: multiple' => array( 'Source Serif Pro' ), + 'handle: multiple' => array( 'source-serif-pro' ), + 'name: single' => array( 'Merriweather' ), + 'handle: single' => array( 'merriweather' ), + 'handle: variation' => array( 'my-custom-font-200-900-normal' ), + ); + } +} diff --git a/phpunit/webfonts/wpWebfontsUtils/convertFontFamilyIntoHandle-test.php b/phpunit/webfonts/wpWebfontsUtils/convertFontFamilyIntoHandle-test.php new file mode 100644 index 00000000000000..d258f1e5c435df --- /dev/null +++ b/phpunit/webfonts/wpWebfontsUtils/convertFontFamilyIntoHandle-test.php @@ -0,0 +1,84 @@ +assertSame( $expected, WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_with_valid_input() { + return array( + 'font family single word name' => array( + 'font_family' => 'Merriweather', + 'expected' => 'merriweather', + ), + 'font family multiword name' => array( + 'font_family' => 'Source Sans Pro', + 'expected' => 'source-sans-pro', + ), + 'font family handle delimited by hyphens' => array( + 'font_family' => 'source-serif-pro', + 'expected' => 'source-serif-pro', + ), + 'font family handle delimited by underscore' => array( + 'font_family' => 'source_serif_pro', + 'expected' => 'source_serif_pro', + ), + 'font family handle delimited by hyphens and underscore' => array( + 'font_family' => 'my-custom_font_family', + 'expected' => 'my-custom_font_family', + ), + 'font family handle delimited mixture' => array( + 'font_family' => 'My custom_font-family', + 'expected' => 'my-custom_font-family', + ), + ); + } + + /** + * @dataProvider data_with_invalid_input + * + * @covers WP_Webfonts_Utils::convert_font_family_into_handle + * + * @param mixed $invalid_input Invalid input. + */ + public function test_should_not_convert_with_invalid_input( $invalid_input ) { + $this->assertNull( WP_Webfonts_Utils::convert_font_family_into_handle( $invalid_input ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_with_invalid_input() { + return array( + 'empty string' => array( '' ), + 'integer' => array( 10 ), + 'font family wrapped in an array' => array( array( 'source-serif-pro' ) ), + ); + } +} From 5e2a3ed160fd58c986e129d586f2bca463af059d Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Thu, 18 Aug 2022 17:02:23 -0500 Subject: [PATCH 10/63] wp_register_webfont_variation() plus tests --- lib/experimental/class-wp-webfonts-utils.php | 77 ++++++++ lib/experimental/class-wp-webfonts.php | 170 +++++++++++------- .../register-webfonts-from-theme-json.php | 2 +- lib/experimental/webfonts.php | 18 +- .../wpRegisterWebfontVariation-test.php | 133 ++++++++++++++ .../webfonts/wpWebfonts/addVariation-test.php | 149 +++++++++++++++ .../convertVariationIntoHandle-test.php | 122 +++++++++++++ .../getFontFamilyFromVariation-test.php | 134 ++++++++++++++ .../wpWebfontsUtils/isDefined-test.php | 61 +++++++ 9 files changed, 793 insertions(+), 73 deletions(-) create mode 100644 phpunit/webfonts/wpRegisterWebfontVariation-test.php create mode 100644 phpunit/webfonts/wpWebfonts/addVariation-test.php create mode 100644 phpunit/webfonts/wpWebfontsUtils/convertVariationIntoHandle-test.php create mode 100644 phpunit/webfonts/wpWebfontsUtils/getFontFamilyFromVariation-test.php create mode 100644 phpunit/webfonts/wpWebfontsUtils/isDefined-test.php diff --git a/lib/experimental/class-wp-webfonts-utils.php b/lib/experimental/class-wp-webfonts-utils.php index eae8c1e7866ce7..e70fc88d20e9fe 100644 --- a/lib/experimental/class-wp-webfonts-utils.php +++ b/lib/experimental/class-wp-webfonts-utils.php @@ -33,4 +33,81 @@ public static function convert_font_family_into_handle( $font_family ) { return sanitize_title( $font_family ); } + + /** + * Converts the given variation and its font-family into a handle. + * + * @since X.X.X + * + * @param string $font_family The font family's handle for this variation. + * @param array $variation An array of variation properties. + * @return string|null The variation handle. + */ + public static function convert_variation_into_handle( $font_family, array $variation ) { + $handle = ''; + foreach ( array( 'font-weight', 'font-style' ) as $property ) { + if ( ! array_key_exists( $property, $variation ) || ! static::is_defined( $variation[ $property ] ) ) { + continue; + } + + $handle .= ' ' . $variation[ $property ]; + } + + if ( '' === $handle ) { + trigger_error( 'Variant handle could not be determined as font-weight and/or font-style are require' ); + return null; + } + + return sanitize_title( $font_family . $handle ); + } + + /** + * Gets the font family from the variation. + * + * @since X.X.X + * + * @param array $variation An array of variation properties to search. + * @return string|null The font family if defined. Else, null. + */ + public static function get_font_family_from_variation( array $variation ) { + return static::search_for_font_family( $variation ); + } + + /** + * Checks if the given input is defined, i.e. meaning is a non-empty string. + * + * @since X.X.X + * + * @param string $input The input to check. + * @return bool True when non-empty string. Else false. + */ + public static function is_defined( $input ) { + return ( is_string( $input ) && ! empty( $input ) ); + } + + /** + * Searches the variation array to extract the font family. + * + * @since X.X.X + * + * @param array $haystack An array of variation properties to search. + * @return string|null The font family when found. Else, null. + */ + private static function search_for_font_family( array $haystack ) { + if ( array_key_exists( 'fontFamily', $haystack ) ) { + $key = 'fontFamily'; + } elseif ( array_key_exists( 'font-family', $haystack ) ) { + $key = 'font-family'; + } else { + trigger_error( 'Font family not found.' ); + return null; + } + + if ( static::is_defined( $haystack[ $key ] ) ) { + return $haystack[ $key ]; + } + + trigger_error( 'Font family not defined in the variation.' ); + return null; + } } diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index aafcf0505526a7..81ac81e40a1934 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -50,40 +50,111 @@ public function get_enqueued() { } /** - * Gets a list of all variations registered for a font family. + * Removes a font family and all registered variations. * - * @param $font_family - * @return array + * @param mixed|string|string[] $font_family */ - public function get_variations( $font_family ) { + function remove_family( $font_family ) { $font_family_handle = sanitize_title( $font_family ); if ( ! isset( $this->registered[ $font_family_handle ] ) ) { - return array(); + return; } - return $this->registered[ $font_family_handle ]->deps; + $variations = $this->registered[ $font_family_handle ]->deps; + + foreach ( $variations as $variation ) { + $this->remove( $variation ); + } + + $this->remove( $font_family_handle ); } /** - * Removes a font family and all registered variations. + * Registers a variation to the given font family. * - * @param mixed|string|string[] $font_family + * @since X.X.X + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. When none is provided, the + * handle will be dynamically generated. + * Default empty string. + * @return string|null Variation handle on success. Else null. */ - function remove_family( $font_family ) { - $font_family_handle = sanitize_title( $font_family ); + public function add_variation( $font_family_handle, array $variation, $variation_handle = '' ) { + if ( ! WP_Webfonts_Utils::is_defined( $font_family_handle ) ) { + trigger_error( 'Font family handle must be a non-empty string.' ); + return null; + } + if ( '' !== $variation_handle && ! WP_Webfonts_Utils::is_defined( $variation_handle ) ) { + trigger_error( 'Variant handle must be a non-empty string.' ); + return null; + } + + // Register the font family when it does not yet exist. if ( ! isset( $this->registered[ $font_family_handle ] ) ) { - return; + if ( ! $this->add( $font_family_handle, false ) ) { + return null; + } } - $variations = $this->registered[ $font_family_handle ]->deps; + $variation = $this->validate_variation( $font_family_handle, $variation ); - foreach ( $variations as $variation ) { - $this->remove( $variation ); + // Variation validation failed. + if ( ! $variation ) { + return null; } - $this->remove( $font_family_handle ); + if ( '' === $variation_handle ) { + $variation_handle = WP_Webfonts_Utils::convert_variation_into_handle( $font_family_handle, $variation ); + if ( is_null( $variation_handle ) ) { + return null; + } + } + + // Bail out if the variant is already registered. + if ( $this->is_variation_registered( $font_family_handle, $variation_handle ) ) { + return $variation_handle; + } + + if ( array_key_exists( 'src', $variation ) ) { + $result = $this->add( $variation_handle, $variation['src'] ); + } else { + $result = $this->add( $variation_handle, false ); + } + + // Bail out if the registration failed. + if ( ! $result ) { + return null; + } + + $this->add_data( $variation_handle, 'font-properties', $variation ); + + // Add the font variation as a dependency to the registered font family. + $this->add_dependency( $font_family_handle, $variation_handle ); + + $this->providers[ $variation['provider'] ]['fonts'][] = $variation_handle; + + return $variation_handle; + } + + /** + * Checks if the variation is registered. + * + * @since X.X.X + * + * @param string $font_family_handle The font family's handle for this variation. + * @param string $variant_handle Variation's handle. + * @return bool + */ + private function is_variation_registered( $font_family_handle, $variant_handle ) { + if ( ! isset( $this->registered[ $font_family_handle ] ) ) { + return array(); + } + + return in_array( $variant_handle, $this->registered[ $font_family_handle ]->deps ); } /** @@ -109,60 +180,27 @@ function remove_variation( $font_family, $variation_handle ) { } /** - * Registers a variation for a font family. + * Adds a variation as a dependency to the given font family. * - * @param string $font_family - * @param string $variation_handle - * @param array $variation - */ - public function add_variation( $font_family, $variation_handle, $variation ) { - $font_family_handle = sanitize_title( $font_family ); - - // Register the font family when it does not yet exist. - if ( ! isset( $this->registered[ $font_family ] ) ) { - $this->add( $font_family_handle, false ); - } - - $variation = $this->validate_variation( $font_family, $variation ); - - // Variation validation failed. - if ( ! $variation ) { - return false; - } - - $variation_handle = $font_family_handle . '-' . $variation_handle; - - if ( $variation['src'] ) { - $result = $this->add( $variation_handle, $variation['src'], array(), false, array( 'font-properties' => $variation ) ); - } else { - $result = $this->add( $variation_handle, false, array(), false, array( 'font-properties' => $variation ) ); - } - - if ( $result ) { - $this->providers[ $variation['provider'] ]['fonts'][] = $variation_handle; - } - - return $result; - } - - /** - * Adds a variation as a dependency for the main font alias. + * @since X.X.X * - * @param $font_family_handle - * @param $variation_handle + * @param string $font_family_handle The font family's handle for this variation. + * @param string $variation_handle The variation's handle. */ - public function add_dependency( $font_family_handle, $variation_handle ) { + private function add_dependency( $font_family_handle, $variation_handle ) { $this->registered[ $font_family_handle ]->deps[] = $variation_handle; } /** * Validates and sanitizes a variation. * - * @param $font_family - * @param $variation - * @return array|false|object + * @since X.X.X + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @return false|array Validated variation on success. Else, false. */ - function validate_variation( $font_family, $variation ) { + private function validate_variation( $font_family_handle, $variation ) { $defaults = array( 'provider' => 'local', 'font-style' => 'normal', @@ -170,20 +208,20 @@ function validate_variation( $font_family, $variation ) { 'font-display' => 'fallback', ); - $defaults = apply_filters( 'wp_web_font_variation_defaults', $defaults ); + $defaults = apply_filters( 'wp_webfont_variation_defaults', $defaults ); - $defaults['font-family'] = $font_family; - $variation = wp_parse_args( $variation, $defaults ); + $defaults['font-family'] = $font_family_handle; + $variation = wp_parse_args( $variation, $defaults ); // Local fonts need a "src". if ( 'local' === $variation['provider'] ) { // Make sure that local fonts have 'src' defined. if ( empty( $variation['src'] ) || ( ! is_string( $variation['src'] ) && ! is_array( $variation['src'] ) ) ) { - trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.', 'gutenberg' ) ); + trigger_error( 'Webfont src must be a non-empty string or an array of strings.' ); return false; } } elseif ( ! class_exists( $variation['provider'] ) ) { - trigger_error( __( 'The provider class specified does not exist.', 'gutenberg' ) ); + trigger_error( 'The provider class specified does not exist.' ); return false; } @@ -191,7 +229,7 @@ function validate_variation( $font_family, $variation ) { if ( ! empty( $variation['src'] ) ) { foreach ( (array) $variation['src'] as $src ) { if ( empty( $src ) || ! is_string( $src ) ) { - trigger_error( __( 'Each webfont src must be a non-empty string.', 'gutenberg' ) ); + trigger_error( 'Each webfont src must be a non-empty string.' ); return false; } } @@ -199,7 +237,7 @@ function validate_variation( $font_family, $variation ) { // Check the font-weight. if ( ! is_string( $variation['font-weight'] ) && ! is_int( $variation['font-weight'] ) ) { - trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.', 'gutenberg' ) ); + trigger_error( 'Webfont font-weight must be a properly formatted string or integer.' ); return false; } diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 0ce37240d5143b..d1394f3428448d 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -94,7 +94,7 @@ function gutenberg_register_webfonts_from_theme_json() { wp_register_webfont_family( $font_family_handle ); $variation_handle = sanitize_title( implode( ' ', array( $webfont['font-weight'], $webfont['font-style'] ) ) ); - wp_register_web_font_variation( $font_family_handle, $variation_handle, $webfont ); + wp_register_webfont_variation( $font_family_handle, $variation_handle, $webfont ); $to_enqueue[] = $font_family_handle; } diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index b89d395c9dfc05..010d6a99bf28b8 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -49,15 +49,21 @@ function wp_register_font_family( $font_family ) { } } -if ( ! function_exists( 'wp_register_web_font_variation' ) ) { +if ( ! function_exists( 'wp_register_webfont_variation' ) ) { /** - * Registers a font variation. + * Registers a variation to the given font family. * - * @param $font_family - * @return mixed + * @since X.X.X + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. When none is provided, the + * handle will be dynamically generated. + * Default empty string. + * @return string|null Variation handle on success. Else null. */ - function wp_register_web_font_variation( $font_family, $variation_handle, $variation ) { - return wp_webfonts()->add_variation( $font_family, $variation_handle, $variation ); + function wp_register_webfont_variation( $font_family_handle, array $variation, $variation_handle = '' ) { + return wp_webfonts()->add_variation( $font_family_handle, $variation, $variation_handle ); } } diff --git a/phpunit/webfonts/wpRegisterWebfontVariation-test.php b/phpunit/webfonts/wpRegisterWebfontVariation-test.php new file mode 100644 index 00000000000000..0c42a7445b8ead --- /dev/null +++ b/phpunit/webfonts/wpRegisterWebfontVariation-test.php @@ -0,0 +1,133 @@ +add( $font_family_handle, false ); + + $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variation_handle, 'Variation should return handle' ); + $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle ), 'Variation should be registered to font family' ); + } + + /** + * @dataProvider data_valid_variation + * + * @param string|bool $expected Expected results. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. + */ + public function test_variation_already_registered( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { + wp_webfonts()->add( $font_family_handle, false ); + + // Set up the test. + $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); + + // Run the test. + $variant_handle_on_reregister = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variant_handle_on_reregister, 'Variation should be registered to font family' ); + $this->assertSame( $variation_handle, $variant_handle_on_reregister, 'Variation should return the previously registered variant handle' ); + $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle ), 'Variation should only be registered once' ); + $expected = array( $font_family_handle, $variation_handle ); + $this->assertSameSets( $expected, $this->get_registered_handles(), 'Register queue should contain the font family and its one variant' ); + } + + /** + * @dataProvider data_valid_variation + * + * @param string|bool $expected Expected results. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. + */ + public function test_register_font_family_and_variation( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { + $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variation_handle, 'Variation should return its registered handle' ); + + // Extra checks to ensure both are registered. + $expected = array( $font_family_handle, $variation_handle ); + $this->assertSame( $expected, wp_webfonts()->get_registered(), 'Font family and variation should be registered' ); + $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle ), 'Variation should be registered to the font family' ); + } + + /** + * @dataProvider data_font_family_not_define_in_variation + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + */ + public function test_should_not_register_font_family_or_variant( $font_family_handle, array $variation ) { + $this->expectNotice(); + $this->expectNoticeMessage( 'Font family handle must be a non-empty string.' ); + + wp_register_webfont_variation( $font_family_handle, $variation ); + $this->assertEmpty( wp_webfonts()->get_registered(), 'Registered queue should be empty' ); + $this->assertEmpty( $this->get_variations( $font_family_handle ), 'Variation should not be registered to the font family' ); + } + + /** + * @dataProvider data_font_family_not_define_in_variation + * @dataProvider data_unable_determine_variation_handle + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $expected_message Expected notice message. + */ + public function test_should_not_register_variation_when_font_family_not_defined( $font_family_handle, array $variation, $expected_message ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected_message ); + + $this->assertNull( wp_register_webfont_variation( $font_family_handle, $variation ) ); + } + + /** + * @dataProvider data_unable_determine_variation_handle + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + */ + public function test_should_register_font_family_when_variant_fails_to_register( $font_family_handle, array $variation ) { + $this->expectNotice(); + $this->expectNoticeMessage( 'Variant handle could not be determined as font-weight and/or font-style are require' ); + + wp_register_webfont_variation( $font_family_handle, $variation ); + $expected = $font_family_handle; + $this->assertContains( $expected, wp_webfonts()->get_registered() ); + } + + /** + * @dataProvider data_invalid_variation + * + * @param string $expected_message Expected notice message. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + */ + public function test_should_not_register_when_variation_fails_validation( $expected_message, $font_family_handle, array $variation ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected_message ); + + $this->assertNull( wp_register_webfont_variation( $font_family_handle, $variation ) ); + } +} diff --git a/phpunit/webfonts/wpWebfonts/addVariation-test.php b/phpunit/webfonts/wpWebfonts/addVariation-test.php new file mode 100644 index 00000000000000..846dd11b87e436 --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/addVariation-test.php @@ -0,0 +1,149 @@ +add( $font_family_handle, false ); + + $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variation_handle, 'Registering a variation should return its handle' ); + $this->assertArrayHasKey( $variation_handle, $wp_webfonts->registered, 'Variation handle should be in the registry after registration' ); + $this->assertSame( array( $expected ), $this->get_variations( $font_family_handle, $wp_webfonts ), 'Variation should be registered to font family' ); + } + + /** + * @dataProvider data_valid_variation + * + * @param string|bool $expected Expected results. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. + */ + public function test_should_not_reregister_font_family( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { + $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->add( $font_family_handle, false ); + + $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); + + // Font family should appear only once in the registered queue. + $expected = array( $font_family_handle, $variation_handle ); + $this->assertSame( $expected, array_keys( $wp_webfonts->registered ), 'Font family should not be re-registered after registering a variation' ); + } + + /** + * @dataProvider data_valid_variation + * + * @param string|bool $expected Expected results. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. + */ + public function test_should_not_reregister_variation( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { + $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->add( $font_family_handle, false ); + + // Set up the test. + $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); + + // Run the test. + $variant_handle_on_reregister = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variant_handle_on_reregister, 'Variation should be registered to font family' ); + $this->assertSame( $variation_handle, $variant_handle_on_reregister, 'Variation should return the previously registered variant handle' ); + $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle, $wp_webfonts ), 'Variation should only be registered once' ); + + $this->assertCount( 2, $wp_webfonts->registered ); + $this->assertArrayHasKey( $variation_handle, $wp_webfonts->registered, 'Variation handle should be in the registry after registration' ); + } + + /** + * @dataProvider data_valid_variation + * + * @param string|bool $expected Expected results. + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. + */ + public function test_should_register_font_family_and_variation( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { + $wp_webfonts = new WP_Webfonts(); + + $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); + $this->assertSame( $expected, $variation_handle, 'Variation should return its registered handle' ); + + // Extra checks to ensure both are registered. + $this->assertCount( 2, $wp_webfonts->registered ); + $this->assertArrayHasKey( $font_family_handle, $wp_webfonts->registered, 'Font family handle should be in the registry after registration' ); + $this->assertArrayHasKey( $variation_handle, $wp_webfonts->registered, 'Variation handle should be in the registry after registration' ); + $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle, $wp_webfonts ), 'Variation should be registered to the font family' ); + } + + /** + * @dataProvider data_font_family_not_define_in_variation + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + */ + public function test_should_not_register_font_family_or_variant( $font_family_handle, array $variation ) { + $this->expectNotice(); + $this->expectNoticeMessage( 'Font family handle must be a non-empty string.' ); + + $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->add_variation( $font_family_handle, $variation ); + + $this->assertEmpty( $wp_webfonts->registered, 'Registered queue should be empty' ); + $this->assertEmpty( $this->get_variations( $font_family_handle, $wp_webfonts ), 'Variation should not be registered to the font family' ); + } + + /** + * @dataProvider data_font_family_not_define_in_variation + * @dataProvider data_unable_determine_variation_handle + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $expected_message Expected notice message. + */ + public function test_should_not_register_variation_when_font_family_not_defined( $font_family_handle, array $variation, $expected_message ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected_message ); + + $wp_webfonts = new WP_Webfonts(); + $this->assertNull( $wp_webfonts->add_variation( $font_family_handle, $variation ) ); + } + + /** + * @dataProvider data_unable_determine_variation_handle + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + */ + public function test_should_register_font_family_when_variant_fails_to_register( $font_family_handle, array $variation ) { + $this->expectNotice(); + $this->expectNoticeMessage( 'Variant handle could not be determined as font-weight and/or font-style are require' ); + + $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->add_variation( $font_family_handle, $variation ); + + $this->assertCount( 1, $wp_webfonts->registered ); + $this->assertArrayHasKey( $font_family_handle, $wp_webfonts->registered ); + } +} diff --git a/phpunit/webfonts/wpWebfontsUtils/convertVariationIntoHandle-test.php b/phpunit/webfonts/wpWebfontsUtils/convertVariationIntoHandle-test.php new file mode 100644 index 00000000000000..9e2a3462ed7a82 --- /dev/null +++ b/phpunit/webfonts/wpWebfontsUtils/convertVariationIntoHandle-test.php @@ -0,0 +1,122 @@ +assertSame( $expected, WP_Webfonts_Utils::convert_variation_into_handle( $font_family, $variation ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_with_valid_input() { + return array( + 'with only font-weight' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-weight' => '400', + ), + 'expected' => 'merriweather-400', + ), + 'with no font-style' => array( + 'font_family' => 'source-sans-pro', + 'variation' => array( + 'font-weight' => '200 900', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'provider' => 'local', + ), + 'expected' => 'source-sans-pro-200-900', + ), + 'with font family name and full variant' => array( + 'font_family' => 'source-sans-pro', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected' => 'source-sans-pro-200-900-normal', + ), + ); + } + + /** + * @dataProvider data_with_invalid_input + * + * @param string $font_family Font family to test. + * @param array $invalid_input Variation to test. + */ + public function tests_should_convert_with_invalid_input( $font_family, $invalid_input ) { + $this->expectNotice(); + $this->expectNoticeMessage( 'Variant handle could not be determined as font-weight and/or font-style are require' ); + + $this->assertNull( WP_Webfonts_Utils::convert_variation_into_handle( $font_family, $invalid_input ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_with_invalid_input() { + return array( + 'with no font-weight or font-style' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'provider' => 'local', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + 'with non-string font-weight' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-weight' => 400, + ), + ), + 'with non-string font-style' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-style' => 0, + ), + ), + 'with empty string font-weight' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-weight' => '', + ), + ), + 'with empty string font-style' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-style' => '', + ), + ), + ); + } +} diff --git a/phpunit/webfonts/wpWebfontsUtils/getFontFamilyFromVariation-test.php b/phpunit/webfonts/wpWebfontsUtils/getFontFamilyFromVariation-test.php new file mode 100644 index 00000000000000..f370e1d043222c --- /dev/null +++ b/phpunit/webfonts/wpWebfontsUtils/getFontFamilyFromVariation-test.php @@ -0,0 +1,134 @@ +assertSame( $expected, WP_Webfonts_Utils::get_font_family_from_variation( $variation ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_with_valid_variation() { + return array( + 'keyed by font-family' => array( + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected' => 'Source Serif Pro', + ), + 'keyed by fontFamily and as a handle' => array( + 'variation' => array( + 'fontFamily' => 'source-sans-pro', + 'font-weight' => '200 900', + 'src' => 'https://example.com/assets/fonts/source-sans-pro/source-sans-pro.ttf.woff2', + 'provider' => 'local', + ), + 'expected' => 'source-sans-pro', + ), + 'with font family name and full variant' => array( + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Merriweather', + 'font-style' => 'normal', + 'font-weight' => '400 600', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected' => 'Merriweather', + ), + ); + } + + /** + * @dataProvider data_with_invalid_input + * + * @param array $invalid_variation Variation to test. + * @param string $expected_message Expected notice message. + */ + public function test_with_invalid_input( array $invalid_variation, $expected_message ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected_message ); + + $this->assertNull( WP_Webfonts_Utils::get_font_family_from_variation( $invalid_variation ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_with_invalid_input() { + return array( + 'keyed with underscore' => array( + 'variation' => array( + 'provider' => 'local', + 'font_family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not found.', + ), + 'keyed with space' => array( + 'variation' => array( + 'font family' => 'Source Sans Pro', + 'font-weight' => '200 900', + 'src' => 'https://example.com/assets/fonts/source-sans-pro/source-sans-pro.ttf.woff2', + 'provider' => 'local', + ), + 'expected_message' => 'Font family not found.', + ), + 'fontFamily => empty string' => array( + 'variation' => array( + 'fontFamily' => '', + 'font-weight' => '200 900', + 'src' => 'https://example.com/assets/fonts/source-sans-pro/source-sans-pro.ttf.woff2', + 'provider' => 'local', + ), + 'expected_message' => 'Font family not defined in the variation.', + ), + 'font-family => empty string' => array( + 'variation' => array( + 'provider' => 'local', + 'font-family' => '', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not defined in the variation.', + ), + ); + } +} diff --git a/phpunit/webfonts/wpWebfontsUtils/isDefined-test.php b/phpunit/webfonts/wpWebfontsUtils/isDefined-test.php new file mode 100644 index 00000000000000..c5b2a1608269c8 --- /dev/null +++ b/phpunit/webfonts/wpWebfontsUtils/isDefined-test.php @@ -0,0 +1,61 @@ +assertTrue( WP_Webfonts_Utils::is_defined( $input ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_when_defined() { + return array( + 'name: non empty string' => array( 'Some Font Family' ), + 'handle: non empty string' => array( 'some-font-family' ), + ); + } + + /** + * @dataProvider data_when_not_defined + * + * @param mixed $invalid_input Input to test. + */ + public function test_should_return_false_when_not_defined( $invalid_input ) { + $this->assertFalse( WP_Webfonts_Utils::is_defined( $invalid_input ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_when_not_defined() { + return array( + 'empty string' => array( '' ), + 'string 0' => array( '0' ), + 'integer' => array( 10 ), + 'name wrapped in an array' => array( array( 'Some Font Family' ) ), + 'handle wrapped in an array' => array( array( 'some-font-family' ) ), + ); + } +} From 43b13d6a10e909a3d75925f21305ebdaaa8023de Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Fri, 19 Aug 2022 06:14:46 -0500 Subject: [PATCH 11/63] wp_register_webfont() plus tests. --- lib/experimental/webfonts.php | 32 +++ phpunit/webfonts/wpRegisterWebfont-test.php | 279 ++++++++++++++++++++ 2 files changed, 311 insertions(+) create mode 100644 phpunit/webfonts/wpRegisterWebfont-test.php diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index 010d6a99bf28b8..a74d5b47b96780 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -93,6 +93,38 @@ function wp_register_webfonts( $webfonts, $enqueue = false ) { } } +if ( ! function_exists( 'wp_register_webfont' ) ) { + /** + * Registers a single web font. + * + * @since X.X.X + * + * @param array $variation Array of variation properties to be registered. + * @param string $font_family_handle Optional. Font family handle for the given variation. + * Default empty string. + * @param string $variation_handle Optional. Handle for the variation to register. + * @return string|null The font family slug if successfully registered. Else null. + */ + function wp_register_webfont( array $variation, $font_family_handle = '', $variation_handle = '' ) { + // When font family's handle is not passed, attempt to get it from the variation. + if ( ! WP_Webfonts_Utils::is_defined( $font_family_handle ) ) { + $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $variation ); + if ( $font_family ) { + $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); + } + } + + if ( empty( $font_family_handle ) ) { + trigger_error( 'Font family handle must be a non-empty string.' ); + return null; + } + + return wp_webfonts()->add_variation( $font_family_handle, $variation, $variation_handle ) + ? $font_family_handle + : null; + } +} + if ( ! function_exists( 'wp_enqueue_web_font' ) ) { /** * Enqueues a web font family and all variations. diff --git a/phpunit/webfonts/wpRegisterWebfont-test.php b/phpunit/webfonts/wpRegisterWebfont-test.php new file mode 100644 index 00000000000000..13aa351d3f7bab --- /dev/null +++ b/phpunit/webfonts/wpRegisterWebfont-test.php @@ -0,0 +1,279 @@ +set_up_mock( 'add_variation' ); + $variation_handle = $expected[1]; + + $mock->expects( $this->once() ) + ->method( 'add_variation' ) + ->with( + $this->identicalTo( $font_family_handle ), + $this->identicalTo( $variation ), + $this->identicalTo( $variation_handle ) + ) + ->will( $this->returnValue( $font_family_handle ) ); + + $this->assertSame( $font_family_handle, wp_register_webfont( $variation, $font_family_handle, $variation_handle ) ); + } + + /** + * Integration test for registering a variation when the font family was previously registered. + * + * @dataProvider data_register + * + * @param string $font_family_handle Font family for this variation. + * @param array $variation Web font to test. + * @param array $expected Expected results. + */ + public function test_should_register_variation_but_not_reregister_font_family( $font_family_handle, array $variation, $expected ) { + $this->setup_font_family( $font_family_handle ); + + $this->assertSame( $font_family_handle, wp_register_webfont( $variation, $font_family_handle ), 'Registering should return the font family handle' ); + $this->assertSame( $expected, $this->get_registered_handles(), 'Registry should contain the font family and variant handles' ); + } + + /** + * Integration test for testing the font family is registered during the variation registration process. + * + * @dataProvider data_register_with_deprecated_structure + * + * @param array $variation Web font to test. + * @param array $expected Expected results. + */ + public function test_should_register_font_family( array $variation, $expected ) { + $font_family_handle = $expected[0]; + + wp_register_webfont( $variation ); + $this->assertContains( $font_family_handle, $this->get_registered_handles() ); + } + + /** + * Integration test to ensure registration does not automatically enqueue. + * + * @dataProvider data_register + * + * @param string $font_family_handle Font family handle. + * @param array $variation Variation. + */ + public function test_does_not_enqueue_when_registering( $font_family_handle, array $variation ) { + $this->setup_font_family( $font_family_handle ); + wp_register_webfont( $variation, $font_family_handle ); + + $this->assertEmpty( $this->get_enqueued_handles() ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_register() { + return array( + 'Source Serif Pro' => array( + 'font_family' => 'source-serif-pro', + 'variation' => array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected' => array( + 'source-serif-pro', + 'source-serif-pro-200-900-normal', + ), + ), + 'Merriweather' => array( + 'font_family' => 'merriweather', + 'variation' => array( + 'font-style' => 'italic', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + 'expected' => array( + 'merriweather', + 'merriweather-400-italic', + ), + ), + ); + } + + /** + * @dataProvider data_register_with_deprecated_structure + * + * @covers WP_Webfonts::add_variation + * + * @param array $variation Web font to test. + * @param array $expected Expected results. + */ + public function test_registers_with_deprecated_structure( + array $variation, $expected + ) { + $font_family_handle = $expected[0]; + $this->setup_font_family( $font_family_handle ); + + $this->assertSame( $font_family_handle, wp_register_webfont( $variation ), 'Registering should return the registered font family handle' ); + $this->assertSame( $expected, $this->get_registered_handles(), 'Registry should contain the font family and variant handles' ); + } + + /** + * @dataProvider data_with_deprecated_structure + * + * @covers WP_Webfonts::add_variation + * + * @param array $variation Web font to test. + * @param array $expected Expected results. + */ + public function test_should_register_font_family_with_deprecated_structure( + array $variation, $expected + ) { + $font_family_handle = $expected[0]; + + wp_register_webfont( $variation ); + $this->assertContains( $font_family_handle, $this->get_registered_handles() ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_with_deprecated_structure() { + return array( + 'font-family as name' => array( + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-weight' => '200 900', + 'src' => 'https://example.com/assets/fonts/font.ttf.woff2', + ), + 'expected' => array( + 'source-serif-pro', + 'source-serif-pro-200-900-normal', + ), + ), + 'font-family as handle/slug' => array( + 'variation' => array( + 'provider' => 'local', + 'font-family' => 'my-font-family', + 'font-style' => 'italic', + 'src' => 'https://example.com/assets/fonts/font.ttf.woff2', + ), + 'expected' => array( + 'my-font-family', + 'my-font-family-400-italic', + ), + ), + ); + } + + /** + * Integration test for testing when font family registration fails. + * + * @dataProvider data_invalid_font_family + * + * @param string $font_family_handle Font family for this variation. + * @param array $variation Web font to test. + * @param string $expected_message Expected notice message. + */ + public function test_should_fail_with_invalid_font_family( $font_family_handle, array $variation, $expected_message ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected_message ); + + $this->assertNull( wp_register_webfont( $variation, $font_family_handle ), 'Should return null when invalid font family given' ); + $this->assertEmpty( $this->get_registered_handles(), 'Font family and variation should not be registered' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_invalid_font_family() { + return array( + 'non-string' => array( + 'font_family_handle' => null, + 'variation' => array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not found.', + 'font-family' => null, + ), + 'empty string' => array( + 'font_family_handle' => '', + 'variation' => array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not found.', + ), + 'non-string in deprecated structure' => array( + 'font_family_handle' => '', + 'variation' => array( + 'provider' => 'local', + 'font-family' => null, + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not defined in the variation.', + ), + 'empty string in deprecated structure' => array( + 'font_family_handle' => '', + 'variation' => array( + 'provider' => 'local', + 'font-family' => '', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => 'Font family not defined in the variation.', + ), + ); + } + + /** + * Sets up the font family by registering it. + * + * @param string $handle Handle to register. + */ + private function setup_font_family( $handle ) { + wp_webfonts()->add( $handle, false ); + } +} From b0cb50386c9289fc907dd4e895bc282c41db3227 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Fri, 19 Aug 2022 06:20:54 -0500 Subject: [PATCH 12/63] wp_register_webfonts() plus tests --- lib/experimental/webfonts.php | 46 ++++-- phpunit/webfonts/wpRegisterWebfonts-test.php | 147 +++++++++++++++++++ 2 files changed, 184 insertions(+), 9 deletions(-) create mode 100644 phpunit/webfonts/wpRegisterWebfonts-test.php diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index a74d5b47b96780..979e4e6e17e462 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -71,22 +71,50 @@ function wp_register_webfont_variation( $font_family_handle, array $variation, $ /** * Registers a list of web fonts and variations. * - * @param $webfonts - * @return array + * @since 6.1.0 + * + * @param array[] $webfonts Web fonts to be registered. + * @return string[] The font family handle of the registered web fonts. */ - function wp_register_webfonts( $webfonts, $enqueue = false ) { + function wp_register_webfonts( array $webfonts ) { $registered = array(); foreach ( $webfonts as $font_family => $variations ) { - wp_register_font_family( $font_family ); + /* + * Handle the deprecated web font's structure but alert developers + * to modify their web font structure to group and key by font family. + * + * Note: This code block will not be backported to Core. + */ + if ( ! WP_Webfonts_Utils::is_defined( $font_family ) ) { + _doing_it_wrong( + __FUNCTION__, + __( 'Variations must be grouped and keyed by their font family.', 'gutenberg' ), + '6.1.0' + ); + $font_family_handle = wp_register_webfont( $variations ); + if ( ! $font_family_handle ) { + continue; + } + $registered[ $font_family_handle ] = true; + continue; + } // end of code block for deprecated web fonts structure. - foreach ( $variations as $variation_handle => $variation ) { - $registered[] = wp_register_web_font_variation( $font_family, $variation_handle, $variation ); + $font_family_handle = wp_register_font_family( $font_family ); + if ( ! $font_family_handle ) { + continue; + } - if ( $enqueue ) { - wp_enqueue_web_font( $variation_handle ); - } + // Register each of the variations for this font family. + foreach ( $variations as $handle => $variation ) { + wp_register_webfont( + $variation, + $font_family_handle, + WP_Webfonts_Utils::is_defined( $handle ) ? $handle : '' + ); } + + $registered[] = $font_family_handle; } return $registered; diff --git a/phpunit/webfonts/wpRegisterWebfonts-test.php b/phpunit/webfonts/wpRegisterWebfonts-test.php new file mode 100644 index 00000000000000..275d73c65a4e08 --- /dev/null +++ b/phpunit/webfonts/wpRegisterWebfonts-test.php @@ -0,0 +1,147 @@ +assertSame( $expected['wp_register_webfonts'], wp_register_webfonts( $webfonts ), 'Font family handle(s) should be returned' ); + $this->assertSame( $expected['get_registered'], $this->get_registered_handles(), 'Web fonts should match registered queue' ); + } + + /** + * @dataProvider data_deprecated_structure + * + * @expectedIncorrectUsage wp_register_webfonts + * + * @param array $webfonts Array of webfonts to test. + * @param array $expected Expected results. + */ + public function test_should_register_with_deprecated_structure( array $webfonts, array $expected ) { + $this->expectNotice(); + $this->expectNoticeMessage( $expected['message'] ); + + $this->assertSame( $expected['wp_register_webfonts'], wp_register_webfonts( $webfonts ), 'Font family handle(s) should be returned' ); + $this->assertSame( $expected['get_registered'], $this->get_registered_handles(), 'Web fonts should match registered queue' ); + } + + /** + * @dataProvider data_webfonts + * + * @param array $webfonts Array of webfonts to test. + */ + public function test_should_do_not_enqueue_on_registration( array $webfonts ) { + wp_register_webfonts( $webfonts ); + $this->assertEmpty( $this->get_enqueued_handles() ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_webfonts() { + return array( + 'font family keyed with slug' => array( + 'webfonts' => array( + 'source-serif-pro' => array( + array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + ), + 'expected' => array( + 'wp_register_webfonts' => array( 'source-serif-pro' ), + 'get_registered' => array( + 'source-serif-pro', + 'source-serif-pro-200-900-normal', + ), + ), + ), + 'font family keyed with name' => array( + 'webfonts' => array( + 'Source Serif Pro' => array( + array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + array( + 'provider' => 'local', + 'font-style' => 'italic', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + ), + 'expected' => array( + 'wp_register_webfonts' => array( 'source-serif-pro' ), + 'get_registered' => array( + 'source-serif-pro', + 'source-serif-pro-200-900-normal', + 'source-serif-pro-200-900-italic', + ), + ), + ), + ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_deprecated_structure() { + return array( + 'font family not keyed' => array( + 'webfonts' => array( + array( + array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + ), + 'expected' => array( + 'wp_register_webfonts' => array(), + 'get_registered' => array(), + 'message' => 'Font family not found.', + ), + ), + ); + } +} From abe2c877e15bb49ed6967703497b470c5eec33a0 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Fri, 19 Aug 2022 06:37:04 -0500 Subject: [PATCH 13/63] wp_enqueue_webfont() plus tests --- lib/experimental/webfonts.php | 13 ++-- phpunit/webfonts/wpEnqueueWebfont-test.php | 69 ++++++++++++++++++++ phpunit/webfonts/wpRegisterWebfont-test.php | 12 ++-- phpunit/webfonts/wpWebfonts/enqueue-test.php | 51 +++++++++++++++ 4 files changed, 134 insertions(+), 11 deletions(-) create mode 100644 phpunit/webfonts/wpEnqueueWebfont-test.php create mode 100644 phpunit/webfonts/wpWebfonts/enqueue-test.php diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index 979e4e6e17e462..ca957601f2edf4 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -153,13 +153,16 @@ function wp_register_webfont( array $variation, $font_family_handle = '', $varia } } -if ( ! function_exists( 'wp_enqueue_web_font' ) ) { +if ( ! function_exists( 'wp_enqueue_webfont' ) ) { /** - * Enqueues a web font family and all variations. + * Enqueues one or more font family and all of its variations. + * + * @since X.X.X + * + * @param string|string[] $font_family Font family handle (string) or handles (array of strings). */ - function wp_enqueue_web_font( $handle ) { - $wp_webfonts = wp_webfonts(); - $wp_webfonts->enqueue( $handle ); + function wp_enqueue_webfont( $font_family ) { + wp_webfonts()->enqueue( $font_family ); } } diff --git a/phpunit/webfonts/wpEnqueueWebfont-test.php b/phpunit/webfonts/wpEnqueueWebfont-test.php new file mode 100644 index 00000000000000..fa371f1c2ec329 --- /dev/null +++ b/phpunit/webfonts/wpEnqueueWebfont-test.php @@ -0,0 +1,69 @@ +set_up_mock( 'enqueue' ); + $mock->expects( $this->once() ) + ->method( 'enqueue' ) + ->with( + $this->identicalTo( $font_family ) + ); + + wp_enqueue_webfont( $font_family ); + } + + /** + * Integration test for enqueuing a font family and all of its variations. + * + * @dataProvider data_enqueue + * + * @param string|string[] $font_family Font family to test. + * @param array $expected Expected queue. + */ + public function test_should_enqueue_after_registration( $font_family, array $expected ) { + foreach ( $this->get_data_registry() as $handle => $variations ) { + $this->setup_register( $handle, $variations ); + } + + wp_enqueue_webfont( $font_family ); + $this->assertEmpty( $this->get_queued_before_register(), '"queued_before_register" queue should be empty' ); + $this->assertSame( $expected, $this->get_enqueued_handles(), 'Queue should contain the given font family(ies)' ); + } + + /** + * Integration test for enqueuing before registering a font family and all of its variations. + * + * @dataProvider data_enqueue + * + * @param string|string[] $font_family Font family to test. + * @param array $not_used Not used. + * @param array $expected Expected "queued_before_register" queue. + */ + public function test_should_enqueue_before_registration( $font_family, array $not_used, array $expected ) { + wp_enqueue_webfont( $font_family ); + + $this->assertSame( $expected, $this->get_queued_before_register(), '"queued_before_register" queue should contain the given font family(ies)' ); + $this->assertEmpty( $this->get_enqueued_handles(), 'Queue should be empty' ); + } +} diff --git a/phpunit/webfonts/wpRegisterWebfont-test.php b/phpunit/webfonts/wpRegisterWebfont-test.php index 13aa351d3f7bab..28d0352150ed43 100644 --- a/phpunit/webfonts/wpRegisterWebfont-test.php +++ b/phpunit/webfonts/wpRegisterWebfont-test.php @@ -17,7 +17,7 @@ class Tests_Webfonts_WpRegisterWebfont extends WP_Webfonts_TestCase { /** * Unit test for registering a variation with a variation handle given. * - * @dataProvider data_register + * @dataProvider data_with_valid_input * * @param string $font_family_handle Font family for this variation. * @param array $variation Web font to test. @@ -42,7 +42,7 @@ public function test_should_register_with_mock_when_handle_given( $font_family_h /** * Integration test for registering a variation when the font family was previously registered. * - * @dataProvider data_register + * @dataProvider data_with_valid_input * * @param string $font_family_handle Font family for this variation. * @param array $variation Web font to test. @@ -58,7 +58,7 @@ public function test_should_register_variation_but_not_reregister_font_family( $ /** * Integration test for testing the font family is registered during the variation registration process. * - * @dataProvider data_register_with_deprecated_structure + * @dataProvider data_with_deprecated_structure * * @param array $variation Web font to test. * @param array $expected Expected results. @@ -73,7 +73,7 @@ public function test_should_register_font_family( array $variation, $expected ) /** * Integration test to ensure registration does not automatically enqueue. * - * @dataProvider data_register + * @dataProvider data_with_valid_input * * @param string $font_family_handle Font family handle. * @param array $variation Variation. @@ -90,7 +90,7 @@ public function test_does_not_enqueue_when_registering( $font_family_handle, arr * * @return array */ - public function data_register() { + public function data_with_valid_input() { return array( 'Source Serif Pro' => array( 'font_family' => 'source-serif-pro', @@ -122,7 +122,7 @@ public function data_register() { } /** - * @dataProvider data_register_with_deprecated_structure + * @dataProvider data_with_deprecated_structure * * @covers WP_Webfonts::add_variation * diff --git a/phpunit/webfonts/wpWebfonts/enqueue-test.php b/phpunit/webfonts/wpWebfonts/enqueue-test.php new file mode 100644 index 00000000000000..e55ea8f51c99c5 --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/enqueue-test.php @@ -0,0 +1,51 @@ +enqueue( $font_family ); + + $this->assertSame( $expected, $this->get_queued_before_register( $wp_webfonts ), 'Font family(ies) should be added to before registered queue' ); + $this->assertEmpty( $this->queue, 'Font family(ies) should not be added to the enqueue queue when not registered' ); + } + + /** + * Integration test for enqueuing a font family and all of its variations. + * + * @dataProvider data_enqueue + * + * @param string|string[] $font_family Font family to test. + * @param array $expected Expected queue. + */ + public function test_should_enqueue_when_registered( $font_family, array $expected ) { + $wp_webfonts = new WP_Webfonts(); + foreach ( $this->get_data_registry() as $handle => $variations ) { + $this->setup_register( $handle, $variations, $wp_webfonts ); + } + + $wp_webfonts->enqueue( $font_family ); + + $this->assertEmpty( $this->get_queued_before_register( $wp_webfonts ), '"queued_before_register" queue should be empty' ); + $this->assertSame( $expected, $wp_webfonts->queue, 'Queue should contain the given font family(ies)' ); + } +} From 69d01490f113e84db23a914367c086e5c884f125 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 24 Aug 2022 05:54:17 -0500 Subject: [PATCH 14/63] wp_enqueue_webfont_variations() plus tests --- lib/experimental/webfonts.php | 15 ++-- .../webfonts/wp-webfonts-tests-dataset.php | 39 ++++++++- .../wpEnqueueWebfontVariations-test.php | 82 +++++++++++++++++++ phpunit/webfonts/wpWebfonts/enqueue-test.php | 28 ++++--- 4 files changed, 140 insertions(+), 24 deletions(-) create mode 100644 phpunit/webfonts/wpEnqueueWebfontVariations-test.php diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index ca957601f2edf4..37758ec2d10f09 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -166,17 +166,16 @@ function wp_enqueue_webfont( $font_family ) { } } -if ( ! function_exists( 'wp_enqueue_web_font_variations' ) ) { +if ( ! function_exists( 'wp_enqueue_webfont_variations' ) ) { /** * Enqueues a specific set of web font variations. + * + * @since X.X.X + * + * @param string|string[] $variation_handles Variation handle (string) or handles (array of strings). */ - function wp_enqueue_web_font_variations( $variations ) { - $wp_webfonts = wp_webfonts(); - - // Looking to enqueue all variations of a font family. - foreach ( $variations as $variation ) { - $wp_webfonts->enqueue( $variation ); - } + function wp_enqueue_webfont_variations( $variation_handles ) { + wp_webfonts()->enqueue( $variation_handles ); } } diff --git a/phpunit/webfonts/wp-webfonts-tests-dataset.php b/phpunit/webfonts/wp-webfonts-tests-dataset.php index 33de17c13580ff..9eeb979cbe71e0 100644 --- a/phpunit/webfonts/wp-webfonts-tests-dataset.php +++ b/phpunit/webfonts/wp-webfonts-tests-dataset.php @@ -439,14 +439,14 @@ public function data_font_family_handles() { public function data_enqueue() { return array( '1 font-family' => array( - 'font_family' => 'lato', + 'handles' => 'lato', 'expected_queue' => array( 'lato' ), 'expected_queued_before_register' => array( 'lato' => null, ), ), '2 font families' => array( - 'font_family' => array( 'merriweather', 'my-font' ), + 'handles' => array( 'merriweather', 'my-font' ), 'expected_queue' => array( 'merriweather', 'my-font' ), 'expected_queued_before_register' => array( 'merriweather' => null, @@ -454,7 +454,7 @@ public function data_enqueue() { ), ), '3 font families' => array( - 'font_family' => array( 'merriweather', 'my-font', 'Source Serif Pro' ), + 'handles' => array( 'merriweather', 'my-font', 'Source Serif Pro' ), 'expected_queue' => array( 'merriweather', 'my-font', 'Source Serif Pro' ), 'expected_queued_before_register' => array( 'merriweather' => null, @@ -465,6 +465,39 @@ public function data_enqueue() { ); } + /** + * Data provider. + * + * @return array + */ + public function data_enqueue_variations() { + return array( + '1 variation' => array( + 'handles' => array( 'my-font-300-normal' ), + 'expected_queue' => array( 'my-font-300-normal' ), + 'expected_queued_before_register' => array( + 'my-font-300-normal' => null, + ), + ), + '1 variation from different font families' => array( + 'handles' => array( 'merriweather-200-900-normal', 'my-font-300-normal' ), + 'expected_queue' => array( 'merriweather-200-900-normal', 'my-font-300-normal' ), + 'expected_queued_before_register' => array( + 'merriweather-200-900-normal' => null, + 'my-font-300-normal' => null, + ), + ), + 'enqueue one variation and its font family' => array( + 'handles' => array( 'merriweather', 'merriweather-200-900-normal' ), + 'expected_queue' => array( 'merriweather', 'merriweather-200-900-normal' ), + 'expected_queued_before_register' => array( + 'merriweather' => null, + 'merriweather-200-900-normal' => null, + ), + ), + ); + } + protected function get_data_registry() { return array( 'lato' => array(), diff --git a/phpunit/webfonts/wpEnqueueWebfontVariations-test.php b/phpunit/webfonts/wpEnqueueWebfontVariations-test.php new file mode 100644 index 00000000000000..f6ce62d3f47ee0 --- /dev/null +++ b/phpunit/webfonts/wpEnqueueWebfontVariations-test.php @@ -0,0 +1,82 @@ +set_up_mock( 'enqueue' ); + $mock->expects( $this->once() ) + ->method( 'enqueue' ) + ->with( + $this->identicalTo( $handles ) + ); + + wp_enqueue_webfont_variations( $handles ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_variation_handles() { + return array( + '1 variation handle' => array( 'merriweather-200-900-normal' ), + 'multiple same font family handles' => array( array( 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic' ) ), + 'handles from different font families' => array( array( 'merriweather-200-900-normal', 'Source Serif Pro-900-italic' ) ), + ); + } + + /** + * Integration test for enqueuing one or more specific variations. + * + * @dataProvider data_enqueue_variations + * + * @param string|string[] $handles Variation handles to test. + * @param array $expected Expected queue. + */ + public function test_should_enqueue_after_registration( $handles, array $expected ) { + foreach ( $this->get_data_registry() as $handle => $variations ) { + $this->setup_register( $handle, $variations ); + } + + wp_enqueue_webfont_variations( $handles ); + $this->assertEmpty( $this->get_queued_before_register(), '"queued_before_register" queue should be empty' ); + $this->assertSame( $expected, $this->get_enqueued_handles(), 'Queue should contain the given handles' ); + } + + /** + * Integration test for enqueuing before registering one or more specific variations. + * + * @dataProvider data_enqueue_variations + * + * @param string|string[] $handles Variation handles to test. + * @param array $not_used Not used. + * @param array $expected Expected "queued_before_register" queue. + */ + public function test_should_enqueue_before_registration( $handles, array $not_used, array $expected ) { + wp_enqueue_webfont_variations( $handles ); + + $this->assertSame( $expected, $this->get_queued_before_register(), '"queued_before_register" queue should contain the given handles' ); + $this->assertEmpty( $this->get_enqueued_handles(), 'Queue should be empty' ); + } +} diff --git a/phpunit/webfonts/wpWebfonts/enqueue-test.php b/phpunit/webfonts/wpWebfonts/enqueue-test.php index e55ea8f51c99c5..ab02bb5cc42a79 100644 --- a/phpunit/webfonts/wpWebfonts/enqueue-test.php +++ b/phpunit/webfonts/wpWebfonts/enqueue-test.php @@ -16,36 +16,38 @@ class Tests_Webfonts_WpWebfonts_Enqueue extends WP_Webfonts_TestCase { /** * @dataProvider data_enqueue + * @dataProvider data_enqueue_variations * - * @param string|string[] $font_family Font family to test. - * @param array $not_used Not used. - * @param array $expected Expected "queued_before_register" queue. + * @param string|string[] $handles Handles to test. + * @param array $not_used Not used. + * @param array $expected Expected "queued_before_register" queue. */ - public function test_should_prequeue_when_not_registered( $font_family, $not_used, $expected ) { + public function test_should_prequeue_when_not_registered( $handles, $not_used, $expected ) { $wp_webfonts = new WP_Webfonts(); - $wp_webfonts->enqueue( $font_family ); + $wp_webfonts->enqueue( $handles ); - $this->assertSame( $expected, $this->get_queued_before_register( $wp_webfonts ), 'Font family(ies) should be added to before registered queue' ); - $this->assertEmpty( $this->queue, 'Font family(ies) should not be added to the enqueue queue when not registered' ); + $this->assertSame( $expected, $this->get_queued_before_register( $wp_webfonts ), 'Handles should be added to before registered queue' ); + $this->assertEmpty( $this->queue, 'Handles should not be added to the enqueue queue when not registered' ); } /** - * Integration test for enqueuing a font family and all of its variations. + * Integration test for enqueuing (a) a font family and all of its variations or (b) specific variations. * * @dataProvider data_enqueue + * @dataProvider data_enqueue_variations * - * @param string|string[] $font_family Font family to test. - * @param array $expected Expected queue. + * @param string|string[] $handles Handles to test. + * @param array $expected Expected queue. */ - public function test_should_enqueue_when_registered( $font_family, array $expected ) { + public function test_should_enqueue_when_registered( $handles, array $expected ) { $wp_webfonts = new WP_Webfonts(); foreach ( $this->get_data_registry() as $handle => $variations ) { $this->setup_register( $handle, $variations, $wp_webfonts ); } - $wp_webfonts->enqueue( $font_family ); + $wp_webfonts->enqueue( $handles ); $this->assertEmpty( $this->get_queued_before_register( $wp_webfonts ), '"queued_before_register" queue should be empty' ); - $this->assertSame( $expected, $wp_webfonts->queue, 'Queue should contain the given font family(ies)' ); + $this->assertSame( $expected, $wp_webfonts->queue, 'Queue should contain the given handles' ); } } From dd0f4ded5fde0948d7e9b5795e3db81d09314e63 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Fri, 19 Aug 2022 06:41:18 -0500 Subject: [PATCH 15/63] Updates register-webfonts-from-theme-json.php --- .../register-webfonts-from-theme-json.php | 68 +++++++++++-------- 1 file changed, 40 insertions(+), 28 deletions(-) diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index d1394f3428448d..682ef2f4be0e2a 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -20,13 +20,17 @@ function gutenberg_register_webfonts_from_theme_json() { 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'] ) || + 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'] = 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'] ); @@ -41,6 +45,7 @@ function gutenberg_register_webfonts_from_theme_json() { } $webfonts = array(); + $handles = array(); // Look for fontFamilies. foreach ( $settings['typography']['fontFamilies'] as $font_families ) { @@ -74,33 +79,34 @@ function gutenberg_register_webfonts_from_theme_json() { // Convert keys to kebab-case. foreach ( $font_face as $property => $value ) { - $kebab_case = _wp_to_kebab_case( $property ); + $kebab_case = _wp_to_kebab_case( $property ); $font_face[ $kebab_case ] = $value; if ( $kebab_case !== $property ) { unset( $font_face[ $property ] ); } } - $webfonts[] = $font_face; - } - } - } - - $to_enqueue = array(); - - foreach ( $webfonts as $webfont ) { - $font_family_handle = sanitize_title( $webfont['font-family'] ); + $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $font_face ); + if ( empty( $font_family_handle ) ) { + $font_family = $font_family['slug']; + } + $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); + if ( is_null( $font_family_handle ) ) { + _doing_it_wrong( __FUNCTION__, __( 'Font family not defined in the variation or "slug".', 'gutenberg' ), '6.1.0' ); + } - wp_register_webfont_family( $font_family_handle ); + $handles[] = $font_family_handle; + if ( ! array_key_exists( $font_family_handle, $webfonts ) ) { + $webfonts[ $font_family_handle ] = array(); + } - $variation_handle = sanitize_title( implode( ' ', array( $webfont['font-weight'], $webfont['font-style'] ) ) ); - wp_register_webfont_variation( $font_family_handle, $variation_handle, $webfont ); - $to_enqueue[] = $font_family_handle; + $webfonts[ $font_family_handle ][] = $font_face; + } + } } - foreach ( $to_enqueue as $font_family ) { - wp_webfonts()->enqueue( $font_family ); - } + wp_register_webfonts( $webfonts ); + wp_enqueue_webfont( $handles ); } } @@ -112,9 +118,13 @@ function gutenberg_register_webfonts_from_theme_json() { * @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_registered = wp_webfonts()->get_registered(); $font_families_from_theme = array(); - if ( ! empty( $data['settings'] ) && ! empty( $data['settings']['typography'] ) && ! empty( $data['settings']['typography']['fontFamilies'] ) ) { + if ( + ! empty( $data['settings'] ) && + ! empty( $data['settings']['typography'] ) && + ! empty( $data['settings']['typography']['fontFamilies'] ) + ) { $font_families_from_theme = $data['settings']['typography']['fontFamilies']; } @@ -127,12 +137,14 @@ function gutenberg_add_registered_webfonts_to_theme_json( $data ) { $get_families = static function ( $families_data ) { $families = array(); foreach ( $families_data as $family ) { - $families[] = WP_Webfonts::get_font_slug( $family ); + $families[] = WP_Webfonts_Utils::convert_font_family_into_handle( $family ); } - // Micro-optimization: Use array_flip( array_flip( $array ) ) - // instead of array_unique( $array ) because it's faster. - // The result is the same. + /* + * 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 ) ); }; @@ -158,8 +170,8 @@ function gutenberg_add_registered_webfonts_to_theme_json( $data ) { 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(); + $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' ); From d4090975ebbddf73992598475db6f850d6351f96 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Fri, 19 Aug 2022 06:44:20 -0500 Subject: [PATCH 16/63] WP_Webfonts::dequeue() --- phpunit/webfonts/wpWebfonts/dequeue-test.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 phpunit/webfonts/wpWebfonts/dequeue-test.php diff --git a/phpunit/webfonts/wpWebfonts/dequeue-test.php b/phpunit/webfonts/wpWebfonts/dequeue-test.php new file mode 100644 index 00000000000000..7a67b07d72ff37 --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/dequeue-test.php @@ -0,0 +1,20 @@ + Date: Fri, 19 Aug 2022 06:50:04 -0500 Subject: [PATCH 17/63] WP_Webfonts::get_enqueued() plus tests --- lib/experimental/class-wp-webfonts.php | 2 +- .../webfonts/wpWebfonts/getEnqueued-test.php | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 phpunit/webfonts/wpWebfonts/getEnqueued-test.php diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 81ac81e40a1934..4c02891a4adc4a 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -39,7 +39,7 @@ public function get_registered() { } /** - * Get the list of enqueued web fonts and variations. + * Get the list of enqueued font families and their variations. * * @since X.X.X * diff --git a/phpunit/webfonts/wpWebfonts/getEnqueued-test.php b/phpunit/webfonts/wpWebfonts/getEnqueued-test.php new file mode 100644 index 00000000000000..7783f34b16c33c --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/getEnqueued-test.php @@ -0,0 +1,57 @@ +assertEmpty( $wp_webfonts->get_enqueued() ); + } + + /** + * Unit test for when font families are enqueued. + * + * @dataProvider data_enqueue + * + * @param string|string[] $not_used Not used. + * @param array $expected Expected queue. + */ + public function test_should_return_queue_when_property_has_font_families( $not_used, array $expected ) { + $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->queue = $expected; + + $this->assertSame( $expected, $wp_webfonts->get_enqueued() ); + } + + /** + * Full integration test that registers and enqueues the queue + * is properly wired for "get_enqueued()". + * + * @dataProvider data_enqueue + * + * @param string|string[] $font_family Font family to test. + * @param array $expected Expected queue. + */ + public function test_should_return_queue_when_font_families_registered_and_enqueued( $font_family, array $expected ) { + $wp_webfonts = new WP_Webfonts(); + + // Register and enqueue. + foreach ( $this->get_data_registry() as $handle => $variations ) { + $this->setup_register( $handle, $variations, $wp_webfonts ); + } + $wp_webfonts->enqueue( $font_family ); + + $this->assertSame( $expected, $wp_webfonts->get_enqueued() ); + } +} From 32939fd69b14ace5f2f3833cc9d830917f3ad812 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Fri, 19 Aug 2022 07:13:20 -0500 Subject: [PATCH 18/63] WP_Webfonts::get_registered() plus tests --- lib/experimental/class-wp-webfonts.php | 2 +- .../webfonts/wp-webfonts-tests-dataset.php | 4 +- .../wpWebfonts/getRegistered-test.php | 90 +++++++++++++++++++ 3 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 phpunit/webfonts/wpWebfonts/getRegistered-test.php diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 4c02891a4adc4a..c9aa1a03d6aa62 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -28,7 +28,7 @@ public function __construct() { } /** - * Get the list of all registered web fonts and variations. + * Get the list of all registered font families and their variations. * * @since X.X.X * diff --git a/phpunit/webfonts/wp-webfonts-tests-dataset.php b/phpunit/webfonts/wp-webfonts-tests-dataset.php index 9eeb979cbe71e0..884a04e27491db 100644 --- a/phpunit/webfonts/wp-webfonts-tests-dataset.php +++ b/phpunit/webfonts/wp-webfonts-tests-dataset.php @@ -298,11 +298,11 @@ public function data_invalid_variation() { } /** - * Data provider. + * Data provider for testing one or more font families with varying number of variations. * * @return array */ - public function data_deregister() { + public function data_one_to_many_font_families_and_zero_to_many_variations() { return array( 'one family family no variations' => array( 'font_family' => 'lato', diff --git a/phpunit/webfonts/wpWebfonts/getRegistered-test.php b/phpunit/webfonts/wpWebfonts/getRegistered-test.php new file mode 100644 index 00000000000000..0160d85552bec9 --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/getRegistered-test.php @@ -0,0 +1,90 @@ +assertEmpty( $wp_webfonts->get_registered() ); + } + + /** + * Unit test for when font families are enqueued. + * + * @dataProvider data_get_registered + * + * @param array $inputs Font family(ies) and variations to register. + */ + public function test_should_return_queue_when_mocking_registered_property( array $inputs ) { + $wp_webfonts = new WP_Webfonts(); + $mocks = $this->setup_registration_mocks( $inputs, $wp_webfonts ); + $expected = array_keys( $mocks ); + + $this->assertSame( $expected, $wp_webfonts->get_registered() ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_get_registered() { + return array( + 'no variations' => array( + 'inputs' => array( + 'lato' => array(), + ), + ), + 'with 1 variation' => array( + 'inputs' => array( + 'Source Serif Pro' => array( 'variation-1' ), + ), + ), + 'with 2 variations' => array( + 'inputs' => array( + 'my-cool-font' => array( 'cool-1', 'cool-2' ), + ), + ), + 'when multiple font families registered' => array( + 'inputs' => array( + 'font-family-1' => array( 'variation-11', 'variation-12' ), + 'font-family-2' => array( 'variation-21', 'variation-22' ), + 'font-family-3' => array( 'variation-31', 'variation-32' ), + ), + ), + ); + } + + /** + * Full integration test that registers varying number of font families and variations + * to validate if "get_registered()" internals is property wired to the registered queue. + * + * @dataProvider data_one_to_many_font_families_and_zero_to_many_variations + * + * @param string $font_family Not used. + * @param array $inputs Font family(ies) and variations to register. + * @param array $expected Expected results. + */ + public function test_should_return_queue_when_items_are_registered( $font_family, array $inputs, array $expected ) { + $wp_webfonts = new WP_Webfonts(); + + // Register before testing. + foreach ( $inputs as $handle => $variations ) { + $this->setup_register( $handle, $variations, $wp_webfonts ); + } + + $this->assertSame( $expected, $wp_webfonts->get_registered() ); + } +} From bde64c045c29e6bdc765c90fe0a2582b6d5a7da1 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Fri, 19 Aug 2022 07:28:55 -0500 Subject: [PATCH 19/63] wp_deregister_font_family() plus tests --- lib/experimental/class-wp-webfonts.php | 8 +- lib/experimental/webfonts.php | 12 +- .../webfonts/wpDeregisterFontFamily-test.php | 74 +++++++++++ phpunit/webfonts/wpWebfonts/remove-test.php | 118 ++++++++++++++++++ .../wpWebfonts/removeFontFamily-test.php | 89 +++++++++++++ 5 files changed, 293 insertions(+), 8 deletions(-) create mode 100644 phpunit/webfonts/wpDeregisterFontFamily-test.php create mode 100644 phpunit/webfonts/wpWebfonts/remove-test.php create mode 100644 phpunit/webfonts/wpWebfonts/removeFontFamily-test.php diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index c9aa1a03d6aa62..728770365cd412 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -52,11 +52,11 @@ public function get_enqueued() { /** * Removes a font family and all registered variations. * - * @param mixed|string|string[] $font_family + * @since X.X.X + * + * @param string $font_family_handle The font family to remove. */ - function remove_family( $font_family ) { - $font_family_handle = sanitize_title( $font_family ); - + public function remove_font_family( $font_family_handle ) { if ( ! isset( $this->registered[ $font_family_handle ] ) ) { return; } diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index 37758ec2d10f09..c2792d7cd44868 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -179,12 +179,16 @@ function wp_enqueue_webfont_variations( $variation_handles ) { } } -if ( ! function_exists( 'wp_deregister_web_font_family' ) ) { +if ( ! function_exists( 'wp_deregister_font_family' ) ) { /** - * Unregisters an entire font family and all variations. + * Deregisters a font family and all of its registered variations. + * + * @since X.X.X + * + * @param string $font_family_handle The font family to remove. */ - function wp_deregister_web_font_family( $font_family ) { - wp_webfonts()->remove_family( $font_family ); + function wp_deregister_font_family( $font_family_handle ) { + wp_webfonts()->remove_font_family( $font_family_handle ); } } diff --git a/phpunit/webfonts/wpDeregisterFontFamily-test.php b/phpunit/webfonts/wpDeregisterFontFamily-test.php new file mode 100644 index 00000000000000..a7e4db544e0ecd --- /dev/null +++ b/phpunit/webfonts/wpDeregisterFontFamily-test.php @@ -0,0 +1,74 @@ +set_up_mock( 'remove_font_family' ); + $mock->expects( $this->once() ) + ->method( 'remove_font_family' ) + ->with( + $this->identicalTo( $font_family_handle ) + ); + + wp_deregister_font_family( $font_family_handle ); + } + + /** + * Integration test for enqueuing before registering a font family and all of its variations. + * + * @dataProvider data_font_family_handles + * + * @param string $font_family Font family to test. + */ + public function test_should_deregister_before_registration( $font_family ) { + wp_deregister_font_family( $font_family ); + + $this->assertIsArray( $this->get_registered(), 'Registration queue should be an array' ); + $this->assertEmpty( $this->get_registered(), 'Registration queue should be empty after deregistering' ); + } + + /** + * Integration test for deregistering a font family and all of its variations. + * + * @dataProvider data_one_to_many_font_families_and_zero_to_many_variations + * + * @param string $font_family Font family to test. + * @param array $inputs Font family(ies) and variations to pre-register. + * @param array $registered_handles Expected handles after registering. + * @param array $expected Array of expected handles. + */ + public function test_deregister_after_registration( $font_family, array $inputs, array $registered_handles, array $expected ) { + foreach ( $inputs as $handle => $variations ) { + $this->setup_register( $handle, $variations ); + } + // Test the before state, just to make sure. + $this->assertSame( $registered_handles, $this->get_registered_handles(), 'Font family and variations should be registered before deregistering' ); + + wp_deregister_font_family( $font_family ); + + // Test after deregistering. + $this->assertIsArray( $this->get_registered_handles(), 'Registration queue should be an array' ); + $this->assertSame( $expected, $this->get_registered_handles(), 'Registration queue should match after deregistering' ); + } +} diff --git a/phpunit/webfonts/wpWebfonts/remove-test.php b/phpunit/webfonts/wpWebfonts/remove-test.php new file mode 100644 index 00000000000000..f595755e85927a --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/remove-test.php @@ -0,0 +1,118 @@ +remove( array( 'handle-1', 'handle2' ) ); + + $this->assertEmpty( $wp_webfonts->registered ); + } + + /** + * @dataProvider data_remove_when_registered + * + * @param array $handles Handles to remove. + * @param array $expected Expected handles are running test. + */ + public function test_should_remove_when_registered( array $handles, array $expected ) { + $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->registered = $this->generate_registered_queue(); + + $wp_webfonts->remove( $handles ); + + $this->assertSameSets( $expected, array_keys( $wp_webfonts->registered ), 'Registered queue should match after removing handles' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_remove_when_registered() { + $all = array( + 'handle-1', + 'handle-2', + 'handle-3', + 'handle-4', + 'handle-5', + 'handle-6', + 'handle-7', + 'handle-8', + 'handle-9', + 'handle-10', + ); + + return array( + 'remove none' => array( + 'handles' => array(), + 'expected' => $all, + ), + 'remove handle-5' => array( + 'handles' => array( 'handle-5' ), + 'expected' => array( + 'handle-1', + 'handle-2', + 'handle-3', + 'handle-4', + 'handle-6', + 'handle-7', + 'handle-8', + 'handle-9', + 'handle-10', + ), + ), + 'remove 2 from start and end' => array( + 'handles' => array( 'handle-1', 'handle-2', 'handle-9', 'handle-10' ), + 'expected' => array( + 'handle-3', + 'handle-4', + 'handle-5', + 'handle-6', + 'handle-7', + 'handle-8', + ), + ), + 'remove all' => array( + 'handles' => $all, + 'expected' => array(), + ), + 'remove only registered' => array( + 'handles' => array( 'handle-1', 'handle-10', 'handle-abc', 'handle-5' ), + 'expected' => array( + 'handle-2', + 'handle-3', + 'handle-4', + 'handle-6', + 'handle-7', + 'handle-8', + 'handle-9', + ), + ), + ); + } + + private function generate_registered_queue() { + $queue = array(); + for ( $num = 1; $num <= 10; $num++ ) { + $handle = "handle-{$num}"; + $queue[ $handle ] = $num; + } + + return $queue; + } +} diff --git a/phpunit/webfonts/wpWebfonts/removeFontFamily-test.php b/phpunit/webfonts/wpWebfonts/removeFontFamily-test.php new file mode 100644 index 00000000000000..5cede6476582bd --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/removeFontFamily-test.php @@ -0,0 +1,89 @@ +setup_registration_mocks( $inputs, $wp_webfonts ); + // Test the before state, just to make sure. + $this->assertArrayHasKey( $font_family, $wp_webfonts->registered, 'Registered queue should contain the font family before remove' ); + $this->assertSame( $registered_handles, array_keys( $wp_webfonts->registered ), 'Font family and variations should be registered before remove' ); + + $wp_webfonts->remove_font_family( $font_family ); + + $this->assertArrayNotHasKey( $font_family, $wp_webfonts->registered, 'Registered queue should not contain the font family' ); + $this->assertSame( $expected, array_keys( $wp_webfonts->registered ), 'Registered queue should match after removing font family' ); + } + + /** + * @dataProvider data_one_to_many_font_families_and_zero_to_many_variations + * + * @param string $font_family Font family to test. + * @param array $inputs Font family(ies) and variations to pre-register. + * @param array $registered_handles Not used. + * @param array $expected Array of expected handles. + */ + public function test_should_bail_out_when_not_registered( $font_family, array $inputs, array $registered_handles, array $expected ) { + $wp_webfonts = new WP_Webfonts(); + unset( $inputs[ $font_family ] ); + $this->setup_registration_mocks( $inputs, $wp_webfonts ); + + $wp_webfonts->remove_font_family( $font_family ); + + $this->assertArrayNotHasKey( $font_family, $wp_webfonts->registered, 'Registered queue should not contain the font family' ); + $this->assertSame( $expected, array_keys( $wp_webfonts->registered ), 'Registered queue should match after removing font family' ); + } + + /** + * Integration test for removing a font family and all of its variation when font family is registered. + * + * @dataProvider data_one_to_many_font_families_and_zero_to_many_variations + * + * @param string $font_family Font family to test. + * @param array $inputs Font family(ies) and variations to pre-register. + * @param array $registered_handles Expected handles after registering. + * @param array $expected Array of expected handles. + */ + public function test_should_deregister_when_registered( $font_family, array $inputs, array $registered_handles, array $expected ) { + $wp_webfonts = new WP_Webfonts(); + // Register all font families and their variations. + foreach ( $inputs as $handle => $variations ) { + $wp_webfonts->add( $handle, false ); + foreach ( $variations as $variation_handle => $variation ) { + if ( ! is_string( $variation_handle ) ) { + $variation_handle = ''; + } + $wp_webfonts->add_variation( $handle, $variation, $variation_handle ); + } + } + // Test the before state, just to make sure. + $this->assertArrayHasKey( $font_family, $wp_webfonts->registered, 'Registered queue should contain the font family before remove' ); + $this->assertSame( $registered_handles, array_keys( $wp_webfonts->registered ), 'Font family and variations should be registered before remove' ); + + $wp_webfonts->remove_font_family( $font_family ); + + $this->assertArrayNotHasKey( $font_family, $wp_webfonts->registered, 'Registered queue should not contain the font family' ); + $this->assertSame( $expected, array_keys( $wp_webfonts->registered ), 'Registered queue should match after removing font family' ); + } +} From a083163d48b867b49e9c0660fd26b646a81003df Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Fri, 19 Aug 2022 07:50:24 -0500 Subject: [PATCH 20/63] wp_deregister_webfont_variation() plus tests --- lib/experimental/class-wp-webfonts.php | 48 ++++----- lib/experimental/webfonts.php | 13 ++- .../wpDeregisterWebfontVariation-test.php | 97 +++++++++++++++++++ .../wpWebfonts/removeVariation-test.php | 20 ++++ 4 files changed, 152 insertions(+), 26 deletions(-) create mode 100644 phpunit/webfonts/wpDeregisterWebfontVariation-test.php create mode 100644 phpunit/webfonts/wpWebfonts/removeVariation-test.php diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 728770365cd412..81d1c5ab120e80 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -141,42 +141,46 @@ public function add_variation( $font_family_handle, array $variation, $variation } /** - * Checks if the variation is registered. + * Removes a variation. * * @since X.X.X * - * @param string $font_family_handle The font family's handle for this variation. - * @param string $variant_handle Variation's handle. - * @return bool + * @param string $font_family_handle The font family for this variation. + * @param string $variation_handle The variation's handle to remove. */ - private function is_variation_registered( $font_family_handle, $variant_handle ) { - if ( ! isset( $this->registered[ $font_family_handle ] ) ) { - return array(); + public function remove_variation( $font_family_handle, $variation_handle ) { + if ( isset( $this->registered[ $variation_handle ] ) ) { + $this->remove( $variation_handle ); } - return in_array( $variant_handle, $this->registered[ $font_family_handle ]->deps ); + if ( ! $this->is_variation_registered( $font_family_handle, $variation_handle ) ) { + return; + } + + // Remove the variation as a dependency from its font family. + $this->registered[ $font_family_handle ]->deps = array_values( + array_diff( + $this->registered[ $font_family_handle ]->deps, + array( $variation_handle ) + ) + ); } /** - * Removes a variation. + * Checks if the variation is registered. * - * @param $font_family - * @param $variation_handle + * @since X.X.X + * + * @param string $font_family_handle The font family's handle for this variation. + * @param string $variation_handle Variation's handle. + * @return bool True when registered to the given font family. Else false. */ - function remove_variation( $font_family, $variation_handle ) { - $font_family_handle = sanitize_title( $font_family ); - - $this->remove( $variation_handle ); - + private function is_variation_registered( $font_family_handle, $variation_handle ) { if ( ! isset( $this->registered[ $font_family_handle ] ) ) { - return; + return false; } - // Remove the variation as a dependency. - $this->registered[ $font_family_handle ]->deps = array_values( array_diff( - $this->registered[ $font_family_handle ]->deps, - array( $variation_handle ) - ) ); + return in_array( $variation_handle, $this->registered[ $font_family_handle ]->deps, true ); } /** diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index c2792d7cd44868..bb5b94b363372c 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -192,12 +192,17 @@ function wp_deregister_font_family( $font_family_handle ) { } } -if ( ! function_exists( 'wp_deregister_web_font_variation' ) ) { +if ( ! function_exists( 'wp_deregister_webfont_variation' ) ) { /** - * @param $variation_handle + * Deregisters a font variation. + * + * @since X.X.X + * + * @param string $font_family_handle The font family for this variation. + * @param string $variation_handle The variation's handle to remove. */ - function wp_deregister_web_font_variation( $font_family, $variation_handle ) { - wp_webfonts()->remove_variation( $font_family, $variation_handle ); + function wp_deregister_webfont_variation( $font_family_handle, $variation_handle ) { + wp_webfonts()->remove_variation( $font_family_handle, $variation_handle ); } } diff --git a/phpunit/webfonts/wpDeregisterWebfontVariation-test.php b/phpunit/webfonts/wpDeregisterWebfontVariation-test.php new file mode 100644 index 00000000000000..d2dcfec7760465 --- /dev/null +++ b/phpunit/webfonts/wpDeregisterWebfontVariation-test.php @@ -0,0 +1,97 @@ +set_up_mock( 'remove_variation' ); + $mock->expects( $this->once() ) + ->method( 'remove_variation' ) + ->with( + $this->identicalTo( $font_family_handle, $variation_handle ) + ); + + wp_deregister_webfont_variation( $font_family_handle, $variation_handle ); + } + + /** + * Integration test for enqueuing before registering a font family and all of its variations. + * + * @dataProvider data_font_family_and_variation_handle + * + * @param string $font_family_handle Font family to test. + * @param string $variation_handle Variation's handle to test. + */ + public function test_should_do_nothing_when_not_registered( $font_family_handle, $variation_handle ) { + wp_deregister_webfont_variation( $font_family_handle, $variation_handle ); + + $this->assertIsArray( $this->get_registered(), 'Registration queue should be an array' ); + $this->assertEmpty( $this->get_registered(), 'Registration queue should be empty after deregistering' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_font_family_and_variation_handle() { + return array( + 'single words name' => array( + 'font_family' => 'Lato', + 'variation_handle' => 'Lato 400 normal', + ), + 'multiple words name' => array( + 'font_family' => 'Source Sans Pro', + 'expected_handle' => 'Source Sans Pro 400 normal', + ), + 'handles' => array( + 'font_family' => 'source-serif-pro', + 'expected_handle' => 'source-serif-pro-400-normal', + ), + ); + } + + /** + * Integration test for deregistering a font family and all of its variations. + * + * @dataProvider data_one_to_many_font_families_and_zero_to_many_variations + * + * @param string $font_family Font family to test. + * @param array $inputs Font family(ies) and variations to pre-register. + * @param array $registered_handles Expected handles after registering. + * @param array $expected Array of expected handles. + */ + public function test_deregister_after_registration( $font_family, array $inputs, array $registered_handles, array $expected ) { + foreach ( $inputs as $handle => $variations ) { + $this->setup_register( $handle, $variations ); + } + // Test the before state, just to make sure. + $this->assertSame( $registered_handles, $this->get_registered_handles(), 'Font family and variations should be registered before deregistering' ); + + wp_deregister_font_family( $font_family ); + + // Test after deregistering. + $this->assertIsArray( $this->get_registered_handles(), 'Registration queue should be an array' ); + $this->assertSame( $expected, $this->get_registered_handles(), 'Registration queue should match after deregistering' ); + } +} diff --git a/phpunit/webfonts/wpWebfonts/removeVariation-test.php b/phpunit/webfonts/wpWebfonts/removeVariation-test.php new file mode 100644 index 00000000000000..f774dedb74e7f6 --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/removeVariation-test.php @@ -0,0 +1,20 @@ + Date: Fri, 19 Aug 2022 09:21:03 -0500 Subject: [PATCH 21/63] wp_get_webfont_providers() plus tests --- lib/experimental/class-wp-webfonts.php | 22 +++--- lib/experimental/webfonts.php | 2 +- .../webfonts/wp-webfonts-tests-dataset.php | 42 +++++++++++ .../webfonts/wpGetWebfontProviders-test.php | 72 +++++++++++++++++++ .../webfonts/wpWebfonts/getProviders-test.php | 62 ++++++++++++++++ 5 files changed, 188 insertions(+), 12 deletions(-) create mode 100644 phpunit/webfonts/wpGetWebfontProviders-test.php create mode 100644 phpunit/webfonts/wpWebfonts/getProviders-test.php diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 81d1c5ab120e80..28acec2ad44c57 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -27,6 +27,17 @@ public function __construct() { do_action_ref_array( 'wp_default_webfonts', array( &$this ) ); } + /** + * Get the list of registered providers. + * + * @since X.X.X + * + * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. + */ + public function get_providers() { + return $this->providers; + } + /** * Get the list of all registered font families and their variations. * @@ -355,17 +366,6 @@ public function register_provider( $provider, $class ) { return true; } - /** - * Get the list of providers. - * - * @since 6.0.0 - * - * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. - */ - public function get_providers() { - return $this->providers; - } - /** * Retrieves a list of enqueued web font variations for a provider. * diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index bb5b94b363372c..396de99b055f63 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -250,7 +250,7 @@ function wp_register_webfont_provider( $name, $classname ) { * process its specific font service (i.e. local or remote) * and how to generate the `@font-face` styles for its service. * - * @since 6.0.0 + * @since X.X.X * * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. */ diff --git a/phpunit/webfonts/wp-webfonts-tests-dataset.php b/phpunit/webfonts/wp-webfonts-tests-dataset.php index 884a04e27491db..8caaeaa510c57d 100644 --- a/phpunit/webfonts/wp-webfonts-tests-dataset.php +++ b/phpunit/webfonts/wp-webfonts-tests-dataset.php @@ -431,6 +431,48 @@ public function data_font_family_handles() { ); } + /** + * Data provider. + * + * @return array + */ + public function data_get_providers() { + $local = array( + 'local' => array( + 'class' => WP_Webfonts_Provider_Local::class, + 'fonts' => array(), + ), + ); + $mock = array( + 'mock' => array( + 'class' => Mock_Provider::class, + 'fonts' => array(), + ), + ); + + return array( + 'local provider' => array( + 'providers' => array( + 'local' => WP_Webfonts_Provider_Local::class, + ), + 'expected' => $local, + ), + 'mock provider' => array( + 'providers' => array( + 'mock' => Mock_Provider::class, + ), + 'expected' => $mock, + ), + 'local and mock providers' => array( + 'providers' => array( + 'local' => WP_Webfonts_Provider_Local::class, + 'mock' => Mock_Provider::class, + ), + 'expected' => array_merge( $local, $mock ), + ), + ); + } + /** * Data provider. * diff --git a/phpunit/webfonts/wpGetWebfontProviders-test.php b/phpunit/webfonts/wpGetWebfontProviders-test.php new file mode 100644 index 00000000000000..b1512669503d6b --- /dev/null +++ b/phpunit/webfonts/wpGetWebfontProviders-test.php @@ -0,0 +1,72 @@ +providers_property = new ReflectionProperty( WP_Webfonts::class, 'providers' ); + $this->providers_property->setAccessible( true ); + } + + /** + * Unit test. + * + * @dataProvider data_get_providers + * + * @param array $providers Not used. + * @param array $expected Expected results. + */ + public function test_should_return_mocked_providers( array $providers, array $expected ) { + $mock = $this->set_up_mock( 'get_providers' ); + $mock->expects( $this->once() ) + ->method( 'get_providers' ) + ->will( $this->returnValue( $expected ) ); + + $this->assertSame( $expected, wp_get_webfont_providers() ); + } + + /** + * Integration test that sets the `WP_Webfonts::providers` property. + * + * @dataProvider data_get_providers + * + * @param array $providers Array of providers to test. + * @param array $expected Expected results. + */ + public function test_should_return_providers( array $providers, array $expected ) { + $this->setup_providers( $providers ); + $this->assertSame( $expected, wp_get_webfont_providers() ); + } + + /** + * Sets up the given providers and stores them in the `WP_Webfonts::providers` property. + * + * @param array $providers Array of providers to set up. + */ + private function setup_providers( array $providers ) { + $data = array(); + + foreach ( $providers as $provider_id => $class ) { + $data[ $provider_id ] = array( + 'class' => $class, + 'fonts' => array(), + ); + } + + $this->providers_property->setValue( wp_webfonts(), $data ); + } +} diff --git a/phpunit/webfonts/wpWebfonts/getProviders-test.php b/phpunit/webfonts/wpWebfonts/getProviders-test.php new file mode 100644 index 00000000000000..527c45cb614263 --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/getProviders-test.php @@ -0,0 +1,62 @@ +wp_webfonts = new WP_Webfonts(); + + $this->providers_property = new ReflectionProperty( WP_Webfonts::class, 'providers' ); + $this->providers_property->setAccessible( true ); + } + + public function test_should_be_empty() { + $actual = $this->wp_webfonts->get_providers(); + $this->assertIsArray( $actual, 'Should return an empty array' ); + $this->assertEmpty( $actual, 'Should return an empty array when no providers are registered' ); + } + + /** + * @dataProvider data_get_providers + * + * @param array $providers Array of providers to test. + * @param array $expected Expected results. + */ + public function test_get_providers( array $providers, array $expected ) { + $this->setup_providers( $providers ); + $this->assertSame( $expected, $this->wp_webfonts->get_providers() ); + } + + /** + * Sets up the given providers and stores them in the `WP_Webfonts::providers` property. + * + * @param array $providers Array of providers to set up. + */ + private function setup_providers( array $providers ) { + $data = array(); + + foreach ( $providers as $provider_id => $class ) { + $data[ $provider_id ] = array( + 'class' => $class, + 'fonts' => array(), + ); + } + + $this->providers_property->setValue( $this->wp_webfonts, $data ); + } +} From c75f21de52fad07bf42700f0df8b27ed0e666155 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Fri, 19 Aug 2022 09:32:59 -0500 Subject: [PATCH 22/63] wp_print_webfonts() et al plus tests --- .../class-wp-webfonts-provider-local.php | 35 +- .../class-wp-webfonts-provider.php | 19 +- lib/experimental/class-wp-webfonts.php | 254 ++++++++--- lib/experimental/webfonts.php | 28 +- phpunit/fixtures/mock-provider.php | 5 +- phpunit/webfonts/wp-webfonts-testcase.php | 117 +++++- .../webfonts/wp-webfonts-tests-dataset.php | 395 +++++++++++++++++- phpunit/webfonts/wpPrintWebfonts-test.php | 126 ++++++ phpunit/webfonts/wpWebfonts/doItem-test.php | 336 +++++++++++++++ phpunit/webfonts/wpWebfonts/doItems-test.php | 203 +++++++++ .../webfonts/wpWebfontsProviderLocal-test.php | 2 +- 11 files changed, 1438 insertions(+), 82 deletions(-) create mode 100644 phpunit/webfonts/wpPrintWebfonts-test.php create mode 100644 phpunit/webfonts/wpWebfonts/doItem-test.php create mode 100644 phpunit/webfonts/wpWebfonts/doItems-test.php diff --git a/lib/experimental/class-wp-webfonts-provider-local.php b/lib/experimental/class-wp-webfonts-provider-local.php index 9af27fa7c436a7..4959fe6f586c27 100644 --- a/lib/experimental/class-wp-webfonts-provider-local.php +++ b/lib/experimental/class-wp-webfonts-provider-local.php @@ -35,6 +35,33 @@ class WP_Webfonts_Provider_Local extends WP_Webfonts_Provider { */ protected $id = 'local'; + /** + * Holds a string which contains the type attribute for style tag. + * + * If the active theme does not declare HTML5 support for 'style', + * then it initializes as `type='text/css'`. + * + * @since 6.1.0 + * + * @var string + */ + private $type_attr = ''; + + /** + * Constructor. + * + * @since 6.1.0 + */ + public function __construct() { + if ( + function_exists( 'is_admin' ) && ! is_admin() + && + function_exists( 'current_theme_supports' ) && ! current_theme_supports( 'html5', 'style' ) + ) { + $this->type_attr = " type='text/css'"; + } + } + /** * Gets the `@font-face` CSS styles for locally-hosted font files. * @@ -81,7 +108,7 @@ class WP_Webfonts_Provider_Local extends WP_Webfonts_Provider { * } * * - * @since 6.0.0 + * @since X.X.X * * @return string The `@font-face` CSS. */ @@ -96,6 +123,12 @@ public function get_css() { $css .= '@font-face{' . $this->build_font_face_css( $webfont ) . '}'; } + $css = sprintf( + "\n", + $this->type_attr, + $css + ); + return $css; } diff --git a/lib/experimental/class-wp-webfonts-provider.php b/lib/experimental/class-wp-webfonts-provider.php index a49b8a324b7f5f..5113c0c46c023a 100644 --- a/lib/experimental/class-wp-webfonts-provider.php +++ b/lib/experimental/class-wp-webfonts-provider.php @@ -6,7 +6,7 @@ * * @package WordPress * @subpackage WebFonts - * @since 6.0.0 + * @since X.X.X */ if ( class_exists( 'WP_Webfonts_Provider' ) ) { @@ -30,14 +30,14 @@ * into styles (in a performant way for the provider service * it manages). * - * @since 6.0.0 + * @since X.X.X */ abstract class WP_Webfonts_Provider { /** * Webfonts to be processed. * - * @since 6.0.0 + * @since X.X.X * * @var array[] */ @@ -49,7 +49,7 @@ abstract class WP_Webfonts_Provider { * The API's Controller passes this provider's webfonts * for processing here in the provider. * - * @since 6.0.0 + * @since X.X.X * * @param array[] $webfonts Registered webfonts. */ @@ -64,9 +64,18 @@ public function set_webfonts( array $webfonts ) { * needed `@font-face` CSS for all of its webfonts. Specifics of how * this processing is done is contained in each provider. * - * @since 6.0.0 + * @since X.X.X * * @return string The `@font-face` CSS. */ abstract public function get_css(); + + /** + * Prints the generated styles. + * + * @since X.X.X + */ + public function print_styles() { + echo $this->get_css(); + } } diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 28acec2ad44c57..155dfc281a43b8 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -11,6 +11,25 @@ class WP_Webfonts extends WP_Dependencies { */ private $providers = array(); + /** + * The flipped $to_do array of web font handles. + * + * Used for a faster lookup of the web font handles. + * + * @since X.X.X + * + * @var string[] + */ + private $to_do_keyed_handles; + + /** + * Array of provider instances, keyed by provider ID. + * + * @since X.X.X + * + * @var array + */ + private $provider_instances = array(); /** * Constructor. * @@ -218,6 +237,7 @@ private function add_dependency( $font_family_handle, $variation_handle ) { private function validate_variation( $font_family_handle, $variation ) { $defaults = array( 'provider' => 'local', + 'font-family' => $font_family_handle, 'font-style' => 'normal', 'font-weight' => '400', 'font-display' => 'fallback', @@ -235,8 +255,11 @@ private function validate_variation( $font_family_handle, $variation ) { trigger_error( 'Webfont src must be a non-empty string or an array of strings.' ); return false; } - } elseif ( ! class_exists( $variation['provider'] ) ) { - trigger_error( 'The provider class specified does not exist.' ); + } elseif ( ! isset( $this->providers[ $variation['provider'] ] ) ) { + trigger_error( sprintf( 'The provider "%s" is not registered', $variation['provider'] ) ); + return false; + } elseif ( ! class_exists( $this->providers[ $variation['provider'] ]['class'] ) ) { + trigger_error( sprintf( 'The provider class "%s" does not exist', $variation['provider'] ) ); return false; } @@ -291,97 +314,230 @@ private function validate_variation( $font_family_handle, $variation ) { } /** - * Generate styles for webfonts. + * Processes the items and dependencies. * - * @since 6.0.0 + * Processes the items passed to it or the queue, and their dependencies. + * + * @since X.X.X + * + * @param string|string[]|false $handles Optional. Items to be processed: queue (false), + * single item (string), or multiple items (array of strings). + * Default false. + * @param int|false $group Optional. Group level: level (int), no group (false). * - * @param array[] $webfonts_by_provider Webfonts organized by provider. - * @return string $styles Generated styles. + * @return array|string[] Array of web font handles that have been processed. + * An empty array if none were processed. */ - public function do_item( $handle, $group = false ) { - if ( ! parent::do_item( $handle ) ) { - return false; + public function do_items( $handles = false, $group = false ) { + $handles = $this->prep_handles_for_printing( $handles ); + if ( empty( $handles ) ) { + return $this->done; } - $styles = ''; - $providers = $this->get_providers(); + $this->all_deps( $handles ); + if ( empty( $this->to_do ) ) { + return $this->done; + } - $obj = $this->registered[ $handle ]; + $this->to_do_keyed_handles = array_flip( $this->to_do ); - /* - * Loop through each of the providers to get the CSS for their respective webfonts - * to incrementally generate the collective styles for all of them. - */ - foreach ( $providers as $provider_id => $provider ) { - // Bail out if the provider class does not exist. + foreach ( $this->get_providers() as $provider_id => $provider ) { + // Alert and skip 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( + 'Class "%s" not found for "%s" web font provider', + $provider['class'], + $provider_id + ) + ); continue; } - $fonts = $this->get_enqueued_fonts_for_provider( $provider_id ); + $this->do_item( $provider_id, $group ); + } - // If there are no registered webfonts for this provider, skip it. - if ( empty( $fonts ) ) { - continue; + return $this->done; + } + + /** + * Prepares the given handles for printing. + * + * @since X.X.X + * + * @param string|string[]|bool $handles Handles to prepare. + * @return array Array of handles. + */ + private function prep_handles_for_printing( $handles = false ) { + if ( false !== $handles ) { + $handles = $this->validate_handles( $handles ); + // Bail out when invalid. + if ( null === $handles ) { + return array(); } + } - $provider_fonts = array(); + // Use the enqueued queue. + if ( empty( $handles ) ) { + if ( empty( $this->queue ) ) { + trigger_error( 'No web fonts are enqueued for printing' ); - foreach ( $fonts as $font_handle ) { - $provider_fonts[ $font_handle ] = $this->get_data( $font_handle, 'font-properties' ); + return array(); } + $handles = $this->queue; + } + + return $handles; + } - /* - * Process the webfonts by first passing them to the provider via `set_webfonts()` - * and then getting the CSS from the provider. - */ - $provider = new $provider['class'](); - $provider->set_webfonts( $provider_fonts ); - $styles .= $provider->get_css(); + /** + * Validates handle(s) to ensure each is a non-empty string. + * + * @since X.X.X + * + * @param mixed $handles Handle or handles to be validated. + * @return string[]|null Array of handles on success. Else null. + */ + private function validate_handles( $handles ) { + // Validate each element is a non-empty string handle. + $handles = array_filter( + (array) $handles, + static function( $handle ) { + return is_string( $handle ) && ! empty( $handle ); + } + ); + + if ( empty( $handles ) ) { + trigger_error( 'Handles must be a non-empty string or array of non-empty strings' ); + return null; } - return $styles; + return $handles; } /** - * Register a provider. + * Invokes each provider to process and print its styles. * - * @since 6.0.0 + * @since X.X.X * - * @param string $provider The provider name. - * @param string $class The provider class name. - * @return bool True if successfully registered, else false. + * @see WP_Dependencies::do_item() + * + * @param string $provider_id The font family to process. + * @param int|false $group Not used. + * @return bool */ - public function register_provider( $provider, $class ) { - if ( empty( $provider ) || empty( $class ) || ! class_exists( $class ) ) { + public function do_item( $provider_id, $group = false ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + // Bail out if the provider is not registered. + if ( ! isset( $this->providers[ $provider_id ] ) ) { return false; } - $this->providers[ $provider ] = array( - 'class' => $class, - 'fonts' => array(), - ); + $font_handles = $this->get_enqueued_fonts_for_provider( $provider_id ); + if ( empty( $font_handles ) ) { + return false; + } + + $properties_by_font = $this->get_font_properties_for_provider( $font_handles ); + if ( empty( $properties_by_font ) ) { + return false; + } + + // Invoke provider to print its styles. + if ( isset( $this->provider_instances[ $provider_id ] ) ) { + $provider = $this->provider_instances[ $provider_id ]; + } else { + $provider = new $this->providers[ $provider_id ]['class'](); + // Store the instance. + $this->provider_instances[ $provider_id ] = $provider; + } + $provider->set_webfonts( $properties_by_font ); + $provider->print_styles(); + + // Clean up. + $this->update_queues_for_printed_fonts( $font_handles ); + return true; } /** * Retrieves a list of enqueued web font variations for a provider. * + * @since X.X.X + * + * @param string $provider_id Provider's unique ID. * @return array[] Webfonts organized by providers. */ - private function get_enqueued_fonts_for_provider( $provider ) { + private function get_enqueued_fonts_for_provider( $provider_id ) { $providers = $this->get_providers(); - if ( empty( $providers[ $provider ] ) ) { + if ( empty( $providers[ $provider_id ] ) ) { return array(); } return array_intersect( - $providers[ $provider ]['fonts'], - $this->get_enqueued() + $providers[ $provider_id ]['fonts'], + $this->to_do ); } + /** + * Gets a list of font properties for each of the given font handles. + * + * @since X.X.X + * + * @param array $font_handles Font handles to get properties. + * @return array A list of fonts with each font's properties. + */ + private function get_font_properties_for_provider( array $font_handles ) { + $font_properties = array(); + + foreach ( $font_handles as $font_handle ) { + $properties = $this->get_data( $font_handle, 'font-properties' ); + if ( ! $properties ) { + continue; + } + $font_properties[ $font_handle ] = $properties; + } + + return $font_properties; + } + + /** + * Update queues for the given printed fonts. + * + * @since X.X.X + * + * @param array $font_handles Font handles to get properties. + */ + private function update_queues_for_printed_fonts( array $font_handles ) { + foreach ( $font_handles as $font_handle ) { + $this->done[] = $font_handle; + unset( + $this->to_do[ $this->to_do_keyed_handles[ $font_handle ] ], + $this->to_do_keyed_handles[ $font_handle ] + ); + } + } + + /** + * Register a provider. + * + * @since 6.0.0 + * + * @param string $provider The provider name. + * @param string $class The provider class name. + * @return bool True if successfully registered, else false. + */ + public function register_provider( $provider, $class ) { + if ( empty( $provider ) || empty( $class ) || ! class_exists( $class ) ) { + return false; + } + + $this->providers[ $provider ] = array( + 'class' => $class, + 'fonts' => array(), + ); + return true; + } } diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index 396de99b055f63..6c62b7be3d2584 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -260,16 +260,20 @@ function wp_get_webfont_providers() { } if ( ! function_exists( 'wp_print_webfonts' ) ) { + /** + * Invokes each provider to process and print its styles. + * + * @since X.X.X + * + * @param string|string[]|false $handles Optional. Items to be processed: queue (false), + * single item (string), or multiple items (array of strings). + * Default false. + * @return array|string[] Array of web font handles that have been processed. + * An empty array if none were processed. + */ function wp_print_webfonts( $handles = false ) { global $wp_webfonts; - /** - * Fires before webfonts in the $handles queue are printed. - * - * @since X.X.X - */ - do_action( 'wp_print_webfonts' ); - if ( '' === $handles ) { // For 'wp_head'. $handles = false; } @@ -286,14 +290,8 @@ function wp_print_webfonts( $handles = false ) { } } - - - - - - - - +add_action( 'admin_print_styles', 'wp_print_webfonts' ); +add_action( 'wp_head', 'wp_print_webfonts' ); /** * Add webfonts mime types. diff --git a/phpunit/fixtures/mock-provider.php b/phpunit/fixtures/mock-provider.php index 152badb1ce266c..2e31092ac8f248 100644 --- a/phpunit/fixtures/mock-provider.php +++ b/phpunit/fixtures/mock-provider.php @@ -13,9 +13,10 @@ class Mock_Provider extends WP_Webfonts_Provider { * * @var string */ - public $css = ''; + public $css = '%s\n'; public function get_css() { - return $this->css; + $handles = array_keys( $this->webfonts ); + return sprintf( $this->css, implode( '; ', $handles ) ); } } diff --git a/phpunit/webfonts/wp-webfonts-testcase.php b/phpunit/webfonts/wp-webfonts-testcase.php index 495ef996a7e51b..317ac1c77ea77d 100644 --- a/phpunit/webfonts/wp-webfonts-testcase.php +++ b/phpunit/webfonts/wp-webfonts-testcase.php @@ -21,6 +21,13 @@ abstract class WP_Webfonts_TestCase extends WP_UnitTestCase { */ private $old_wp_webfonts; + /** + * Reflection data store for non-public property access. + * + * @var ReflectionProperty[] + */ + protected $property = array(); + public function set_up() { parent::set_up(); @@ -29,15 +36,13 @@ public function set_up() { } public function tear_down() { + $this->property = array(); $GLOBALS['wp_webfonts'] = $this->old_wp_webfonts; parent::tear_down(); } protected function set_up_mock( $method ) { - if ( is_string( $method ) ) { - $method = array( $method ); - } - $mock = $this->getMockBuilder( WP_Webfonts::class )->setMethods( $method )->getMock(); + $mock = $this->setup_object_mock( $method, WP_Webfonts::class ); // Set the global. $GLOBALS['wp_webfonts'] = $mock; @@ -45,6 +50,14 @@ protected function set_up_mock( $method ) { return $mock; } + protected function setup_object_mock( $method, $class ) { + if ( is_string( $method ) ) { + $method = array( $method ); + } + + return $this->getMockBuilder( $class )->setMethods( $method )->getMock(); + } + protected function get_registered_handles() { return array_keys( $this->get_registered() ); } @@ -57,6 +70,7 @@ protected function get_variations( $font_family, $wp_webfonts = null ) { if ( ! ( $wp_webfonts instanceof WP_Webfonts ) ) { $wp_webfonts = wp_webfonts(); } + return $wp_webfonts->registered[ $font_family ]->deps; } @@ -68,16 +82,51 @@ protected function get_queued_before_register( $wp_webfonts = null ) { return $this->get_property_value( 'queued_before_register', WP_Dependencies::class, $wp_webfonts ); } - protected function get_property_value( $property_name, $class, $wp_webfonts = null ) { + protected function get_reflection_property( $property_name, $class = 'WP_Webfonts' ) { $property = new ReflectionProperty( $class, $property_name ); $property->setAccessible( true ); + return $property; + } + + protected function get_property_value( $property_name, $class, $wp_webfonts = null ) { + $property = $this->get_reflection_property( $property_name, $class ); + if ( ! $wp_webfonts ) { $wp_webfonts = wp_webfonts(); } + return $property->getValue( $wp_webfonts ); } + protected function setup_property( $class, $property_name ) { + $key = $this->get_property_key( $class, $property_name ); + + if ( ! isset( $this->property[ $key ] ) ) { + $this->property[ $key ] = new ReflectionProperty( $class, 'providers' ); + $this->property[ $key ]->setAccessible( true ); + } + + return $this->property[ $key ]; + } + + protected function get_property_key( $class, $property_name ) { + return $class . '::$' . $property_name; + } + + /** + * Opens the accessibility to access the given private or protected method. + * + * @param string $method_name Name of the method to open. + * @return ReflectionMethod Instance of the method, ie to invoke it in the test. + */ + protected function get_reflection_method( $method_name ) { + $method = new ReflectionMethod( WP_Webfonts::class, $method_name ); + $method->setAccessible( true ); + + return $method; + } + /** * Sets up multiple font family and variation mocks. * @@ -88,7 +137,7 @@ protected function get_property_value( $property_name, $class, $wp_webfonts = nu protected function setup_registration_mocks( array $inputs, WP_Webfonts $wp_webfonts ) { $mocks = array(); - $build_mock = function( $handle ) use ( &$mocks, $wp_webfonts ) { + $build_mock = function ( $handle ) use ( &$mocks, $wp_webfonts ) { $mock = new stdClass(); $mock->deps = array(); // Add to each queue. @@ -105,8 +154,9 @@ protected function setup_registration_mocks( array $inputs, WP_Webfonts $wp_webf if ( ! is_string( $variation_handle ) ) { $variation_handle = $variation; } - $build_mock( $variation_handle ); - $font_mock->deps[] = $variation_handle; + $variation_mock = $build_mock( $variation_handle ); + $variation_mock->extra = array( 'font-properties' => $variation ); + $font_mock->deps[] = $variation_handle; } } @@ -134,4 +184,55 @@ protected function setup_register( $font_family, $variations, $wp_webfonts = nul $wp_webfonts->add_variation( $font_family, $variation, $variation_handle ); } } + + /** + * Sets up the WP_Webfonts::$provider property. + * + * @param WP_Webfonts $wp_webfonts Instance of WP_Webfonts. + * @param string|array $provider Provider ID when string. Else provider definition with 'id' and 'class' keys. + * @param array $font_handles Optional. Font handles for this provider. + */ + protected function setup_provider_property_mock( WP_Webfonts $wp_webfonts, $provider, array $font_handles = array() ) { + if ( is_string( $provider ) ) { + $provider = $this->get_provider_definitions( $provider ); + } + + $property = $this->setup_property( WP_Webfonts::class, 'providers' ); + $providers = $property->getValue( $wp_webfonts ); + + if ( ! isset( $providers[ $provider['id'] ] ) ) { + $providers[ $provider['id'] ] = array( + 'class' => $provider['class'], + 'fonts' => $font_handles, + ); + } else { + $providers[ $provider['id'] ] = array_merge( $font_handles, $providers[ $provider['id'] ]['fonts'] ); + } + + $property->setValue( $wp_webfonts, $providers ); + } + + /** + * Gets the variation handles for the provider from the given fonts. + * + * @since X.X.X + * + * @param array $fonts Fonts definitions keyed by font family. + * @param string $provider_id Provider ID. + * @return array|string[] Array of handles on success. Else empty array. + */ + protected function get_handles_for_provider( array $fonts, $provider_id ) { + $handles = array(); + + foreach ( $fonts as $variations ) { + foreach ( $variations as $variation_handle => $variation ) { + if ( $provider_id !== $variation['provider'] ) { + continue; + } + $handles[] = $variation_handle; + } + } + + return $handles; + } } diff --git a/phpunit/webfonts/wp-webfonts-tests-dataset.php b/phpunit/webfonts/wp-webfonts-tests-dataset.php index 8caaeaa510c57d..730a719ce736fd 100644 --- a/phpunit/webfonts/wp-webfonts-tests-dataset.php +++ b/phpunit/webfonts/wp-webfonts-tests-dataset.php @@ -278,7 +278,7 @@ public function data_invalid_variation() { ), ), 'provider does not exist' => array( - 'expected' => 'The provider class specified does not exist.', + 'expected' => 'The provider "doesnotexit" is not registered', 'font_family_handle' => 'merriweather', 'variation' => array( 'provider' => 'doesnotexit', @@ -540,6 +540,219 @@ public function data_enqueue_variations() { ); } + /** + * Data provider. + * + * @return array + */ + public function data_print_enqueued() { + $providers = $this->get_provider_definitions(); + $mock_fonts = $this->get_registered_mock_fonts(); + $mock_font_handles = $this->get_handles_for_provider( $mock_fonts, 'mock' ); + $local_fonts = $this->get_registered_local_fonts(); + $local_font_handles = $this->get_handles_for_provider( $local_fonts, 'local' ); + $font_faces = $this->get_registered_fonts_css(); + + $all_variation_handles = array_merge( $mock_font_handles, $local_font_handles ); + $setup_all = array( + 'provider' => array( + 'local' => $providers['local'], + 'mock' => $providers['mock'], + ), + 'provider_handles' => array( + 'local' => $local_font_handles, + 'mock' => $mock_font_handles, + ), + 'registered' => array_merge( $mock_fonts, $local_fonts ), + ); + + return array( + + // One provider registered with multiple fonts. + + 'print font2 for mock provider' => array( + 'setup' => array( + 'provider' => array( 'mock' => $providers['mock'] ), + 'provider_handles' => array( 'mock' => $mock_font_handles ), + 'registered' => $mock_fonts, + 'enqueued' => array( 'font2' ), + ), + 'expected_done' => array( 'font2-200-900-normal', 'font2-200-900-italic' ), + 'expected_output' => sprintf( + '%s; %s\n', + $font_faces['font2-200-900-normal'], + $font_faces['font2-200-900-italic'] + ), + ), + 'print all fonts for mock provider' => array( + 'setup' => array( + 'provider' => array( 'mock' => $providers['mock'] ), + 'provider_handles' => array( 'mock' => $mock_font_handles ), + 'registered' => $mock_fonts, + 'enqueued' => array( 'font1', 'font2', 'font3' ), + ), + 'expected_done' => $mock_font_handles, + 'expected_output' => sprintf( + '%s; %s; %s; %s; %s; %s\n', + $font_faces['font1-300-normal'], + $font_faces['font1-300-italic'], + $font_faces['font1-900-normal'], + $font_faces['font2-200-900-normal'], + $font_faces['font2-200-900-italic'], + $font_faces['font3-bold-normal'] + ), + ), + 'print merriweather for local provider' => array( + 'setup' => array( + 'provider' => array( 'local' => $providers['local'] ), + 'provider_handles' => array( 'local' => $local_font_handles ), + 'registered' => $local_fonts, + 'enqueued' => array( 'merriweather' ), + ), + 'expected_done' => array( 'merriweather-200-900-normal' ), + 'expected_output' => sprintf( + "\n", + $font_faces['merriweather-200-900-normal'] + ), + ), + 'print Source Serif Pro for local provider' => array( + 'setup' => array( + 'provider' => array( 'local' => $providers['local'] ), + 'provider_handles' => array( 'local' => $local_font_handles ), + 'registered' => $local_fonts, + 'enqueued' => array( 'Source Serif Pro' ), + ), + 'expected_done' => array( 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic' ), + 'expected_output' => sprintf( + "\n", + $font_faces['Source Serif Pro-300-normal'], + $font_faces['Source Serif Pro-900-italic'] + ), + ), + 'print all fonts for local provider' => array( + 'setup' => array( + 'provider' => array( 'local' => $providers['local'] ), + 'provider_handles' => array( 'local' => $local_font_handles ), + 'registered' => $local_fonts, + 'enqueued' => $local_font_handles, + ), + 'expected_done' => array( 'merriweather-200-900-normal', 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic' ), + 'expected_output' => sprintf( + "\n", + $font_faces['merriweather-200-900-normal'], + $font_faces['Source Serif Pro-300-normal'], + $font_faces['Source Serif Pro-900-italic'] + ), + ), + + // All providers registered with multiple fonts. + + 'print font1 when all providers registered' => array( + 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'font1' ) ) ), + 'expected_done' => array( 'font1-300-normal', 'font1-300-italic', 'font1-900-normal' ), + 'expected_output' => sprintf( + '%s; %s; %s\n', + $font_faces['font1-300-normal'], + $font_faces['font1-300-italic'], + $font_faces['font1-900-normal'] + ), + ), + 'print all mock fonts when all providers registered' => array( + 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'font1', 'font2', 'font3' ) ) ), + 'expected_done' => $mock_font_handles, + 'expected_output' => sprintf( + '%s; %s; %s; %s; %s; %s\n', + $font_faces['font1-300-normal'], + $font_faces['font1-300-italic'], + $font_faces['font1-900-normal'], + $font_faces['font2-200-900-normal'], + $font_faces['font2-200-900-italic'], + $font_faces['font3-bold-normal'] + ), + ), + 'print merriweather when all providers registered' => array( + 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'merriweather' ) ) ), + 'expected_done' => array( 'merriweather-200-900-normal' ), + 'expected_output' => sprintf( + "\n", + $font_faces['merriweather-200-900-normal'] + ), + ), + 'print all local fonts when all providers registered' => array( + 'setup' => array_merge( $setup_all, array( 'enqueued' => $local_font_handles ) ), + 'expected_done' => array( 'merriweather-200-900-normal', 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic' ), + 'expected_output' => sprintf( + "\n", + $font_faces['merriweather-200-900-normal'], + $font_faces['Source Serif Pro-300-normal'], + $font_faces['Source Serif Pro-900-italic'] + ), + ), + + 'print all fonts for all providers' => array( + 'setup' => array_merge( $setup_all, array( 'enqueued' => $all_variation_handles ) ), + 'expected_done' => $all_variation_handles, + 'expected_output' => + sprintf( + "\n", + $font_faces['merriweather-200-900-normal'], + $font_faces['Source Serif Pro-300-normal'], + $font_faces['Source Serif Pro-900-italic'] + ) . + sprintf( + '%s; %s; %s; %s; %s; %s\n', + $font_faces['font1-300-normal'], + $font_faces['font1-300-italic'], + $font_faces['font1-900-normal'], + $font_faces['font2-200-900-normal'], + $font_faces['font2-200-900-italic'], + $font_faces['font3-bold-normal'] + ), + ), + + // Specific variations enqueued. + // Validates that only these specific variations print once. + + 'specific variation: 1 local' => array( + 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'merriweather-200-900-normal' ) ) ), + 'expected_done' => array( 'merriweather-200-900-normal' ), + 'expected_output' => sprintf( + "\n", + $font_faces['merriweather-200-900-normal'] + ), + ), + 'specific variation: 1 local from different font families' => array( + 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'merriweather-200-900-normal', 'Source Serif Pro-900-italic' ) ) ), + 'expected_done' => array( 'merriweather-200-900-normal', 'Source Serif Pro-900-italic' ), + 'expected_output' => sprintf( + "\n", + $font_faces['merriweather-200-900-normal'], + $font_faces['Source Serif Pro-900-italic'] + ), + ), + 'specific variation: 1 local and 1 mock' => array( + 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'merriweather-200-900-normal', 'font2-200-900-normal' ) ) ), + 'expected_done' => array( 'merriweather-200-900-normal', 'font2-200-900-normal' ), + 'expected_output' => sprintf( + "\n" . + '%s\n', + $font_faces['merriweather-200-900-normal'], + $font_faces['font2-200-900-normal'] + ), + ), + 'specific variation: 1 mock and 1 local' => array( + 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'font2-200-900-normal', 'Source Serif Pro-300-normal' ) ) ), + 'expected_done' => array( 'font2-200-900-normal', 'Source Serif Pro-300-normal' ), + 'expected_output' => sprintf( + "\n" . + '%s\n', + $font_faces['Source Serif Pro-300-normal'], + $font_faces['font2-200-900-normal'] + ), + ), + ); + } + protected function get_data_registry() { return array( 'lato' => array(), @@ -585,4 +798,184 @@ protected function get_data_registry() { ), ); } + + /** + * Gets the provider definitions. + * + * @since X.X.X + * + * @param string $provider_id Optional. Provider ID to get. Default empty string. + * @return array + */ + protected function get_provider_definitions( $provider_id = '' ) { + $providers = array( + 'mock' => array( + 'id' => 'mock', + 'class' => Mock_Provider::class, + ), + 'local' => array( + 'id' => 'local', + 'class' => WP_Webfonts_Provider_Local::class, + ), + ); + + if ( '' === $provider_id ) { + return $providers; + } + + if ( isset( $providers[ $provider_id ] ) ) { + return $providers[ $provider_id ]; + } + + return array( + 'id' => $provider_id, + 'class' => '', + ); + } + + /** + * Gets web font definitions for both local and mock providers. + * + * @since X.X.X + * + * @return array|string[][][] + */ + protected function get_registered_fonts() { + return array_merge( + $this->get_registered_local_fonts(), + $this->get_registered_mock_fonts() + ); + } + + /** + * Returns an array of font-face styles that matches the font definitions + * in get_registered_local_fonts() and get_registered_mock_fonts(). + * + * @since X.X.X + * + * @return string[] + */ + protected function get_registered_fonts_css() { + return array( + 'merriweather-200-900-normal' => << << << 'font1-300-normal', + 'font1-300-italic' => 'font1-300-italic', + 'font1-900-normal' => 'font1-900-normal', + 'font2-200-900-normal' => 'font2-200-900-normal', + 'font2-200-900-italic' => 'font2-200-900-italic', + 'font3-bold-normal' => 'font3-bold-normal', + ); + } + + /** + * Gets web font definitions for local provider. + * + * @since X.X.X + * + * @return string[][][] + */ + protected function get_registered_local_fonts() { + return array( + 'lato' => array(), + 'merriweather' => array( + 'merriweather-200-900-normal' => array( + 'provider' => 'local', + 'font-family' => 'Merriweather', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + ), + 'Source Serif Pro' => array( + 'Source Serif Pro-300-normal' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '300', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'Source Serif Pro-900-italic' => array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'italic', + 'font-weight' => '900', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + ); + } + + /** + * Gets web font definitions for mock provider. + * + * @since X.X.X + * + * @return string[][][] + */ + protected function get_registered_mock_fonts() { + return array( + 'font1' => array( + 'font1-300-normal' => array( + 'provider' => 'mock', + 'font-weight' => '300', + 'font-style' => 'normal', + 'font-display' => 'fallback', + ), + 'font1-300-italic' => array( + 'provider' => 'mock', + 'font-weight' => '300', + 'font-style' => 'italic', + 'font-display' => 'fallback', + ), + 'font1-900-normal' => array( + 'provider' => 'mock', + 'font-weight' => '900', + 'font-style' => 'normal', + 'font-display' => 'fallback', + ), + ), + 'font2' => array( + 'font2-200-900-normal' => array( + 'provider' => 'mock', + 'font-weight' => '200 900', + 'font-style' => 'normal', + 'font-display' => 'fallback', + ), + 'font2-200-900-italic' => array( + 'provider' => 'mock', + 'font-weight' => '200 900', + 'font-style' => 'italic', + 'font-display' => 'fallback', + ), + ), + 'font3' => array( + 'font3-bold-normal' => array( + 'provider' => 'mock', + 'font-weight' => 'bold', + 'font-style' => 'normal', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + ), + ), + ); + } } diff --git a/phpunit/webfonts/wpPrintWebfonts-test.php b/phpunit/webfonts/wpPrintWebfonts-test.php new file mode 100644 index 00000000000000..d10731c2fc4cf8 --- /dev/null +++ b/phpunit/webfonts/wpPrintWebfonts-test.php @@ -0,0 +1,126 @@ +assertSame( array(), wp_print_webfonts() ); + $this->assertNotInstanceOf( WP_Webfonts::class, $wp_webfonts ); + } + + /** + * Unit test to mock WP_Webfonts::do_items(). + * + * @dataProvider data_mocked_handles + * + * @param string|string[]|false $handles Handles to test. + * @param array|string[] $expected Expected array of processed handles. + */ + public function test_should_return_mocked_handles( $handles, $expected ) { + $mock = $this->set_up_mock( 'do_items' ); + $mock->expects( $this->once() ) + ->method( 'do_items' ) + ->with( + $this->identicalTo( $handles ) + ) + ->will( $this->returnValue( $expected ) ); + + wp_print_webfonts( $handles ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_mocked_handles() { + return array( + 'no handles' => array( + 'handles' => false, + 'expected' => array(), + ), + 'font family handles' => array( + 'handles' => array( 'my-custom-font' ), + 'expected' => array( 'my-custom-font' ), + ), + ); + } + + /** + * Integration test that registers providers and fonts and then enqueues before + * testing the printing functionality. + * + * @dataProvider data_print_enqueued + * + * @param array $setup Test set up information for provider, fonts, and enqueued. + * @param array $expected_done Expected array of printed handles. + * @param string $expected_output Expected printed output. + */ + public function test_should_print_enqueued( $setup, $expected_done, $expected_output ) { + $wp_webfonts = wp_webfonts(); + + // Set up test. + foreach ( $setup['provider'] as $provider ) { + $wp_webfonts->register_provider( $provider['id'], $provider['class'] ); + } + foreach ( $setup['registered'] as $font_family => $variations ) { + $wp_webfonts->add( $font_family, false ); + foreach ( $variations as $variation_handle => $variation ) { + $wp_webfonts->add_variation( $font_family, $variation, $variation_handle ); + } + } + $wp_webfonts->enqueue( $setup['enqueued'] ); + + $this->expectOutputString( $expected_output ); + $actual_done = $wp_webfonts->do_items(); + $this->assertSameSets( $expected_done, $actual_done, 'Printed handles should match' ); + } + + /** + * Integration test to validate printing given handles. Rather than mocking internal functionality, + * it registers providers and fonts but does not enqueue. + * + * @dataProvider data_print_enqueued + * + * @param array $setup Test set up information for provider, fonts, and enqueued. + * @param array $expected_done Expected array of printed handles. + * @param string $expected_output Expected printed output. + */ + public function test_should_print_handles_when_not_enqueued( $setup, $expected_done, $expected_output ) { + $wp_webfonts = wp_webfonts(); + + // Set up test. + foreach ( $setup['provider'] as $provider ) { + $wp_webfonts->register_provider( $provider['id'], $provider['class'] ); + } + foreach ( $setup['registered'] as $font_family => $variations ) { + $wp_webfonts->add( $font_family, false ); + foreach ( $variations as $variation_handle => $variation ) { + $wp_webfonts->add_variation( $font_family, $variation, $variation_handle ); + } + } + // Do not enqueue. Instead, pass the handles to wp_print_webfonts(). + $handles = $setup['enqueued']; + $this->assertEmpty( $wp_webfonts->queue, 'No fonts should be enqueued' ); + + $this->expectOutputString( $expected_output ); + $actual_done = wp_print_webfonts( $handles ); + $this->assertSameSets( $expected_done, $actual_done, 'Printed handles should match' ); + } +} diff --git a/phpunit/webfonts/wpWebfonts/doItem-test.php b/phpunit/webfonts/wpWebfonts/doItem-test.php new file mode 100644 index 00000000000000..e37590c6c01e2f --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/doItem-test.php @@ -0,0 +1,336 @@ +wp_webfonts = new WP_Webfonts; + } + + public function test_should_return_false_when_provider_not_registered() { + $this->assertFalse( $this->wp_webfonts->do_item( 'provider_not_registered' ) ); + } + + /** + * @dataProvider data_provider_definitions + * + * @param array $provider Provider to mock. + */ + public function test_should_return_false_when_no_fonts_enqueued_for_provider( array $provider ) { + $this->setup_provider_property_mock( $this->wp_webfonts, $provider ); + $this->assertFalse( $this->wp_webfonts->do_item( $provider['id'] ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_provider_definitions() { + $providers = $this->get_provider_definitions(); + + return array( + 'mock' => array( $providers['mock'] ), + 'local' => array( $providers['local'] ), + ); + } + + /** + * Test the test set up to ensure the `Tests_Webfonts_WpWebfonts_DoItem_::setup_provider_property_mock()` + * method works as expected. + */ + public function test_mocking_providers_property() { + $font_handles = array( 'font1', 'font2', 'font3' ); + $expected = array( + 'mock' => array( + 'class' => Mock_Provider::class, + 'fonts' => $font_handles, + ), + ); + + $this->setup_provider_property_mock( $this->wp_webfonts, $this->get_provider_definitions( 'mock' ), $font_handles ); + $actual = $this->property['WP_Webfonts::$providers']->getValue( $this->wp_webfonts ); + $this->assertSame( $expected, $actual ); + } + + /** + * Test the private method WP_Webfonts::get_enqueued_fonts_for_provider(). + * + * Why? This test validates the right fonts are returned for use within + * WP_Webfonts::do_item(). + * + * @dataProvider data_get_enqueued_fonts_for_provider + * + * @param array $font_handles Array of handles for the provider. + * @param array $to_do Handles to set for the WP_Webfonts::$to_do property. + * @param array $expected Expected result. + */ + public function test_get_enqueued_fonts_for_provider( $font_handles, $to_do, $expected ) { + // Set up the `to_do` property. + $this->wp_webfonts->to_do = $to_do; + + // Open the method's visibility for testing. + $get_enqueued_fonts_for_provider = $this->get_reflection_method( 'get_enqueued_fonts_for_provider' ); + + // Mock the WP_Webfonts::$property to set up the test. + $this->setup_provider_property_mock( $this->wp_webfonts, $this->get_provider_definitions( 'mock' ), $font_handles ); + + $actual = $get_enqueued_fonts_for_provider->invoke( $this->wp_webfonts, 'mock' ); + $this->assertSameSets( $expected, $actual ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_get_enqueued_fonts_for_provider() { + return array( + 'to_do queue is empty' => array( + 'font_handles ' => array( 'font1', 'font2', 'font3' ), + 'to_do' => array(), + 'expected' => array(), + ), + 'fonts not in to_do queue' => array( + 'font_handles ' => array( 'font1', 'font2', 'font3' ), + 'to_do' => array( 'font12', 'font13' ), + 'expected' => array(), + ), + '2 of the provider fonts in to_do queue' => array( + 'font_handles ' => array( 'font11', 'font12', 'font13' ), + 'to_do' => array( 'font11', 'font13' ), + 'expected' => array( 'font11', 'font13' ), + ), + 'do all of the provider fonts' => array( + 'font_handles ' => array( 'font21', 'font22', 'font23' ), + 'to_do' => array( 'font21', 'font22', 'font23' ), + 'expected' => array( 'font21', 'font22', 'font23' ), + ), + ); + } + + /** + * Test the private method WP_Webfonts::get_font_properties_for_provider(). + * + * Why? This test validates the right font properties are returned for use within + * WP_Webfonts::do_item(). + * + * @dataProvider data_get_font_properties_for_provider + * + * @param array $font_handles Web fonts for testing. + * @param array $expected Expected result. + */ + public function test_get_font_properties_for_provider( $font_handles, $expected ) { + // Set up the fonts for WP_Dependencies:get_data(). + $fonts = $this->get_registered_fonts(); + // Set all variations to 'mock' provider. + + // Mock the WP_Webfonts::$property to set up the test. + $this->setup_provider_property_mock( $this->wp_webfonts, $this->get_provider_definitions( 'mock' ), $font_handles ); + $this->setup_registration_mocks( $fonts, $this->wp_webfonts ); + + // Open the method's visibility for testing. + $method = $this->get_reflection_method( 'get_font_properties_for_provider' ); + + $actual = $method->invoke( $this->wp_webfonts, $font_handles ); + $this->assertSame( $expected, $actual ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_get_font_properties_for_provider() { + $fonts = $this->get_registered_fonts(); + + return array( + 'handles not registered' => array( + 'font_handles' => array( 'font-not-registered1', 'font-not-registered2', 'font-not-registered3' ), + 'expected' => array(), + ), + 'registered and non-registered handles' => array( + 'font_handles' => array( 'Source Serif Pro-300-normal', 'not-registered-handle', 'Source Serif Pro-900-italic' ), + 'expected' => array( + 'Source Serif Pro-300-normal' => $fonts['Source Serif Pro']['Source Serif Pro-300-normal'], + 'Source Serif Pro-900-italic' => $fonts['Source Serif Pro']['Source Serif Pro-900-italic'], + ), + ), + 'font-family handles, ie no "font-properties" extra data' => array( + 'font_handles' => array( 'font1', 'font2', 'merriweather' ), + 'expected' => array(), + ), + ); + } + + /** + * @dataProvider data_print_enqueued_fonts + * + * @param array $provider Define provider. + * @param array $fonts Fonts to register and enqueue. + * @param array $expected Expected results. + */ + public function test_should_trigger_provider_when_mocked( array $provider, array $fonts, array $expected ) { + $this->setup_print_deps( $provider, $fonts ); + + $provider_mock = $this->setup_object_mock( array( 'set_webfonts', 'print_styles' ), $provider['class'] ); + + // Test the provider's methods are invoked. + $provider_mock->expects( $this->once() )->method( 'set_webfonts' )->with( $this->identicalTo( $expected['set_webfonts'] ) ); + $provider_mock->expects( $this->once() )->method( 'print_styles' ); + + // Set up the WP_Webfonts::$provider_instances property. + $provider_instances = $this->get_reflection_property( 'provider_instances' ); + $provider_instances->setValue( $this->wp_webfonts, array( $provider['id'] => $provider_mock ) ); + + // Test the method successfully processes the provider. + $this->expectOutputString( '' ); + $this->assertTrue( $this->wp_webfonts->do_item( $provider['id'] ), 'WP_Webfonts::do_item() should return true' ); + } + + /** + * Integration test. + * + * @dataProvider data_print_enqueued_fonts + * + * @param array $provider Define provider. + * @param array $fonts Fonts to register and enqueue. + * @param array $expected Expected results. + */ + public function test_should_print( array $provider, array $fonts, array $expected ) { + $this->setup_print_deps( $provider, $fonts ); + + // Test the method successfully processes the provider. + $this->expectOutputString( $expected['printed_output'] ); + $this->assertTrue( $this->wp_webfonts->do_item( $provider['id'] ), 'WP_Webfonts::do_item() should return true' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_print_enqueued_fonts() { + $mock = $this->get_registered_mock_fonts(); + $local = $this->get_registered_local_fonts(); + $font_faces = $this->get_registered_fonts_css(); + + return array( + 'mock' => array( + 'provider' => $this->get_provider_definitions( 'mock' ), + 'fonts' => $mock, + 'expected' => array( + 'set_webfonts' => array_merge( $mock['font1'], $mock['font2'], $mock['font3'] ), + 'printed_output' => sprintf( + '%s; %s; %s; %s; %s; %s\n', + $font_faces['font1-300-normal'], + $font_faces['font1-300-italic'], + $font_faces['font1-900-normal'], + $font_faces['font2-200-900-normal'], + $font_faces['font2-200-900-italic'], + $font_faces['font3-bold-normal'] + ), + ), + ), + 'local' => array( + 'provider' => $this->get_provider_definitions( 'local' ), + 'fonts' => $local, + 'expected' => array( + 'set_webfonts' => array_merge( $local['merriweather'], $local['Source Serif Pro'] ), + 'printed_output' => sprintf( + "\n", + $font_faces['merriweather-200-900-normal'], + $font_faces['Source Serif Pro-300-normal'], + $font_faces['Source Serif Pro-900-italic'] + ), + ), + ), + ); + } + + /** + * Integration test. + * + * @dataProvider data_not_print_enqueued_fonts + * + * @param array $provider Define provider. + * @param array $fonts Fonts to register and enqueue. + * @param array $expected Not used. + * @param array $to_do_queue Value to set in the WP_Webfonts::$to_do queue. + */ + public function test_should_not_print_when_to_do_queue_empty( array $provider, array $fonts, $expected, $to_do_queue ) { + $this->setup_print_deps( $provider, $fonts, $to_do_queue ); + + // Test the method successfully processes the provider. + $this->expectOutputString( '' ); + $this->assertFalse( $this->wp_webfonts->do_item( $provider['id'] ), 'WP_Webfonts::do_item() should return false' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_not_print_enqueued_fonts() { + $mock = $this->get_registered_mock_fonts(); + $local = $this->get_registered_local_fonts(); + + return array( + 'mock provider when to_do queue is empty' => array( + 'provider' => $this->get_provider_definitions( 'mock' ), + 'fonts' => $mock, + 'expected' => array(), + 'to_do_queue' => array(), + ), + 'local provider when to_do queue is empty' => array( + 'provider' => $this->get_provider_definitions( 'local' ), + 'fonts' => $local, + 'expected' => array(), + 'to_do_queue' => array(), + ), + 'fonts not in to_do queue' => array( + 'provider' => $this->get_provider_definitions( 'mock' ), + 'fonts' => $mock, + 'expected' => array(), + 'to_do_queue' => array(), + ), + ); + } + + /** + * Sets up the print dependencies. + * + * @param array $provider Provider id and class. + * @param array $fonts Fonts to register and enqueue. + * @param array|null $to_do_queue Set the WP_Webfonts:$to_do queue. + */ + private function setup_print_deps( $provider, $fonts, $to_do_queue = null ) { + // Set up the fonts for WP_Dependencies:get_data(). + $mocks = $this->setup_registration_mocks( $fonts, $this->wp_webfonts ); + $handles = array_keys( $mocks ); + $this->setup_provider_property_mock( $this->wp_webfonts, $provider, $handles ); + + // Set up the `WP_Webfonts::$to_do` and `WP_Webfonts::$to_do_keyed_handles` properties. + if ( null === $to_do_queue ) { + $to_do_queue = $handles; + } + + $this->wp_webfonts->to_do = $to_do_queue; + $to_do_keyed_handles = $this->get_reflection_property( 'to_do_keyed_handles' ); + $to_do_keyed_handles->setValue( $this->wp_webfonts, array_flip( $to_do_queue ) ); + } +} diff --git a/phpunit/webfonts/wpWebfonts/doItems-test.php b/phpunit/webfonts/wpWebfonts/doItems-test.php new file mode 100644 index 00000000000000..517145615e3b6f --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/doItems-test.php @@ -0,0 +1,203 @@ +wp_webfonts = new WP_Webfonts; + } + + public function test_should_not_process_when_no_providers_registered() { + $this->setup_deps( array( 'enqueued' => 'font1' ) ); + + $done = $this->wp_webfonts->do_items(); + + $this->assertSame( array(), $done, 'WP_Webfonts::do_items() should return an empty array' ); + $this->assertSame( array(), $this->wp_webfonts->to_do, 'WP_Webfonts::$to_do should be an empty array' ); + } + + public function test_should_throw_notice_when_queue_is_empty() { + $this->expectNotice(); + $this->expectNoticeMessage( 'No web fonts are enqueued for printing' ); + + $this->wp_webfonts->do_items(); + } + + /** + * @dataProvider data_invalid_handles + * + * @param mixed $handles Handles to test. + */ + public function test_should_throw_notice_when_invalid_handles( $handles ) { + $this->expectNotice(); + $this->expectNoticeMessage( 'Handles must be a non-empty string or array of non-empty strings' ); + + $this->wp_webfonts->do_items( $handles ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_invalid_handles() { + return array( + 'null' => array( null ), + 'empty array' => array( array() ), + 'empty string' => array( '' ), + 'array of empty strings' => array( array( '', '' ) ), + 'array of mixed falsey values' => array( array( '', false, null, array() ) ), + ); + } + + public function test_should_throw_notice_when_provider_class_not_found() { + $this->expectNotice(); + $this->expectNoticeMessage( 'Class "Provider_Does_Not_Exist" not found for "doesnotexist" web font provider' ); + + $setup = array( + 'provider' => array( + 'doesnotexist' => array( + 'id' => 'doesnotexist', + 'class' => 'Provider_Does_Not_Exist', + ), + ), + 'provider_handles' => array( 'doesnotexist' => array( 'font1' ) ), + 'registered' => array( + 'doesnotexist' => array( + 'font1' => array( + 'font1-300-normal' => array( + 'provider' => 'doesnotexist', + 'font-weight' => '300', + 'font-style' => 'normal', + 'font-display' => 'fallback', + ), + ), + ), + ), + 'enqueued' => array( 'font1', 'font1-300-normal' ), + ); + $this->setup_deps( $setup ); + + $this->wp_webfonts->do_items(); + } + + /** + * @dataProvider data_print_enqueued + * + * @param array $setup Test set up information for provider, fonts, and enqueued. + * @param array $expected_done Expected array of printed handles. + * @param string $expected_output Expected printed output. + */ + public function test_should_print_mocked_enqueued( $setup, $expected_done, $expected_output ) { + $this->setup_deps( $setup ); + + $this->expectOutputString( $expected_output ); + $actual_done = $this->wp_webfonts->do_items(); + $this->assertSameSets( $expected_done, $actual_done, 'Printed handles should match' ); + } + + /** + * Integration test that registers providers and fonts and then enqueues before + * testing the printing funtionality. + * + * @dataProvider data_print_enqueued + * + * @param array $setup Test set up information for provider, fonts, and enqueued. + * @param array $expected_done Expected array of printed handles. + * @param string $expected_output Expected printed output. + */ + public function test_should_print_enqueued( $setup, $expected_done, $expected_output ) { + // Set up test. + foreach ( $setup['provider'] as $provider ) { + $this->wp_webfonts->register_provider( $provider['id'], $provider['class'] ); + } + foreach ( $setup['registered'] as $font_family => $variations ) { + $this->wp_webfonts->add( $font_family, false ); + foreach ( $variations as $variation_handle => $variation ) { + $this->wp_webfonts->add_variation( $font_family, $variation, $variation_handle ); + } + } + $this->wp_webfonts->enqueue( $setup['enqueued'] ); + + $this->expectOutputString( $expected_output ); + $actual_done = $this->wp_webfonts->do_items(); + $this->assertSameSets( $expected_done, $actual_done, 'Printed handles should match' ); + } + + /** + * Integration test to validate printing given handles. Rather than mocking internal functionality, + * it registers providers and fonts but does not enqueue. + * + * @dataProvider data_print_enqueued + * + * @param array $setup Test set up information for provider, fonts, and enqueued. + * @param array $expected_done Expected array of printed handles. + * @param string $expected_output Expected printed output. + */ + public function test_should_print_handles_when_not_enqueued( $setup, $expected_done, $expected_output ) { + // Set up test. + foreach ( $setup['provider'] as $provider ) { + $this->wp_webfonts->register_provider( $provider['id'], $provider['class'] ); + } + foreach ( $setup['registered'] as $font_family => $variations ) { + $this->wp_webfonts->add( $font_family, false ); + foreach ( $variations as $variation_handle => $variation ) { + $this->wp_webfonts->add_variation( $font_family, $variation, $variation_handle ); + } + } + // Do not enqueue. Instead pass the handles to WP_Webfonts::do_items(). + $handles = $setup['enqueued']; + $this->assertEmpty( $this->wp_webfonts->queue, 'No fonts should be enqueued' ); + + $this->expectOutputString( $expected_output ); + $actual_done = $this->wp_webfonts->do_items( $handles ); + $this->assertSameSets( $expected_done, $actual_done, 'Printed handles should match' ); + } + + /** + * Sets up the dependencies for the test. + * + * @param array $setup Dependencies to set up. + */ + private function setup_deps( array $setup ) { + $setup = array_merge( + array( + 'provider' => array(), + 'provider_handles' => array(), + 'registered' => array(), + 'enqueued' => array(), + ), + $setup + ); + + if ( ! empty( $setup['provider'] ) ) { + foreach ( $setup['provider'] as $provider_id => $provider ) { + $this->setup_provider_property_mock( $this->wp_webfonts, $provider, $setup['provider_handles'][ $provider_id ] ); + } + } + + if ( ! empty( $setup['registered'] ) ) { + $this->setup_registration_mocks( $setup['registered'], $this->wp_webfonts ); + } + + if ( ! empty( $setup['enqueued'] ) ) { + $queue = $this->get_reflection_property( 'queue' ); + $queue->setValue( $this->wp_webfonts, $setup['enqueued'] ); + } + } +} diff --git a/phpunit/webfonts/wpWebfontsProviderLocal-test.php b/phpunit/webfonts/wpWebfontsProviderLocal-test.php index 9b60283fce9642..462c3e0612fb8a 100644 --- a/phpunit/webfonts/wpWebfontsProviderLocal-test.php +++ b/phpunit/webfonts/wpWebfontsProviderLocal-test.php @@ -7,7 +7,7 @@ */ /** - * @group webfonts + * @group webfonts */ class Tests_Webfonts_WpWebfontsProviderLocal extends WP_UnitTestCase { private $provider; From 61725e1b8af514b618b38c4a63c44a5af989cf4f Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Tue, 23 Aug 2022 15:51:52 -0500 Subject: [PATCH 23/63] wp_register_webfont_provider() plus tests --- lib/experimental/class-wp-webfonts.php | 42 +++---- .../wpRegisterWebfontProvider-test.php | 96 +++++++++++++++ .../wpWebfonts/registerProvider-test.php | 116 ++++++++++++++++++ 3 files changed, 233 insertions(+), 21 deletions(-) create mode 100644 phpunit/webfonts/wpRegisterWebfontProvider-test.php create mode 100644 phpunit/webfonts/wpWebfonts/registerProvider-test.php diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 155dfc281a43b8..0d41a4e309cbf1 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -57,6 +57,27 @@ public function get_providers() { return $this->providers; } + /** + * Register a provider. + * + * @since X.X.X + * + * @param string $provider_id The provider's unique ID. + * @param string $class The provider class name. + * @return bool True if successfully registered, else false. + */ + public function register_provider( $provider_id, $class ) { + if ( empty( $provider_id ) || empty( $class ) || ! class_exists( $class ) ) { + return false; + } + + $this->providers[ $provider_id ] = array( + 'class' => $class, + 'fonts' => array(), + ); + return true; + } + /** * Get the list of all registered font families and their variations. * @@ -519,25 +540,4 @@ private function update_queues_for_printed_fonts( array $font_handles ) { ); } } - - /** - * Register a provider. - * - * @since 6.0.0 - * - * @param string $provider The provider name. - * @param string $class The provider class name. - * @return bool True if successfully registered, else false. - */ - public function register_provider( $provider, $class ) { - if ( empty( $provider ) || empty( $class ) || ! class_exists( $class ) ) { - return false; - } - - $this->providers[ $provider ] = array( - 'class' => $class, - 'fonts' => array(), - ); - return true; - } } diff --git a/phpunit/webfonts/wpRegisterWebfontProvider-test.php b/phpunit/webfonts/wpRegisterWebfontProvider-test.php new file mode 100644 index 00000000000000..8f1367d6dbb23d --- /dev/null +++ b/phpunit/webfonts/wpRegisterWebfontProvider-test.php @@ -0,0 +1,96 @@ +set_up_mock( 'register_provider' ); + $mock->expects( $this->once() ) + ->method( 'register_provider' ) + ->with( + $this->identicalTo( $provider_id ), + $this->identicalTo( $class ) + ) + ->will( $this->returnValue( true ) ); + + $this->assertTrue( wp_register_webfont_provider( $provider_id, $class ), 'wp_register_webfont_provider() should return true' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_register_providers() { + return array( + 'mock' => array( + 'provider_id' => 'mock', + 'class' => Mock_Provider::class, + ), + 'local' => array( + 'provider_id' => 'local', + 'class' => WP_Webfonts_Provider_Local::class, + ), + ); + } + + /** + * @dataProvider data_invalid_providers + * + * @param string $provider_id Provider ID. + * @param string $class Provider class name. + */ + public function test_should_not_register( $provider_id, $class ) { + $mock = $this->set_up_mock( 'register_provider' ); + $mock->expects( $this->once() ) + ->method( 'register_provider' ) + ->with( + $this->identicalTo( $provider_id ), + $this->identicalTo( $class ) + ) + ->will( $this->returnValue( false ) ); + + $this->assertFalse( wp_register_webfont_provider( $provider_id, $class ), 'wp_register_webfont_provider() should return false' ); + + } + + /** + * Data provider. + * + * @return array + */ + public function data_invalid_providers() { + return array( + 'provider_id is empty' => array( + 'provider_id' => '', + 'class' => Mock_Provider::class, + ), + 'class is empty' => array( + 'provider_id' => 'local', + 'class' => '', + ), + 'class does not exist' => array( + 'provider_id' => 'doesnotexist', + 'class' => 'Provider_Does_Not_Exist', + ), + ); + } +} diff --git a/phpunit/webfonts/wpWebfonts/registerProvider-test.php b/phpunit/webfonts/wpWebfonts/registerProvider-test.php new file mode 100644 index 00000000000000..9e1423cfdf53ae --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/registerProvider-test.php @@ -0,0 +1,116 @@ +assertTrue( $wp_webfonts->register_provider( $provider_id, $class ), 'WP_Webfonts::register_provider() should return true' ); + $this->assertSame( $expected, $wp_webfonts->get_providers(), 'Provider "' . $provider_id . '" should be registered in providers queue' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_register_providers() { + return array( + 'mock' => array( + 'provider_id' => 'mock', + 'class' => Mock_Provider::class, + 'expected' => array( + 'mock' => array( + 'class' => Mock_Provider::class, + 'fonts' => array(), + ), + ), + ), + 'local' => array( + 'provider_id' => 'local', + 'class' => WP_Webfonts_Provider_Local::class, + 'expected' => array( + 'local' => array( + 'class' => WP_Webfonts_Provider_Local::class, + 'fonts' => array(), + ), + ), + ), + ); + } + + public function test_should_register_mutliple_providers() { + $wp_webfonts = new WP_Webfonts(); + $providers = $this->get_provider_definitions(); + foreach ( $providers as $provider ) { + $this->assertTrue( $wp_webfonts->register_provider( $provider['id'], $provider['class'] ), 'WP_Webfonts::register_provider() should return true for provider ' . $provider['id'] ); + } + + $expected = array( + 'mock' => array( + 'class' => $providers['mock']['class'], + 'fonts' => array(), + ), + 'local' => array( + 'class' => $providers['local']['class'], + 'fonts' => array(), + ), + ); + + $this->assertSame( $expected, $wp_webfonts->get_providers(), 'Both local and mock providers should be registered' ); + } + + /** + * @dataProvider data_invalid_providers + * + * @param string $provider_id Provider ID. + * @param string $class Provider class name. + */ + public function test_should_not_register( $provider_id, $class ) { + $wp_webfonts = new WP_Webfonts(); + + $this->assertFalse( $wp_webfonts->register_provider( $provider_id, $class ), 'WP_Webfonts::register_provider() should return false' ); + $this->assertArrayNotHasKey( $provider_id, $wp_webfonts->get_providers(), 'Both local and mock providers should be registered' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_invalid_providers() { + return array( + 'provider_id is empty' => array( + 'provider_id' => '', + 'class' => Mock_Provider::class, + ), + 'class is empty' => array( + 'provider_id' => 'local', + 'class' => '', + ), + 'class does not exist' => array( + 'provider_id' => 'doesnotexist', + 'class' => 'Provider_Does_Not_Exist', + ), + ); + } +} From 1a83fc4d2fea99ceeec32179f3e8d50de670e688 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Tue, 23 Aug 2022 15:54:01 -0500 Subject: [PATCH 24/63] Add file and class docs to WP_Webfonts --- lib/experimental/class-wp-webfonts.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 0d41a4e309cbf1..8191f260b74453 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -1,5 +1,21 @@ Date: Tue, 23 Aug 2022 15:57:00 -0500 Subject: [PATCH 25/63] Deletes old WP_Webfonts file --- lib/experimental/class-old-wp-webfonts.php | 397 --------------------- 1 file changed, 397 deletions(-) delete mode 100644 lib/experimental/class-old-wp-webfonts.php diff --git a/lib/experimental/class-old-wp-webfonts.php b/lib/experimental/class-old-wp-webfonts.php deleted file mode 100644 index 4c66383765db9f..00000000000000 --- a/lib/experimental/class-old-wp-webfonts.php +++ /dev/null @@ -1,397 +0,0 @@ -register_provider( 'local', 'WP_Webfonts_Provider_Local' ); - - // Register callback to generate and enqueue styles. - if ( did_action( 'wp_enqueue_scripts' ) ) { - $this->stylesheet_handle = 'webfonts-footer'; - $hook = 'wp_print_footer_scripts'; - } else { - $this->stylesheet_handle = 'webfonts'; - $hook = 'wp_enqueue_scripts'; - } - add_action( $hook, array( $this, 'generate_and_enqueue_styles' ) ); - - // Enqueue webfonts in the block editor. - add_action( 'admin_init', array( $this, 'generate_and_enqueue_editor_styles' ) ); - } - - /** - * Get the list of all fonts. - * - * @return array[] - */ - public function get_all_webfonts() { - return array_merge( $this->get_registered_webfonts(), $this->get_enqueued_webfonts() ); - } - - /** - * Get the list of providers. - * - * @since 6.0.0 - * - * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. - */ - public function get_providers() { - return $this->providers; - } - - /** - * Register a webfont. - * - * @since 6.0.0 - * - * @param array $webfont Webfont to be registered. - * @return string|false The font family slug if successfully registered, else false. - */ - public function register_webfont( array $webfont ) { - $webfont = $this->validate_webfont( $webfont ); - - // If not valid, bail out. - if ( ! $webfont ) { - return false; - } - - $slug = $this->get_font_slug( $webfont ); - - // Initialize a new font-family collection. - if ( ! isset( $this->registered_webfonts[ $slug ] ) ) { - $this->registered_webfonts[ $slug ] = array(); - } - - $this->registered_webfonts[ $slug ][] = $webfont; - return $slug; - } - - /** - * Enqueue a font-family that has been already registered. - * - * @param string $font_family_name The font family name to be enqueued. - * @return bool True if successfully enqueued, else false. - */ - public function enqueue_webfont( $font_family_name ) { - $slug = $this->get_font_slug( $font_family_name ); - - if ( isset( $this->enqueued_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' ); - - return false; - } - - $this->enqueued_webfonts[ $slug ] = $this->registered_webfonts[ $slug ]; - unset( $this->registered_webfonts[ $slug ] ); - return true; - } - - /** - * Get the font slug. - * - * @since 6.0.0 - * - * @param array|string $to_convert The value to convert into a slug. Expected as the web font's array - * or a font-family as a string. - * @return string|false The font slug on success, or false if the font-family cannot be determined. - */ - public static function get_font_slug( $to_convert ) { - if ( is_array( $to_convert ) ) { - if ( isset( $to_convert['font-family'] ) ) { - $to_convert = $to_convert['font-family']; - } elseif ( isset( $to_convert['fontFamily'] ) ) { - $to_convert = $to_convert['fontFamily']; - } else { - _doing_it_wrong( __METHOD__, __( 'Could not determine the font family name.', 'gutenberg' ), '6.0.0' ); - return false; - } - } - - return sanitize_title( $to_convert ); - } - - /** - * Validate a webfont. - * - * @since 6.0.0 - * - * @param array $webfont The webfont arguments. - * - * @return array|false The validated webfont arguments, or false if the webfont is invalid. - */ - public function validate_webfont( $webfont ) { - $webfont = wp_parse_args( - $webfont, - array( - 'provider' => 'local', - 'font-family' => '', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ) - ); - - // Check the font-family. - if ( empty( $webfont['font-family'] ) || ! is_string( $webfont['font-family'] ) ) { - trigger_error( __( 'Webfont font family must be a non-empty string.', 'gutenberg' ) ); - return false; - } - - // Local fonts need a "src". - if ( 'local' === $webfont['provider'] ) { - // Make sure that local fonts have 'src' defined. - if ( empty( $webfont['src'] ) || ( ! is_string( $webfont['src'] ) && ! is_array( $webfont['src'] ) ) ) { - trigger_error( __( 'Webfont src must be a non-empty string or an array of strings.', 'gutenberg' ) ); - return false; - } - } - - // Validate the 'src' property. - if ( ! empty( $webfont['src'] ) ) { - foreach ( (array) $webfont['src'] as $src ) { - if ( empty( $src ) || ! is_string( $src ) ) { - trigger_error( __( 'Each webfont src must be a non-empty string.', 'gutenberg' ) ); - return false; - } - } - } - - // Check the font-weight. - if ( ! is_string( $webfont['font-weight'] ) && ! is_int( $webfont['font-weight'] ) ) { - trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.', 'gutenberg' ) ); - return false; - } - - // Check the font-display. - if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'swap' ), true ) ) { - $webfont['font-display'] = 'fallback'; - } - - $valid_props = array( - 'ascend-override', - 'descend-override', - 'font-display', - 'font-family', - 'font-stretch', - 'font-style', - 'font-weight', - 'font-variant', - 'font-feature-settings', - 'font-variation-settings', - 'line-gap-override', - 'size-adjust', - 'src', - 'unicode-range', - - // Exceptions. - 'provider', - ); - - foreach ( $webfont as $prop => $value ) { - if ( ! in_array( $prop, $valid_props, true ) ) { - unset( $webfont[ $prop ] ); - } - } - - return $webfont; - } - - /** - * Register a provider. - * - * @since 6.0.0 - * - * @param string $provider The provider name. - * @param string $class The provider class name. - * @return bool True if successfully registered, else false. - */ - public function register_provider( $provider, $class ) { - if ( empty( $provider ) || empty( $class ) ) { - return false; - } - $this->providers[ $provider ] = $class; - return true; - } - - /** - * Generate and enqueue webfonts styles. - * - * @since 6.0.0 - */ - public function generate_and_enqueue_styles() { - // Generate the styles. - $webfonts = $this->get_webfonts_by_provider( $this->get_enqueued_webfonts() ); - $styles = $this->generate_styles( $webfonts ); - - // Bail out if there are no styles to enqueue. - if ( '' === $styles ) { - return; - } - - // Enqueue the stylesheet. - wp_register_style( $this->stylesheet_handle, '' ); - wp_enqueue_style( $this->stylesheet_handle ); - - // Add the styles to the stylesheet. - wp_add_inline_style( $this->stylesheet_handle, $styles ); - } - - /** - * Generate and enqueue editor styles. - * - * @since 6.0.0 - */ - public function generate_and_enqueue_editor_styles() { - // Generate the styles. - $webfonts = $this->get_webfonts_by_provider( $this->get_all_webfonts() ); - $styles = $this->generate_styles( $webfonts ); - - // Bail out if there are no styles to enqueue. - if ( '' === $styles ) { - return; - } - - wp_enqueue_style( 'wp-block-library' ); - wp_add_inline_style( 'wp-block-library', $styles ); - } - - /** - * Generate styles for webfonts. - * - * @since 6.0.0 - * - * @param array[] $webfonts_by_provider Webfonts organized by provider. - * @return string $styles Generated styles. - */ - private function generate_styles( array $webfonts_by_provider ) { - $styles = ''; - $providers = $this->get_providers(); - - /* - * Loop through each of the providers to get the CSS for their respective webfonts - * to incrementally generate the collective styles for all of them. - */ - foreach ( $providers as $provider_id => $provider_class ) { - - // 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 ) ); - continue; - } - - $provider_webfonts = isset( $webfonts_by_provider[ $provider_id ] ) - ? $webfonts_by_provider[ $provider_id ] - : array(); - - // If there are no registered webfonts for this provider, skip it. - if ( empty( $provider_webfonts ) ) { - continue; - } - - /* - * Process the webfonts by first passing them to the provider via `set_webfonts()` - * and then getting the CSS from the provider. - */ - $provider = new $provider_class(); - $provider->set_webfonts( $provider_webfonts ); - $styles .= $provider->get_css(); - } - - return $styles; - } - - - /** - * Reorganizes webfonts grouped by font-family into grouped by provider. - * - * @param array[] $font_families Font families and each of their webfonts. - * @return array[] Webfonts organized by providers. - */ - private function get_webfonts_by_provider( array $font_families ) { - $providers = $this->get_providers(); - $webfonts_by_provider = array(); - - foreach ( $font_families as $webfonts ) { - foreach ( $webfonts as $webfont ) { - $provider = $webfont['provider']; - - // 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 ) ); - continue; - } - - // Initialize a new provider collection. - if ( ! isset( $webfonts_by_provider[ $provider ] ) ) { - $webfonts_by_provider[ $provider ] = array(); - } - $webfonts_by_provider[ $provider ][] = $webfont; - } - } - - return $webfonts_by_provider; - } -} From 3ac8feae282baa45ba61491a13f9f99f35ec616d Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 24 Aug 2022 08:52:24 -0500 Subject: [PATCH 26/63] More tests for wp_deregister_webfont_variation() --- .../webfonts/wp-webfonts-tests-dataset.php | 36 +++ .../wpDeregisterWebfontVariation-test.php | 261 +++++++++++++++--- .../wpWebfonts/removeVariation-test.php | 240 +++++++++++++++- 3 files changed, 494 insertions(+), 43 deletions(-) diff --git a/phpunit/webfonts/wp-webfonts-tests-dataset.php b/phpunit/webfonts/wp-webfonts-tests-dataset.php index 730a719ce736fd..c28162f877e95f 100644 --- a/phpunit/webfonts/wp-webfonts-tests-dataset.php +++ b/phpunit/webfonts/wp-webfonts-tests-dataset.php @@ -473,6 +473,42 @@ public function data_get_providers() { ); } + /** + * Data provider for testing removal of variations. + * + * @return array + */ + public function data_remove_variations() { + return array( + 'Font with 1 variation' => array( + 'font_family' => 'merriweather', + 'variation_handle' => 'merriweather-200-900-normal', + 'expected' => array( + 'registered' => array( + 'merriweather', + 'Source Serif Pro', + 'Source Serif Pro-300-normal', + 'Source Serif Pro-900-italic', + ), + 'font_family_deps' => array(), + ), + ), + 'Font with multiple variations' => array( + 'font_family' => 'Source Serif Pro', + 'variation_handle' => 'Source Serif Pro-300-normal', + 'expected' => array( + 'registered' => array( + 'merriweather', + 'merriweather-200-900-normal', + 'Source Serif Pro', + 'Source Serif Pro-900-italic', + ), + 'font_family_deps' => array( 'Source Serif Pro-900-italic' ), + ), + ), + ); + } + /** * Data provider. * diff --git a/phpunit/webfonts/wpDeregisterWebfontVariation-test.php b/phpunit/webfonts/wpDeregisterWebfontVariation-test.php index d2dcfec7760465..14107dcdcb74f8 100644 --- a/phpunit/webfonts/wpDeregisterWebfontVariation-test.php +++ b/phpunit/webfonts/wpDeregisterWebfontVariation-test.php @@ -10,15 +10,58 @@ /** * @group webfonts + * @group remove_webfonts * @covers ::wp_deregister_webfont_variation * @covers WP_Webfonts::remove_variation */ class Tests_Webfonts_WpDeregisterWebfontVariation extends WP_Webfonts_TestCase { + private $wp_webfonts; + private $fonts_to_register = array(); + + public function set_up() { + parent::set_up(); + $this->wp_webfonts = wp_webfonts(); + $this->fonts_to_register = $this->get_registered_local_fonts(); + } + + /** + * Sets up the unit test by mocking the WP_Dependencies object using stdClass and + * registering each font family directly to the WP_Webfonts::$registered property + * and its variations to the mocked $deps property. + */ + private function setup_unit_test() { + $this->setup_registration_mocks( $this->fonts_to_register, $this->wp_webfonts ); + } + + /** + * Sets up the integration test by properly registering each font family and its variations + * by using the WP_Webfonts::add() and WP_Webfonts::add_variation() methods. + */ + private function setup_integration_test() { + foreach ( $this->fonts_to_register as $font_family_handle => $variations ) { + $this->setup_register( $font_family_handle, $variations, $this->wp_webfonts ); + } + } + + /** + * Testing the test setup to ensure it works. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + */ + public function test_mocked_setup( $font_family_handle, $variation_handle ) { + $this->setup_unit_test(); + + $this->assertArrayHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variation should be in the registered queue before remval' ); + $this->assertContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should be in its font family deps before removal' ); + } /** * Unit test for deregistering a font-family's variation using mock of WP_Webfonts. * - * @dataProvider data_font_family_and_variation_handle + * @dataProvider data_remove_variations * * @param string $font_family_handle Font family to test. * @param string $variation_handle Variation's handle to test. @@ -35,63 +78,199 @@ public function test_should_deregister_when_mocked( $font_family_handle, $variat } /** - * Integration test for enqueuing before registering a font family and all of its variations. + * Unit test. * - * @dataProvider data_font_family_and_variation_handle + * @dataProvider data_remove_variations * - * @param string $font_family_handle Font family to test. - * @param string $variation_handle Variation's handle to test. + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + */ + public function test_unit_should_do_nothing_when_variation_and_font_family_not_registered( $font_family_handle, $variation_handle ) { + // Set up the test. + unset( $this->fonts_to_register[ $font_family_handle ] ); + $this->setup_unit_test(); + $registered_queue = $this->wp_webfonts->registered; + + // Run the tests. + wp_deregister_webfont_variation( $font_family_handle, $variation_handle ); + $this->assertArrayNotHasKey( $font_family_handle, $this->wp_webfonts->registered, 'Font family should not be registered' ); + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variant should not be registered' ); + $this->assertSame( $registered_queue, $this->wp_webfonts->registered, 'Registered queue should not have changed' ); + } + + /** + * Integration test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. */ - public function test_should_do_nothing_when_not_registered( $font_family_handle, $variation_handle ) { + public function test_should_do_nothing_when_variation_and_font_family_not_registered( $font_family_handle, $variation_handle ) { + // Set up the test. + unset( $this->fonts_to_register[ $font_family_handle ] ); + $this->setup_integration_test(); + $registered_queue = $this->wp_webfonts->get_registered(); + + // Run the tests. wp_deregister_webfont_variation( $font_family_handle, $variation_handle ); + $this->assertArrayNotHasKey( $font_family_handle, $this->wp_webfonts->registered, 'Font family should not be registered' ); + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variant should not be registered' ); + $this->assertSameSets( $registered_queue, $this->wp_webfonts->get_registered(), 'Registered queue should not have changed' ); + } - $this->assertIsArray( $this->get_registered(), 'Registration queue should be an array' ); - $this->assertEmpty( $this->get_registered(), 'Registration queue should be empty after deregistering' ); + /** + * Unit test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. + */ + public function test_unit_should_only_remove_from_font_family_deps_when_variation_not_in_queue( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_unit_test(); + $this->setup_remove_variation_from_registered( $variation_handle ); + + // Run the tests. + wp_deregister_webfont_variation( $font_family_handle, $variation_handle ); + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variant should not be registered' ); + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); } /** - * Data provider. + * Integration test. + * + * @dataProvider data_remove_variations * - * @return array + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. */ - public function data_font_family_and_variation_handle() { - return array( - 'single words name' => array( - 'font_family' => 'Lato', - 'variation_handle' => 'Lato 400 normal', - ), - 'multiple words name' => array( - 'font_family' => 'Source Sans Pro', - 'expected_handle' => 'Source Sans Pro 400 normal', - ), - 'handles' => array( - 'font_family' => 'source-serif-pro', - 'expected_handle' => 'source-serif-pro-400-normal', - ), - ); + public function test_should_only_remove_from_font_family_deps_when_variation_not_in_queue( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_integration_test(); + $this->setup_remove_variation_from_registered( $variation_handle ); + + // Run the tests. + wp_deregister_webfont_variation( $font_family_handle, $variation_handle ); + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variant should not be registered' ); + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); } /** - * Integration test for deregistering a font family and all of its variations. + * Unit test. * - * @dataProvider data_one_to_many_font_families_and_zero_to_many_variations + * @dataProvider data_remove_variations * - * @param string $font_family Font family to test. - * @param array $inputs Font family(ies) and variations to pre-register. - * @param array $registered_handles Expected handles after registering. - * @param array $expected Array of expected handles. + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. */ - public function test_deregister_after_registration( $font_family, array $inputs, array $registered_handles, array $expected ) { - foreach ( $inputs as $handle => $variations ) { - $this->setup_register( $handle, $variations ); - } - // Test the before state, just to make sure. - $this->assertSame( $registered_handles, $this->get_registered_handles(), 'Font family and variations should be registered before deregistering' ); + public function test_unit_should_remove_variation_from_registered_queue_though_font_family_not_registered( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_unit_test(); + $this->setup_remove_from_font_family_deps( $font_family_handle, $variation_handle ); - wp_deregister_font_family( $font_family ); + $this->assertArrayNotHasKey( $variation_handle, array_flip( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Variation should not be in its font family deps before removal' ); + + wp_deregister_webfont_variation( $font_family_handle, $variation_handle ); - // Test after deregistering. - $this->assertIsArray( $this->get_registered_handles(), 'Registration queue should be an array' ); - $this->assertSame( $expected, $this->get_registered_handles(), 'Registration queue should match after deregistering' ); + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); + } + + /** + * Integration test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. + */ + public function test_should_remove_variation_from_registered_queue_though_font_family_not_registered( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_integration_test(); + $this->setup_remove_from_font_family_deps( $font_family_handle, $variation_handle ); + + $this->assertArrayNotHasKey( $variation_handle, array_flip( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Variation should not be in its font family deps before removal' ); + + wp_deregister_webfont_variation( $font_family_handle, $variation_handle ); + + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); + } + + /** + * Unit test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. + */ + public function test_unit_should_remove_variation_from_queue_and_font_family_deps( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_unit_test(); + + $this->assertArrayHasKey( $variation_handle, array_flip( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Variation should be in its font family deps before removal' ); + + wp_deregister_webfont_variation( $font_family_handle, $variation_handle ); + + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variation should be not be in registered queue' ); + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); + } + + /** + * Integration test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. + */ + public function test_should_remove_variation_from_queue_and_font_family_deps( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_integration_test(); + + $this->assertArrayHasKey( $variation_handle, array_flip( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Variation should be in its font family deps before removal' ); + + wp_deregister_webfont_variation( $font_family_handle, $variation_handle ); + + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variation should be not be in registered queue' ); + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); + } + + /** + * Remove the variation handle from the font family's deps. + * + * @param string $font_family_handle Font family. + * @param string $variation_handle The variation handle to remove. + */ + private function setup_remove_from_font_family_deps( $font_family_handle, $variation_handle ) { + foreach ( $this->wp_webfonts->registered[ $font_family_handle ]->deps as $index => $vhandle ) { + if ( $variation_handle !== $vhandle ) { + continue; + } + unset( $this->wp_webfonts->registered[ $font_family_handle ]->deps[ $index ] ); + break; + } + } + + /** + * Removes the variation from the WP_Webfonts::$registered queue. + * + * @param string $variation_handle The variation handle to remove. + */ + private function setup_remove_variation_from_registered( $variation_handle ) { + unset( $this->wp_webfonts->registered[ $variation_handle ] ); } } diff --git a/phpunit/webfonts/wpWebfonts/removeVariation-test.php b/phpunit/webfonts/wpWebfonts/removeVariation-test.php index f774dedb74e7f6..f82dbf0f4576af 100644 --- a/phpunit/webfonts/wpWebfonts/removeVariation-test.php +++ b/phpunit/webfonts/wpWebfonts/removeVariation-test.php @@ -10,11 +10,247 @@ /** * @group webfonts + * @group remove_webfonts * @covers WP_Webfonts::remove_variation */ class Tests_Webfonts_WpWebfonts_RemoveVariation extends WP_Webfonts_TestCase { + private $wp_webfonts; + private $fonts_to_register = array(); - public function test_remove_variation() { - // TODO: Add tests for WP_Webfonts::remove_variation(). + public function set_up() { + parent::set_up(); + $this->wp_webfonts = new WP_Webfonts(); + $this->fonts_to_register = $this->get_registered_local_fonts(); + } + + /** + * Sets up the unit test by mocking the WP_Dependencies object using stdClass and + * registering each font family directly to the WP_Webfonts::$registered property + * and its variations to the mocked $deps property. + */ + private function setup_unit_test() { + $this->setup_registration_mocks( $this->fonts_to_register, $this->wp_webfonts ); + } + + /** + * Sets up the integration test by properly registering each font family and its variations + * by using the WP_Webfonts::add() and WP_Webfonts::add_variation() methods. + */ + private function setup_integration_test() { + foreach ( $this->fonts_to_register as $font_family_handle => $variations ) { + $this->setup_register( $font_family_handle, $variations, $this->wp_webfonts ); + } + } + + /** + * Testing the test setup to ensure it works. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + */ + public function test_mocked_setup( $font_family_handle, $variation_handle ) { + $this->setup_unit_test(); + + $this->assertArrayHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variation should be in the registered queue before remval' ); + $this->assertContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should be in its font family deps before removal' ); + } + + /** + * Unit test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + */ + public function test_unit_should_do_nothing_when_variation_and_font_family_not_registered( $font_family_handle, $variation_handle ) { + // Set up the test. + unset( $this->fonts_to_register[ $font_family_handle ] ); + $this->setup_unit_test(); + $registered_queue = $this->wp_webfonts->registered; + + // Run the tests. + $this->wp_webfonts->remove_variation( $font_family_handle, $variation_handle ); + $this->assertArrayNotHasKey( $font_family_handle, $this->wp_webfonts->registered, 'Font family should not be registered' ); + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variant should not be registered' ); + $this->assertSame( $registered_queue, $this->wp_webfonts->registered, 'Registered queue should not have changed' ); + } + + /** + * Integration test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + */ + public function test_should_do_nothing_when_variation_and_font_family_not_registered( $font_family_handle, $variation_handle ) { + // Set up the test. + unset( $this->fonts_to_register[ $font_family_handle ] ); + $this->setup_integration_test(); + $registered_queue = $this->wp_webfonts->get_registered(); + + // Run the tests. + $this->wp_webfonts->remove_variation( $font_family_handle, $variation_handle ); + $this->assertArrayNotHasKey( $font_family_handle, $this->wp_webfonts->registered, 'Font family should not be registered' ); + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variant should not be registered' ); + $this->assertSameSets( $registered_queue, $this->wp_webfonts->get_registered(), 'Registered queue should not have changed' ); + } + + /** + * Unit test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. + */ + public function test_unit_should_only_remove_from_font_family_deps_when_variation_not_in_queue( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_unit_test(); + $this->setup_remove_variation_from_registered( $variation_handle ); + + // Run the tests. + $this->wp_webfonts->remove_variation( $font_family_handle, $variation_handle ); + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variant should not be registered' ); + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); + } + + /** + * Integration test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. + */ + public function test_should_only_remove_from_font_family_deps_when_variation_not_in_queue( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_integration_test(); + $this->setup_remove_variation_from_registered( $variation_handle ); + + // Run the tests. + $this->wp_webfonts->remove_variation( $font_family_handle, $variation_handle ); + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variant should not be registered' ); + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); + } + + /** + * Unit test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. + */ + public function test_unit_should_remove_variation_from_registered_queue_though_font_family_not_registered( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_unit_test(); + $this->setup_remove_from_font_family_deps( $font_family_handle, $variation_handle ); + + $this->assertArrayNotHasKey( $variation_handle, array_flip( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Variation should not be in its font family deps before removal' ); + + $this->wp_webfonts->remove_variation( $font_family_handle, $variation_handle ); + + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); + } + + /** + * Integration test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. + */ + public function test_should_remove_variation_from_registered_queue_though_font_family_not_registered( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_integration_test(); + $this->setup_remove_from_font_family_deps( $font_family_handle, $variation_handle ); + + $this->assertArrayNotHasKey( $variation_handle, array_flip( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Variation should not be in its font family deps before removal' ); + + $this->wp_webfonts->remove_variation( $font_family_handle, $variation_handle ); + + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); + } + + /** + * Unit test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. + */ + public function test_unit_should_remove_variation_from_queue_and_font_family_deps( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_unit_test(); + + $this->assertArrayHasKey( $variation_handle, array_flip( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Variation should be in its font family deps before removal' ); + + $this->wp_webfonts->remove_variation( $font_family_handle, $variation_handle ); + + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variation should be not be in registered queue' ); + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); + } + + /** + * Integration test. + * + * @dataProvider data_remove_variations + * + * @param string $font_family_handle Font family for the variation. + * @param string $variation_handle Variation handle to remove. + * @param array $expected Expected results. + */ + public function test_should_remove_variation_from_queue_and_font_family_deps( $font_family_handle, $variation_handle, $expected ) { + // Set up the test. + $this->setup_integration_test(); + + $this->assertArrayHasKey( $variation_handle, array_flip( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Variation should be in its font family deps before removal' ); + + $this->wp_webfonts->remove_variation( $font_family_handle, $variation_handle ); + + $this->assertArrayNotHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variation should be not be in registered queue' ); + $this->assertNotContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should not be its font family deps' ); + $this->assertSameSets( $expected['font_family_deps'], array_values( $this->wp_webfonts->registered[ $font_family_handle ]->deps ), 'Only the tested variation handle should be removed from font family deps' ); + } + + /** + * Remove the variation handle from the font family's deps. + * + * @param string $font_family_handle Font family. + * @param string $variation_handle The variation handle to remove. + */ + private function setup_remove_from_font_family_deps( $font_family_handle, $variation_handle ) { + foreach ( $this->wp_webfonts->registered[ $font_family_handle ]->deps as $index => $vhandle ) { + if ( $variation_handle !== $vhandle ) { + continue; + } + unset( $this->wp_webfonts->registered[ $font_family_handle ]->deps[ $index ] ); + break; + } + } + + /** + * Removes the variation from the WP_Webfonts::$registered queue. + * + * @param string $variation_handle The variation handle to remove. + */ + private function setup_remove_variation_from_registered( $variation_handle ) { + unset( $this->wp_webfonts->registered[ $variation_handle ] ); } } From e575e31ad0421144e2956e2fe3027ce07e192e14 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Tue, 30 Aug 2022 15:29:11 -0500 Subject: [PATCH 27/63] Adds temporary deprecated functionality. Provides extenders deprecation notices to alert where to update their plugins/themes before the API is backported to Core. --- lib/experimental/class-wp-webfonts.php | 159 ++++++++++++ lib/experimental/webfonts.php | 91 +++++-- phpunit/webfonts/wp-webfonts-testcase.php | 23 ++ phpunit/webfonts/wpRegisterWebfont-test.php | 60 +++-- phpunit/webfonts/wpRegisterWebfonts-test.php | 242 ++++++++++++++++--- 5 files changed, 511 insertions(+), 64 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 8191f260b74453..1dbad9286e1343 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -556,4 +556,163 @@ private function update_queues_for_printed_fonts( array $font_handles ) { ); } } + + /** + * Gets the font slug. + * + * BACKPORT NOTE: Do not backport this method. + * + * @since X.X.X + * @deprecated Use WP_Webfonts_Utils::convert_font_family_into_handle() or WP_Webfonts_Utils::get_font_family_from_variation(). + * + * @param array|string $to_convert The value to convert into a slug. Expected as the web font's array + * or a font-family as a string. + * @return string|false The font slug on success, or false if the font-family cannot be determined. + */ + public static function get_font_slug( $to_convert ) { + _deprecated_function( + __METHOD__, + '6.1.0', + 'Use WP_Webfonts_Utils::get_font_family_from_variation() to get the font family from an array and WP_Webfonts_Utils::convert_font_family_into_handle() to get the handle' + ); + + if ( is_array( $to_convert ) ) { + if ( isset( $to_convert['font-family'] ) ) { + $to_convert = $to_convert['font-family']; + } elseif ( isset( $to_convert['fontFamily'] ) ) { + $to_convert = $to_convert['fontFamily']; + } else { + _doing_it_wrong( __METHOD__, __( 'Could not determine the font family name.', 'gutenberg' ), '6.0.0' ); + return false; + } + } + + return sanitize_title( $to_convert ); + } + + /** + * Initializes the API. + * + * BACKPORT NOTE: Do not backport this method. + * + * @since 6.0.0 + * @deprecated 6.1.0 Use wp_webfonts(). + */ + public static function init() { + _deprecated_function( __METHOD__, '6.1.0', 'wp_webfonts()' ); + } + + /** + * Gets the list of registered fonts. + * + * BACKPORT NOTE: Do not backport this method. + * + * @since 6.0.0 + * @deprecated 6.1.0 Use wp_webfonts()->get_registered(). + * + * @return array[] + */ + public function get_registered_webfonts() { + _deprecated_function( __METHOD__, '6.1.0', 'wp_webfonts()->get_registered()' ); + + return $this->registered; + } + + /** + * Gets the list of enqueued fonts. + * + * BACKPORT NOTE: Do not backport this method. + * + * @since 6.0.0 + * @deprecated 6.1.0 Use wp_webfonts()->get_enqueued(). + * + * @return array[] + */ + public function get_enqueued_webfonts() { + _deprecated_function( __METHOD__, '6.1.0', 'wp_webfonts()->get_enqueued()' ); + + return $this->queue; + } + + /** + * Gets the list of all fonts. + * + * BACKPORT NOTE: Do not backport this method. + * + * @since 6.0.0 + * @deprecated 6.1.0 Use wp_webfonts()->get_registered(). + * + * @return array[] + */ + public function get_all_webfonts() { + _deprecated_function( __METHOD__, '6.1.0', 'wp_webfonts()->get_registered()' ); + + return $this->get_registered(); + } + + /** + * Registers a webfont. + * + * BACKPORT NOTE: Do not backport this method. + * + * @since 6.0.0 + * @deprecated 6.1.0 Use wp_register_webfont(). + * + * @param array $webfont Web font to register. + * @param string $font_family_handle Optional. Font family handle for the given variation. + * Default empty string. + * @param string $variation_handle Optional. Handle for the variation to register. + * @return string|false The font family slug if successfully registered, else false. + */ + public function register_webfont( array $webfont, $font_family_handle = '', $variation_handle = '' ) { + _deprecated_function( __METHOD__, '6.1.0', 'wp_register_webfont()' ); + + // When font family's handle is not passed, attempt to get it from the variation. + if ( ! WP_Webfonts_Utils::is_defined( $font_family_handle ) ) { + $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $webfont ); + if ( $font_family ) { + $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); + } + } + + if ( empty( $font_family_handle ) ) { + trigger_error( 'Font family handle must be a non-empty string.' ); + return false; + } + + return $this->add_variation( $font_family_handle, $webfont, $variation_handle ) + ? $font_family_handle + : false; + } + + /** + * Enqueue a font-family that has been already registered. + * + * BACKPORT NOTE: Do not backport this method. + * + * @since 6.0.0 + * @deprecated 6.1.0 Use wp_webfonts()->enqueue() or wp_enqueue_webfont(). + * + * @param string $font_family_name The font family name to be enqueued. + * @return bool True if successfully enqueued, else false. + */ + public function enqueue_webfont( $font_family_name ) { + _deprecated_function( __METHOD__, '6.1.0', 'wp_webfonts()->enqueue() or wp_enqueue_webfont()' ); + + $slug = $this->get_font_slug( $font_family_name ); + + if ( isset( $this->enqueued[ $slug ] ) ) { + return true; + } + + if ( ! isset( $this->registered[ $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' ); + + return false; + } + + $this->enqueue( $slug ); + return true; + } } diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index 6c62b7be3d2584..00ecea68b69b33 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -84,21 +84,26 @@ function wp_register_webfonts( array $webfonts ) { * Handle the deprecated web font's structure but alert developers * to modify their web font structure to group and key by font family. * - * Note: This code block will not be backported to Core. - */ + * BACKPORT NOTE: Do not backport this code block. + */ if ( ! WP_Webfonts_Utils::is_defined( $font_family ) ) { - _doing_it_wrong( - __FUNCTION__, - __( 'Variations must be grouped and keyed by their font family.', 'gutenberg' ), - '6.1.0' + $font_family_handle = _gutenberg_extract_font_family_from_deprecated_webfonts_structure( + $variations, + 'A deprecated web fonts array structure passed to wp_register_webfonts(). ' . + 'Variations must be grouped and keyed by their font family.' ); - $font_family_handle = wp_register_webfont( $variations ); + if ( ! $font_family_handle ) { + continue; + } + + $font_family_handle = wp_register_webfont( $variations, $font_family_handle ); if ( ! $font_family_handle ) { continue; } $registered[ $font_family_handle ] = true; continue; - } // end of code block for deprecated web fonts structure. + } + // BACKPORT NOTE: End of the deprecated code block. $font_family_handle = wp_register_font_family( $font_family ); if ( ! $font_family_handle ) { @@ -128,18 +133,18 @@ function wp_register_webfonts( array $webfonts ) { * @since X.X.X * * @param array $variation Array of variation properties to be registered. - * @param string $font_family_handle Optional. Font family handle for the given variation. - * Default empty string. + * @param string $font_family_handle Font family handle for the given variation. + * Temporarily optional. Will be required when backported to Core. * @param string $variation_handle Optional. Handle for the variation to register. * @return string|null The font family slug if successfully registered. Else null. */ function wp_register_webfont( array $variation, $font_family_handle = '', $variation_handle = '' ) { // When font family's handle is not passed, attempt to get it from the variation. if ( ! WP_Webfonts_Utils::is_defined( $font_family_handle ) ) { - $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $variation ); - if ( $font_family ) { - $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); - } + $font_family_handle = _gutenberg_extract_font_family_from_deprecated_webfonts_structure( + $variation, + 'Not passing the font family handle parameter to wp_register_webfont() is deprecated' + ); } if ( empty( $font_family_handle ) ) { @@ -309,3 +314,61 @@ function( $mime_types ) { return $mime_types; } ); + +/* + * Deprecated functions provided here to give extenders time to change + * their plugins/themes before this API is introduced into Core. + * + * BACKPORT NOTE: Do not backport these deprecated functions to Core. + */ + +if ( ! function_exists( 'wp_enqueue_webfonts' ) ) { + /** + * Enqueues a collection of font families. + * + * Example of how to enqueue Source Serif Pro and Roboto font families, both registered beforehand. + * + * + * wp_enqueue_webfonts( + * 'Roboto', + * 'Sans Serif Pro' + * ); + * + * + * Font families should be enqueued from the `init` hook or later. + * + * BACKPORT NOTE: Do not backport this function. + * + * @since 6.0.0 + * @deprecated 6.1.0 Use wp_enqueue_webfont(). + * + * @param string[] $font_families Font family handles (array of strings). + */ + function wp_enqueue_webfonts( array $font_families ) { + _deprecated_function( __FUNCTION__, '6.1.0', 'wp_enqueue_webfont()' ); + + wp_enqueue_webfont( $font_families ); + } +} + +/** + * Handle the deprecated web fonts structure. + * + * BACKPORT NOTE: Do not backport this function. + * + * @access private + * + * @param array $webfont Web font for extracting font family. + * @param string $message Deprecation message to throw. + * @return string|null The font family slug if successfully registered. Else null. + */ +function _gutenberg_extract_font_family_from_deprecated_webfonts_structure( array $webfont, $message ) { + trigger_error( $message, E_USER_DEPRECATED ); + + $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $webfont ); + if ( ! $font_family ) { + return null; + } + + return WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); +} diff --git a/phpunit/webfonts/wp-webfonts-testcase.php b/phpunit/webfonts/wp-webfonts-testcase.php index 317ac1c77ea77d..c6ded968478d32 100644 --- a/phpunit/webfonts/wp-webfonts-testcase.php +++ b/phpunit/webfonts/wp-webfonts-testcase.php @@ -21,6 +21,13 @@ abstract class WP_Webfonts_TestCase extends WP_UnitTestCase { */ private $old_wp_webfonts; + /** + * Current error reporting level (before a test changes it). + * + * @var null|int + */ + protected $error_reporting_level = null; + /** * Reflection data store for non-public property access. * @@ -38,6 +45,13 @@ public function set_up() { public function tear_down() { $this->property = array(); $GLOBALS['wp_webfonts'] = $this->old_wp_webfonts; + + // Reset the error reporting when modified within a test. + if ( is_int( $this->error_reporting_level ) ) { + error_reporting( $this->error_reporting_level ); + $this->error_reporting_level = null; + } + parent::tear_down(); } @@ -235,4 +249,13 @@ protected function get_handles_for_provider( array $fonts, $provider_id ) { return $handles; } + + /** + * Suppresses deprecation notices allowing a test to skip deprecations + * to test notices or other specifics. + */ + protected function suppress_deprecations() { + $this->error_reporting_level = error_reporting(); + error_reporting( $this->error_reporting_level & ~E_USER_DEPRECATED ); + } } diff --git a/phpunit/webfonts/wpRegisterWebfont-test.php b/phpunit/webfonts/wpRegisterWebfont-test.php index 28d0352150ed43..bfd673ab84e4d6 100644 --- a/phpunit/webfonts/wpRegisterWebfont-test.php +++ b/phpunit/webfonts/wpRegisterWebfont-test.php @@ -11,6 +11,7 @@ /** * @group webfonts * @covers ::wp_register_webfont + * @covers WP_Webfonts::add_variation */ class Tests_Webfonts_WpRegisterWebfont extends WP_Webfonts_TestCase { @@ -58,16 +59,15 @@ public function test_should_register_variation_but_not_reregister_font_family( $ /** * Integration test for testing the font family is registered during the variation registration process. * - * @dataProvider data_with_deprecated_structure + * @dataProvider data_with_valid_input * - * @param array $variation Web font to test. - * @param array $expected Expected results. + * @param string $font_family_handle Font family handle. + * @param array $variation Variation. + * @param array $expected Expected results. */ - public function test_should_register_font_family( array $variation, $expected ) { - $font_family_handle = $expected[0]; - - wp_register_webfont( $variation ); - $this->assertContains( $font_family_handle, $this->get_registered_handles() ); + public function test_should_register_font_family( $font_family_handle, array $variation, array $expected ) { + wp_register_webfont( $variation, $font_family_handle ); + $this->assertSame( $expected, $this->get_registered_handles() ); } /** @@ -124,14 +124,37 @@ public function data_with_valid_input() { /** * @dataProvider data_with_deprecated_structure * - * @covers WP_Webfonts::add_variation + * @param array $variation Web font to test. + */ + public function test_should_throw_deprecation_with_deprecated_structure( array $variation ) { + $this->expectDeprecation(); + $this->expectDeprecationMessage( 'Not passing the font family handle parameter to wp_register_webfont() is deprecated' ); + + wp_register_webfont( $variation ); + } + + /** + * @dataProvider data_with_deprecated_structure + * + * @param array $variation Web font to test. + * @param array $expected Expected results. + */ + public function test_should_extract_font_family_with_deprecated_structure( array $variation, $expected ) { + $this->suppress_deprecations(); + + $expected_handle = $expected[0]; + $this->assertSame( $expected_handle, wp_register_webfont( $variation ), 'Registering should return the registered font family handle' ); + } + + /** + * @dataProvider data_with_deprecated_structure * * @param array $variation Web font to test. * @param array $expected Expected results. */ - public function test_registers_with_deprecated_structure( - array $variation, $expected - ) { + public function test_should_register_with_deprecated_structure( array $variation, $expected ) { + $this->suppress_deprecations(); + $font_family_handle = $expected[0]; $this->setup_font_family( $font_family_handle ); @@ -142,18 +165,17 @@ public function test_registers_with_deprecated_structure( /** * @dataProvider data_with_deprecated_structure * - * @covers WP_Webfonts::add_variation - * * @param array $variation Web font to test. * @param array $expected Expected results. */ - public function test_should_register_font_family_with_deprecated_structure( - array $variation, $expected - ) { + public function test_should_register_font_family_with_deprecated_structure( array $variation, $expected ) { + $this->suppress_deprecations(); + $font_family_handle = $expected[0]; wp_register_webfont( $variation ); $this->assertContains( $font_family_handle, $this->get_registered_handles() ); + $this->assertSame( $expected, $this->get_registered_handles(), 'Registry should contain the font family and variant handles' ); } /** @@ -199,7 +221,9 @@ public function data_with_deprecated_structure() { * @param array $variation Web font to test. * @param string $expected_message Expected notice message. */ - public function test_should_fail_with_invalid_font_family( $font_family_handle, array $variation, $expected_message ) { + public function test_should_not_register_with_undefined_font_family( $font_family_handle, array $variation, $expected_message ) { + $this->suppress_deprecations(); + $this->expectNotice(); $this->expectNoticeMessage( $expected_message ); diff --git a/phpunit/webfonts/wpRegisterWebfonts-test.php b/phpunit/webfonts/wpRegisterWebfonts-test.php index 275d73c65a4e08..6b022dae56d7b5 100644 --- a/phpunit/webfonts/wpRegisterWebfonts-test.php +++ b/phpunit/webfonts/wpRegisterWebfonts-test.php @@ -2,7 +2,7 @@ /** * Integration tests for wp_register_webfonts(). * - * @package WordPress + * @package WordPress * @subpackage Webfonts */ @@ -24,23 +24,8 @@ class Tests_Webfonts_WpRegisterWebfonts extends WP_Webfonts_TestCase { * @param array $expected Expected results. */ public function test_should_register( array $webfonts, array $expected ) { - $this->assertSame( $expected['wp_register_webfonts'], wp_register_webfonts( $webfonts ), 'Font family handle(s) should be returned' ); - $this->assertSame( $expected['get_registered'], $this->get_registered_handles(), 'Web fonts should match registered queue' ); - } - - /** - * @dataProvider data_deprecated_structure - * - * @expectedIncorrectUsage wp_register_webfonts - * - * @param array $webfonts Array of webfonts to test. - * @param array $expected Expected results. - */ - public function test_should_register_with_deprecated_structure( array $webfonts, array $expected ) { - $this->expectNotice(); - $this->expectNoticeMessage( $expected['message'] ); - - $this->assertSame( $expected['wp_register_webfonts'], wp_register_webfonts( $webfonts ), 'Font family handle(s) should be returned' ); + $actual = wp_register_webfonts( $webfonts ); + $this->assertSame( $expected['wp_register_webfonts'], $actual, 'Font family handle(s) should be returned' ); $this->assertSame( $expected['get_registered'], $this->get_registered_handles(), 'Web fonts should match registered queue' ); } @@ -49,7 +34,7 @@ public function test_should_register_with_deprecated_structure( array $webfonts, * * @param array $webfonts Array of webfonts to test. */ - public function test_should_do_not_enqueue_on_registration( array $webfonts ) { + public function test_should_not_enqueue_on_registration( array $webfonts ) { wp_register_webfonts( $webfonts ); $this->assertEmpty( $this->get_enqueued_handles() ); } @@ -115,6 +100,35 @@ public function data_webfonts() { ); } + /** + * @dataProvider data_deprecated_structure + * + * @param array $webfonts Webfonts to test. + */ + public function test_should_throw_deprecation_with_deprecated_structure( array $webfonts ) { + $this->expectDeprecation(); + $this->expectDeprecationMessage( + 'A deprecated web fonts array structure passed to wp_register_webfonts(). ' . + 'Variations must be grouped and keyed by their font family.' + ); + + wp_register_webfonts( $webfonts ); + } + + /** + * @dataProvider data_deprecated_structure + * + * @param array $webfonts Webfonts to test. + * @param array $expected Expected results. + */ + public function test_should_register_with_deprecated_structure( array $webfonts, array $expected ) { + $this->suppress_deprecations(); + + $actual = wp_register_webfonts( $webfonts ); + $this->assertSame( $expected['wp_register_webfonts'], $actual, 'Font family handle(s) should be returned' ); + $this->assertSame( $expected['get_registered'], $this->get_registered_handles(), 'Web fonts should match registered queue' ); + } + /** * Data provider. * @@ -122,25 +136,189 @@ public function data_webfonts() { */ public function data_deprecated_structure() { return array( - 'font family not keyed' => array( + '1 web font' => array( 'webfonts' => array( array( - array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-stretch' => 'normal', - 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', - 'font-display' => 'fallback', - ), + 'provider' => 'local', + 'font-family' => 'Merriweather', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + ), + 'expected' => array( + 'wp_register_webfonts' => array( 'merriweather' => true ), + 'get_registered' => array( 'merriweather', 'merriweather-200-900-normal' ), + ), + ), + '2 web font in same font family' => array( + 'webfonts' => array( + array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '300', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'italic', + 'font-weight' => '900', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2', + 'font-display' => 'fallback', ), ), 'expected' => array( - 'wp_register_webfonts' => array(), - 'get_registered' => array(), - 'message' => 'Font family not found.', + 'wp_register_webfonts' => array( 'source-serif-pro' => true ), + 'get_registered' => array( + 'source-serif-pro', + 'source-serif-pro-300-normal', + 'source-serif-pro-900-italic', + ), + ), + ), + 'Web fonts in different font families' => array( + 'webfonts' => array( + array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '300', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + array( + 'provider' => 'local', + 'font-family' => 'Merriweather', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + 'font-style' => 'italic', + 'font-weight' => '900', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + 'expected' => array( + 'wp_register_webfonts' => array( + 'source-serif-pro' => true, + 'merriweather' => true, + ), + 'get_registered' => array( + 'source-serif-pro', + 'source-serif-pro-300-normal', + 'merriweather', + 'merriweather-200-900-normal', + 'source-serif-pro-900-italic', + ), + ), + ), + ); + } + + /** + * @dataProvider data_invalid_font_family + * + * @param array $webfonts Web fonts to test. + * @param string $expected_message Expected notice message. + */ + public function test_should_not_register_with_undefined_font_family( array $webfonts, $expected_message ) { + $this->suppress_deprecations(); + + $this->expectNotice(); + $this->expectNoticeMessage( $expected_message ); + + $actual = wp_register_webfonts( $webfonts ); + $this->assertSame( array(), $actual, 'Return value should be an empty array' ); + $this->assertEmpty( $this->get_registered_handles(), 'No Web fonts should have registered' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_invalid_font_family() { + return array( + 'non-string' => array( + 'webfonts' => array( + array( + 'provider' => 'local', + 'font-family' => null, + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + ), + 'expected_message' => 'Font family not defined in the variation.', + ), + 'empty string in deprecated structure' => array( + 'webfonts' => array( + '0' => array( + 'provider' => 'local', + 'font-style' => 'normal', + 'font-weight' => '300', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + ), + 'expected_message' => 'Font family not found.', + ), + 'incorrect parameter in deprecated structure' => array( + 'webfonts' => array( + array( + 'provider' => 'local', + 'FontFamily' => 'Source Serif Pro', + 'font-style' => 'normal', + 'font-weight' => '300', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + array( + 'provider' => 'local', + 'font_family' => 'Merriweather', + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + ), + array( + 'provider' => 'local', + 'font family' => 'Source Serif Pro', + 'font-style' => 'italic', + 'font-weight' => '900', + 'font-display' => 'fallback', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2', + 'font-display' => 'fallback', + ), ), + 'expected_message' => 'Font family not found.', ), ); } From eb97c86a7a5d63c0ad42d426d8cef022c90c28c8 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 31 Aug 2022 10:47:52 -0500 Subject: [PATCH 28/63] Turns on deprecations in multisite tests --- phpunit/multisite.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/phpunit/multisite.xml b/phpunit/multisite.xml index 494c9a4610d07b..7a6117948547d3 100644 --- a/phpunit/multisite.xml +++ b/phpunit/multisite.xml @@ -5,6 +5,7 @@ convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" + convertDeprecationsToExceptions="true" > From 873ca612484301ddd96d9e0ade09abdf06af7855 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 31 Aug 2022 11:22:37 -0500 Subject: [PATCH 29/63] Add tests for WP_Webfonts::dequeue() --- phpunit/webfonts/wpWebfonts/dequeue-test.php | 56 +++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/phpunit/webfonts/wpWebfonts/dequeue-test.php b/phpunit/webfonts/wpWebfonts/dequeue-test.php index 7a67b07d72ff37..d5e49c1aa8f929 100644 --- a/phpunit/webfonts/wpWebfonts/dequeue-test.php +++ b/phpunit/webfonts/wpWebfonts/dequeue-test.php @@ -14,7 +14,59 @@ */ class Tests_Webfonts_WpWebfonts_Dequeue extends WP_Webfonts_TestCase { - public function test_dequeue() { - // TODO: Add tests for WP_Webfonts::dequeue(). + /** + * @dataProvider data_enqueue + * @dataProvider data_enqueue_variations + * + * @param string|string[] $handles Handles to test. + */ + public function test_should_do_nothing_when_handles_not_queued( $handles ) { + $wp_webfonts = new WP_Webfonts(); + + $wp_webfonts->dequeue( $handles ); + $this->assertEmpty( $this->get_queued_before_register( $wp_webfonts ), 'Prequeue should be empty' ); + $this->assertEmpty( $wp_webfonts->queue, 'Queue should be empty' ); + } + + /** + * Integration test for dequeuing from queue. It first registers and then enqueues before dequeuing. + * + * @dataProvider data_enqueue + * @dataProvider data_enqueue_variations + * + * @param string|string[] $handles Handles to test. + */ + public function test_should_dequeue_from_queue( $handles ) { + $wp_webfonts = new WP_Webfonts(); + + // Register and enqueue. + foreach ( $this->get_data_registry() as $handle => $variations ) { + $this->setup_register( $handle, $variations, $wp_webfonts ); + } + $wp_webfonts->enqueue( $handles ); + + // To make sure the handles are in the queue before dequeuing. + $this->assertNotEmpty( $wp_webfonts->queue, 'Queue not be empty before dequeueing' ); + + // Run the test. + $wp_webfonts->dequeue( $handles ); + $this->assertEmpty( $wp_webfonts->queue, 'Queue should be empty after dequeueing' ); + } + + /** + * Integration test for dequeuing from prequeue. It enqueues first. + * + * @dataProvider data_enqueue + * @dataProvider data_enqueue_variations + * + * @param string|string[] $handles Handles to test. + */ + public function test_should_dequeue_from_prequeue( $handles ) { + $wp_webfonts = new WP_Webfonts(); + $wp_webfonts->enqueue( $handles ); + $this->assertNotEmpty( $this->get_queued_before_register( $wp_webfonts ), 'Prequeue not be empty before dequeueing' ); + + $wp_webfonts->dequeue( $handles ); + $this->assertEmpty( $this->get_queued_before_register( $wp_webfonts ), 'Prequeue should be empty after dequeueing' ); } } From 3ce6cec5e56a718ff740f147e68a84e5cd0d307a Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 31 Aug 2022 12:37:20 -0500 Subject: [PATCH 30/63] Adds WP_Webfonts::query() tests --- phpunit/webfonts/wpWebfonts/query-test.php | 111 +++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 phpunit/webfonts/wpWebfonts/query-test.php diff --git a/phpunit/webfonts/wpWebfonts/query-test.php b/phpunit/webfonts/wpWebfonts/query-test.php new file mode 100644 index 00000000000000..03e2cd28873634 --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/query-test.php @@ -0,0 +1,111 @@ +wp_webfonts = new WP_Webfonts(); + } + + /** + * @dataProvider data_invalid_query + * @dataProvider data_valid_query + * + * @param string $query_handle Handle to test. + */ + public function test_should_fail_when_handles_not_registered( $query_handle ) { + $this->assertFalse( $this->wp_webfonts->query( $query_handle, 'registered' ) ); + } + + /** + * @dataProvider data_invalid_query + * @dataProvider data_valid_query + * + * @param string $query_handle Handle to test. + */ + public function test_should_fail_when_handles_not_registered_or_enqueued( $query_handle ) { + $this->assertFalse( $this->wp_webfonts->query( $query_handle, 'queue' ) ); + } + + /** + * @dataProvider data_valid_query + * + * @param string $query_handle Handle to test. + */ + public function test_registered_query_should_succeed_when_registered( $query_handle ) { + $this->setup_registry(); + + $actual = $this->wp_webfonts->query( $query_handle, 'registered' ); + $this->assertInstanceOf( '_WP_Dependency', $actual, 'Query should return an instance of _WP_Dependency' ); + $this->assertSame( $query_handle, $actual->handle, 'Query object handle should match the given handle to query' ); + } + + /** + * @dataProvider data_valid_query + * + * @param string $query_handle Handle to test. + */ + public function test_enqueued_query_should_succeed_when_registered_and_enqueued( $query_handle ) { + $this->setup_registry(); + $this->wp_webfonts->enqueue( $query_handle ); + + $this->assertTrue( $this->wp_webfonts->query( $query_handle, 'enqueued' ) ); + } + + /** + * @dataProvider data_valid_query + * + * @param string $query_handle Handle to test. + */ + public function test_enqueued_query_should_fail_when_not_registered_but_enqueued( $query_handle ) { + $this->wp_webfonts->enqueue( $query_handle ); + + $this->assertFalse( $this->wp_webfonts->query( $query_handle, 'enqueued' ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_invalid_query() { + return array( + 'DM Sans' => array( 'DM Sans' ), + 'roboto' => array( 'roboto' ), + ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_valid_query() { + return array( + 'lato' => array( 'lato' ), + 'merriweather' => array( 'merriweather' ), + 'Source Serif Pro' => array( 'Source Serif Pro' ), + 'my-font' => array( 'my-font' ), + ); + } + + private function setup_registry() { + foreach ( $this->get_data_registry() as $handle => $variations ) { + $this->setup_register( $handle, $variations, $this->wp_webfonts ); + } + } +} From 750f730d3538fa7dd0e59f85ab7c0fbe3417c819 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 31 Aug 2022 15:31:13 -0500 Subject: [PATCH 31/63] Set font family done after printing Fixes an issue where the `WP_Webfonts::$to_do` has each font family, but the `WP_Webfonts::$done` does not. Found when working on the `query()`. After printing the variations, the font family for these printed variations will be added to the `WP_Webfonts::$done` property. In order to make this work, a `is_font_family` flag is added to `extra` data. --- lib/experimental/class-wp-webfonts.php | 94 +++++++++++++++++-- lib/experimental/webfonts.php | 3 +- phpunit/webfonts/wp-webfonts-testcase.php | 18 ++-- .../webfonts/wp-webfonts-tests-dataset.php | 54 ++++++++--- phpunit/webfonts/wpPrintWebfonts-test.php | 43 ++++----- .../webfonts/wpRegisterFontFamily-test.php | 13 ++- .../wpWebfonts/addFontFamily-test.php | 45 +++++++++ phpunit/webfonts/wpWebfonts/doItems-test.php | 50 +++++----- phpunit/webfonts/wpWebfonts/query-test.php | 44 ++++++++- 9 files changed, 282 insertions(+), 82 deletions(-) create mode 100644 phpunit/webfonts/wpWebfonts/addFontFamily-test.php diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 1dbad9286e1343..937cd293955053 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -116,6 +116,26 @@ public function get_enqueued() { return $this->queue; } + /** + * Removes a font family and all registered variations. + * + * @since X.X.X + * + * @param string $font_family_handle The font family to register. + * @return bool True when registered, else false. + */ + public function add_font_family( $font_family_handle ) { + if ( isset( $this->registered[ $font_family_handle ] ) ) { + return true; + } + + $registered = $this->add( $font_family_handle, false ); + if ( ! $registered ) { + return false; + } + return $this->add_data( $font_family_handle, 'is_font_family', true ); + } + /** * Removes a font family and all registered variations. * @@ -162,7 +182,7 @@ public function add_variation( $font_family_handle, array $variation, $variation // Register the font family when it does not yet exist. if ( ! isset( $this->registered[ $font_family_handle ] ) ) { - if ( ! $this->add( $font_family_handle, false ) ) { + if ( ! $this->add_font_family( $font_family_handle ) ) { return null; } } @@ -198,6 +218,7 @@ public function add_variation( $font_family_handle, array $variation, $variation } $this->add_data( $variation_handle, 'font-properties', $variation ); + $this->add_data( $variation_handle, 'is_font_family', false ); // Add the font variation as a dependency to the registered font family. $this->add_dependency( $font_family_handle, $variation_handle ); @@ -395,6 +416,8 @@ public function do_items( $handles = false, $group = false ) { $this->do_item( $provider_id, $group ); } + $this->process_font_families_after_printing( $handles ); + return $this->done; } @@ -549,12 +572,71 @@ private function get_font_properties_for_provider( array $font_handles ) { */ private function update_queues_for_printed_fonts( array $font_handles ) { foreach ( $font_handles as $font_handle ) { - $this->done[] = $font_handle; - unset( - $this->to_do[ $this->to_do_keyed_handles[ $font_handle ] ], - $this->to_do_keyed_handles[ $font_handle ] - ); + $this->set_as_done( $font_handle ); + $this->remove_from_to_do_queues( $font_handle ); + } + } + + /** + * Processes the font families after printing the variations. + * + * For each queued font family: + * + * a. if any of their variations were printed, the font family is added to the `done` list. + * b. removes each from the to_do queues. + * + * @since X.X.X + * + * @param array $handles Handles to process. + */ + private function process_font_families_after_printing( array $handles ) { + foreach ( $handles as $handle ) { + if ( + ! $this->get_data( $handle, 'is_font_family' ) || + ! isset( $this->to_do_keyed_handles[ $handle ] ) + ) { + continue; + } + $font_family = $this->registered[ $handle ]; + + // Add the font family to `done` list if any of its variations were printed. + if ( ! empty( $font_family->deps ) ) { + $processed = array_intersect( $font_family->deps, $this->done ); + if ( ! empty( $processed ) ) { + $this->set_as_done( $handle ); + } + } + + $this->remove_from_to_do_queues( $handle ); + } + } + + /** + * Removes the handle from the `to_do` and `to_do_keyed_handles` lists. + * + * @since X.X.X + * + * @param string $handle Handle to remove. + */ + private function remove_from_to_do_queues( $handle ) { + unset( + $this->to_do[ $this->to_do_keyed_handles[ $handle ] ], + $this->to_do_keyed_handles[ $handle ] + ); + } + + /** + * Sets the given handle to done by adding it to the `done` list. + * + * @since X.X.X + * + * @param string $handle Handle to set as done. + */ + private function set_as_done( $handle ) { + if ( ! is_array( $this->done ) ) { + $this->done = array(); } + $this->done[] = $handle; } /** diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index 00ecea68b69b33..c7506413980464 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -44,8 +44,7 @@ function wp_register_font_family( $font_family ) { return null; } - $result = wp_webfonts()->add( $handle, false ) ? $handle : null; - return $result ? $handle : null; + return wp_webfonts()->add_font_family( $handle ) ? $handle : null; } } diff --git a/phpunit/webfonts/wp-webfonts-testcase.php b/phpunit/webfonts/wp-webfonts-testcase.php index c6ded968478d32..7e79f5f8f186ec 100644 --- a/phpunit/webfonts/wp-webfonts-testcase.php +++ b/phpunit/webfonts/wp-webfonts-testcase.php @@ -151,9 +151,11 @@ protected function get_reflection_method( $method_name ) { protected function setup_registration_mocks( array $inputs, WP_Webfonts $wp_webfonts ) { $mocks = array(); - $build_mock = function ( $handle ) use ( &$mocks, $wp_webfonts ) { - $mock = new stdClass(); - $mock->deps = array(); + $build_mock = function ( $handle, $is_font_family = false ) use ( &$mocks, $wp_webfonts ) { + $mock = new stdClass(); + $mock->deps = array(); + $mock->extra = array( 'is_font_family' => $is_font_family ); + // Add to each queue. $mocks[ $handle ] = $mock; $wp_webfonts->registered[ $handle ] = $mock; @@ -162,15 +164,15 @@ protected function setup_registration_mocks( array $inputs, WP_Webfonts $wp_webf }; foreach ( $inputs as $font_family => $variations ) { - $font_mock = $build_mock( $font_family ); + $font_mock = $build_mock( $font_family, true ); foreach ( $variations as $variation_handle => $variation ) { if ( ! is_string( $variation_handle ) ) { $variation_handle = $variation; } - $variation_mock = $build_mock( $variation_handle ); - $variation_mock->extra = array( 'font-properties' => $variation ); - $font_mock->deps[] = $variation_handle; + $variation_mock = $build_mock( $variation_handle ); + $variation_mock->extra['font-properties'] = $variation; + $font_mock->deps[] = $variation_handle; } } @@ -189,7 +191,7 @@ protected function setup_register( $font_family, $variations, $wp_webfonts = nul $wp_webfonts = wp_webfonts(); } - $wp_webfonts->add( $font_family, false ); + $wp_webfonts->add_font_family( $font_family ); foreach ( $variations as $variation_handle => $variation ) { if ( ! is_string( $variation_handle ) ) { diff --git a/phpunit/webfonts/wp-webfonts-tests-dataset.php b/phpunit/webfonts/wp-webfonts-tests-dataset.php index c28162f877e95f..b5d25a61952b53 100644 --- a/phpunit/webfonts/wp-webfonts-tests-dataset.php +++ b/phpunit/webfonts/wp-webfonts-tests-dataset.php @@ -613,7 +613,7 @@ public function data_print_enqueued() { 'registered' => $mock_fonts, 'enqueued' => array( 'font2' ), ), - 'expected_done' => array( 'font2-200-900-normal', 'font2-200-900-italic' ), + 'expected_done' => array( 'font2', 'font2-200-900-normal', 'font2-200-900-italic' ), 'expected_output' => sprintf( '%s; %s\n', $font_faces['font2-200-900-normal'], @@ -627,7 +627,17 @@ public function data_print_enqueued() { 'registered' => $mock_fonts, 'enqueued' => array( 'font1', 'font2', 'font3' ), ), - 'expected_done' => $mock_font_handles, + 'expected_done' => array( + 'font1', + 'font1-300-normal', + 'font1-300-italic', + 'font1-900-normal', + 'font2', + 'font2-200-900-normal', + 'font2-200-900-italic', + 'font3', + 'font3-bold-normal', + ), 'expected_output' => sprintf( '%s; %s; %s; %s; %s; %s\n', $font_faces['font1-300-normal'], @@ -645,7 +655,7 @@ public function data_print_enqueued() { 'registered' => $local_fonts, 'enqueued' => array( 'merriweather' ), ), - 'expected_done' => array( 'merriweather-200-900-normal' ), + 'expected_done' => array( 'merriweather', 'merriweather-200-900-normal' ), 'expected_output' => sprintf( "\n", $font_faces['merriweather-200-900-normal'] @@ -658,7 +668,7 @@ public function data_print_enqueued() { 'registered' => $local_fonts, 'enqueued' => array( 'Source Serif Pro' ), ), - 'expected_done' => array( 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic' ), + 'expected_done' => array( 'Source Serif Pro', 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic' ), 'expected_output' => sprintf( "\n", $font_faces['Source Serif Pro-300-normal'], @@ -670,9 +680,15 @@ public function data_print_enqueued() { 'provider' => array( 'local' => $providers['local'] ), 'provider_handles' => array( 'local' => $local_font_handles ), 'registered' => $local_fonts, - 'enqueued' => $local_font_handles, + 'enqueued' => array( 'merriweather', 'Source Serif Pro' ), + ), + 'expected_done' => array( + 'merriweather', + 'merriweather-200-900-normal', + 'Source Serif Pro', + 'Source Serif Pro-300-normal', + 'Source Serif Pro-900-italic', ), - 'expected_done' => array( 'merriweather-200-900-normal', 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic' ), 'expected_output' => sprintf( "\n", $font_faces['merriweather-200-900-normal'], @@ -685,7 +701,7 @@ public function data_print_enqueued() { 'print font1 when all providers registered' => array( 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'font1' ) ) ), - 'expected_done' => array( 'font1-300-normal', 'font1-300-italic', 'font1-900-normal' ), + 'expected_done' => array( 'font1', 'font1-300-normal', 'font1-300-italic', 'font1-900-normal' ), 'expected_output' => sprintf( '%s; %s; %s\n', $font_faces['font1-300-normal'], @@ -695,7 +711,17 @@ public function data_print_enqueued() { ), 'print all mock fonts when all providers registered' => array( 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'font1', 'font2', 'font3' ) ) ), - 'expected_done' => $mock_font_handles, + 'expected_done' => array( + 'font1', + 'font1-300-normal', + 'font1-300-italic', + 'font1-900-normal', + 'font2', + 'font2-200-900-normal', + 'font2-200-900-italic', + 'font3', + 'font3-bold-normal', + ), 'expected_output' => sprintf( '%s; %s; %s; %s; %s; %s\n', $font_faces['font1-300-normal'], @@ -708,15 +734,21 @@ public function data_print_enqueued() { ), 'print merriweather when all providers registered' => array( 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'merriweather' ) ) ), - 'expected_done' => array( 'merriweather-200-900-normal' ), + 'expected_done' => array( 'merriweather', 'merriweather-200-900-normal' ), 'expected_output' => sprintf( "\n", $font_faces['merriweather-200-900-normal'] ), ), 'print all local fonts when all providers registered' => array( - 'setup' => array_merge( $setup_all, array( 'enqueued' => $local_font_handles ) ), - 'expected_done' => array( 'merriweather-200-900-normal', 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic' ), + 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'merriweather', 'Source Serif Pro' ) ) ), + 'expected_done' => array( + 'merriweather', + 'merriweather-200-900-normal', + 'Source Serif Pro', + 'Source Serif Pro-300-normal', + 'Source Serif Pro-900-italic', + ), 'expected_output' => sprintf( "\n", $font_faces['merriweather-200-900-normal'], diff --git a/phpunit/webfonts/wpPrintWebfonts-test.php b/phpunit/webfonts/wpPrintWebfonts-test.php index d10731c2fc4cf8..0ab4bcbcc29c39 100644 --- a/phpunit/webfonts/wpPrintWebfonts-test.php +++ b/phpunit/webfonts/wpPrintWebfonts-test.php @@ -75,17 +75,7 @@ public function data_mocked_handles() { public function test_should_print_enqueued( $setup, $expected_done, $expected_output ) { $wp_webfonts = wp_webfonts(); - // Set up test. - foreach ( $setup['provider'] as $provider ) { - $wp_webfonts->register_provider( $provider['id'], $provider['class'] ); - } - foreach ( $setup['registered'] as $font_family => $variations ) { - $wp_webfonts->add( $font_family, false ); - foreach ( $variations as $variation_handle => $variation ) { - $wp_webfonts->add_variation( $font_family, $variation, $variation_handle ); - } - } - $wp_webfonts->enqueue( $setup['enqueued'] ); + $this->setup_integrated_deps( $setup, $wp_webfonts ); $this->expectOutputString( $expected_output ); $actual_done = $wp_webfonts->do_items(); @@ -105,16 +95,7 @@ public function test_should_print_enqueued( $setup, $expected_done, $expected_ou public function test_should_print_handles_when_not_enqueued( $setup, $expected_done, $expected_output ) { $wp_webfonts = wp_webfonts(); - // Set up test. - foreach ( $setup['provider'] as $provider ) { - $wp_webfonts->register_provider( $provider['id'], $provider['class'] ); - } - foreach ( $setup['registered'] as $font_family => $variations ) { - $wp_webfonts->add( $font_family, false ); - foreach ( $variations as $variation_handle => $variation ) { - $wp_webfonts->add_variation( $font_family, $variation, $variation_handle ); - } - } + $this->setup_integrated_deps( $setup, $wp_webfonts, false ); // Do not enqueue. Instead, pass the handles to wp_print_webfonts(). $handles = $setup['enqueued']; $this->assertEmpty( $wp_webfonts->queue, 'No fonts should be enqueued' ); @@ -123,4 +104,24 @@ public function test_should_print_handles_when_not_enqueued( $setup, $expected_d $actual_done = wp_print_webfonts( $handles ); $this->assertSameSets( $expected_done, $actual_done, 'Printed handles should match' ); } + + /** + * Sets up the dependencies for integration test. + * + * @param array $setup Dependencies to set up. + * @param WP_Webfonts $wp_webfonts Instance of WP_Webfonts. + * @param bool $enqueue Whether to enqueue. Default true. + */ + private function setup_integrated_deps( array $setup, $wp_webfonts, $enqueue = true ) { + foreach ( $setup['provider'] as $provider ) { + $wp_webfonts->register_provider( $provider['id'], $provider['class'] ); + } + foreach ( $setup['registered'] as $handle => $variations ) { + $this->setup_register( $handle, $variations, $wp_webfonts ); + } + + if ( $enqueue ) { + $wp_webfonts->enqueue( $setup['enqueued'] ); + } + } } diff --git a/phpunit/webfonts/wpRegisterFontFamily-test.php b/phpunit/webfonts/wpRegisterFontFamily-test.php index 6064fbac37c761..87628329e51cf0 100644 --- a/phpunit/webfonts/wpRegisterFontFamily-test.php +++ b/phpunit/webfonts/wpRegisterFontFamily-test.php @@ -23,12 +23,11 @@ class Tests_Webfonts_WpRegisterFontFamily extends WP_Webfonts_TestCase { * @param string $expected_handle Expected registered handle. */ public function test_unit_register( $font_family, $expected_handle ) { - $mock = $this->set_up_mock( 'add' ); + $mock = $this->set_up_mock( 'add_font_family' ); $mock->expects( $this->once() ) - ->method( 'add' ) + ->method( 'add_font_family' ) ->with( - $this->identicalTo( $expected_handle ), - $this->identicalTo( false ) + $this->identicalTo( $expected_handle ) ) ->will( $this->returnValue( $expected_handle ) ); @@ -80,8 +79,8 @@ public function data_font_family() { * @param string $invalid_input Invalid input to test. */ public function test_unit_register_fails( $invalid_input ) { - $mock = $this->set_up_mock( 'add' ); - $mock->expects( $this->never() )->method( 'add' ); + $mock = $this->set_up_mock( 'add_font_family' ); + $mock->expects( $this->never() )->method( 'add_font_family' ); $this->assertNull( wp_register_font_family( $invalid_input ), 'Registering an invalid input should return null' ); } @@ -127,7 +126,7 @@ public function test_re_register( $font_family, $expected_handle ) { wp_register_font_family( $font_family ); // Attempt to re-register it. - $this->assertNull( wp_register_font_family( $font_family ), 'Font family should return true after registering' ); + $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family handle should be returned after registering' ); $this->assertSame( array( $expected_handle ), $this->get_registered_handles(), 'The font family should only be registered once' ); } } diff --git a/phpunit/webfonts/wpWebfonts/addFontFamily-test.php b/phpunit/webfonts/wpWebfonts/addFontFamily-test.php new file mode 100644 index 00000000000000..84780c8dd57dcf --- /dev/null +++ b/phpunit/webfonts/wpWebfonts/addFontFamily-test.php @@ -0,0 +1,45 @@ +assertTrue( $wp_webfonts->add_font_family( $handle ), 'Registering a handle should return true' ); + $this->assertCount( 1, $wp_webfonts->registered ); + $this->assertArrayHasKey( $handle, $wp_webfonts->registered, 'Font family handle should be in the registry after registration' ); + + } + + /** + * Data provider. + * + * @return array + */ + public function data_handles() { + return array( + 'name: multiple' => array( 'Source Serif Pro' ), + 'handle: multiple' => array( 'source-serif-pro' ), + 'name: single' => array( 'Merriweather' ), + 'handle: single' => array( 'merriweather' ), + 'handle: variation' => array( 'my-custom-font-200-900-normal' ), + ); + } +} diff --git a/phpunit/webfonts/wpWebfonts/doItems-test.php b/phpunit/webfonts/wpWebfonts/doItems-test.php index 517145615e3b6f..ee7aca2304a30e 100644 --- a/phpunit/webfonts/wpWebfonts/doItems-test.php +++ b/phpunit/webfonts/wpWebfonts/doItems-test.php @@ -113,7 +113,7 @@ public function test_should_print_mocked_enqueued( $setup, $expected_done, $expe /** * Integration test that registers providers and fonts and then enqueues before - * testing the printing funtionality. + * testing the printing functionality. * * @dataProvider data_print_enqueued * @@ -122,19 +122,9 @@ public function test_should_print_mocked_enqueued( $setup, $expected_done, $expe * @param string $expected_output Expected printed output. */ public function test_should_print_enqueued( $setup, $expected_done, $expected_output ) { - // Set up test. - foreach ( $setup['provider'] as $provider ) { - $this->wp_webfonts->register_provider( $provider['id'], $provider['class'] ); - } - foreach ( $setup['registered'] as $font_family => $variations ) { - $this->wp_webfonts->add( $font_family, false ); - foreach ( $variations as $variation_handle => $variation ) { - $this->wp_webfonts->add_variation( $font_family, $variation, $variation_handle ); - } - } - $this->wp_webfonts->enqueue( $setup['enqueued'] ); + $this->setup_integrated_deps( $setup ); - $this->expectOutputString( $expected_output ); + $this->expectOutputString( $expected_output, 'Printed @font-face styles should match' ); $actual_done = $this->wp_webfonts->do_items(); $this->assertSameSets( $expected_done, $actual_done, 'Printed handles should match' ); } @@ -150,17 +140,8 @@ public function test_should_print_enqueued( $setup, $expected_done, $expected_ou * @param string $expected_output Expected printed output. */ public function test_should_print_handles_when_not_enqueued( $setup, $expected_done, $expected_output ) { - // Set up test. - foreach ( $setup['provider'] as $provider ) { - $this->wp_webfonts->register_provider( $provider['id'], $provider['class'] ); - } - foreach ( $setup['registered'] as $font_family => $variations ) { - $this->wp_webfonts->add( $font_family, false ); - foreach ( $variations as $variation_handle => $variation ) { - $this->wp_webfonts->add_variation( $font_family, $variation, $variation_handle ); - } - } - // Do not enqueue. Instead pass the handles to WP_Webfonts::do_items(). + $this->setup_integrated_deps( $setup, false ); + // Do not enqueue. Instead, pass the handles to WP_Webfonts::do_items(). $handles = $setup['enqueued']; $this->assertEmpty( $this->wp_webfonts->queue, 'No fonts should be enqueued' ); @@ -170,7 +151,7 @@ public function test_should_print_handles_when_not_enqueued( $setup, $expected_d } /** - * Sets up the dependencies for the test. + * Sets up the dependencies for the mocked test. * * @param array $setup Dependencies to set up. */ @@ -200,4 +181,23 @@ private function setup_deps( array $setup ) { $queue->setValue( $this->wp_webfonts, $setup['enqueued'] ); } } + + /** + * Sets up the dependencies for integration test. + * + * @param array $setup Dependencies to set up. + * @param bool $enqueue Whether to enqueue. Default true. + */ + private function setup_integrated_deps( array $setup, $enqueue = true ) { + foreach ( $setup['provider'] as $provider ) { + $this->wp_webfonts->register_provider( $provider['id'], $provider['class'] ); + } + foreach ( $setup['registered'] as $handle => $variations ) { + $this->setup_register( $handle, $variations, $this->wp_webfonts ); + } + + if ( $enqueue ) { + $this->wp_webfonts->enqueue( $setup['enqueued'] ); + } + } } diff --git a/phpunit/webfonts/wpWebfonts/query-test.php b/phpunit/webfonts/wpWebfonts/query-test.php index 03e2cd28873634..ced376555cccb8 100644 --- a/phpunit/webfonts/wpWebfonts/query-test.php +++ b/phpunit/webfonts/wpWebfonts/query-test.php @@ -86,6 +86,7 @@ public function data_invalid_query() { return array( 'DM Sans' => array( 'DM Sans' ), 'roboto' => array( 'roboto' ), + 'my-font' => array( 'my-font' ), ); } @@ -99,12 +100,51 @@ public function data_valid_query() { 'lato' => array( 'lato' ), 'merriweather' => array( 'merriweather' ), 'Source Serif Pro' => array( 'Source Serif Pro' ), - 'my-font' => array( 'my-font' ), + ); + } + + public function test_done_query_should_fail_when_no_variations() { + $this->wp_webfonts->register_provider( 'local', WP_Webfonts_Provider_Local::class ); + $this->setup_registry(); + $this->wp_webfonts->enqueue( 'lato' ); + + $this->wp_webfonts->do_items( 'lato' ); + + $this->assertFalse( $this->wp_webfonts->query( 'lato', 'done' ) ); + } + + /** + * @dataProvider data_done_query + * + * @param string $query_handle Handle to test. + */ + public function test_done_query_should_succeed_when_registered_and_enqueued( $query_handle ) { + $this->wp_webfonts->register_provider( 'local', WP_Webfonts_Provider_Local::class ); + $this->setup_registry(); + $this->wp_webfonts->enqueue( $query_handle ); + + // Process the web fonts while ignoring all the printed output. + $this->expectOutputRegex( '`.`' ); + $this->wp_webfonts->do_items( $query_handle ); + $this->getActualOutput(); + + $this->assertTrue( $this->wp_webfonts->query( $query_handle, 'done' ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_done_query() { + return array( + 'merriweather' => array( 'merriweather' ), + 'Source Serif Pro' => array( 'Source Serif Pro' ), ); } private function setup_registry() { - foreach ( $this->get_data_registry() as $handle => $variations ) { + foreach ( $this->get_registered_local_fonts() as $handle => $variations ) { $this->setup_register( $handle, $variations, $this->wp_webfonts ); } } From cd873c984dbf102d37bdbd91061294bf2307a466 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Thu, 1 Sep 2022 08:35:33 -0500 Subject: [PATCH 32/63] Fix missing key PHP notices --- .../register-webfonts-from-theme-json.php | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index 682ef2f4be0e2a..25a95ce9452d6d 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -86,12 +86,14 @@ function gutenberg_register_webfonts_from_theme_json() { } } - $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $font_face ); - if ( empty( $font_family_handle ) ) { - $font_family = $font_family['slug']; + $font_family_handle = WP_Webfonts_Utils::get_font_family_from_variation( $font_face ); + if ( empty( $font_family_handle ) && isset( $font_family['slug'] ) ) { + $font_family_handle = $font_family['slug']; + } + if ( ! empty( $font_family_handle ) ) { + $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family_handle ); } - $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); - if ( is_null( $font_family_handle ) ) { + if ( empty( $font_family_handle ) ) { _doing_it_wrong( __FUNCTION__, __( 'Font family not defined in the variation or "slug".', 'gutenberg' ), '6.1.0' ); } @@ -137,7 +139,10 @@ function gutenberg_add_registered_webfonts_to_theme_json( $data ) { $get_families = static function ( $families_data ) { $families = array(); foreach ( $families_data as $family ) { - $families[] = WP_Webfonts_Utils::convert_font_family_into_handle( $family ); + $handle = WP_Webfonts_Utils::convert_font_family_into_handle( $family ); + if ( ! empty( $handle ) ) { + $families[] = $handle; + } } /* @@ -145,7 +150,7 @@ function gutenberg_add_registered_webfonts_to_theme_json( $data ) { * instead of array_unique( $array ) because it's faster. * The result is the same. */ - return array_flip( array_flip( $families ) ); + return ! empty( $families ) ? array_flip( array_flip( $families ) ) : array(); }; // Diff the arrays to find the missing fonts. From 4607c6e06e3c8335527964b7661b1798b4dcb76a Mon Sep 17 00:00:00 2001 From: Tonya Mork Date: Thu, 1 Sep 2022 08:39:58 -0500 Subject: [PATCH 33/63] Explicitly define add() 2nd arg Why? * To make the intent more clear by conditionally setting the add() 2nd argument * To compress code * To reduce redundancy Co-authored-by: Ari Stathopoulos --- lib/experimental/class-wp-webfonts.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 937cd293955053..835b9d6341d616 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -206,11 +206,8 @@ public function add_variation( $font_family_handle, array $variation, $variation return $variation_handle; } - if ( array_key_exists( 'src', $variation ) ) { - $result = $this->add( $variation_handle, $variation['src'] ); - } else { - $result = $this->add( $variation_handle, false ); - } + $variation_src = array_key_exists( 'src', $variation ) ? $variation['src'] : false; + $result = $this->add( $variation_handle, $variation_src ); // Bail out if the registration failed. if ( ! $result ) { From 96dc4c4ad652725d266854debbd55eb06bf58981 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Thu, 1 Sep 2022 09:44:16 -0500 Subject: [PATCH 34/63] Simplify and encapsulate getting provider instance Props @aristath The knowledge of how to get the instance and put it into the store is now encapsulated in a private method. Why? It's a different task from what do_item() is doing. By moving to a private method, its intent is documented and more clear for future understanding. --- lib/experimental/class-wp-webfonts.php | 29 +++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 835b9d6341d616..93d33826fdff10 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -39,7 +39,7 @@ class WP_Webfonts extends WP_Dependencies { private $to_do_keyed_handles; /** - * Array of provider instances, keyed by provider ID. + * Provider instance store, keyed by provider ID. * * @since X.X.X * @@ -480,7 +480,7 @@ static function( $handle ) { * * @see WP_Dependencies::do_item() * - * @param string $provider_id The font family to process. + * @param string $provider_id The provider to process. * @param int|false $group Not used. * @return bool */ @@ -501,13 +501,7 @@ public function do_item( $provider_id, $group = false ) { // phpcs:ignore Variab } // Invoke provider to print its styles. - if ( isset( $this->provider_instances[ $provider_id ] ) ) { - $provider = $this->provider_instances[ $provider_id ]; - } else { - $provider = new $this->providers[ $provider_id ]['class'](); - // Store the instance. - $this->provider_instances[ $provider_id ] = $provider; - } + $provider = $this->get_provider_instance( $provider_id ); $provider->set_webfonts( $properties_by_font ); $provider->print_styles(); @@ -522,7 +516,7 @@ public function do_item( $provider_id, $group = false ) { // phpcs:ignore Variab * * @since X.X.X * - * @param string $provider_id Provider's unique ID. + * @param string $provider_id The provider to process. * @return array[] Webfonts organized by providers. */ private function get_enqueued_fonts_for_provider( $provider_id ) { @@ -560,6 +554,21 @@ private function get_font_properties_for_provider( array $font_handles ) { return $font_properties; } + /** + * Gets the instance of the provider from the WP_Webfonts::$provider_instance store. + * + * @since X.X.X + * + * @param string $provider_id The provider to get. + * @return object Instance of the provider. + */ + private function get_provider_instance( $provider_id ) { + if ( ! isset( $this->provider_instances[ $provider_id ] ) ) { + $this->provider_instances[ $provider_id ] = new $this->providers[ $provider_id ]['class'](); + } + return $this->provider_instances[ $provider_id ]; + } + /** * Update queues for the given printed fonts. * From 30c00538289f4f74eb84a866964f8ed181621ddc Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Thu, 1 Sep 2022 10:03:02 -0500 Subject: [PATCH 35/63] Docs and performance: variation property defaults Performance tweak: * What: Moves default declaration to a property and the filtering to the constructor. * Why: As the default structure and values are filtered, the filtering should only happen once, rather than repeating for each variation processed. Documentation: Documents the filter following WordPress Core coding standards. --- lib/experimental/class-wp-webfonts.php | 55 +++++++++++++++++++------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 93d33826fdff10..dd1485de330c43 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -46,12 +46,45 @@ class WP_Webfonts extends WP_Dependencies { * @var array */ private $provider_instances = array(); + + /** + * Variation property defaults. + * + * @since X.X.X + * + * @var array + */ + private $variation_property_defaults = array( + 'provider' => 'local', + 'font-family' => '', + 'font-style' => 'normal', + 'font-weight' => '400', + 'font-display' => 'fallback', + ); + /** * Constructor. * * @since X.X.X */ public function __construct() { + /** + * Filters the web font variation's property defaults. + * + * @since X.X.X + * + * @param array $defaults { + * An array of required web font properties and defaults. + * + * @type string $provider The provider ID. Default 'local'. + * @type string $font-family The font-family property. Default empty string. + * @type string $font-style The font-style property. Default 'normal'. + * @type string $font-weight The font-weight property. Default '400'. + * @type string $font-display The font-display property. Default 'fallback'. + * } + */ + $this->variation_property_defaults = apply_filters( 'wp_webfont_variation_defaults', $this->variation_property_defaults ); + /** * Fires when the WP_Webfonts instance is initialized. * @@ -285,23 +318,15 @@ private function add_dependency( $font_family_handle, $variation_handle ) { * * @since X.X.X * - * @param string $font_family_handle The font family's handle for this variation. - * @param array $variation An array of variation properties to add. + * @param string $font_family The font family for this variation. + * @param array $variation An array of variation properties to add. * @return false|array Validated variation on success. Else, false. */ - private function validate_variation( $font_family_handle, $variation ) { - $defaults = array( - 'provider' => 'local', - 'font-family' => $font_family_handle, - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ); - - $defaults = apply_filters( 'wp_webfont_variation_defaults', $defaults ); - - $defaults['font-family'] = $font_family_handle; - $variation = wp_parse_args( $variation, $defaults ); + private function validate_variation( $font_family, $variation ) { + $variation = wp_parse_args( $variation, $this->variation_property_defaults ); + if ( empty( $variation['font-family'] ) ) { + $variation['font-family'] = $font_family; + } // Local fonts need a "src". if ( 'local' === $variation['provider'] ) { From 176eb29ef70c06e1a23134d943813dcf0577d6ab Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Thu, 1 Sep 2022 11:48:42 -0500 Subject: [PATCH 36/63] Restore font family in variation required Restores `font-family` in variation requirement when registering a variation. The restore includes the notice being thrown when not defined. --- lib/experimental/class-wp-webfonts.php | 14 ++- .../webfonts/wp-webfonts-tests-dataset.php | 114 +++++++++++++++++- phpunit/webfonts/wpRegisterWebfont-test.php | 6 +- .../wpRegisterWebfontVariation-test.php | 4 +- phpunit/webfonts/wpRegisterWebfonts-test.php | 3 + .../webfonts/wpWebfonts/addVariation-test.php | 4 +- 6 files changed, 129 insertions(+), 16 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index dd1485de330c43..240b8233a513b4 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -220,7 +220,7 @@ public function add_variation( $font_family_handle, array $variation, $variation } } - $variation = $this->validate_variation( $font_family_handle, $variation ); + $variation = $this->validate_variation( $variation ); // Variation validation failed. if ( ! $variation ) { @@ -318,14 +318,16 @@ private function add_dependency( $font_family_handle, $variation_handle ) { * * @since X.X.X * - * @param string $font_family The font family for this variation. - * @param array $variation An array of variation properties to add. + * @param array $variation Variation properties to add. * @return false|array Validated variation on success. Else, false. */ - private function validate_variation( $font_family, $variation ) { + private function validate_variation( $variation ) { $variation = wp_parse_args( $variation, $this->variation_property_defaults ); - if ( empty( $variation['font-family'] ) ) { - $variation['font-family'] = $font_family; + + // Check the font-family. + if ( empty( $variation['font-family'] ) || ! is_string( $variation['font-family'] ) ) { + trigger_error( 'Webfont font-family must be a non-empty string.' ); + return false; } // Local fonts need a "src". diff --git a/phpunit/webfonts/wp-webfonts-tests-dataset.php b/phpunit/webfonts/wp-webfonts-tests-dataset.php index b5d25a61952b53..1e78422368582b 100644 --- a/phpunit/webfonts/wp-webfonts-tests-dataset.php +++ b/phpunit/webfonts/wp-webfonts-tests-dataset.php @@ -12,7 +12,8 @@ public function data_valid_variation() { 'expected' => 'lato-400-normal', 'font_family_handle' => 'lato', 'variation' => array( - 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + 'font-family' => 'Lato', + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', ), ), @@ -20,7 +21,8 @@ public function data_valid_variation() { 'expected' => 'my-custom-handle', 'font_family_handle' => 'lato', 'variation' => array( - 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + 'font-family' => 'Lato', + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', ), 'variation_handle' => 'my-custom-handle', ), @@ -103,11 +105,12 @@ public function data_valid_variation() { } /** - * Data provider for testing registration of variations where the font family is not defined. + * Data provider for testing registration of variations where the font family handle + * is not defined. * * @return array */ - public function data_font_family_not_define_in_variation() { + public function data_font_family_handle_undefined() { return array( 'empty string font family handle' => array( 'font_family_handle' => '', @@ -142,6 +145,56 @@ public function data_font_family_not_define_in_variation() { ); } + /** + * Data provider for testing registration of variations where the font family is not defined + * in the variation. + * + * @return array + */ + public function data_font_family_undefined_in_variation() { + $message = 'Webfont font-family must be a non-empty string.'; + return array( + 'font-family: undefined' => array( + 'font_family_handle' => 'lato', + 'variation' => array( + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + ), + 'expected_message' => $message, + ), + 'font-family: null' => array( + 'font_family_handle' => 'Lato', + 'variation' => array( + 'provider' => 'local', + 'font-family' => null, + 'font-weight' => '200', + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + ), + 'expected_message' => $message, + ), + 'font-family: non string' => array( + 'font_family_handle' => 'Source Serif Pro', + 'variation' => array( + 'provider' => 'local', + 'font-family' => 10, + 'font-style' => 'normal', + 'font-weight' => '200 900', + 'font-stretch' => 'normal', + 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', + 'font-display' => 'fallback', + ), + 'expected_message' => $message, + ), + 'font-family: empty string' => array( + 'font_family_handle' => 'lato', + 'variation' => array( + 'font-family' => '', + 'src' => 'https://example.com/assets/fonts/lato/lato.ttf.woff2', + ), + 'expected_message' => $message, + ), + ); + } + /** * Data provider for testing when the variation's handle can't be determine from the given input. * @@ -152,6 +205,7 @@ public function data_unable_determine_variation_handle() { 'integer values' => array( 'font_family_handle' => 'lato', 'variation' => array( + 'font-family' => 'Lato', 'font-weight' => 400, 'font-style' => 0, 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', @@ -161,6 +215,7 @@ public function data_unable_determine_variation_handle() { 'with empty string font-weight and font-style' => array( 'font_family_handle' => 'merriweather', 'variation' => array( + 'font-family' => 'Merriweather', 'font-weight' => '', 'font-style' => '', 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', @@ -170,6 +225,7 @@ public function data_unable_determine_variation_handle() { 'integer font-weight, empty string font-style' => array( 'font_family' => 'merriweather', 'variation' => array( + 'font-family' => 'Merriweather', 'font-weight' => 400, 'font-style' => '', 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', @@ -179,6 +235,7 @@ public function data_unable_determine_variation_handle() { 'empty string font-weight, integer font-style' => array( 'font_family' => 'lato', 'variation' => array( + 'font-family' => 'Merriweather', 'font-weight' => '', 'font-style' => 400, 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', @@ -195,6 +252,29 @@ public function data_unable_determine_variation_handle() { */ public function data_invalid_variation() { return array( + 'font-family: undefined' => array( + 'expected' => 'Webfont font-family must be a non-empty string.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + ), + 'font-family: null' => array( + 'expected' => 'Webfont font-family must be a non-empty string.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'font-family' => null, + 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + ), + 'font-family: empty string' => array( + 'expected' => 'Webfont font-family must be a non-empty string.', + 'font_family_handle' => 'lato', + 'variation' => array( + 'font-family' => '', + 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', + ), + ), 'src: undefined' => array( 'expected' => 'Webfont src must be a non-empty string or an array of strings.', 'font_family_handle' => 'lato', @@ -229,6 +309,7 @@ public function data_invalid_variation() { 'font_family_handle' => 'lato', 'variation' => array( 'provider' => 'local', + 'font-family' => 'Lato', 'font-weight' => '200', 'src' => array(), ), @@ -238,6 +319,7 @@ public function data_invalid_variation() { 'font_family_handle' => 'lato', 'variation' => array( 'provider' => 'local', + 'font-family' => 'Lato', 'font-weight' => '200', 'src' => array( '' ), ), @@ -247,6 +329,7 @@ public function data_invalid_variation() { 'font_family_handle' => 'lato', 'variation' => array( 'provider' => 'local', + 'font-family' => 'Lato', 'font-weight' => '200', 'src' => array( null ), ), @@ -256,6 +339,7 @@ public function data_invalid_variation() { 'font_family_handle' => 'lato', 'variation' => array( 'provider' => 'local', + 'font-family' => 'Lato', 'font-weight' => '200', 'src' => array( 'https://example.com/assets/fonts/merriweather.ttf.woff2', @@ -269,6 +353,7 @@ public function data_invalid_variation() { 'font_family_handle' => 'lato', 'variation' => array( 'provider' => 'local', + 'font-family' => 'Lato', 'font-weight' => '200', 'src' => array( 'https://example.com/assets/fonts/merriweather.ttf.woff2', @@ -282,6 +367,7 @@ public function data_invalid_variation() { 'font_family_handle' => 'merriweather', 'variation' => array( 'provider' => 'doesnotexit', + 'font-family' => 'Merriweather', 'font-weight' => '200 900', ), ), @@ -289,6 +375,7 @@ public function data_invalid_variation() { 'expected' => 'Webfont font-weight must be a properly formatted string or integer.', 'font_family_handle' => 'merriweather', 'variation' => array( + 'font-family' => 'Merriweather', 'font-weight' => null, 'font-style' => 'normal', 'src' => 'https://example.com/assets/fonts/lato.ttf.woff2', @@ -317,6 +404,7 @@ public function data_one_to_many_font_families_and_zero_to_many_variations() { 'inputs' => array( 'merriweather' => array( 'merriweather-200-900-normal' => array( + 'font-family' => 'Merriweather', 'font-weight' => '200 900', 'font-stretch' => 'normal', 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', @@ -332,6 +420,7 @@ public function data_one_to_many_font_families_and_zero_to_many_variations() { 'Source Serif Pro' => array( 'Source Serif Pro-300-normal' => array( 'provider' => 'local', + 'font-family' => 'Source Serif Pro', 'font-style' => 'normal', 'font-weight' => '300', 'font-stretch' => 'normal', @@ -340,6 +429,7 @@ public function data_one_to_many_font_families_and_zero_to_many_variations() { ), 'Source Serif Pro-900-italic' => array( 'provider' => 'local', + 'font-family' => 'Source Serif Pro', 'font-style' => 'italic', 'font-weight' => '900', 'font-stretch' => 'normal', @@ -367,6 +457,7 @@ public function data_one_to_many_font_families_and_zero_to_many_variations() { 'inputs' => array( 'merriweather' => array( 'merriweather-200-900-normal' => array( + 'font-family' => 'Merriweather', 'font-weight' => '200 900', 'font-stretch' => 'normal', 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', @@ -375,6 +466,7 @@ public function data_one_to_many_font_families_and_zero_to_many_variations() { 'Source Serif Pro' => array( 'Source Serif Pro-300-normal' => array( 'provider' => 'local', + 'font-family' => 'Source Serif Pro', 'font-style' => 'normal', 'font-weight' => '300', 'font-stretch' => 'normal', @@ -383,6 +475,7 @@ public function data_one_to_many_font_families_and_zero_to_many_variations() { ), 'Source Serif Pro-900-italic' => array( 'provider' => 'local', + 'font-family' => 'Source Serif Pro', 'font-style' => 'italic', 'font-weight' => '900', 'font-stretch' => 'normal', @@ -392,6 +485,7 @@ public function data_one_to_many_font_families_and_zero_to_many_variations() { ), 'my-font' => array( 'my-font-300-italic' => array( + 'font-family' => 'My Font', 'font-weight' => '300', 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2', ), @@ -826,6 +920,7 @@ protected function get_data_registry() { 'lato' => array(), 'merriweather' => array( 'merriweather-200-900-normal' => array( + 'font-family' => 'Merriweather', 'font-weight' => '200 900', 'font-stretch' => 'normal', 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', @@ -834,6 +929,7 @@ protected function get_data_registry() { 'Source Serif Pro' => array( 'Source Serif Pro-300-normal' => array( 'provider' => 'local', + 'font-family' => 'Source Serif Pro', 'font-style' => 'normal', 'font-weight' => '300', 'font-stretch' => 'normal', @@ -842,6 +938,7 @@ protected function get_data_registry() { ), 'Source Serif Pro-900-italic' => array( 'provider' => 'local', + 'font-family' => 'Source Serif Pro', 'font-style' => 'italic', 'font-weight' => '900', 'font-stretch' => 'normal', @@ -851,15 +948,18 @@ protected function get_data_registry() { ), 'my-font' => array( 'my-font-300-normal' => array( + 'font-family' => 'My Font', 'font-weight' => '300', 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2', ), 'my-font-300-italic' => array( + 'font-family' => 'My Font', 'font-weight' => '300', 'font-style' => 'italic', 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2', ), 'my-font-900-normal' => array( + 'font-family' => 'My Font', 'font-weight' => '900', 'src' => 'https://example.com/assets/fonts/my-font.ttf.woff2', ), @@ -1004,18 +1104,21 @@ protected function get_registered_mock_fonts() { 'font1' => array( 'font1-300-normal' => array( 'provider' => 'mock', + 'font-family' => 'Font 1', 'font-weight' => '300', 'font-style' => 'normal', 'font-display' => 'fallback', ), 'font1-300-italic' => array( 'provider' => 'mock', + 'font-family' => 'Font 1', 'font-weight' => '300', 'font-style' => 'italic', 'font-display' => 'fallback', ), 'font1-900-normal' => array( 'provider' => 'mock', + 'font-family' => 'Font 1', 'font-weight' => '900', 'font-style' => 'normal', 'font-display' => 'fallback', @@ -1024,12 +1127,14 @@ protected function get_registered_mock_fonts() { 'font2' => array( 'font2-200-900-normal' => array( 'provider' => 'mock', + 'font-family' => 'Font 2', 'font-weight' => '200 900', 'font-style' => 'normal', 'font-display' => 'fallback', ), 'font2-200-900-italic' => array( 'provider' => 'mock', + 'font-family' => 'Font 2', 'font-weight' => '200 900', 'font-style' => 'italic', 'font-display' => 'fallback', @@ -1038,6 +1143,7 @@ protected function get_registered_mock_fonts() { 'font3' => array( 'font3-bold-normal' => array( 'provider' => 'mock', + 'font-family' => 'Font 3', 'font-weight' => 'bold', 'font-style' => 'normal', 'font-display' => 'fallback', diff --git a/phpunit/webfonts/wpRegisterWebfont-test.php b/phpunit/webfonts/wpRegisterWebfont-test.php index bfd673ab84e4d6..3fe9c794f8ce21 100644 --- a/phpunit/webfonts/wpRegisterWebfont-test.php +++ b/phpunit/webfonts/wpRegisterWebfont-test.php @@ -96,6 +96,7 @@ public function data_with_valid_input() { 'font_family' => 'source-serif-pro', 'variation' => array( 'provider' => 'local', + 'font-family' => 'Source Serif Pro', 'font-style' => 'normal', 'font-weight' => '200 900', 'font-stretch' => 'normal', @@ -110,8 +111,9 @@ public function data_with_valid_input() { 'Merriweather' => array( 'font_family' => 'merriweather', 'variation' => array( - 'font-style' => 'italic', - 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', + 'font-family' => 'Merriweather', + 'font-style' => 'italic', + 'src' => 'https://example.com/assets/fonts/merriweather.ttf.woff2', ), 'expected' => array( 'merriweather', diff --git a/phpunit/webfonts/wpRegisterWebfontVariation-test.php b/phpunit/webfonts/wpRegisterWebfontVariation-test.php index 0c42a7445b8ead..6f8d759be35870 100644 --- a/phpunit/webfonts/wpRegisterWebfontVariation-test.php +++ b/phpunit/webfonts/wpRegisterWebfontVariation-test.php @@ -73,7 +73,7 @@ public function test_register_font_family_and_variation( $expected, $font_family } /** - * @dataProvider data_font_family_not_define_in_variation + * @dataProvider data_font_family_handle_undefined * * @param string $font_family_handle The font family's handle for this variation. * @param array $variation An array of variation properties to add. @@ -88,7 +88,7 @@ public function test_should_not_register_font_family_or_variant( $font_family_ha } /** - * @dataProvider data_font_family_not_define_in_variation + * @dataProvider data_font_family_undefined_in_variation * @dataProvider data_unable_determine_variation_handle * * @param string $font_family_handle The font family's handle for this variation. diff --git a/phpunit/webfonts/wpRegisterWebfonts-test.php b/phpunit/webfonts/wpRegisterWebfonts-test.php index 6b022dae56d7b5..ccb0e9aed798f1 100644 --- a/phpunit/webfonts/wpRegisterWebfonts-test.php +++ b/phpunit/webfonts/wpRegisterWebfonts-test.php @@ -51,6 +51,7 @@ public function data_webfonts() { 'source-serif-pro' => array( array( 'provider' => 'local', + 'font-family' => 'Source Serif Pro', 'font-style' => 'normal', 'font-weight' => '200 900', 'font-stretch' => 'normal', @@ -72,6 +73,7 @@ public function data_webfonts() { 'Source Serif Pro' => array( array( 'provider' => 'local', + 'font-family' => 'Source Serif Pro', 'font-style' => 'normal', 'font-weight' => '200 900', 'font-stretch' => 'normal', @@ -80,6 +82,7 @@ public function data_webfonts() { ), array( 'provider' => 'local', + 'font-family' => 'Source Serif Pro', 'font-style' => 'italic', 'font-weight' => '200 900', 'font-stretch' => 'normal', diff --git a/phpunit/webfonts/wpWebfonts/addVariation-test.php b/phpunit/webfonts/wpWebfonts/addVariation-test.php index 846dd11b87e436..809cc41f84e585 100644 --- a/phpunit/webfonts/wpWebfonts/addVariation-test.php +++ b/phpunit/webfonts/wpWebfonts/addVariation-test.php @@ -98,7 +98,7 @@ public function test_should_register_font_family_and_variation( $expected, $font } /** - * @dataProvider data_font_family_not_define_in_variation + * @dataProvider data_font_family_handle_undefined * * @param string $font_family_handle The font family's handle for this variation. * @param array $variation An array of variation properties to add. @@ -115,7 +115,7 @@ public function test_should_not_register_font_family_or_variant( $font_family_ha } /** - * @dataProvider data_font_family_not_define_in_variation + * @dataProvider data_font_family_undefined_in_variation * @dataProvider data_unable_determine_variation_handle * * @param string $font_family_handle The font family's handle for this variation. From 4e572a60208a28fa998fe17b48393d1d6a05bb6e Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Mon, 3 Oct 2022 10:38:14 +0200 Subject: [PATCH 37/63] Add 'optional' to the list of supported values Porting https://github.com/WordPress/gutenberg/pull/44622 --- 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 240b8233a513b4..9e6afd41fd3d09 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -362,8 +362,8 @@ private function validate_variation( $variation ) { } // Check the font-display. - if ( ! in_array( $webfont['font-display'], array( 'auto', 'block', 'fallback', 'swap', 'optional' ), true ) ) { - $webfont['font-display'] = 'fallback'; + if ( ! in_array( $variation['font-display'], array( 'auto', 'block', 'fallback', 'swap', 'optional' ), true ) ) { + $variation['font-display'] = 'fallback'; } $valid_props = array( From 880302b8cf38cb13a6226d0fa0d4eec149a382a0 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Thu, 1 Dec 2022 11:31:59 -0600 Subject: [PATCH 38/63] Separate style element from get_css() Moves the \n", - $this->type_attr, - $css - ); - return $css; } diff --git a/lib/experimental/class-wp-webfonts-provider.php b/lib/experimental/class-wp-webfonts-provider.php index 5113c0c46c023a..2de789bb7bb09d 100644 --- a/lib/experimental/class-wp-webfonts-provider.php +++ b/lib/experimental/class-wp-webfonts-provider.php @@ -34,6 +34,15 @@ */ abstract class WP_Webfonts_Provider { + /** + * The provider's unique ID. + * + * @since X.X.X + * + * @var string + */ + protected $id = ''; + /** * Webfonts to be processed. * @@ -43,6 +52,15 @@ abstract class WP_Webfonts_Provider { */ protected $webfonts = array(); + /** + * Font-face style tag's attribute(s). + * + * @since X.X.X + * + * @var string + */ + protected $style_tag_atts = ''; + /** * Sets this provider's webfonts property. * @@ -57,6 +75,18 @@ public function set_webfonts( array $webfonts ) { $this->webfonts = $webfonts; } + /** + * Prints the generated styles. + * + * @since X.X.X + */ + public function print_styles() { + printf( + $this->get_style_element(), + $this->get_css() + ); + } + /** * Gets the `@font-face` CSS for the provider's webfonts. * @@ -71,11 +101,13 @@ public function set_webfonts( array $webfonts ) { abstract public function get_css(); /** - * Prints the generated styles. + * Gets the `\n"; } } diff --git a/phpunit/fixtures/mock-provider.php b/phpunit/fixtures/mock-provider.php index 2e31092ac8f248..91475837e0e916 100644 --- a/phpunit/fixtures/mock-provider.php +++ b/phpunit/fixtures/mock-provider.php @@ -8,15 +8,20 @@ class Mock_Provider extends WP_Webfonts_Provider { */ protected $id = 'mock'; - /** - * CSS to print. - * - * @var string - */ - public $css = '%s\n'; - public function get_css() { $handles = array_keys( $this->webfonts ); + return implode( '; ', $handles ); return sprintf( $this->css, implode( '; ', $handles ) ); } + + /** + * Gets the `\n", + 'font-face-css' => << - CSS - , + , + ), ), 'woff2 format' => array( 'webfonts' => array( @@ -119,13 +136,14 @@ public function data_get_css() { 'src' => 'http://example.org/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2', ), ), - 'expected' => << + 'expected' => array( + 'style-element' => "\n", + 'font-face-css' => << - CSS - , + + , + ), ), ); } From 7417fc8fb13c2adc0e4340404444b63f2b551bbf Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Thu, 1 Dec 2022 11:47:49 -0600 Subject: [PATCH 39/63] Allow for multiple style element attributes. --- .../class-wp-webfonts-provider-local.php | 2 +- .../class-wp-webfonts-provider.php | 27 ++++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/experimental/class-wp-webfonts-provider-local.php b/lib/experimental/class-wp-webfonts-provider-local.php index bf04108524dd72..06558e5715224a 100644 --- a/lib/experimental/class-wp-webfonts-provider-local.php +++ b/lib/experimental/class-wp-webfonts-provider-local.php @@ -46,7 +46,7 @@ function_exists( 'is_admin' ) && ! is_admin() && function_exists( 'current_theme_supports' ) && ! current_theme_supports( 'html5', 'style' ) ) { - $this->style_tag_atts = " type='text/css'"; + $this->style_tag_atts = array( 'type' => 'text/css' ); } } diff --git a/lib/experimental/class-wp-webfonts-provider.php b/lib/experimental/class-wp-webfonts-provider.php index 2de789bb7bb09d..8fcbd76a76d3cf 100644 --- a/lib/experimental/class-wp-webfonts-provider.php +++ b/lib/experimental/class-wp-webfonts-provider.php @@ -53,13 +53,15 @@ abstract class WP_Webfonts_Provider { protected $webfonts = array(); /** - * Font-face style tag's attribute(s). + * Array of Font-face style tag's attribute(s) + * where the key is the attribute name and the + * value is its value. * * @since X.X.X * - * @var string + * @var string[] */ - protected $style_tag_atts = ''; + protected $style_tag_atts = array(); /** * Sets this provider's webfonts property. @@ -108,6 +110,23 @@ abstract public function get_css(); * @return string The style element. */ protected function get_style_element() { - return "\n"; + $attributes = $this->generate_style_element_attributes(); + + return "\n"; + } + + /** + * Gets the defined \n", $font_faces['Source Serif Pro-300-normal'], @@ -774,12 +774,12 @@ public function data_print_enqueued() { 'provider' => array( 'local' => $providers['local'] ), 'provider_handles' => array( 'local' => $local_font_handles ), 'registered' => $local_fonts, - 'enqueued' => array( 'merriweather', 'Source Serif Pro' ), + 'enqueued' => array( 'merriweather', 'source-serif-pro' ), ), 'expected_done' => array( 'merriweather', 'merriweather-200-900-normal', - 'Source Serif Pro', + 'source-serif-pro', 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic', ), @@ -835,11 +835,11 @@ public function data_print_enqueued() { ), ), 'print all local fonts when all providers registered' => array( - 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'merriweather', 'Source Serif Pro' ) ) ), + 'setup' => array_merge( $setup_all, array( 'enqueued' => array( 'merriweather', 'source-serif-pro' ) ) ), 'expected_done' => array( 'merriweather', 'merriweather-200-900-normal', - 'Source Serif Pro', + 'source-serif-pro', 'Source Serif Pro-300-normal', 'Source Serif Pro-900-italic', ), diff --git a/phpunit/webfonts/wpDeregisterFontFamily-test.php b/phpunit/webfonts/wpDeregisterFontFamily-test.php index a7e4db544e0ecd..2487053b6149c5 100644 --- a/phpunit/webfonts/wpDeregisterFontFamily-test.php +++ b/phpunit/webfonts/wpDeregisterFontFamily-test.php @@ -12,16 +12,16 @@ * @group webfonts * @group remove_webfonts * @covers ::wp_deregister_font_family - * @covers WP_Webfonts::remove_font_family + * @covers WP_Web_Fonts::remove_font_family */ class Tests_Webfonts_WpDeregisterFontFamily extends WP_Webfonts_TestCase { /** - * Unit test for registering a font-family that mocks WP_Webfonts. + * Unit test for registering a font-family that mocks WP_Web_Fonts. * * @dataProvider data_font_family_handles * - * @param string $font_family_handle Font font handle to test. + * @param string $font_family_handle Font family handle to test. */ public function test_unit_should_deregister( $font_family_handle ) { $mock = $this->set_up_mock( 'remove_font_family' ); diff --git a/phpunit/webfonts/wpDeregisterWebfontVariation-test.php b/phpunit/webfonts/wpDeregisterWebfontVariation-test.php index 14107dcdcb74f8..a6a0ab67ad4480 100644 --- a/phpunit/webfonts/wpDeregisterWebfontVariation-test.php +++ b/phpunit/webfonts/wpDeregisterWebfontVariation-test.php @@ -54,7 +54,7 @@ private function setup_integration_test() { public function test_mocked_setup( $font_family_handle, $variation_handle ) { $this->setup_unit_test(); - $this->assertArrayHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variation should be in the registered queue before remval' ); + $this->assertArrayHasKey( $variation_handle, $this->wp_webfonts->registered, 'Variation should be in the registered queue before removal' ); $this->assertContains( $variation_handle, $this->wp_webfonts->registered[ $font_family_handle ]->deps, 'Variation should be in its font family deps before removal' ); } @@ -80,14 +80,15 @@ public function test_should_deregister_when_mocked( $font_family_handle, $variat /** * Unit test. * - * @dataProvider data_remove_variations + * @dataProvider data_should_do_nothing * - * @param string $font_family_handle Font family for the variation. + * @param string $font_family Font family name. + * @param string $font_family_handle Font family handle. * @param string $variation_handle Variation handle to remove. */ - public function test_unit_should_do_nothing_when_variation_and_font_family_not_registered( $font_family_handle, $variation_handle ) { + public function test_unit_should_do_nothing_when_variation_and_font_family_not_registered( $font_family, $font_family_handle, $variation_handle ) { // Set up the test. - unset( $this->fonts_to_register[ $font_family_handle ] ); + unset( $this->fonts_to_register[ $font_family ] ); $this->setup_unit_test(); $registered_queue = $this->wp_webfonts->registered; @@ -101,14 +102,15 @@ public function test_unit_should_do_nothing_when_variation_and_font_family_not_r /** * Integration test. * - * @dataProvider data_remove_variations + * @dataProvider data_should_do_nothing * - * @param string $font_family_handle Font family for the variation. + * @param string $font_family Font family name. + * @param string $font_family_handle Font family handle. * @param string $variation_handle Variation handle to remove. */ - public function test_should_do_nothing_when_variation_and_font_family_not_registered( $font_family_handle, $variation_handle ) { + public function test_should_do_nothing_when_variation_and_font_family_not_registered( $font_family, $font_family_handle, $variation_handle ) { // Set up the test. - unset( $this->fonts_to_register[ $font_family_handle ] ); + unset( $this->fonts_to_register[ $font_family ] ); $this->setup_integration_test(); $registered_queue = $this->wp_webfonts->get_registered(); @@ -119,6 +121,26 @@ public function test_should_do_nothing_when_variation_and_font_family_not_regist $this->assertSameSets( $registered_queue, $this->wp_webfonts->get_registered(), 'Registered queue should not have changed' ); } + /** + * Data provider for testing removal of variations. + * + * @return array + */ + public function data_should_do_nothing() { + return array( + 'Font with 1 variation' => array( + 'font_family' => 'merriweather', + 'font_family_handle' => 'merriweather', + 'variation_handle' => 'merriweather-200-900-normal', + ), + 'Font with multiple variations' => array( + 'font_family' => 'Source Serif Pro', + 'font_family_handle' => 'source-serif-pro', + 'variation_handle' => 'Source Serif Pro-300-normal', + ), + ); + } + /** * Unit test. * diff --git a/phpunit/webfonts/wpGetWebfontProviders-test.php b/phpunit/webfonts/wpGetWebfontProviders-test.php index b1512669503d6b..2e64db09006e37 100644 --- a/phpunit/webfonts/wpGetWebfontProviders-test.php +++ b/phpunit/webfonts/wpGetWebfontProviders-test.php @@ -18,7 +18,7 @@ class Tests_Webfonts_WpGetWebfontProviders extends WP_Webfonts_TestCase { public function set_up() { parent::set_up(); - $this->providers_property = new ReflectionProperty( WP_Webfonts::class, 'providers' ); + $this->providers_property = new ReflectionProperty( WP_Web_Fonts::class, 'providers' ); $this->providers_property->setAccessible( true ); } diff --git a/phpunit/webfonts/wpRegisterFontFamily-test.php b/phpunit/webfonts/wpRegisterFontFamily-test.php index 87628329e51cf0..33e1730fd37c83 100644 --- a/phpunit/webfonts/wpRegisterFontFamily-test.php +++ b/phpunit/webfonts/wpRegisterFontFamily-test.php @@ -27,11 +27,11 @@ public function test_unit_register( $font_family, $expected_handle ) { $mock->expects( $this->once() ) ->method( 'add_font_family' ) ->with( - $this->identicalTo( $expected_handle ) + $this->identicalTo( $font_family ) ) ->will( $this->returnValue( $expected_handle ) ); - $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family should return true after registering' ); + $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family handle should be returned after registering' ); } /** @@ -45,7 +45,7 @@ public function test_unit_register( $font_family, $expected_handle ) { * @param string $expected_handle Expected registered handle. */ public function test_register( $font_family, $expected_handle ) { - $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family should return true after registering' ); + $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family handle should be returned after registering' ); $this->assertSame( array( $expected_handle ), $this->get_registered_handles(), 'After registering, the registry should contain the font family handle' ); } @@ -71,20 +71,6 @@ public function data_font_family() { ); } - /** - * Unit test for registering a font-family that mocks WP_Webfonts. - * - * @dataProvider data_invalid_font_family - * - * @param string $invalid_input Invalid input to test. - */ - public function test_unit_register_fails( $invalid_input ) { - $mock = $this->set_up_mock( 'add_font_family' ); - $mock->expects( $this->never() )->method( 'add_font_family' ); - - $this->assertNull( wp_register_font_family( $invalid_input ), 'Registering an invalid input should return null' ); - } - /** * Integration test for registering a font family. * diff --git a/phpunit/webfonts/wpRegisterWebfonts-test.php b/phpunit/webfonts/wpRegisterWebfonts-test.php index ccb0e9aed798f1..11dbf9d73c2ea3 100644 --- a/phpunit/webfonts/wpRegisterWebfonts-test.php +++ b/phpunit/webfonts/wpRegisterWebfonts-test.php @@ -11,8 +11,8 @@ /** * @group webfonts * @covers ::wp_register_webfonts - * @covers WP_Webfonts::add - * @covers WP_Webfonts::add_variation + * @covers WP_Web_Fonts::add + * @covers WP_Web_Fonts::add_variation */ class Tests_Webfonts_WpRegisterWebfonts extends WP_Webfonts_TestCase { use WP_Webfonts_Tests_Datasets; @@ -152,7 +152,7 @@ public function data_deprecated_structure() { ), ), 'expected' => array( - 'wp_register_webfonts' => array( 'merriweather' => true ), + 'wp_register_webfonts' => array( 'merriweather' ), 'get_registered' => array( 'merriweather', 'merriweather-200-900-normal' ), ), ), @@ -180,7 +180,7 @@ public function data_deprecated_structure() { ), ), 'expected' => array( - 'wp_register_webfonts' => array( 'source-serif-pro' => true ), + 'wp_register_webfonts' => array( 'source-serif-pro' ), 'get_registered' => array( 'source-serif-pro', 'source-serif-pro-300-normal', @@ -221,16 +221,13 @@ public function data_deprecated_structure() { ), ), 'expected' => array( - 'wp_register_webfonts' => array( - 'source-serif-pro' => true, - 'merriweather' => true, - ), + 'wp_register_webfonts' => array( 'source-serif-pro', 'merriweather' ), 'get_registered' => array( 'source-serif-pro', 'source-serif-pro-300-normal', + 'source-serif-pro-900-italic', 'merriweather', 'merriweather-200-900-normal', - 'source-serif-pro-900-italic', ), ), ), diff --git a/phpunit/webfonts/wpWebfonts-test.php b/phpunit/webfonts/wpWebfonts-test.php index 32067a9fa61c9a..17ab8c60583fae 100644 --- a/phpunit/webfonts/wpWebfonts-test.php +++ b/phpunit/webfonts/wpWebfonts-test.php @@ -15,14 +15,14 @@ class Tests_Webfonts_WpWebfonts extends WP_Webfonts_TestCase { public function test_returns_instance() { - $this->assertInstanceOf( WP_Webfonts::class, wp_webfonts() ); + $this->assertInstanceOf( WP_Web_Fonts::class, wp_webfonts() ); } public function test_global_set() { global $wp_webfonts; $this->assertNull( $wp_webfonts ); $instance = wp_webfonts(); - $this->assertInstanceOf( WP_Webfonts::class, $wp_webfonts ); + $this->assertInstanceOf( WP_Web_Fonts::class, $wp_webfonts ); $this->assertSame( $instance, $wp_webfonts ); } diff --git a/phpunit/webfonts/wpWebfonts/add-test.php b/phpunit/webfonts/wpWebfonts/add-test.php index 91c79bf1542a6f..a432c7e8572129 100644 --- a/phpunit/webfonts/wpWebfonts/add-test.php +++ b/phpunit/webfonts/wpWebfonts/add-test.php @@ -1,6 +1,6 @@ assertTrue( $wp_webfonts->add( $handle, false ), 'Registering a handle should return true' ); $this->assertCount( 1, $wp_webfonts->registered ); diff --git a/phpunit/webfonts/wpWebfonts/addFontFamily-test.php b/phpunit/webfonts/wpWebfonts/addFontFamily-test.php index 84780c8dd57dcf..4aa5e55b1ef3cb 100644 --- a/phpunit/webfonts/wpWebfonts/addFontFamily-test.php +++ b/phpunit/webfonts/wpWebfonts/addFontFamily-test.php @@ -1,6 +1,6 @@ add_font_family( $font_family ); - $this->assertTrue( $wp_webfonts->add_font_family( $handle ), 'Registering a handle should return true' ); + $this->assertSame( $expected, $font_family_handle, 'Registering a font-family should return its handle' ); $this->assertCount( 1, $wp_webfonts->registered ); - $this->assertArrayHasKey( $handle, $wp_webfonts->registered, 'Font family handle should be in the registry after registration' ); + $this->assertArrayHasKey( $font_family_handle, $wp_webfonts->registered, 'Font family handle should be in the registry after registration' ); } @@ -35,11 +37,30 @@ public function test_should_register( $handle ) { */ public function data_handles() { return array( - 'name: multiple' => array( 'Source Serif Pro' ), - 'handle: multiple' => array( 'source-serif-pro' ), - 'name: single' => array( 'Merriweather' ), - 'handle: single' => array( 'merriweather' ), - 'handle: variation' => array( 'my-custom-font-200-900-normal' ), + 'name: multiple' => array( + 'font_family' => 'Source Serif Pro', + 'expected' => 'source-serif-pro', + ), + 'handle: multiple' => array( + 'font_family' => 'source-serif-pro', + 'expected' => 'source-serif-pro', + ), + 'name: single' => array( + 'font_family' => 'Merriweather', + 'expected' => 'merriweather', + ), + 'handle: single' => array( + 'font_family' => 'merriweather', + 'expected' => 'merriweather', + ), + 'handle: variation' => array( + 'font_family' => 'my-custom-font-200-900-normal', + 'expected' => 'my-custom-font-200-900-normal', + ), + 'name: multiple font-families' => array( + 'font_family' => 'Source Serif Pro, Merriweather', + 'expected' => 'source-serif-pro', + ), ); } } diff --git a/phpunit/webfonts/wpWebfonts/addVariation-test.php b/phpunit/webfonts/wpWebfonts/addVariation-test.php index 809cc41f84e585..5f948b81fd146b 100644 --- a/phpunit/webfonts/wpWebfonts/addVariation-test.php +++ b/phpunit/webfonts/wpWebfonts/addVariation-test.php @@ -1,6 +1,6 @@ add( $font_family_handle, false ); $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); @@ -41,7 +41,7 @@ public function test_should_register_variation_when_font_family_is_registered( $ * @param string $variation_handle Optional. The variation's handle. */ public function test_should_not_reregister_font_family( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); $wp_webfonts->add( $font_family_handle, false ); $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); @@ -60,7 +60,7 @@ public function test_should_not_reregister_font_family( $expected, $font_family_ * @param string $variation_handle Optional. The variation's handle. */ public function test_should_not_reregister_variation( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); $wp_webfonts->add( $font_family_handle, false ); // Set up the test. @@ -85,7 +85,7 @@ public function test_should_not_reregister_variation( $expected, $font_family_ha * @param string $variation_handle Optional. The variation's handle. */ public function test_should_register_font_family_and_variation( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); $variation_handle = $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); $this->assertSame( $expected, $variation_handle, 'Variation should return its registered handle' ); @@ -107,7 +107,7 @@ public function test_should_not_register_font_family_or_variant( $font_family_ha $this->expectNotice(); $this->expectNoticeMessage( 'Font family handle must be a non-empty string.' ); - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); $wp_webfonts->add_variation( $font_family_handle, $variation ); $this->assertEmpty( $wp_webfonts->registered, 'Registered queue should be empty' ); @@ -116,7 +116,7 @@ public function test_should_not_register_font_family_or_variant( $font_family_ha /** * @dataProvider data_font_family_undefined_in_variation - * @dataProvider data_unable_determine_variation_handle + * @dataProviders data_unable_determine_variation_handle * * @param string $font_family_handle The font family's handle for this variation. * @param array $variation An array of variation properties to add. @@ -126,7 +126,7 @@ public function test_should_not_register_variation_when_font_family_not_defined( $this->expectNotice(); $this->expectNoticeMessage( $expected_message ); - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); $this->assertNull( $wp_webfonts->add_variation( $font_family_handle, $variation ) ); } @@ -140,7 +140,7 @@ public function test_should_register_font_family_when_variant_fails_to_register( $this->expectNotice(); $this->expectNoticeMessage( 'Variant handle could not be determined as font-weight and/or font-style are require' ); - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); $wp_webfonts->add_variation( $font_family_handle, $variation ); $this->assertCount( 1, $wp_webfonts->registered ); diff --git a/phpunit/webfonts/wpWebfonts/dequeue-test.php b/phpunit/webfonts/wpWebfonts/dequeue-test.php index d5e49c1aa8f929..c4959958a2ccf4 100644 --- a/phpunit/webfonts/wpWebfonts/dequeue-test.php +++ b/phpunit/webfonts/wpWebfonts/dequeue-test.php @@ -1,6 +1,6 @@ dequeue( $handles ); $this->assertEmpty( $this->get_queued_before_register( $wp_webfonts ), 'Prequeue should be empty' ); @@ -37,7 +37,7 @@ public function test_should_do_nothing_when_handles_not_queued( $handles ) { * @param string|string[] $handles Handles to test. */ public function test_should_dequeue_from_queue( $handles ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); // Register and enqueue. foreach ( $this->get_data_registry() as $handle => $variations ) { @@ -62,7 +62,7 @@ public function test_should_dequeue_from_queue( $handles ) { * @param string|string[] $handles Handles to test. */ public function test_should_dequeue_from_prequeue( $handles ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); $wp_webfonts->enqueue( $handles ); $this->assertNotEmpty( $this->get_queued_before_register( $wp_webfonts ), 'Prequeue not be empty before dequeueing' ); diff --git a/phpunit/webfonts/wpWebfonts/doItem-test.php b/phpunit/webfonts/wpWebfonts/doItem-test.php index e37590c6c01e2f..e54b909f83429e 100644 --- a/phpunit/webfonts/wpWebfonts/doItem-test.php +++ b/phpunit/webfonts/wpWebfonts/doItem-test.php @@ -1,6 +1,6 @@ wp_webfonts = new WP_Webfonts; + $this->wp_webfonts = new WP_Web_Fonts; } public function test_should_return_false_when_provider_not_registered() { @@ -63,20 +63,20 @@ public function test_mocking_providers_property() { ); $this->setup_provider_property_mock( $this->wp_webfonts, $this->get_provider_definitions( 'mock' ), $font_handles ); - $actual = $this->property['WP_Webfonts::$providers']->getValue( $this->wp_webfonts ); + $actual = $this->property['WP_Web_Fonts::$providers']->getValue( $this->wp_webfonts ); $this->assertSame( $expected, $actual ); } /** - * Test the private method WP_Webfonts::get_enqueued_fonts_for_provider(). + * Test the private method WP_Web_Fonts::get_enqueued_fonts_for_provider(). * * Why? This test validates the right fonts are returned for use within - * WP_Webfonts::do_item(). + * WP_Web_Fonts::do_item(). * * @dataProvider data_get_enqueued_fonts_for_provider * * @param array $font_handles Array of handles for the provider. - * @param array $to_do Handles to set for the WP_Webfonts::$to_do property. + * @param array $to_do Handles to set for the WP_Web_Fonts::$to_do property. * @param array $expected Expected result. */ public function test_get_enqueued_fonts_for_provider( $font_handles, $to_do, $expected ) { @@ -86,7 +86,7 @@ public function test_get_enqueued_fonts_for_provider( $font_handles, $to_do, $ex // Open the method's visibility for testing. $get_enqueued_fonts_for_provider = $this->get_reflection_method( 'get_enqueued_fonts_for_provider' ); - // Mock the WP_Webfonts::$property to set up the test. + // Mock the WP_Web_Fonts::$property to set up the test. $this->setup_provider_property_mock( $this->wp_webfonts, $this->get_provider_definitions( 'mock' ), $font_handles ); $actual = $get_enqueued_fonts_for_provider->invoke( $this->wp_webfonts, 'mock' ); @@ -124,10 +124,10 @@ public function data_get_enqueued_fonts_for_provider() { } /** - * Test the private method WP_Webfonts::get_font_properties_for_provider(). + * Test the private method WP_Web_Fonts::get_font_properties_for_provider(). * * Why? This test validates the right font properties are returned for use within - * WP_Webfonts::do_item(). + * WP_Web_Fonts::do_item(). * * @dataProvider data_get_font_properties_for_provider * @@ -139,7 +139,7 @@ public function test_get_font_properties_for_provider( $font_handles, $expected $fonts = $this->get_registered_fonts(); // Set all variations to 'mock' provider. - // Mock the WP_Webfonts::$property to set up the test. + // Mock the WP_Web_Fonts::$property to set up the test. $this->setup_provider_property_mock( $this->wp_webfonts, $this->get_provider_definitions( 'mock' ), $font_handles ); $this->setup_registration_mocks( $fonts, $this->wp_webfonts ); @@ -193,13 +193,13 @@ public function test_should_trigger_provider_when_mocked( array $provider, array $provider_mock->expects( $this->once() )->method( 'set_webfonts' )->with( $this->identicalTo( $expected['set_webfonts'] ) ); $provider_mock->expects( $this->once() )->method( 'print_styles' ); - // Set up the WP_Webfonts::$provider_instances property. + // Set up the WP_Web_Fonts::$provider_instances property. $provider_instances = $this->get_reflection_property( 'provider_instances' ); $provider_instances->setValue( $this->wp_webfonts, array( $provider['id'] => $provider_mock ) ); // Test the method successfully processes the provider. $this->expectOutputString( '' ); - $this->assertTrue( $this->wp_webfonts->do_item( $provider['id'] ), 'WP_Webfonts::do_item() should return true' ); + $this->assertTrue( $this->wp_webfonts->do_item( $provider['id'] ), 'WP_Web_Fonts::do_item() should return true' ); } /** @@ -216,7 +216,7 @@ public function test_should_print( array $provider, array $fonts, array $expecte // Test the method successfully processes the provider. $this->expectOutputString( $expected['printed_output'] ); - $this->assertTrue( $this->wp_webfonts->do_item( $provider['id'] ), 'WP_Webfonts::do_item() should return true' ); + $this->assertTrue( $this->wp_webfonts->do_item( $provider['id'] ), 'WP_Web_Fonts::do_item() should return true' ); } /** @@ -270,14 +270,14 @@ public function data_print_enqueued_fonts() { * @param array $provider Define provider. * @param array $fonts Fonts to register and enqueue. * @param array $expected Not used. - * @param array $to_do_queue Value to set in the WP_Webfonts::$to_do queue. + * @param array $to_do_queue Value to set in the WP_Web_Fonts::$to_do queue. */ public function test_should_not_print_when_to_do_queue_empty( array $provider, array $fonts, $expected, $to_do_queue ) { $this->setup_print_deps( $provider, $fonts, $to_do_queue ); // Test the method successfully processes the provider. $this->expectOutputString( '' ); - $this->assertFalse( $this->wp_webfonts->do_item( $provider['id'] ), 'WP_Webfonts::do_item() should return false' ); + $this->assertFalse( $this->wp_webfonts->do_item( $provider['id'] ), 'WP_Web_Fonts::do_item() should return false' ); } /** @@ -316,7 +316,7 @@ public function data_not_print_enqueued_fonts() { * * @param array $provider Provider id and class. * @param array $fonts Fonts to register and enqueue. - * @param array|null $to_do_queue Set the WP_Webfonts:$to_do queue. + * @param array|null $to_do_queue Set the WP_Web_Fonts:$to_do queue. */ private function setup_print_deps( $provider, $fonts, $to_do_queue = null ) { // Set up the fonts for WP_Dependencies:get_data(). @@ -324,7 +324,7 @@ private function setup_print_deps( $provider, $fonts, $to_do_queue = null ) { $handles = array_keys( $mocks ); $this->setup_provider_property_mock( $this->wp_webfonts, $provider, $handles ); - // Set up the `WP_Webfonts::$to_do` and `WP_Webfonts::$to_do_keyed_handles` properties. + // Set up the `WP_Web_Fonts::$to_do` and `WP_Web_Fonts::$to_do_keyed_handles` properties. if ( null === $to_do_queue ) { $to_do_queue = $handles; } diff --git a/phpunit/webfonts/wpWebfonts/doItems-test.php b/phpunit/webfonts/wpWebfonts/doItems-test.php index ee7aca2304a30e..da4c338f86338e 100644 --- a/phpunit/webfonts/wpWebfonts/doItems-test.php +++ b/phpunit/webfonts/wpWebfonts/doItems-test.php @@ -1,6 +1,6 @@ wp_webfonts = new WP_Webfonts; + $this->wp_webfonts = new WP_Web_Fonts; } public function test_should_not_process_when_no_providers_registered() { @@ -27,8 +27,8 @@ public function test_should_not_process_when_no_providers_registered() { $done = $this->wp_webfonts->do_items(); - $this->assertSame( array(), $done, 'WP_Webfonts::do_items() should return an empty array' ); - $this->assertSame( array(), $this->wp_webfonts->to_do, 'WP_Webfonts::$to_do should be an empty array' ); + $this->assertSame( array(), $done, 'WP_Web_Fonts::do_items() should return an empty array' ); + $this->assertSame( array(), $this->wp_webfonts->to_do, 'WP_Web_Fonts::$to_do should be an empty array' ); } public function test_should_throw_notice_when_queue_is_empty() { @@ -141,7 +141,7 @@ public function test_should_print_enqueued( $setup, $expected_done, $expected_ou */ public function test_should_print_handles_when_not_enqueued( $setup, $expected_done, $expected_output ) { $this->setup_integrated_deps( $setup, false ); - // Do not enqueue. Instead, pass the handles to WP_Webfonts::do_items(). + // Do not enqueue. Instead, pass the handles to WP_Web_Fonts::do_items(). $handles = $setup['enqueued']; $this->assertEmpty( $this->wp_webfonts->queue, 'No fonts should be enqueued' ); diff --git a/phpunit/webfonts/wpWebfonts/enqueue-test.php b/phpunit/webfonts/wpWebfonts/enqueue-test.php index 770e4079aca8c4..dde2d92c6df377 100644 --- a/phpunit/webfonts/wpWebfonts/enqueue-test.php +++ b/phpunit/webfonts/wpWebfonts/enqueue-test.php @@ -1,6 +1,6 @@ enqueue( $handles ); $this->assertSame( $expected, $this->get_queued_before_register( $wp_webfonts ), 'Handles should be added to before registered queue' ); @@ -34,15 +34,15 @@ public function test_should_prequeue_when_not_registered( $handles, $not_used, $ * Integration test for enqueuing (a) a font family and all of its variations or (b) specific variations. * * @dataProvider data_enqueue - * @dataProvider data_enqueue_variations + * @dataProviders data_enqueue_variations * * @param string|string[] $handles Handles to test. * @param array $expected Expected queue. */ public function test_should_enqueue_when_registered( $handles, array $expected ) { - $wp_webfonts = new WP_Webfonts(); - foreach ( $this->get_data_registry() as $handle => $variations ) { - $this->setup_register( $handle, $variations, $wp_webfonts ); + $wp_webfonts = new WP_Web_Fonts(); + foreach ( $this->get_data_registry() as $font_family => $variations ) { + $this->setup_register( $font_family, $variations, $wp_webfonts ); } $wp_webfonts->enqueue( $handles ); diff --git a/phpunit/webfonts/wpWebfonts/getEnqueued-test.php b/phpunit/webfonts/wpWebfonts/getEnqueued-test.php index 7783f34b16c33c..63ea923c085f54 100644 --- a/phpunit/webfonts/wpWebfonts/getEnqueued-test.php +++ b/phpunit/webfonts/wpWebfonts/getEnqueued-test.php @@ -1,6 +1,6 @@ assertEmpty( $wp_webfonts->get_enqueued() ); } @@ -28,7 +28,7 @@ public function test_should_return_empty_when_non_enqueued() { * @param array $expected Expected queue. */ public function test_should_return_queue_when_property_has_font_families( $not_used, array $expected ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); $wp_webfonts->queue = $expected; $this->assertSame( $expected, $wp_webfonts->get_enqueued() ); @@ -44,7 +44,7 @@ public function test_should_return_queue_when_property_has_font_families( $not_u * @param array $expected Expected queue. */ public function test_should_return_queue_when_font_families_registered_and_enqueued( $font_family, array $expected ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); // Register and enqueue. foreach ( $this->get_data_registry() as $handle => $variations ) { diff --git a/phpunit/webfonts/wpWebfonts/getProviders-test.php b/phpunit/webfonts/wpWebfonts/getProviders-test.php index 527c45cb614263..7aa758582cb7c7 100644 --- a/phpunit/webfonts/wpWebfonts/getProviders-test.php +++ b/phpunit/webfonts/wpWebfonts/getProviders-test.php @@ -1,6 +1,6 @@ wp_webfonts = new WP_Webfonts(); + $this->wp_webfonts = new WP_Web_Fonts(); - $this->providers_property = new ReflectionProperty( WP_Webfonts::class, 'providers' ); + $this->providers_property = new ReflectionProperty( WP_Web_Fonts::class, 'providers' ); $this->providers_property->setAccessible( true ); } @@ -43,7 +43,7 @@ public function test_get_providers( array $providers, array $expected ) { } /** - * Sets up the given providers and stores them in the `WP_Webfonts::providers` property. + * Sets up the given providers and stores them in the `WP_Web_Fonts::providers` property. * * @param array $providers Array of providers to set up. */ diff --git a/phpunit/webfonts/wpWebfonts/getRegistered-test.php b/phpunit/webfonts/wpWebfonts/getRegistered-test.php index 0160d85552bec9..76b0ab3a5d097c 100644 --- a/phpunit/webfonts/wpWebfonts/getRegistered-test.php +++ b/phpunit/webfonts/wpWebfonts/getRegistered-test.php @@ -1,6 +1,6 @@ assertEmpty( $wp_webfonts->get_registered() ); } @@ -28,7 +28,7 @@ public function test_should_return_empty_when_none_registered() { * @param array $inputs Font family(ies) and variations to register. */ public function test_should_return_queue_when_mocking_registered_property( array $inputs ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); $mocks = $this->setup_registration_mocks( $inputs, $wp_webfonts ); $expected = array_keys( $mocks ); @@ -78,7 +78,7 @@ public function data_get_registered() { * @param array $expected Expected results. */ public function test_should_return_queue_when_items_are_registered( $font_family, array $inputs, array $expected ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); // Register before testing. foreach ( $inputs as $handle => $variations ) { diff --git a/phpunit/webfonts/wpWebfonts/query-test.php b/phpunit/webfonts/wpWebfonts/query-test.php index ced376555cccb8..75b44b2717f2b9 100644 --- a/phpunit/webfonts/wpWebfonts/query-test.php +++ b/phpunit/webfonts/wpWebfonts/query-test.php @@ -1,6 +1,6 @@ wp_webfonts = new WP_Webfonts(); + $this->wp_webfonts = new WP_Web_Fonts(); } /** @@ -99,7 +99,7 @@ public function data_valid_query() { return array( 'lato' => array( 'lato' ), 'merriweather' => array( 'merriweather' ), - 'Source Serif Pro' => array( 'Source Serif Pro' ), + 'Source Serif Pro' => array( 'source-serif-pro' ), ); } @@ -139,7 +139,7 @@ public function test_done_query_should_succeed_when_registered_and_enqueued( $qu public function data_done_query() { return array( 'merriweather' => array( 'merriweather' ), - 'Source Serif Pro' => array( 'Source Serif Pro' ), + 'Source Serif Pro' => array( 'source-serif-pro' ), ); } diff --git a/phpunit/webfonts/wpWebfonts/registerProvider-test.php b/phpunit/webfonts/wpWebfonts/registerProvider-test.php index 9e1423cfdf53ae..b73623259fcf48 100644 --- a/phpunit/webfonts/wpWebfonts/registerProvider-test.php +++ b/phpunit/webfonts/wpWebfonts/registerProvider-test.php @@ -1,6 +1,6 @@ assertTrue( $wp_webfonts->register_provider( $provider_id, $class ), 'WP_Webfonts::register_provider() should return true' ); + $wp_webfonts = new WP_Web_Fonts(); + $this->assertTrue( $wp_webfonts->register_provider( $provider_id, $class ), 'WP_Web_Fonts::register_provider() should return true' ); $this->assertSame( $expected, $wp_webfonts->get_providers(), 'Provider "' . $provider_id . '" should be registered in providers queue' ); } @@ -59,10 +59,10 @@ public function data_register_providers() { } public function test_should_register_mutliple_providers() { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); $providers = $this->get_provider_definitions(); foreach ( $providers as $provider ) { - $this->assertTrue( $wp_webfonts->register_provider( $provider['id'], $provider['class'] ), 'WP_Webfonts::register_provider() should return true for provider ' . $provider['id'] ); + $this->assertTrue( $wp_webfonts->register_provider( $provider['id'], $provider['class'] ), 'WP_Web_Fonts::register_provider() should return true for provider ' . $provider['id'] ); } $expected = array( @@ -86,9 +86,9 @@ public function test_should_register_mutliple_providers() { * @param string $class Provider class name. */ public function test_should_not_register( $provider_id, $class ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); - $this->assertFalse( $wp_webfonts->register_provider( $provider_id, $class ), 'WP_Webfonts::register_provider() should return false' ); + $this->assertFalse( $wp_webfonts->register_provider( $provider_id, $class ), 'WP_Web_Fonts::register_provider() should return false' ); $this->assertArrayNotHasKey( $provider_id, $wp_webfonts->get_providers(), 'Both local and mock providers should be registered' ); } diff --git a/phpunit/webfonts/wpWebfonts/remove-test.php b/phpunit/webfonts/wpWebfonts/remove-test.php index f595755e85927a..86cf9fa6ad1bac 100644 --- a/phpunit/webfonts/wpWebfonts/remove-test.php +++ b/phpunit/webfonts/wpWebfonts/remove-test.php @@ -1,6 +1,6 @@ remove( array( 'handle-1', 'handle2' ) ); @@ -30,7 +30,7 @@ public function test_should_not_remove_when_none_registered() { * @param array $expected Expected handles are running test. */ public function test_should_remove_when_registered( array $handles, array $expected ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); $wp_webfonts->registered = $this->generate_registered_queue(); $wp_webfonts->remove( $handles ); diff --git a/phpunit/webfonts/wpWebfonts/removeFontFamily-test.php b/phpunit/webfonts/wpWebfonts/removeFontFamily-test.php index 5cede6476582bd..959744e555202f 100644 --- a/phpunit/webfonts/wpWebfonts/removeFontFamily-test.php +++ b/phpunit/webfonts/wpWebfonts/removeFontFamily-test.php @@ -1,6 +1,6 @@ setup_registration_mocks( $inputs, $wp_webfonts ); // Test the before state, just to make sure. $this->assertArrayHasKey( $font_family, $wp_webfonts->registered, 'Registered queue should contain the font family before remove' ); @@ -45,7 +45,7 @@ public function test_should_dequeue_when_mocks_registered( $font_family, array $ * @param array $expected Array of expected handles. */ public function test_should_bail_out_when_not_registered( $font_family, array $inputs, array $registered_handles, array $expected ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); unset( $inputs[ $font_family ] ); $this->setup_registration_mocks( $inputs, $wp_webfonts ); @@ -66,10 +66,10 @@ public function test_should_bail_out_when_not_registered( $font_family, array $i * @param array $expected Array of expected handles. */ public function test_should_deregister_when_registered( $font_family, array $inputs, array $registered_handles, array $expected ) { - $wp_webfonts = new WP_Webfonts(); + $wp_webfonts = new WP_Web_Fonts(); // Register all font families and their variations. - foreach ( $inputs as $handle => $variations ) { - $wp_webfonts->add( $handle, false ); + foreach ( $inputs as $input_font_family => $variations ) { + $handle = $wp_webfonts->add_font_family( $input_font_family ); foreach ( $variations as $variation_handle => $variation ) { if ( ! is_string( $variation_handle ) ) { $variation_handle = ''; diff --git a/phpunit/webfonts/wpWebfonts/removeVariation-test.php b/phpunit/webfonts/wpWebfonts/removeVariation-test.php index f82dbf0f4576af..dd3b21a9573eaa 100644 --- a/phpunit/webfonts/wpWebfonts/removeVariation-test.php +++ b/phpunit/webfonts/wpWebfonts/removeVariation-test.php @@ -1,6 +1,6 @@ wp_webfonts = new WP_Webfonts(); + $this->wp_webfonts = new WP_Web_Fonts(); $this->fonts_to_register = $this->get_registered_local_fonts(); } /** * Sets up the unit test by mocking the WP_Dependencies object using stdClass and - * registering each font family directly to the WP_Webfonts::$registered property + * registering each font family directly to the WP_Web_Fonts::$registered property * and its variations to the mocked $deps property. */ private function setup_unit_test() { @@ -34,7 +34,7 @@ private function setup_unit_test() { /** * Sets up the integration test by properly registering each font family and its variations - * by using the WP_Webfonts::add() and WP_Webfonts::add_variation() methods. + * by using the WP_Web_Fonts::add() and WP_Web_Fonts::add_variation() methods. */ private function setup_integration_test() { foreach ( $this->fonts_to_register as $font_family_handle => $variations ) { @@ -60,14 +60,15 @@ public function test_mocked_setup( $font_family_handle, $variation_handle ) { /** * Unit test. * - * @dataProvider data_remove_variations + * @dataProvider data_should_do_nothing_when_variation_and_font_family_not_registered * - * @param string $font_family_handle Font family for the variation. + * @param string $font_family Font family name. + * @param string $font_family_handle Font family handle. * @param string $variation_handle Variation handle to remove. */ - public function test_unit_should_do_nothing_when_variation_and_font_family_not_registered( $font_family_handle, $variation_handle ) { + public function test_unit_should_do_nothing_when_variation_and_font_family_not_registered( $font_family, $font_family_handle, $variation_handle ) { // Set up the test. - unset( $this->fonts_to_register[ $font_family_handle ] ); + unset( $this->fonts_to_register[ $font_family ] ); $this->setup_unit_test(); $registered_queue = $this->wp_webfonts->registered; @@ -81,14 +82,15 @@ public function test_unit_should_do_nothing_when_variation_and_font_family_not_r /** * Integration test. * - * @dataProvider data_remove_variations + * @dataProvider data_should_do_nothing_when_variation_and_font_family_not_registered * - * @param string $font_family_handle Font family for the variation. + * @param string $font_family Font family name. + * @param string $font_family_handle Font family handle. * @param string $variation_handle Variation handle to remove. */ - public function test_should_do_nothing_when_variation_and_font_family_not_registered( $font_family_handle, $variation_handle ) { + public function test_should_do_nothing_when_variation_and_font_family_not_registered( $font_family, $font_family_handle, $variation_handle ) { // Set up the test. - unset( $this->fonts_to_register[ $font_family_handle ] ); + unset( $this->fonts_to_register[ $font_family ] ); $this->setup_integration_test(); $registered_queue = $this->wp_webfonts->get_registered(); @@ -99,6 +101,26 @@ public function test_should_do_nothing_when_variation_and_font_family_not_regist $this->assertSameSets( $registered_queue, $this->wp_webfonts->get_registered(), 'Registered queue should not have changed' ); } + /** + * Data provider for testing removal of variations. + * + * @return array + */ + public function data_should_do_nothing_when_variation_and_font_family_not_registered() { + return array( + 'Font with 1 variation' => array( + 'font_family' => 'merriweather', + 'font_family_handle' => 'merriweather', + 'variation_handle' => 'merriweather-200-900-normal', + ), + 'Font with multiple variations' => array( + 'font_family' => 'Source Serif Pro', + 'font_family_handle' => 'source-serif-pro', + 'variation_handle' => 'Source Serif Pro-300-normal', + ), + ); + } + /** * Unit test. * @@ -246,7 +268,7 @@ private function setup_remove_from_font_family_deps( $font_family_handle, $varia } /** - * Removes the variation from the WP_Webfonts::$registered queue. + * Removes the variation from the WP_Web_Fonts::$registered queue. * * @param string $variation_handle The variation handle to remove. */ From b42bba8220b49a2cd2f905bbacd7f0878db865d3 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 14 Dec 2022 08:07:23 -0600 Subject: [PATCH 56/63] Add web fonts CSS to Site Editor iframe assets --- lib/compat/wordpress-6.2/script-loader.php | 20 ++++++++++++++++++++ lib/experimental/webfonts.php | 8 ++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/compat/wordpress-6.2/script-loader.php b/lib/compat/wordpress-6.2/script-loader.php index 84681b31512386..72540a48e58708 100644 --- a/lib/compat/wordpress-6.2/script-loader.php +++ b/lib/compat/wordpress-6.2/script-loader.php @@ -125,6 +125,26 @@ function gutenberg_resolve_assets_override() { $scripts = ob_get_clean(); + /* + * Generate web font @font-face styles for the site editor iframe. + * Use the registered font families for printing. + */ + $wp_webfonts = wp_webfonts(); + $registered = $wp_webfonts->get_registered_font_families(); + $queue = $wp_webfonts->queue; + $done = $wp_webfonts->done; + + $wp_webfonts->done = array(); + $wp_webfonts->queue = $registered; + + ob_start(); + $wp_webfonts->do_items(); + $styles .= ob_get_clean(); + + // Reset the Web Fonts API. + $wp_webfonts->done = $done; + $wp_webfonts->queue = $queue; + return array( 'styles' => $styles, 'scripts' => $scripts, diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index 5fc5b9a154f333..90578fba29f747 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -236,13 +236,13 @@ function wp_get_webfont_providers() { function wp_print_webfonts( $handles = false ) { global $wp_webfonts; - if ( '' === $handles ) { // For 'wp_head'. + if ( empty( $handles ) ) { $handles = false; } _wp_scripts_maybe_doing_it_wrong( __FUNCTION__ ); - if ( ! ( $wp_webfonts instanceof WP_Webfonts ) ) { + if ( ! ( $wp_webfonts instanceof WP_Web_Fonts ) ) { if ( ! $handles ) { return array(); // No need to instantiate if nothing is there. } @@ -252,8 +252,8 @@ function wp_print_webfonts( $handles = false ) { } } -add_action( 'admin_print_styles', 'wp_print_webfonts' ); -add_action( 'wp_head', 'wp_print_webfonts' ); +add_action( 'admin_print_styles', 'wp_print_webfonts', 50 ); +add_action( 'wp_head', 'wp_print_webfonts', 50 ); /** * Add webfonts mime types. From f6c541b642a102174ac7fafe9d926d474e199589 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 14 Dec 2022 10:27:39 -0600 Subject: [PATCH 57/63] Make deprecated methods work --- lib/experimental/class-wp-webfonts.php | 104 ++++++++++++++++++++----- 1 file changed, 84 insertions(+), 20 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index ead5e3163d22fd..7b2554de642436 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -1,10 +1,15 @@ get_registered()' ); - return $this->registered; + return $this->_get_registered_webfonts(); } /** @@ -100,7 +93,7 @@ public function get_enqueued_webfonts() { public function get_all_webfonts() { _deprecated_function( __METHOD__, 'X.X.X', 'wp_webfonts()->get_registered()' ); - return $this->get_registered(); + return $this->_get_registered_webfonts(); } /** @@ -147,7 +140,7 @@ public function register_webfont( array $webfont, $font_family_handle = '', $var public function enqueue_webfont( $font_family_name ) { _deprecated_function( __METHOD__, 'X.X.X', 'wp_webfonts()->enqueue() or wp_enqueue_webfont()' ); - $slug = static::get_font_slug( $font_family_name ); + $slug = static::_get_font_slug( $font_family_name ); if ( isset( $this->enqueued[ $slug ] ) ) { return true; @@ -223,4 +216,75 @@ protected function extract_font_family_from_deprecated_webfonts_structure( array return WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); } + + /** + * Gets the font slug. + * + * Helper function for reuse without the deprecation. + * + * @param array|string $to_convert The value to convert into a slug. Expected as the web font's array + * or a font-family as a string. + * @return string|false The font slug on success, or false if the font-family cannot be determined. + */ + private static function _get_font_slug( $to_convert ) { + $font_family_name = is_array( $to_convert ) ? WP_Webfonts_Utils::get_font_family_from_variation( $to_convert ) : $to_convert; + return ! empty( $font_family_name ) + ? WP_Webfonts_Utils::convert_font_family_into_handle( $font_family_name ) + : false; + } + + /** + * Gets the registered webfonts in the original web font property structure keyed by each handle. + * + * @return array[] + */ + private function _get_registered_webfonts() { + $registered = array(); + foreach ( $this->registered as $handle => $obj ) { + // Skip the font-family. + if ( $obj->extra['is_font_family'] ) { + continue; + } + + $registered[ $handle ] = $obj->extra['font-properties']; + } + + return $registered; + } + + /** + * Gets the enqueued webfonts in the original web font property structure keyed by each handle. + * + * @return array[] + */ + private function _get_enqueued_webfonts() { + $enqueued = array(); + foreach ( $this->queue as $handle ) { + // Skip if not registered. + if ( ! isset( $this->registered[ $handle ] ) ) { + continue; + } + + // Skip if already found. + if ( isset( $enqueued[ $handle ] ) ) { + continue; + } + + $obj = $this->registered[ $handle ]; + + // If a variation, add it. + if ( ! $obj->extra['is_font_family'] ) { + $enqueued[ $handle ] = $obj->extra['font-properties']; + continue; + } + + // If font-family, add all of its variations. + foreach ( $obj->deps as $variation_handle ) { + $obj = $this->registered[ $variation_handle ]; + $enqueued[ $variation_handle ] = $obj->extra['font-properties']; + } + } + + return $enqueued; + } } From 15b075dd89adc07f1906172aceca196a7fcd8c72 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 14 Dec 2022 10:45:50 -0600 Subject: [PATCH 58/63] Removes or deprecates redundant global functions Why? Primary reason is to reduce the amount of code that Core will need to maintain. If not adding value, then remove it. 1. Each is a wrapper for `wp_webfonts()->method_name()`. 2. There's no extra context or meaning to providing these wrappers. 3. Each is likely not needed by the majority of extenders. For those extenders who need access to this functionality, they can use the `WP_Web_Fonts` methods instead: * Deprecated wp_get_webfont_providers() Instead use wp_webfonts()->get_providers() * Removed wp_register_font_family() Instead pass an array keyed by the font-family with an empty array to wp_register_webfonts(). For example, wp_register_webfonts( array( 'Lato' => array() ) ); * Removed wp_register_webfont_variation() Instead use wp_register_webfonts(). Why? To ensure the font-family is also registered. A variation needs to have a font-family. --- lib/experimental/webfonts-deprecations.php | 25 ++++ lib/experimental/webfonts.php | 57 +------- .../webfonts/wpGetWebfontProviders-test.php | 72 ---------- .../webfonts/wpRegisterFontFamily-test.php | 118 ---------------- .../wpRegisterWebfontVariation-test.php | 133 ------------------ 5 files changed, 27 insertions(+), 378 deletions(-) delete mode 100644 phpunit/webfonts/wpGetWebfontProviders-test.php delete mode 100644 phpunit/webfonts/wpRegisterFontFamily-test.php delete mode 100644 phpunit/webfonts/wpRegisterWebfontVariation-test.php diff --git a/lib/experimental/webfonts-deprecations.php b/lib/experimental/webfonts-deprecations.php index 03dfd1ef522cf3..cd8bebddfc3e87 100644 --- a/lib/experimental/webfonts-deprecations.php +++ b/lib/experimental/webfonts-deprecations.php @@ -71,3 +71,28 @@ function wp_register_webfont( array $webfont ) { return wp_webfonts()->register_webfont( $webfont ); } } + +if ( ! function_exists( 'wp_get_webfont_providers' ) ) { + /** + * Gets all registered providers. + * + * Return an array of providers, each keyed by their unique + * ID (i.e. the `$id` property in the provider's object) with + * an instance of the provider (object): + * ID => provider instance + * + * Each provider contains the business logic for how to + * process its specific font service (i.e. local or remote) + * and how to generate the `@font-face` styles for its service. + * + * @since X.X.X + * @deprecated X.X.X Use wp_webfonts()->get_providers(). + * + * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. + */ + function wp_get_webfont_providers() { + _deprecated_function( __FUNCTION__, 'X.X.X', 'wp_webfonts()->get_providers()' ); + + return wp_webfonts()->get_providers(); + } +} diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index 90578fba29f747..f72bab3f1ff3c5 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -29,38 +29,6 @@ function wp_webfonts() { } } -if ( ! function_exists( 'wp_register_font_family' ) ) { - /** - * Registers a font family. - * - * @since X.X.X - * - * @param string $font_family Font family name to register. - * @return string|null Font family handle when registration successes. Null on failure. - */ - function wp_register_font_family( $font_family ) { - return wp_webfonts()->add_font_family( $font_family ); - } -} - -if ( ! function_exists( 'wp_register_webfont_variation' ) ) { - /** - * Registers a variation to the given font family. - * - * @since X.X.X - * - * @param string $font_family_handle The font family's handle for this variation. - * @param array $variation An array of variation properties to add. - * @param string $variation_handle Optional. The variation's handle. When none is provided, the - * handle will be dynamically generated. - * Default empty string. - * @return string|null Variation handle on success. Else null. - */ - function wp_register_webfont_variation( $font_family_handle, array $variation, $variation_handle = '' ) { - return wp_webfonts()->add_variation( $font_family_handle, $variation, $variation_handle ); - } -} - if ( ! function_exists( 'wp_register_webfonts' ) ) { /** * Registers one or more font-families and each of their variations. @@ -88,10 +56,11 @@ function wp_register_webfonts( array $webfonts ) { $registered = array(); $wp_webfonts = wp_webfonts(); - // BACKPORT NOTE: Do not backport this line of code to Core. + // BACKPORT NOTE: Do not backport this code block to Core. if ( $wp_webfonts->is_deprecated_structure( $webfonts ) ) { $webfonts = $wp_webfonts->migrate_deprecated_structure( $webfonts ); } + // BACKPORT NOTE: end of code block. foreach ( $webfonts as $font_family => $variations ) { $font_family_handle = $wp_webfonts->add_font_family( $font_family ); @@ -199,28 +168,6 @@ function wp_register_webfont_provider( $name, $classname ) { } } -if ( ! function_exists( 'wp_get_webfont_providers' ) ) { - /** - * Gets all registered providers. - * - * Return an array of providers, each keyed by their unique - * ID (i.e. the `$id` property in the provider's object) with - * an instance of the provider (object): - * ID => provider instance - * - * Each provider contains the business logic for how to - * process its specific font service (i.e. local or remote) - * and how to generate the `@font-face` styles for its service. - * - * @since X.X.X - * - * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. - */ - function wp_get_webfont_providers() { - return wp_webfonts()->get_providers(); - } -} - if ( ! function_exists( 'wp_print_webfonts' ) ) { /** * Invokes each provider to process and print its styles. diff --git a/phpunit/webfonts/wpGetWebfontProviders-test.php b/phpunit/webfonts/wpGetWebfontProviders-test.php deleted file mode 100644 index 2e64db09006e37..00000000000000 --- a/phpunit/webfonts/wpGetWebfontProviders-test.php +++ /dev/null @@ -1,72 +0,0 @@ -providers_property = new ReflectionProperty( WP_Web_Fonts::class, 'providers' ); - $this->providers_property->setAccessible( true ); - } - - /** - * Unit test. - * - * @dataProvider data_get_providers - * - * @param array $providers Not used. - * @param array $expected Expected results. - */ - public function test_should_return_mocked_providers( array $providers, array $expected ) { - $mock = $this->set_up_mock( 'get_providers' ); - $mock->expects( $this->once() ) - ->method( 'get_providers' ) - ->will( $this->returnValue( $expected ) ); - - $this->assertSame( $expected, wp_get_webfont_providers() ); - } - - /** - * Integration test that sets the `WP_Webfonts::providers` property. - * - * @dataProvider data_get_providers - * - * @param array $providers Array of providers to test. - * @param array $expected Expected results. - */ - public function test_should_return_providers( array $providers, array $expected ) { - $this->setup_providers( $providers ); - $this->assertSame( $expected, wp_get_webfont_providers() ); - } - - /** - * Sets up the given providers and stores them in the `WP_Webfonts::providers` property. - * - * @param array $providers Array of providers to set up. - */ - private function setup_providers( array $providers ) { - $data = array(); - - foreach ( $providers as $provider_id => $class ) { - $data[ $provider_id ] = array( - 'class' => $class, - 'fonts' => array(), - ); - } - - $this->providers_property->setValue( wp_webfonts(), $data ); - } -} diff --git a/phpunit/webfonts/wpRegisterFontFamily-test.php b/phpunit/webfonts/wpRegisterFontFamily-test.php deleted file mode 100644 index 33e1730fd37c83..00000000000000 --- a/phpunit/webfonts/wpRegisterFontFamily-test.php +++ /dev/null @@ -1,118 +0,0 @@ -set_up_mock( 'add_font_family' ); - $mock->expects( $this->once() ) - ->method( 'add_font_family' ) - ->with( - $this->identicalTo( $font_family ) - ) - ->will( $this->returnValue( $expected_handle ) ); - - $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family handle should be returned after registering' ); - } - - /** - * Integration test for registering a font family. - * - * @dataProvider data_font_family - * - * @covers WP_Webfonts::add - * - * @param string $font_family Font family to test. - * @param string $expected_handle Expected registered handle. - */ - public function test_register( $font_family, $expected_handle ) { - $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family handle should be returned after registering' ); - $this->assertSame( array( $expected_handle ), $this->get_registered_handles(), 'After registering, the registry should contain the font family handle' ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_font_family() { - return array( - 'single word name' => array( - 'font_family' => 'Lato', - 'expected_handle' => 'lato', - ), - 'multiple word name' => array( - 'font_family' => 'Source Sans Pro', - 'expected_handle' => 'source-sans-pro', - ), - 'handle' => array( - 'font_family' => 'source-serif-pro', - 'expected_handle' => 'source-serif-pro', - ), - ); - } - - /** - * Integration test for registering a font family. - * - * @dataProvider data_invalid_font_family - * - * @covers WP_Webfonts::add - * - * @param string $invalid_input Invalid input to test. - */ - public function test_register_fails( $invalid_input ) { - $this->assertNull( wp_register_font_family( $invalid_input ), 'Registering an invalid input should return null' ); - $this->assertEmpty( $this->get_registered(), 'Invalid input should not register' ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_invalid_font_family() { - return array( - 'non-string' => array( null ), - 'empty string' => array( '' ), - ); - } - - /** - * Integration test for attempting to re-register a font family. - * - * @dataProvider data_font_family - * - * @covers WP_Webfonts::add - * - * @param string $font_family Font family to test. - * @param string $expected_handle Expected registered handle. - */ - public function test_re_register( $font_family, $expected_handle ) { - // Register the font family. - wp_register_font_family( $font_family ); - - // Attempt to re-register it. - $this->assertSame( $expected_handle, wp_register_font_family( $font_family ), 'Font family handle should be returned after registering' ); - $this->assertSame( array( $expected_handle ), $this->get_registered_handles(), 'The font family should only be registered once' ); - } -} diff --git a/phpunit/webfonts/wpRegisterWebfontVariation-test.php b/phpunit/webfonts/wpRegisterWebfontVariation-test.php deleted file mode 100644 index 6f8d759be35870..00000000000000 --- a/phpunit/webfonts/wpRegisterWebfontVariation-test.php +++ /dev/null @@ -1,133 +0,0 @@ -add( $font_family_handle, false ); - - $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); - $this->assertSame( $expected, $variation_handle, 'Variation should return handle' ); - $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle ), 'Variation should be registered to font family' ); - } - - /** - * @dataProvider data_valid_variation - * - * @param string|bool $expected Expected results. - * @param string $font_family_handle The font family's handle for this variation. - * @param array $variation An array of variation properties to add. - * @param string $variation_handle Optional. The variation's handle. - */ - public function test_variation_already_registered( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { - wp_webfonts()->add( $font_family_handle, false ); - - // Set up the test. - $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); - - // Run the test. - $variant_handle_on_reregister = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); - $this->assertSame( $expected, $variant_handle_on_reregister, 'Variation should be registered to font family' ); - $this->assertSame( $variation_handle, $variant_handle_on_reregister, 'Variation should return the previously registered variant handle' ); - $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle ), 'Variation should only be registered once' ); - $expected = array( $font_family_handle, $variation_handle ); - $this->assertSameSets( $expected, $this->get_registered_handles(), 'Register queue should contain the font family and its one variant' ); - } - - /** - * @dataProvider data_valid_variation - * - * @param string|bool $expected Expected results. - * @param string $font_family_handle The font family's handle for this variation. - * @param array $variation An array of variation properties to add. - * @param string $variation_handle Optional. The variation's handle. - */ - public function test_register_font_family_and_variation( $expected, $font_family_handle, array $variation, $variation_handle = '' ) { - $variation_handle = wp_register_webfont_variation( $font_family_handle, $variation, $variation_handle ); - $this->assertSame( $expected, $variation_handle, 'Variation should return its registered handle' ); - - // Extra checks to ensure both are registered. - $expected = array( $font_family_handle, $variation_handle ); - $this->assertSame( $expected, wp_webfonts()->get_registered(), 'Font family and variation should be registered' ); - $this->assertSame( array( $variation_handle ), $this->get_variations( $font_family_handle ), 'Variation should be registered to the font family' ); - } - - /** - * @dataProvider data_font_family_handle_undefined - * - * @param string $font_family_handle The font family's handle for this variation. - * @param array $variation An array of variation properties to add. - */ - public function test_should_not_register_font_family_or_variant( $font_family_handle, array $variation ) { - $this->expectNotice(); - $this->expectNoticeMessage( 'Font family handle must be a non-empty string.' ); - - wp_register_webfont_variation( $font_family_handle, $variation ); - $this->assertEmpty( wp_webfonts()->get_registered(), 'Registered queue should be empty' ); - $this->assertEmpty( $this->get_variations( $font_family_handle ), 'Variation should not be registered to the font family' ); - } - - /** - * @dataProvider data_font_family_undefined_in_variation - * @dataProvider data_unable_determine_variation_handle - * - * @param string $font_family_handle The font family's handle for this variation. - * @param array $variation An array of variation properties to add. - * @param string $expected_message Expected notice message. - */ - public function test_should_not_register_variation_when_font_family_not_defined( $font_family_handle, array $variation, $expected_message ) { - $this->expectNotice(); - $this->expectNoticeMessage( $expected_message ); - - $this->assertNull( wp_register_webfont_variation( $font_family_handle, $variation ) ); - } - - /** - * @dataProvider data_unable_determine_variation_handle - * - * @param string $font_family_handle The font family's handle for this variation. - * @param array $variation An array of variation properties to add. - */ - public function test_should_register_font_family_when_variant_fails_to_register( $font_family_handle, array $variation ) { - $this->expectNotice(); - $this->expectNoticeMessage( 'Variant handle could not be determined as font-weight and/or font-style are require' ); - - wp_register_webfont_variation( $font_family_handle, $variation ); - $expected = $font_family_handle; - $this->assertContains( $expected, wp_webfonts()->get_registered() ); - } - - /** - * @dataProvider data_invalid_variation - * - * @param string $expected_message Expected notice message. - * @param string $font_family_handle The font family's handle for this variation. - * @param array $variation An array of variation properties to add. - */ - public function test_should_not_register_when_variation_fails_validation( $expected_message, $font_family_handle, array $variation ) { - $this->expectNotice(); - $this->expectNoticeMessage( $expected_message ); - - $this->assertNull( wp_register_webfont_variation( $font_family_handle, $variation ) ); - } -} From 709d6401e485ef9d40002f9a041883d97c7a0a29 Mon Sep 17 00:00:00 2001 From: Tonya Mork Date: Wed, 14 Dec 2022 11:37:09 -0600 Subject: [PATCH 59/63] Removes duplicate from merge conflict resolution --- lib/load.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/load.php b/lib/load.php index b787de3df453ab..e432a369d59d32 100644 --- a/lib/load.php +++ b/lib/load.php @@ -97,8 +97,6 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/experimental/blocks.php'; require __DIR__ . '/experimental/navigation-theme-opt-in.php'; require __DIR__ . '/experimental/navigation-page.php'; -require __DIR__ . '/experimental/navigation-theme-opt-in.php'; -require __DIR__ . '/experimental/navigation-page.php'; require __DIR__ . '/experimental/kses.php'; // Web Fonts API From 230cf7c6cf1498cab0335f27b2cf2487db9fc427 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 14 Dec 2022 11:49:56 -0600 Subject: [PATCH 60/63] Guard script-loader to prevent errors --- lib/compat/wordpress-6.2/script-loader.php | 34 ++++++++++++---------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/lib/compat/wordpress-6.2/script-loader.php b/lib/compat/wordpress-6.2/script-loader.php index cfbf633ef62d5f..f3fde930383bc2 100644 --- a/lib/compat/wordpress-6.2/script-loader.php +++ b/lib/compat/wordpress-6.2/script-loader.php @@ -131,21 +131,25 @@ function gutenberg_resolve_assets_override() { * Generate web font @font-face styles for the site editor iframe. * Use the registered font families for printing. */ - $wp_webfonts = wp_webfonts(); - $registered = $wp_webfonts->get_registered_font_families(); - $queue = $wp_webfonts->queue; - $done = $wp_webfonts->done; - - $wp_webfonts->done = array(); - $wp_webfonts->queue = $registered; - - ob_start(); - $wp_webfonts->do_items(); - $styles .= ob_get_clean(); - - // Reset the Web Fonts API. - $wp_webfonts->done = $done; - $wp_webfonts->queue = $queue; + if ( class_exists( 'WP_Web_Fonts' ) ) { + $wp_webfonts = wp_webfonts(); + $registered = $wp_webfonts->get_registered_font_families(); + if ( ! empty( $registered ) ) { + $queue = $wp_webfonts->queue; + $done = $wp_webfonts->done; + + $wp_webfonts->done = array(); + $wp_webfonts->queue = $registered; + + ob_start(); + $wp_webfonts->do_items(); + $styles .= ob_get_clean(); + + // Reset the Web Fonts API. + $wp_webfonts->done = $done; + $wp_webfonts->queue = $queue; + } + } return array( 'styles' => $styles, From b0c2037407ebc34a09e2670c723522d324192e60 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 14 Dec 2022 12:39:19 -0600 Subject: [PATCH 61/63] Removes "No web fonts are enqueued for printing" --- lib/experimental/class-wp-web-fonts.php | 29 ++++++++------------ phpunit/webfonts/wpPrintWebfonts-test.php | 8 +++--- phpunit/webfonts/wpWebfonts/doItems-test.php | 7 ----- 3 files changed, 16 insertions(+), 28 deletions(-) diff --git a/lib/experimental/class-wp-web-fonts.php b/lib/experimental/class-wp-web-fonts.php index 715d537ce0a516..9c6b08892b54fc 100644 --- a/lib/experimental/class-wp-web-fonts.php +++ b/lib/experimental/class-wp-web-fonts.php @@ -430,16 +430,17 @@ private function validate_variation( $variation ) { * * @since X.X.X * - * @param string|string[]|false $handles Optional. Items to be processed: queue (false), - * single item (string), or multiple items (array of strings). - * Default false. - * @param int|false $group Optional. Group level: level (int), no group (false). + * @param string|string[]|bool $handles Optional. Items to be processed: queue (false), + * single item (string), or multiple items (array of strings). + * Default false. + * @param int|false $group Optional. Group level: level (int), no group (false). * * @return array|string[] Array of web font handles that have been processed. * An empty array if none were processed. */ public function do_items( $handles = false, $group = false ) { - $handles = $this->prep_handles_for_printing( $handles ); + $handles = $this->prepare_handles_for_printing( $handles ); + if ( empty( $handles ) ) { return $this->done; } @@ -478,14 +479,15 @@ public function do_items( $handles = false, $group = false ) { * * @since X.X.X * - * @param string|string[]|bool $handles Handles to prepare. + * @param string|string[]|bool $handles Optional. Handles to prepare. + * Default false. * @return array Array of handles. */ - private function prep_handles_for_printing( $handles = false ) { + private function prepare_handles_for_printing( $handles = false ) { if ( false !== $handles ) { $handles = $this->validate_handles( $handles ); // Bail out when invalid. - if ( null === $handles ) { + if ( empty( $handles ) ) { return array(); } } @@ -493,8 +495,6 @@ private function prep_handles_for_printing( $handles = false ) { // Use the enqueued queue. if ( empty( $handles ) ) { if ( empty( $this->queue ) ) { - trigger_error( 'No web fonts are enqueued for printing' ); - return array(); } $handles = $this->queue; @@ -508,17 +508,12 @@ private function prep_handles_for_printing( $handles = false ) { * * @since X.X.X * - * @param mixed $handles Handle or handles to be validated. + * @param string|string[] $handles Handles to prepare. * @return string[]|null Array of handles on success. Else null. */ private function validate_handles( $handles ) { // Validate each element is a non-empty string handle. - $handles = array_filter( - (array) $handles, - static function( $handle ) { - return is_string( $handle ) && ! empty( $handle ); - } - ); + $handles = array_filter( (array) $handles, array( WP_Webfonts_Utils::class, 'is_defined' ) ); if ( empty( $handles ) ) { trigger_error( 'Handles must be a non-empty string or array of non-empty strings' ); diff --git a/phpunit/webfonts/wpPrintWebfonts-test.php b/phpunit/webfonts/wpPrintWebfonts-test.php index 0ab4bcbcc29c39..3f782fec580fd7 100644 --- a/phpunit/webfonts/wpPrintWebfonts-test.php +++ b/phpunit/webfonts/wpPrintWebfonts-test.php @@ -78,7 +78,7 @@ public function test_should_print_enqueued( $setup, $expected_done, $expected_ou $this->setup_integrated_deps( $setup, $wp_webfonts ); $this->expectOutputString( $expected_output ); - $actual_done = $wp_webfonts->do_items(); + $actual_done = wp_print_webfonts(); $this->assertSameSets( $expected_done, $actual_done, 'Printed handles should match' ); } @@ -108,9 +108,9 @@ public function test_should_print_handles_when_not_enqueued( $setup, $expected_d /** * Sets up the dependencies for integration test. * - * @param array $setup Dependencies to set up. - * @param WP_Webfonts $wp_webfonts Instance of WP_Webfonts. - * @param bool $enqueue Whether to enqueue. Default true. + * @param array $setup Dependencies to set up. + * @param WP_Web_Fonts $wp_webfonts Instance of WP_Web_Fonts. + * @param bool $enqueue Whether to enqueue. Default true. */ private function setup_integrated_deps( array $setup, $wp_webfonts, $enqueue = true ) { foreach ( $setup['provider'] as $provider ) { diff --git a/phpunit/webfonts/wpWebfonts/doItems-test.php b/phpunit/webfonts/wpWebfonts/doItems-test.php index da4c338f86338e..7efb8dff67b7ec 100644 --- a/phpunit/webfonts/wpWebfonts/doItems-test.php +++ b/phpunit/webfonts/wpWebfonts/doItems-test.php @@ -31,13 +31,6 @@ public function test_should_not_process_when_no_providers_registered() { $this->assertSame( array(), $this->wp_webfonts->to_do, 'WP_Web_Fonts::$to_do should be an empty array' ); } - public function test_should_throw_notice_when_queue_is_empty() { - $this->expectNotice(); - $this->expectNoticeMessage( 'No web fonts are enqueued for printing' ); - - $this->wp_webfonts->do_items(); - } - /** * @dataProvider data_invalid_handles * From 23dc407397640256bf9c965edc2c9cc2ed2d938c Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Wed, 14 Dec 2022 12:53:57 -0600 Subject: [PATCH 62/63] Fix phpcs --- lib/experimental/class-wp-webfonts.php | 2 +- lib/load.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index 7b2554de642436..f03ee14da605ee 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -280,7 +280,7 @@ private function _get_enqueued_webfonts() { // If font-family, add all of its variations. foreach ( $obj->deps as $variation_handle ) { - $obj = $this->registered[ $variation_handle ]; + $obj = $this->registered[ $variation_handle ]; $enqueued[ $variation_handle ] = $obj->extra['font-properties']; } } diff --git a/lib/load.php b/lib/load.php index e432a369d59d32..b2a9425d491fa9 100644 --- a/lib/load.php +++ b/lib/load.php @@ -99,7 +99,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/experimental/navigation-page.php'; require __DIR__ . '/experimental/kses.php'; -// Web Fonts API +// Web Fonts API. require __DIR__ . '/experimental/webfonts-deprecations.php'; // Temporary deprecated functions. require __DIR__ . '/experimental/class-wp-webfonts.php'; // Temporary deprecated class. require __DIR__ . '/experimental/class-wp-webfonts-utils.php'; From 4ac7be0d7fd5cbe5aa4d4aa5f9db2766db31ad67 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Thu, 15 Dec 2022 10:18:19 -0600 Subject: [PATCH 63/63] Improve deprecations --- lib/experimental/class-wp-web-fonts.php | 11 +- lib/experimental/class-wp-webfonts.php | 61 +++++---- .../register-webfonts-from-theme-json.php | 2 +- lib/experimental/webfonts-deprecations.php | 40 +++--- lib/experimental/webfonts.php | 10 +- phpunit/webfonts/wpEnqueueWebfont-test.php | 69 ---------- phpunit/webfonts/wpEnqueueWebfonts-test.php | 122 ++++++++++++++++++ 7 files changed, 193 insertions(+), 122 deletions(-) delete mode 100644 phpunit/webfonts/wpEnqueueWebfont-test.php create mode 100644 phpunit/webfonts/wpEnqueueWebfonts-test.php diff --git a/lib/experimental/class-wp-web-fonts.php b/lib/experimental/class-wp-web-fonts.php index 9c6b08892b54fc..15df7ecf47e5c5 100644 --- a/lib/experimental/class-wp-web-fonts.php +++ b/lib/experimental/class-wp-web-fonts.php @@ -100,7 +100,16 @@ public function __construct() { * * @since X.X.X * - * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. + * @return array $providers { + * An associative array of registered providers, keyed by their unique ID. + * + * @type string $provider_id => array { + * An associate array of provider's class name and fonts. + * + * @type string $class Fully qualified name of the provider's class. + * @type string[] $fonts An array of enqueued font handles for this provider. + * } + * } */ public function get_providers() { return $this->providers; diff --git a/lib/experimental/class-wp-webfonts.php b/lib/experimental/class-wp-webfonts.php index f03ee14da605ee..fd00d39cfc5bf8 100644 --- a/lib/experimental/class-wp-webfonts.php +++ b/lib/experimental/class-wp-webfonts.php @@ -37,7 +37,7 @@ class WP_Webfonts extends WP_Dependencies { */ public static function get_font_slug( $to_convert ) { $message = is_array( $to_convert ) - ? 'Use WP_Webfonts_Utils::get_font_family_from_variation() to get the font family from an array and then WP_Webfonts_Utils::convert_font_family_into_handle() to convert the font-family name into a handle' + ? 'Use WP_Webfonts_Utils::get l_font_family_from_variation() to get the font family from an array and then WP_Webfonts_Utils::convert_font_family_into_handle() to convert the font-family name into a handle' : 'Use WP_Webfonts_Utils::convert_font_family_into_handle() to convert the font-family name into a handle'; _deprecated_function( __METHOD__, 'X.X.X', $message ); @@ -100,16 +100,19 @@ public function get_all_webfonts() { * Registers a webfont. * * @since 6.0.0 - * @deprecated X.X.X Use wp_register_webfont_variation(). + * @deprecated X.X.X Use wp_register_webfonts(). * - * @param array $webfont Web font to register. - * @param string $font_family_handle Optional. Font family handle for the given variation. - * Default empty string. - * @param string $variation_handle Optional. Handle for the variation to register. + * @param array $webfont Web font to register. + * @param string $font_family_handle Optional. Font family handle for the given variation. + * Default empty string. + * @param string $variation_handle Optional. Handle for the variation to register. + * @param bool $silence_deprecation Optional. Silences the deprecation notice. For internal use. * @return string|false The font family slug if successfully registered, else false. */ - public function register_webfont( array $webfont, $font_family_handle = '', $variation_handle = '' ) { - _deprecated_function( __METHOD__, 'X.X.X', 'wp_register_webfont_variation()' ); + public function register_webfont( array $webfont, $font_family_handle = '', $variation_handle = '', $silence_deprecation = false ) { + if ( ! $silence_deprecation ) { + _deprecated_function( __METHOD__, 'X.X.X', 'wp_register_webfonts()' ); + } // When font family's handle is not passed, attempt to get it from the variation. if ( ! WP_Webfonts_Utils::is_defined( $font_family_handle ) ) { @@ -132,28 +135,15 @@ public function register_webfont( array $webfont, $font_family_handle = '', $var * Enqueue a font-family that has been already registered. * * @since 6.0.0 - * @deprecated X.X.X Use wp_webfonts()->enqueue() or wp_enqueue_webfont(). + * @deprecated X.X.X Use wp_enqueue_webfonts(). * * @param string $font_family_name The font family name to be enqueued. * @return bool True if successfully enqueued, else false. */ public function enqueue_webfont( $font_family_name ) { - _deprecated_function( __METHOD__, 'X.X.X', 'wp_webfonts()->enqueue() or wp_enqueue_webfont()' ); - - $slug = static::_get_font_slug( $font_family_name ); - - if ( isset( $this->enqueued[ $slug ] ) ) { - return true; - } - - if ( ! isset( $this->registered[ $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' ); - - return false; - } + _deprecated_function( __METHOD__, 'X.X.X', 'wp_enqueue_webfonts()' ); - $this->enqueue( $slug ); + wp_enqueue_webfonts( array( $font_family_name ) ); return true; } @@ -239,14 +229,29 @@ private static function _get_font_slug( $to_convert ) { * @return array[] */ private function _get_registered_webfonts() { - $registered = array(); + $font_families = array(); + $registered = array(); + + // Find the registered font families. foreach ( $this->registered as $handle => $obj ) { - // Skip the font-family. - if ( $obj->extra['is_font_family'] ) { + if ( ! $obj->extra['is_font_family'] ) { continue; } - $registered[ $handle ] = $obj->extra['font-properties']; + if ( ! isset( $registered[ $handle ] ) ) { + $registered[ $handle ] = array(); + } + + $font_families[ $handle ] = $obj->deps; + } + + // Build the return array structure. + foreach ( $font_families as $font_family_handle => $variations ) { + foreach ( $variations as $variation_handle ) { + $variation_obj = $this->registered[ $variation_handle ]; + + $registered[ $font_family_handle ][ $variation_handle ] = $variation_obj->extra['font-properties']; + } } return $registered; diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/register-webfonts-from-theme-json.php index d590d28cda0d93..4b49f6e0534fa3 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/register-webfonts-from-theme-json.php @@ -108,7 +108,7 @@ function gutenberg_register_webfonts_from_theme_json() { } wp_register_webfonts( $webfonts ); - wp_enqueue_webfont( $handles ); + wp_enqueue_webfonts( $handles ); } } diff --git a/lib/experimental/webfonts-deprecations.php b/lib/experimental/webfonts-deprecations.php index cd8bebddfc3e87..bd50b0f476d96a 100644 --- a/lib/experimental/webfonts-deprecations.php +++ b/lib/experimental/webfonts-deprecations.php @@ -10,32 +10,29 @@ * @package WordPress */ -if ( ! function_exists( 'wp_enqueue_webfonts' ) ) { +if ( ! function_exists( 'wp_enqueue_webfont' ) ) { /** - * Enqueues a collection of font families. + * Enqueue a single font family that has been registered beforehand. * - * Example of how to enqueue Source Serif Pro and Roboto font families, both registered beforehand. + * Example of how to enqueue Source Serif Pro font: * * - * wp_enqueue_webfonts( - * 'Roboto', - * 'Sans Serif Pro' - * ); + * wp_enqueue_webfont( 'Source Serif Pro' ); * * * Font families should be enqueued from the `init` hook or later. * - * BACKPORT NOTE: Do not backport this function. - * * @since 6.0.0 - * @deprecated X.X.X Use wp_enqueue_webfont(). + * @deprecated X.X.X Use wp_enqueue_webfonts(). * - * @param string[] $font_families Font family handles (array of strings). + * @param string $font_family_name The font family name to be enqueued. + * @return bool True if successfully enqueued, else false. */ - function wp_enqueue_webfonts( array $font_families ) { - _deprecated_function( __FUNCTION__, 'X.X.X', 'wp_enqueue_webfont()' ); + function wp_enqueue_webfont( $font_family_name ) { + _deprecated_function( __FUNCTION__, 'X.X.X', 'wp_enqueue_webfonts()' ); - wp_enqueue_webfont( $font_families ); + wp_enqueue_webfonts( array( $font_family_name ) ); + return true; } } @@ -60,15 +57,15 @@ function wp_enqueue_webfonts( array $font_families ) { * * * @since 6.0.0 - * @deprecated X.X.X Use wp_enqueue_webfont(). + * @deprecated X.X.X Use wp_register_webfonts(). * * @param array $webfont Webfont to be registered. * @return string|false The font family slug if successfully registered, else false. */ function wp_register_webfont( array $webfont ) { - _deprecated_function( __FUNCTION__, 'X.X.X', 'wp_register_webfont_variation()' ); + _deprecated_function( __FUNCTION__, 'X.X.X', 'wp_register_webfonts()' ); - return wp_webfonts()->register_webfont( $webfont ); + return wp_webfonts()->register_webfont( $webfont, '', '', false ); } } @@ -88,11 +85,16 @@ function wp_register_webfont( array $webfont ) { * @since X.X.X * @deprecated X.X.X Use wp_webfonts()->get_providers(). * - * @return WP_Webfonts_Provider[] All registered providers, each keyed by their unique ID. + * @return string[] All registered providers, each keyed by their unique ID. */ function wp_get_webfont_providers() { _deprecated_function( __FUNCTION__, 'X.X.X', 'wp_webfonts()->get_providers()' ); - return wp_webfonts()->get_providers(); + $providers = array(); + foreach ( wp_webfonts()->get_providers() as $id => $config ) { + $providers[ $id ] = $config['class']; + } + + return $providers; } } diff --git a/lib/experimental/webfonts.php b/lib/experimental/webfonts.php index f72bab3f1ff3c5..c4ccc1640d9c83 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/webfonts.php @@ -84,16 +84,18 @@ function wp_register_webfonts( array $webfonts ) { } } -if ( ! function_exists( 'wp_enqueue_webfont' ) ) { +if ( ! function_exists( 'wp_enqueue_webfonts' ) ) { /** * Enqueues one or more font family and all of its variations. * * @since X.X.X * - * @param string|string[] $font_family Font family handle (string) or handles (array of strings). + * @param string[] $font_families Font family(ies) to enqueue. */ - function wp_enqueue_webfont( $font_family ) { - wp_webfonts()->enqueue( $font_family ); + function wp_enqueue_webfonts( array $font_families ) { + $handles = array_map( array( WP_Webfonts_Utils::class, 'convert_font_family_into_handle' ), $font_families ); + + wp_webfonts()->enqueue( $handles ); } } diff --git a/phpunit/webfonts/wpEnqueueWebfont-test.php b/phpunit/webfonts/wpEnqueueWebfont-test.php deleted file mode 100644 index fa371f1c2ec329..00000000000000 --- a/phpunit/webfonts/wpEnqueueWebfont-test.php +++ /dev/null @@ -1,69 +0,0 @@ -set_up_mock( 'enqueue' ); - $mock->expects( $this->once() ) - ->method( 'enqueue' ) - ->with( - $this->identicalTo( $font_family ) - ); - - wp_enqueue_webfont( $font_family ); - } - - /** - * Integration test for enqueuing a font family and all of its variations. - * - * @dataProvider data_enqueue - * - * @param string|string[] $font_family Font family to test. - * @param array $expected Expected queue. - */ - public function test_should_enqueue_after_registration( $font_family, array $expected ) { - foreach ( $this->get_data_registry() as $handle => $variations ) { - $this->setup_register( $handle, $variations ); - } - - wp_enqueue_webfont( $font_family ); - $this->assertEmpty( $this->get_queued_before_register(), '"queued_before_register" queue should be empty' ); - $this->assertSame( $expected, $this->get_enqueued_handles(), 'Queue should contain the given font family(ies)' ); - } - - /** - * Integration test for enqueuing before registering a font family and all of its variations. - * - * @dataProvider data_enqueue - * - * @param string|string[] $font_family Font family to test. - * @param array $not_used Not used. - * @param array $expected Expected "queued_before_register" queue. - */ - public function test_should_enqueue_before_registration( $font_family, array $not_used, array $expected ) { - wp_enqueue_webfont( $font_family ); - - $this->assertSame( $expected, $this->get_queued_before_register(), '"queued_before_register" queue should contain the given font family(ies)' ); - $this->assertEmpty( $this->get_enqueued_handles(), 'Queue should be empty' ); - } -} diff --git a/phpunit/webfonts/wpEnqueueWebfonts-test.php b/phpunit/webfonts/wpEnqueueWebfonts-test.php new file mode 100644 index 00000000000000..a0ee6af5c1ddad --- /dev/null +++ b/phpunit/webfonts/wpEnqueueWebfonts-test.php @@ -0,0 +1,122 @@ +set_up_mock( 'enqueue' ); + $mock->expects( $this->once() ) + ->method( 'enqueue' ) + ->with( + $this->identicalTo( $expected_handles ) + ); + + wp_enqueue_webfonts( $font_families ); + } + + /** + * Integration test for enqueuing a font family and all of its variations. + * + * @dataProvider data_should_enqueue + * + * @param string[] $font_families Font families to test. + * @param string[] $expected_handles Expected handles passed to WP_Web_Fonts::enqueue(). + */ + public function test_should_enqueue_after_registration( $font_families, $expected_handles ) { + // Register the font-families. + foreach ( $this->get_data_registry() as $handle => $variations ) { + $this->setup_register( $handle, $variations ); + } + + wp_enqueue_webfonts( $font_families ); + + $this->assertEmpty( $this->get_queued_before_register(), '"queued_before_register" queue should be empty' ); + $this->assertSame( $expected_handles, $this->get_enqueued_handles(), 'Queue should contain the given font family(ies)' ); + } + + /** + * Integration test for enqueuing before registering a font family and all of its variations. + * + * @dataProvider data_should_enqueue + * + * @param string[] $font_families Font families to test. + * @param string[] $expected_handles Expected handles passed to WP_Web_Fonts::enqueue(). + */ + public function test_should_enqueue_before_registration( $font_families, $expected_handles ) { + wp_enqueue_webfonts( $font_families ); + + // Set up what "queued_before_register" queue should be. + $expected = array(); + foreach ( $expected_handles as $handle ) { + $expected[ $handle ] = null; + } + $this->assertSame( $expected, $this->get_queued_before_register(), '"queued_before_register" queue should contain the given font family(ies)' ); + $this->assertEmpty( $this->get_enqueued_handles(), 'Queue should be empty' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_should_enqueue() { + return array( + '1: single word handle' => array( + 'font_families' => array( 'lato' ), + 'expected_handles' => array( 'lato' ), + ), + '1: multiple word handle' => array( + 'font_families' => array( 'source-serif-pro' ), + 'expected_handles' => array( 'source-serif-pro' ), + ), + '1: single word name' => array( + 'font_families' => array( 'Merriweather' ), + 'expected_handles' => array( 'merriweather' ), + ), + '1: multiple word name' => array( + 'font_families' => array( 'My Font' ), + 'expected_handles' => array( 'my-font' ), + ), + '>1: single word handle' => array( + 'font_families' => array( 'lato', 'merriweather' ), + 'expected_handles' => array( 'lato', 'merriweather' ), + ), + '>1: multiple word handle' => array( + 'font_families' => array( 'source-serif-pro', 'my-font' ), + 'expected_handles' => array( 'source-serif-pro', 'my-font' ), + ), + '>1: single word name' => array( + 'font_families' => array( 'Lato', 'Merriweather' ), + 'expected_handles' => array( 'lato', 'merriweather' ), + ), + '>1: multiple word name' => array( + 'font_families' => array( 'My Font', 'Source Serif Pro' ), + 'expected_handles' => array( 'my-font', 'source-serif-pro' ), + ), + '>1: mixture of word handles and names' => array( + 'font_families' => array( 'Source Serif Pro', 'Merriweather', 'my-font', 'Lato' ), + 'expected_handles' => array( 'source-serif-pro', 'merriweather', 'my-font', 'lato' ), + ), + ); + } +}