From 8eef162bdc2c939e422b69879dfbfb7a6cbf2613 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Thu, 2 Dec 2021 14:38:59 +0200 Subject: [PATCH] simplified API --- ...p => class-wp-webfonts-provider-local.php} | 20 +- lib/class-wp-webfonts-provider.php | 68 +++ lib/class-wp-webfonts.php | 323 ++++++++++++ lib/global-styles.php | 2 +- lib/load.php | 7 +- .../class-wp-webfonts-controller.php | 276 ----------- .../class-wp-webfonts-provider-registry.php | 132 ----- .../class-wp-webfonts-registry.php | 245 --------- .../class-wp-webfonts-schema-validator.php | 335 ------------- .../providers/class-wp-webfonts-provider.php | 135 ----- lib/webfonts.php | 35 +- .../class-wp-webfonts-local-provider-test.php | 25 +- phpunit/class-wp-webfonts-test.php | 143 ++++++ .../class-wp-webfonts-controller-test.php | 211 -------- ...ass-wp-webfonts-provider-registry-test.php | 82 ---- .../class-wp-webfonts-registry-test.php | 341 ------------- ...lass-wp-webfonts-schema-validator-test.php | 463 ------------------ ...class-my-custom-webfonts-provider-mock.php | 35 -- 18 files changed, 573 insertions(+), 2305 deletions(-) rename lib/{webfonts-api/providers/class-wp-webfonts-local-provider.php => class-wp-webfonts-provider-local.php} (96%) create mode 100644 lib/class-wp-webfonts-provider.php create mode 100644 lib/class-wp-webfonts.php delete mode 100644 lib/webfonts-api/class-wp-webfonts-controller.php delete mode 100644 lib/webfonts-api/class-wp-webfonts-provider-registry.php delete mode 100644 lib/webfonts-api/class-wp-webfonts-registry.php delete mode 100644 lib/webfonts-api/class-wp-webfonts-schema-validator.php delete mode 100644 lib/webfonts-api/providers/class-wp-webfonts-provider.php rename phpunit/{webfonts-api/providers => }/class-wp-webfonts-local-provider-test.php (84%) create mode 100644 phpunit/class-wp-webfonts-test.php delete mode 100644 phpunit/webfonts-api/class-wp-webfonts-controller-test.php delete mode 100644 phpunit/webfonts-api/class-wp-webfonts-provider-registry-test.php delete mode 100644 phpunit/webfonts-api/class-wp-webfonts-registry-test.php delete mode 100644 phpunit/webfonts-api/class-wp-webfonts-schema-validator-test.php delete mode 100644 phpunit/webfonts-api/mocks/class-my-custom-webfonts-provider-mock.php diff --git a/lib/webfonts-api/providers/class-wp-webfonts-local-provider.php b/lib/class-wp-webfonts-provider-local.php similarity index 96% rename from lib/webfonts-api/providers/class-wp-webfonts-local-provider.php rename to lib/class-wp-webfonts-provider-local.php index 6030cbffbe3265..b2cc2524c27e74 100644 --- a/lib/webfonts-api/providers/class-wp-webfonts-local-provider.php +++ b/lib/class-wp-webfonts-provider-local.php @@ -4,7 +4,7 @@ * * @package WordPress * @subpackage WebFonts - * @since 5.9.0 + * @since 6.0.0 */ /** @@ -16,21 +16,21 @@ * * When enqueued styles are rendered, the Controller passes its * 'local' webfonts {@see WP_Webfonts_Provider::set_setfonts()} - * and then triggers {@see WP_Webfonts_Local_Provider::get_css()} + * and then triggers {@see WP_Webfonts_Provider_Local::get_css()} * the processing to transform them into `@font-face` styles. * * All know-how (business logic) for how to interact with and * generate styles from locally-hosted font files is contained * in this provider. * - * @since 5.9.0 + * @since 6.0.0 */ -class WP_Webfonts_Local_Provider extends WP_Webfonts_Provider { +class WP_Webfonts_Provider_Local extends WP_Webfonts_Provider { /** * The provider's unique ID. * - * @since 5.9.0 + * @since 6.0.0 * * @var string */ @@ -82,7 +82,7 @@ class WP_Webfonts_Local_Provider extends WP_Webfonts_Provider { * } * * - * @since 5.9.0 + * @since 6.0.0 * * @return string The `@font-face` CSS. */ @@ -103,7 +103,7 @@ public function get_css() { /** * Order `src` items to optimize for browser support. * - * @since 5.9.0 + * @since 6.0.0 * * @param array $webfont Webfont to process. * @return array @@ -176,7 +176,7 @@ private function order_src( array $webfont ) { /** * Builds the font-family's CSS. * - * @since 5.9.0 + * @since 6.0.0 * * @param array $webfont Webfont to process. * @return string This font-family's CSS. @@ -221,7 +221,7 @@ private function build_font_face_css( array $webfont ) { /** * Compiles the `src` into valid CSS. * - * @since 5.9.0 + * @since 6.0.0 * * @param string $font_family Font family. * @param array $value Value to process. @@ -246,7 +246,7 @@ private function compile_src( $font_family, array $value ) { /** * Compiles the font variation settings. * - * @since 5.9.0 + * @since 6.0.0 * * @param array $font_variation_settings Array of font variation settings. * @return string The CSS. diff --git a/lib/class-wp-webfonts-provider.php b/lib/class-wp-webfonts-provider.php new file mode 100644 index 00000000000000..96b12547986425 --- /dev/null +++ b/lib/class-wp-webfonts-provider.php @@ -0,0 +1,68 @@ +webfonts = $webfonts; + } + + /** + * Gets the `@font-face` CSS for the provider's webfonts. + * + * This method is where the provider does it processing to build the + * 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 + * + * @return string The `@font-face` CSS. + */ + abstract public function get_css(); +} diff --git a/lib/class-wp-webfonts.php b/lib/class-wp-webfonts.php new file mode 100644 index 00000000000000..903032760de7f4 --- /dev/null +++ b/lib/class-wp-webfonts.php @@ -0,0 +1,323 @@ +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 fonts. + * + * @return array + */ + public function get_fonts() { + return self::$webfonts; + } + + /** + * Get the list of providers. + * + * @return array + */ + public function get_providers() { + return self::$providers; + } + + /** + * Register a webfont. + * + * @param array $font The font arguments. + */ + public function register_font( $font ) { + $font = $this->validate_font( $font ); + if ( $font ) { + $id = $this->get_font_id( $font ); + self::$webfonts[ $id ] = $font; + } + } + + /** + * Get the font ID. + * + * @param array $font The font arguments. + * @return string + */ + public function get_font_id( $font ) { + return sanitize_title( "{$font['font-family']}-{$font['font-weight']}-{$font['font-style']}-{$font['provider']}" ); + } + + /** + * Validate a font. + * + * @param array $font The font arguments. + * + * @return array|false The validated font arguments, or false if the font is invalid. + */ + public function validate_font( $font ) { + $font = wp_parse_args( + $font, + array( + 'provider' => 'local', + 'font-family' => '', + 'font-style' => 'normal', + 'font-weight' => '400', + 'font-display' => 'fallback', + ) + ); + + // Check the font-family. + if ( empty( $font['font-family'] ) || ! is_string( $font['font-family'] ) ) { + trigger_error( __( 'Webfont font family must be a non-empty string.', 'gutenberg' ) ); + return false; + } + + // Local fonts need a "src". + if ( 'local' === $font['provider'] ) { + // Make sure that local fonts have 'src' defined. + if ( empty( $font['src'] ) || ( ! is_string( $font['src'] ) && ! is_array( $font['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( $font['src'] ) ) { + foreach ( (array) $font['src'] as $src ) { + if ( empty( $src ) || ! is_string( $src ) ) { + trigger_error( __( 'Each webfont src must be a non-empty string.', 'gutenberg' ) ); + return false; + } + + if ( + // Validate data URLs. + ! preg_match( '/^data:.+;base64/', $src ) && + // Validate URLs. + ! filter_var( $src, FILTER_VALIDATE_URL ) && + // Check if it's a URL starting with "//" (omitted protocol). + 0 !== strpos( $src, '//' ) + ) { + trigger_error( __( 'Webfont src must be a valid URL or a data URI.', 'gutenberg' ) ); + return false; + } + } + } + + // Check the font-style. + $valid_font_styles = array( 'normal', 'italic', 'oblique', 'inherit', 'initial', 'revert', 'unset' ); + if ( ! in_array( $font['font-style'], $valid_font_styles, true ) && ! preg_match( '/^oblique\s+(\d+)%/', $font['font-style'] ) ) { + return false; + } + + // Check the font-weight. + if ( // Bail out if the font-weight is not a valid value. + ( ! is_string( $font['font-weight'] ) && ! is_int( $font['font-weight'] ) ) || + ( + // Check if value is a single font-weight, formatted as a number. + ! in_array( $font['font-weight'], array( 'normal', 'bold', 'bolder', 'lighter', 'inherit' ), true ) && + // Check if value is a single font-weight, formatted as a number. + ! preg_match( '/^(\d+)$/', $font['font-weight'], $matches ) && + // Check if value is a range of font-weights, formatted as a number range. + ! preg_match( '/^(\d+)\s+(\d+)$/', $font['font-weight'], $matches ) + ) + ) { + trigger_error( __( 'Webfont font weight must be a properly formatted string or integer.', 'gutenberg' ) ); + return false; + } + + // Check the font-display. + if ( ! in_array( $font['font-display'], array( 'auto', 'block', 'fallback', 'swap' ), true ) ) { + $font['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 ( $font as $prop => $value ) { + if ( ! in_array( $prop, $valid_props, true ) ) { + unset( $font[ $prop ] ); + } + } + + return $font; + } + + /** + * Register a provider. + * + * @param string $provider The provider name. + * @param string $class The provider class name. + * + * @return bool Whether the provider was registered successfully. + */ + public function register_provider( $provider, $class ) { + if ( empty( $provider ) || empty( $class ) ) { + return false; + } + self::$providers[ $provider ] = $class; + return true; + } + + /** + * Generate and enqueue webfonts styles. + */ + public function generate_and_enqueue_styles() { + // Generate the styles. + $styles = $this->generate_styles(); + + // 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. + */ + public function generate_and_enqueue_editor_styles() { + // Generate the styles. + $styles = $this->generate_styles(); + + // Bail out if there are no styles to enqueue. + if ( '' === $styles ) { + return; + } + + wp_add_inline_style( 'wp-block-library', $styles ); + } + + /** + * Generate styles for webfonts. + * + * By default (due to privacy concerns), this API will not do remote requests to + * external webfont services nor generate `@font-face` styles for these remote + * providers. The filter `'has_remote_webfonts_request_permission'` is provided + * to grant permission to do the remote request. + * + * @since 6.0.0 + * + * @return string $styles Generated styles. + */ + public function generate_styles() { + $styles = ''; + $providers = $this->get_providers(); + + // Group webfonts by provider. + $webfonts_by_provider = array(); + $registered_webfonts = $this->get_fonts(); + foreach ( $registered_webfonts as $id => $webfont ) { + $provider = $webfont['provider']; + if ( ! isset( $providers[ $provider ] ) ) { + continue; + } + $webfonts_by_provider[ $provider ] = isset( $webfonts_by_provider[ $provider ] ) ? $webfonts_by_provider[ $provider ] : array(); + $webfonts_by_provider[ $provider ][ $id ] = $webfont; + } + + /* + * 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 ) ) { + 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; + } +} diff --git a/lib/global-styles.php b/lib/global-styles.php index be822b4bd73394..1842305f5975f7 100644 --- a/lib/global-styles.php +++ b/lib/global-styles.php @@ -351,7 +351,7 @@ 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()->webfonts()->get_all_registered(); + $font_families_registered = wp_webfonts()->get_fonts(); $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']; diff --git a/lib/load.php b/lib/load.php index 02a0c557f6a97a..99a9d99efe7bba 100644 --- a/lib/load.php +++ b/lib/load.php @@ -150,10 +150,9 @@ function gutenberg_is_experiment_enabled( $name ) { if ( ! function_exists( 'wp_webfonts' ) ) { /** WordPress Webfonts Classes & Functions */ - require_once __DIR__ . '/webfonts-api/class-wp-webfonts-schema-validator.php'; - require_once __DIR__ . '/webfonts-api/class-wp-webfonts-registry.php'; - require_once __DIR__ . '/webfonts-api/class-wp-webfonts-provider-registry.php'; - require_once __DIR__ . '/webfonts-api/class-wp-webfonts-controller.php'; + require_once __DIR__ . '/class-wp-webfonts.php'; + require_once __DIR__ . '/class-wp-webfonts-provider.php'; + require_once __DIR__ . '/class-wp-webfonts-provider-local.php'; require_once __DIR__ . '/webfonts.php'; /** diff --git a/lib/webfonts-api/class-wp-webfonts-controller.php b/lib/webfonts-api/class-wp-webfonts-controller.php deleted file mode 100644 index bd0038e9bcfdfa..00000000000000 --- a/lib/webfonts-api/class-wp-webfonts-controller.php +++ /dev/null @@ -1,276 +0,0 @@ -` - * (e.g. `'wp_enqueue_scripts'`), or print the resource `` - * (`'wp_resource_hints'` ). Then it interacts with the components - * in this API to process the event. - * - * @since 5.9.0 - */ -class WP_Webfonts_Controller { - - /** - * Instance of the webfont's registry. - * - * @since 5.9.0 - * - * @var WP_Webfonts_Registry - */ - private $webfonts_registry; - - /** - * Instance of the providers' registry. - * - * @since 5.9.0 - * - * @var WP_Webfonts_Provider_Registry - */ - private $providers_registry; - - /** - * Stylesheet handle. - * - * @since 5.9.0 - * - * @var string - */ - private $stylesheet_handle = ''; - - /** - * Create the controller. - * - * @since 5.9.0 - * - * @param WP_Webfonts_Registry $webfonts_registry Instance of the webfonts' registry. - * @param WP_Webfonts_Provider_Registry $providers_registry Instance of the providers' registry. - */ - public function __construct( - WP_Webfonts_Registry $webfonts_registry, - WP_Webfonts_Provider_Registry $providers_registry - ) { - $this->webfonts_registry = $webfonts_registry; - $this->providers_registry = $providers_registry; - } - - /** - * Initializes the controller. - * - * @since 5.9.0 - */ - public function init() { - $this->providers_registry->init(); - - // 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' ) ); - - // Add resources hints. - add_filter( 'wp_resource_hints', array( $this, 'get_resource_hints' ), 10, 2 ); - } - - /** - * Gets the instance of the webfonts' registry. - * - * The Webfonts Registry handles the registration - * and in-memory storage of webfonts. - * - * @since 5.9.0 - * - * @return WP_Webfonts_Registry - */ - public function webfonts() { - return $this->webfonts_registry; - } - - /** - * Gets the instance of the providers' registry. - * - * @see WP_Webfonts_Provider_Registry for more information - * on the available methods for use. - * - * @since 5.9.0 - * - * @return WP_Webfonts_Provider_Registry - */ - public function providers() { - return $this->providers_registry; - } - - /** - * Generate and enqueue webfonts styles. - * - * @since 5.9.0 - */ - public function generate_and_enqueue_styles() { - // Generate the styles. - $styles = $this->generate_styles(); - - // 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 5.9.0 - */ - public function generate_and_enqueue_editor_styles() { - // Generate the styles. - $styles = $this->generate_styles(); - - // Bail out if there are no styles to enqueue. - if ( '' === $styles ) { - return; - } - - wp_add_inline_style( 'wp-block-library', $styles ); - } - - /** - * Generate styles for webfonts. - * - * By default (due to privacy concerns), this API will not do remote requests to - * external webfont services nor generate `@font-face` styles for these remote - * providers. The filter `'has_remote_webfonts_request_permission'` is provided - * to grant permission to do the remote request. - * - * @since 5.9.0 - * - * @return string $styles Generated styles. - */ - private function generate_styles() { - $styles = ''; - $providers = $this->providers_registry->get_all_registered(); - - /* - * 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 ) { - $registered_webfonts = $this->webfonts_registry->get_by_provider( $provider_id ); - - // If there are no registered webfonts for this provider, skip it. - if ( empty( $registered_webfonts ) ) { - continue; - } - - /* - * Skip fetching from a remote fonts service if the user has not - * consented to the remote request. - */ - if ( - 'local' !== $provider_id && - /** - * Allows permission to be set for doing remote requests - * to a webfont service provider. - * - * By default, the Webfonts API will not make remote requests - * due to privacy concerns. - * - * @since 5.9.0 - * - * @param bool $has_permission Permission to do the remote request. - * Default false. - * @param string $provider_id Provider's ID, e.g. 'local', to identify - * the remote webfonts service provider. - */ - true !== apply_filters( 'has_remote_webfonts_request_permission', false, $provider_id ) - ) { - continue; - } - - /* - * Process the webfonts by first passing them to the provider via `set_webfonts()` - * and then getting the CSS from the provider. - */ - $provider->set_webfonts( $registered_webfonts ); - $styles .= $provider->get_css(); - } - - return $styles; - } - - /** - * Gets the resource hints. - * - * Callback hooked to the filter `'wp_resource_hints'`. Generation - * and rendering of the resource `` is handled where that filter - * fires. This method adds the resource link attributes to pass back - * to that handler. - * - * @since 5.9.0 - * - * @param array $urls { - * Array of resources and their attributes, or URLs to print for resource hints. - * - * @type array|string ...$0 { - * Array of resource attributes, or a URL string. - * - * @type string $href URL to include in resource hints. Required. - * @type string $as How the browser should treat the resource - * (`script`, `style`, `image`, `document`, etc). - * @type string $crossorigin Indicates the CORS policy of the specified resource. - * @type float $pr Expected probability that the resource hint will be used. - * @type string $type Type of the resource (`text/html`, `text/css`, etc). - * } - * } - * @param string $relation_type The relation type the URLs are printed for, - * e.g. 'preconnect' or 'prerender'. - * @return array URLs to print for resource hints. - */ - public function get_resource_hints( $urls, $relation_type ) { - foreach ( $this->providers_registry->get_all_registered() as $provider ) { - foreach ( $provider->get_resource_hints() as $relation => $relation_hints ) { - if ( $relation !== $relation_type ) { - continue; - } - // Append this provider's resource hints to the end of the given `$urls` array. - array_push( $urls, ...$relation_hints ); - } - } - - return $urls; - } -} diff --git a/lib/webfonts-api/class-wp-webfonts-provider-registry.php b/lib/webfonts-api/class-wp-webfonts-provider-registry.php deleted file mode 100644 index 462f1f590e5572..00000000000000 --- a/lib/webfonts-api/class-wp-webfonts-provider-registry.php +++ /dev/null @@ -1,132 +0,0 @@ - @type WP_Webfonts_Provider Provider instance. - * - * @since 5.9.0 - * - * @var WP_Webfonts_Provider[] - */ - private $registered = array(); - - /** - * 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 - * - * @since 5.9.0 - * - * @return WP_Webfonts_Provider[] All registered providers, - * each keyed by their unique ID. - */ - public function get_all_registered() { - return $this->registered; - } - - /** - * Initializes the registry. - * - * @since 5.9.0 - */ - public function init() { - $this->register_core_providers(); - } - - /** - * Registers the core providers. - * - * Loads each bundled provider's file into memory and - * then registers it for use with the API. - * - * @since 5.9.0 - */ - private function register_core_providers() { - // Load the abstract class into memory. - require_once __DIR__ . '/providers/class-wp-webfonts-provider.php'; - - // Register the Local Provider. - require_once __DIR__ . '/providers/class-wp-webfonts-local-provider.php'; - $this->register( WP_Webfonts_Local_Provider::class ); - } - - /** - * Registers a webfont provider. - * - * The provider will be registered by its unique ID - * (via `WP_Webfonts_Provider::get_id()`) and instance of - * the provider (object): - * ID => provider instance - * - * Once registered, provider is ready for use within the API. - * - * @since 5.9.0 - * - * @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 when registered. False when provider does not exist. - */ - public function register( $classname ) { - /* - * Bail out if the class does not exist in memory (its file - * has to be loaded into memory before registration) or the - * `class` itself is not a child that extends `WP_Webfonts_Provider` - * (the parent class of a provider). - */ - if ( - ! class_exists( $classname ) || - ! is_subclass_of( $classname, 'WP_Webfonts_Provider' ) - ) { - return false; - } - - /* - * Create an instance of the provider. - * This API uses one instance of each provider. - */ - $provider = new $classname; - $id = $provider->get_id(); - - // Store the provider's instance by its unique provider ID. - if ( ! isset( $this->registered[ $id ] ) ) { - $this->registered[ $id ] = $provider; - } - - return true; - } -} diff --git a/lib/webfonts-api/class-wp-webfonts-registry.php b/lib/webfonts-api/class-wp-webfonts-registry.php deleted file mode 100644 index d197431f76b1b5..00000000000000 --- a/lib/webfonts-api/class-wp-webfonts-registry.php +++ /dev/null @@ -1,245 +0,0 @@ - @type array Webfont. - * - * @since 5.9.0 - * - * @var array[] - */ - private $registered = array(); - - /** - * Registration keys per provider. - * - * Provides a O(1) lookup when querying by provider. - * - * @since 5.9.0 - * - * @var array[] - */ - private $registry_by_provider = array(); - - /** - * Schema validator. - * - * @since 5.9.0 - * - * @var WP_Webfonts_Schema_Validator - */ - private $validator; - - /** - * Creates the registry. - * - * @since 5.9.0 - * - * @param WP_Webfonts_Schema_Validator $validator Instance of the validator. - */ - public function __construct( WP_Webfonts_Schema_Validator $validator ) { - $this->validator = $validator; - } - - /** - * Gets all registered webfonts. - * - * @since 5.9.0 - * - * @return array[] Registered webfonts each keyed by font-family.font-style.font-weight. - */ - public function get_all_registered() { - return $this->registered; - } - - /** - * Gets the registered webfonts for the given provider. - * - * @since 5.9.0 - * - * @param string $provider_id Provider ID to fetch. - * @return array[] Registered webfonts. - */ - public function get_by_provider( $provider_id ) { - if ( ! isset( $this->registry_by_provider[ $provider_id ] ) ) { - return array(); - } - - $webfonts = array(); - foreach ( $this->registry_by_provider[ $provider_id ] as $registration_key ) { - // Skip if not registered. - if ( ! isset( $this->registered[ $registration_key ] ) ) { - continue; - } - - $webfonts[ $registration_key ] = $this->registered[ $registration_key ]; - } - - return $webfonts; - } - - /** - * Registers the given webfont if its schema is valid. - * - * @since 5.9.0 - * - * @param array $webfont { - * Webfont definition. - * - * @type string $provider The provider ID (e.g. 'local'). - * @type string $font_family The @font-face font-family property. - * @type string $font_weight The @font-face font-weight property. - * The font-weight can be a single value, or a range. - * If a single value, then the font-weight can either be - * a numeric value (400, 700, etc), or a word value - * (normal, bold, etc). - * If a range, then the font-weight can be a numeric range - * using 2 values, separated by a space ('100 700'). - * @type string $font_style The @font-face font-style property. - * The font-style can be a valid CSS value (normal, italic etc). - * @type string $font_display The @font-face font-display property. - * Accepted values: 'auto', 'block', 'fallback', 'swap'. - * @type array|string $src The @font-face src property. - * The src can be a single URL, or an array of URLs. - * @type string $font_stretch The @font-face font-stretch property. - * @type string $font_variant The @font-face font-variant property. - * @type string $font_feature_settings The @font-face font-feature-settings property. - * @type string $font_variation_settings The @font-face font-variation-settings property. - * @type string $line_gap_override The @font-face line-gap-override property. - * @type string $size_adjust The @font-face size-adjust property. - * @type string $unicode_range The @font-face unicode-range property. - * @type string $ascend_override The @font-face ascend-override property. - * @type string $descend_override The @font-face descend-override property. - * } - * @return string Registration key. - */ - public function register( array $webfont ) { - $webfont = $this->convert_to_kebab_case( $webfont ); - - // Validate schema. - if ( ! $this->validator->is_valid_schema( $webfont ) ) { - return ''; - } - - $webfont = $this->validator->set_valid_properties( $webfont ); - - // Add to registry. - $registration_key = $this->generate_registration_key( $webfont ); - if ( isset( $this->registered[ $registration_key ] ) ) { - return $registration_key; - } - - $this->registered[ $registration_key ] = $webfont; - $this->store_for_query_by( $webfont, $registration_key ); - - return $registration_key; - } - - /** - * Convert snake_case keys into kebab-case. - * - * @since 5.9.0 - * - * @param array $webfont Webfont definition. - * @return array Webfont with kebab-case properties (keys). - */ - private function convert_to_kebab_case( array $webfont ) { - $kebab_case = array(); - foreach ( $webfont as $key => $value ) { - $converted_key = str_replace( '_', '-', $key ); - $kebab_case[ $converted_key ] = $value; - } - - return $kebab_case; - } - - /** - * Store the webfont for query by request. - * - * This container provides a performant way to quickly query webfonts by - * provider. The registration keys are stored for O(1) lookup. - * - * @since 5.9.0 - * - * @param array $webfont Webfont definition. - * @param string $registration_key Webfont's registration key. - */ - private function store_for_query_by( array $webfont, $registration_key ) { - $provider = $webfont['provider']; - - // Initialize the array if it does not exist. - if ( ! isset( $this->registry_by_provider[ $provider ] ) ) { - $this->registry_by_provider[ $provider ] = array(); - } - - $this->registry_by_provider[ $provider ][] = $registration_key; - } - - /** - * Generates the registration key. - * - * Format: font-family.font-style.font-weight - * For example: `'open-sans.normal.400'`. - * - * @since 5.9.0 - * - * @param array $webfont Webfont definition. - * @return string Registration key. - */ - private function generate_registration_key( array $webfont ) { - return sprintf( - '%s.%s.%s', - $this->convert_font_family_into_key( $webfont['font-family'] ), - trim( $webfont['font-style'] ), - trim( $webfont['font-weight'] ) - ); - } - - /** - * Converts the given font family into a key. - * - * For example: 'Open Sans' becomes 'open-sans'. - * - * @since 5.9.0 - * - * @param string $font_family Font family to convert into a key. - * @return string Font-family as a key. - */ - private function convert_font_family_into_key( $font_family ) { - return sanitize_title( $font_family ); - } -} diff --git a/lib/webfonts-api/class-wp-webfonts-schema-validator.php b/lib/webfonts-api/class-wp-webfonts-schema-validator.php deleted file mode 100644 index 85ec5966a6a4dc..00000000000000 --- a/lib/webfonts-api/class-wp-webfonts-schema-validator.php +++ /dev/null @@ -1,335 +0,0 @@ - 'local', - 'font-family' => '', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ); - - /** - * Webfont being validated. - * - * Set as a property for performance. - * - * @var array - */ - private $webfont = array(); - - /** - * Checks if the given webfont schema is valid. - * - * @since 5.9.0 - * - * @param array $webfont Webfont to validate. - * @return bool True when valid. False when invalid. - */ - public function is_valid_schema( array $webfont ) { - $is_valid = ( - $this->is_valid_provider( $webfont ) && - $this->is_valid_font_family( $webfont ) - ); - - if ( ! $is_valid ) { - return false; - } - - if ( 'local' === $webfont['provider'] || array_key_exists( 'src', $webfont ) ) { - $is_valid = $this->is_src_valid( $webfont ); - } - - return $is_valid; - } - - /** - * Checks if the provider is valid. - * - * @since 5.9.0 - * - * @param array $webfont Webfont to validate. - * @return bool True if valid. False if invalid. - */ - private function is_valid_provider( array $webfont ) { - if ( - empty( $webfont['provider'] ) || - ! is_string( $webfont['provider'] ) - ) { - trigger_error( __( 'Webfont provider must be a non-empty string.', 'gutenberg' ) ); - - return false; - } - - return true; - } - - /** - * Checks if the font family is valid. - * - * @since 5.9.0 - * - * @param array $webfont Webfont to validate. - * @return bool True when valid. False when invalid. - */ - private function is_valid_font_family( array $webfont ) { - if ( - empty( $webfont['font-family'] ) || - ! is_string( $webfont['font-family'] ) - ) { - trigger_error( __( 'Webfont font family must be a non-empty string.', 'gutenberg' ) ); - - return false; - } - - return true; - } - - /** - * Checks if the "src" value is valid. - * - * @since 5.9.0 - * - * @param array $webfont Webfont to validate. - * @return bool True if valid. False if invalid. - */ - private function is_src_valid( array $webfont ) { - 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; - } - - 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; - } - - if ( ! $this->is_src_value_valid( $src ) ) { - trigger_error( __( 'Webfont src must be a valid URL or a data URI.', 'gutenberg' ) ); - - return false; - } - } - - return true; - } - - /** - * Checks if the given `src` value is valid. - * - * @since 5.9.0 - * - * @param string $src Source to validate. - * @return bool True when valid. False when invalid. - */ - private function is_src_value_valid( $src ) { - if ( - // Validate data URLs. - preg_match( '/^data:.+;base64/', $src ) || - // Validate URLs. - filter_var( $src, FILTER_VALIDATE_URL ) || - // Check if it's a URL starting with "//" (omitted protocol). - 0 === strpos( $src, '//' ) - ) { - return true; - } - - return false; - } - - /** - * Sets valid properties. - * - * @since 5.9.0 - * - * @param array $webfont Webfont definition. - * @return array Updated webfont. - */ - public function set_valid_properties( array $webfont ) { - $this->webfont = array_merge( $this->basic_schema, $webfont ); - - $this->set_valid_font_face_property(); - $this->set_valid_font_style(); - $this->set_valid_font_weight(); - $this->set_valid_font_display(); - - $webfont = $this->webfont; - $this->webfont = array(); // Reset property. - - return $webfont; - } - - /** - * Checks if the CSS property is valid for @font-face. - * - * @since 5.9.0 - */ - private function set_valid_font_face_property() { - foreach ( array_keys( $this->webfont ) as $property ) { - /* - * Skip valid configuration parameters - * (these are configuring the webfont but are not @font-face properties). - */ - if ( 'provider' === $property || 'provider-params' === $property ) { - continue; - } - - if ( ! in_array( $property, $this->font_face_properties, true ) ) { - unset( $this->webfont[ $property ] ); - } - } - } - - /** - * Sets a default font-style if invalid. - * - * @since 5.9.0 - */ - private function set_valid_font_style() { - // If empty or not a string, trigger an error and then set the default value. - if ( - empty( $this->webfont['font-style'] ) || - ! is_string( $this->webfont['font-style'] ) - ) { - trigger_error( __( 'Webfont font style must be a non-empty string.', 'gutenberg' ) ); - - } elseif ( // Bail out if the font-style is a valid value. - in_array( $this->webfont['font-style'], self::VALID_FONT_STYLE, true ) || - preg_match( '/^oblique\s+(\d+)%/', $this->webfont['font-style'] ) - ) { - return; - } - - $this->webfont['font-style'] = 'normal'; - } - - /** - * Sets a default font-weight if invalid. - * - * @since 5.9.0 - */ - private function set_valid_font_weight() { - // If empty or not a string, trigger an error and then set the default value. - if ( - empty( $this->webfont['font-weight'] ) || - ! is_string( $this->webfont['font-weight'] ) - ) { - trigger_error( __( 'Webfont font weight must be a non-empty string.', 'gutenberg' ) ); - - } elseif ( // Bail out if the font-weight is a valid value. - // Check if value is a single font-weight, formatted as a number. - in_array( $this->webfont['font-weight'], self::VALID_FONT_WEIGHT, true ) || - // Check if value is a single font-weight, formatted as a number. - preg_match( '/^(\d+)$/', $this->webfont['font-weight'], $matches ) || - // Check if value is a range of font-weights, formatted as a number range. - preg_match( '/^(\d+)\s+(\d+)$/', $this->webfont['font-weight'], $matches ) - ) { - return; - } - - // Not valid. Set the default value. - $this->webfont['font-weight'] = '400'; - } - - /** - * Sets a default font-display if invalid. - * - * @since 5.9.0 - */ - private function set_valid_font_display() { - if ( - empty( $this->webfont['font-display'] ) || - ! in_array( $this->webfont['font-display'], self::VALID_FONT_DISPLAY, true ) - ) { - $this->webfont['font-display'] = 'fallback'; - } - } -} diff --git a/lib/webfonts-api/providers/class-wp-webfonts-provider.php b/lib/webfonts-api/providers/class-wp-webfonts-provider.php deleted file mode 100644 index f6a66b4d73812c..00000000000000 --- a/lib/webfonts-api/providers/class-wp-webfonts-provider.php +++ /dev/null @@ -1,135 +0,0 @@ -` in the ``. - * - * @since 5.9.0 - * - * @var string[] { - * Resource attributes for each relation type (e.g. 'preconnect' or 'prerender'). - * - * @type string $relation_type => array { - * Array of resource attributes. - * - * @type string $href URL to include in resource hints. Required. - * @type string $as Optional. How the browser should treat the resource - * (`script`, `style`, `image`, `document`, etc). - * @type string $crossorigin Optional. Indicates the CORS policy of the specified resource. - * @type float $pr Optional. Expected probability that the resource hint will be used. - * @type string $type Optional. Type of the resource (`text/html`, `text/css`, etc). - * } - * } - */ - protected $resource_hints = array(); - - /** - * Get the provider's unique ID. - * - * @since 5.9.0 - * - * @return string - */ - public function get_id() { - return $this->id; - } - - /** - * Sets this provider's webfonts property. - * - * The API's Controller passes this provider's webfonts - * for processing here in the provider. - * - * @since 5.9.0 - * - * @param array[] $webfonts Registered webfonts. - */ - public function set_webfonts( array $webfonts ) { - $this->webfonts = $webfonts; - } - - /** - * Gets the `@font-face` CSS for the provider's webfonts. - * - * This method is where the provider does it processing to build the - * needed `@font-face` CSS for all of its webfonts. Specifics of how - * this processing is done is contained in each provider. - * - * @since 5.9.0 - * - * @return string The `@font-face` CSS. - */ - abstract public function get_css(); - - /** - * Gets the provider's resource hints. - * - * The Controller calls this method {@see WP_Webfonts_Controller::get_resource_hints()} - * when the `'wp_resource_hints'` filter fires. - * - * @since 5.9.0 - * - * @return string[] Array of resource attributes. - * See {@see WP_Webfonts_Provider::$resource_hints} for - * the list of resource hints. - */ - public function get_resource_hints() { - return $this->resource_hints; - } -} diff --git a/lib/webfonts.php b/lib/webfonts.php index 2ad7fcee36eb94..c722b9521548d3 100644 --- a/lib/webfonts.php +++ b/lib/webfonts.php @@ -2,7 +2,7 @@ /** * Webfonts API: Webfonts functions * - * @since 5.9.0 + * @since 6.0.0 * * @package WordPress * @subpackage Webfonts @@ -11,20 +11,15 @@ /** * Instantiates the webfonts controller, if not already set, and returns it. * - * @since 5.9.0 + * @since 6.0.0 * - * @return WP_Webfonts_Controller Instance of the controller. + * @return WP_Webfonts Instance of the controller. */ function wp_webfonts() { static $instance; - if ( ! $instance instanceof WP_Webfonts_Controller ) { - $instance = new WP_Webfonts_Controller( - new WP_Webfonts_Registry( - new WP_Webfonts_Schema_Validator() - ), - new WP_Webfonts_Provider_Registry() - ); + if ( ! $instance instanceof WP_Webfonts ) { + $instance = new WP_Webfonts(); $instance->init(); } @@ -79,7 +74,7 @@ function wp_webfonts() { * ); * * - * @since 5.9.0 + * @since 6.0.0 * * @param array $webfonts Webfonts to be registered. * This contains an array of webfonts to be registered. @@ -89,7 +84,7 @@ function wp_webfonts() { */ function wp_register_webfonts( array $webfonts = array() ) { foreach ( $webfonts as $webfont ) { - wp_webfonts()->webfonts()->register( $webfont ); + wp_register_webfont( $webfont ); } } @@ -123,14 +118,13 @@ function wp_register_webfonts( array $webfonts = array() ) { * ); * ``` * - * @since 5.9.0 + * @since 6.0.0 * * @param array $webfont Webfont to be registered. * See {@see WP_Webfonts_Registry::register()} for a list of supported arguments. - * @return string Registration key. */ function wp_register_webfont( array $webfont ) { - return wp_webfonts()->webfonts()->register( $webfont ); + wp_webfonts()->register_font( $webfont ); } /** @@ -151,16 +145,17 @@ function wp_register_webfont( array $webfont ) { * wp_register_webfont_provider( My_Custom_Font_Service_Provider::class ); * ``` * - * @since 5.9.0 + * @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 when registered. False when provider does not exist. */ -function wp_register_webfont_provider( $classname ) { - return wp_webfonts()->providers()->register( $classname ); +function wp_register_webfont_provider( $name, $classname ) { + return wp_webfonts()->register_provider( $name, $classname ); } /** @@ -175,11 +170,11 @@ function wp_register_webfont_provider( $classname ) { * process its specific font service (i.e. local or remote) * and how to generate the `@font-face` styles for its service. * - * @since 5.9.0 + * @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()->providers()->get_all_registered(); + return wp_webfonts()->get_providers(); } diff --git a/phpunit/webfonts-api/providers/class-wp-webfonts-local-provider-test.php b/phpunit/class-wp-webfonts-local-provider-test.php similarity index 84% rename from phpunit/webfonts-api/providers/class-wp-webfonts-local-provider-test.php rename to phpunit/class-wp-webfonts-local-provider-test.php index 0db1ea11c3f941..69892d277bc227 100644 --- a/phpunit/webfonts-api/providers/class-wp-webfonts-local-provider-test.php +++ b/phpunit/class-wp-webfonts-local-provider-test.php @@ -4,20 +4,15 @@ * @group webfonts * @covers WP_WebfontsLocal_Provider */ -class WP_Webfonts_Local_Provider_Test extends WP_UnitTestCase { +class WP_Webfonts_Provider_Local_Test extends WP_UnitTestCase { private $provider; private $theme_root; private $orig_theme_dir; - public static function setUpBeforeClass() { - require_once dirname( dirname( dirname( __DIR__ ) ) ) . '/lib/webfonts-api/providers/class-wp-webfonts-provider.php'; - require_once dirname( dirname( dirname( __DIR__ ) ) ) . '/lib/webfonts-api/providers/class-wp-webfonts-local-provider.php'; - } - public function setUp() { parent::setUp(); - $this->provider = new WP_Webfonts_Local_Provider(); + $this->provider = new WP_Webfonts_Provider_Local(); $this->set_up_theme(); } @@ -53,11 +48,11 @@ function tear_down() { } /** - * @covers WP_Webfonts_Local_Provider::set_webfonts + * @covers WP_Webfonts_Provider_Local::set_webfonts */ public function test_set_webfonts() { $webfonts = array( - 'source-serif-pro.normal.200 900' => array( + 'source-serif-pro-200-900-normal-local' => array( 'provider' => 'local', 'font-family' => 'Source Serif Pro', 'font-style' => 'normal', @@ -65,7 +60,7 @@ public function test_set_webfonts() { 'font-stretch' => 'normal', 'src' => 'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', ), - 'source-serif-pro.italic.200 900' => array( + 'source-serif-pro-200-900-italic-local' => array( 'provider' => 'local', 'font-family' => 'Source Serif Pro', 'font-style' => 'italic', @@ -82,11 +77,11 @@ public function test_set_webfonts() { } /** - * @covers WP_Webfonts_Local_Provider::get_css + * @covers WP_Webfonts_Provider_Local::get_css * * @dataProvider data_get_css * - * @param array $webfonts Prepared webfonts (to store in WP_Webfonts_Local_Provider::$webfonts property). + * @param array $webfonts Prepared webfonts (to store in WP_Webfonts_Provider_Local::$webfonts property). * @param string $expected Expected CSS. */ public function test_get_css( array $webfonts, $expected ) { @@ -105,7 +100,7 @@ public function data_get_css() { return array( 'truetype format' => array( 'webfonts' => array( - 'open-sans.italic.bold' => array( + 'open-sans-bold-italic-local' => array( 'provider' => 'local', 'font-family' => 'Open Sans', 'font-style' => 'italic', @@ -120,7 +115,7 @@ public function data_get_css() { ), 'woff2 format' => array( 'webfonts' => array( - 'source-serif-pro.normal.200 900' => array( + 'source-serif-pro-200-900-normal-local' => array( 'provider' => 'local', 'font-family' => 'Source Serif Pro', 'font-style' => 'normal', @@ -128,7 +123,7 @@ public function data_get_css() { 'font-stretch' => 'normal', 'src' => 'http://example.org/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2', ), - 'source-serif-pro.italic.400 900' => array( + 'source-serif-pro-400-900-italic-local' => array( 'provider' => 'local', 'font-family' => 'Source Serif Pro', 'font-style' => 'italic', diff --git a/phpunit/class-wp-webfonts-test.php b/phpunit/class-wp-webfonts-test.php new file mode 100644 index 00000000000000..5b7edc6b2bceee --- /dev/null +++ b/phpunit/class-wp-webfonts-test.php @@ -0,0 +1,143 @@ + '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', + ), + array( + 'provider' => 'local', + 'font-family' => 'Source Serif Pro', + '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( + 'source-serif-pro-200-900-normal-local' => $fonts[0], + 'source-serif-pro-200-900-italic-local' => $fonts[1], + ); + + wp_register_webfonts( $fonts ); + $this->assertEquals( $expected, wp_webfonts()->get_fonts() ); + } + + /** + * @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() + ); + } + + /** + * @covers WP_Webfonts::validate_font + */ + public function test_validate_font() { + // Test empty array. + $this->assertFalse( wp_webfonts()->validate_font( 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_font( $font )['provider'] ); + + // Test missing font-weight fallback to 400. + $this->assertEquals( '400', wp_webfonts()->validate_font( $font )['font-weight'] ); + + // Test missing font-style fallback to normal. + $this->assertEquals( 'normal', wp_webfonts()->validate_font( $font )['font-style'] ); + + // Test missing font-display fallback to fallback. + $this->assertEquals( 'fallback', wp_webfonts()->validate_font( $font )['font-display'] ); + + // Test local font with missing "src". + $this->assertFalse( wp_webfonts()->validate_font( array( 'font-family' => 'Test Font 2' ) ) ); + + // Test malformatted src. + $invalid_src_values = array( + '', // Empty string. + array(), // EMpty array. + 10, // Not a string or array. + array( '', 'https://example.com/font.woff2' ), // Array containing an empty string. + 'invalid-url', // Not a valid URL. + ); + foreach ( $invalid_src_values as $invalid_src_value ) { + $font['src'] = $invalid_src_value; + $this->assertFalse( wp_webfonts()->validate_font( $font ) ); + } + + // Test valid src URL, without a protocol. + $font['src'] = '//example.com/SourceSerif4Variable-Roman.ttf.woff2'; + $this->assertEquals( wp_webfonts()->validate_font( $font )['src'], $font['src'] ); + + // Test valid font. + $this->assertNotEmpty( wp_webfonts()->validate_font( $font ) ); + + // Test font-style. + $font['font-style'] = 'invalid'; + $this->assertFalse( wp_webfonts()->validate_font( $font ) ); + $font['font-style'] = 'italic'; + $this->assertNotEmpty( wp_webfonts()->validate_font( $font ) ); + + // Test font-weight. + $font_weights = array( + 'invalid' => array( 'invalid', '', '100-900' ), + 'valid' => array( 100, '100', '100 900', 'normal' ), + ); + foreach ( $font_weights['invalid'] as $value ) { + $font['font-weight'] = $value; + $this->assertFalse( wp_webfonts()->validate_font( $font ) ); + } + foreach ( $font_weights['valid'] as $value ) { + $font['font-weight'] = $value; + $this->assertEquals( wp_webfonts()->validate_font( $font )['font-weight'], $value ); + } + + // Test that invalid keys get removed from the font. + $font['invalid-key'] = 'invalid'; + $this->assertArrayNotHasKey( 'invalid-key', wp_webfonts()->validate_font( $font ) ); + } + + /** + * @covers WP_Webfonts::generate_styles + */ + public function test_generate_styles() { + $this->assertEquals( + wp_webfonts()->generate_styles(), + '@font-face{font-family:"Source Serif Pro";font-style:normal;font-weight:200 900;font-display:fallback;font-stretch:normal;src:local("Source Serif Pro"), url(\'https://example.com/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-display:fallback;font-stretch:normal;src:local("Source Serif Pro"), url(\'https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2\') format(\'woff2\');}' + ); + } +} diff --git a/phpunit/webfonts-api/class-wp-webfonts-controller-test.php b/phpunit/webfonts-api/class-wp-webfonts-controller-test.php deleted file mode 100644 index 2f9dad2b9db463..00000000000000 --- a/phpunit/webfonts-api/class-wp-webfonts-controller-test.php +++ /dev/null @@ -1,211 +0,0 @@ -webfont_registry_mock = $this->getMockBuilder( 'WP_Webfonts_Registry' ) - ->disableOriginalConstructor() - ->getMock(); - $this->provider_registry_mock = $this->getMockBuilder( 'WP_Webfonts_Provider_Registry' ) - ->getMock(); - $this->controller = new WP_Webfonts_Controller( - $this->webfont_registry_mock, - $this->provider_registry_mock - ); - } - - /** - * @covers WP_Webfonts_Controller::init - * - * @dataProvider data_init - * - * @param string $hook Expected hook name. - * @param bool $did_action Whether the action fired or not. - */ - public function test_init( $hook, $did_action ) { - $this->provider_registry_mock - ->expects( $this->once() ) - ->method( 'init' ); - - if ( $did_action ) { - do_action( 'wp_enqueue_scripts' ); - } - - $this->controller->init(); - - $this->assertSame( - 10, - has_action( $hook, array( $this->controller, 'generate_and_enqueue_styles' ) ) - ); - $this->assertSame( - 10, - has_action( 'admin_init', array( $this->controller, 'generate_and_enqueue_editor_styles' ) ) - ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_init() { - return array( - 'did_action fired' => array( - 'hook' => 'wp_print_footer_scripts', - 'did_action' => true, - ), - 'did_action did not fire' => array( - 'hook' => 'wp_enqueue_scripts', - 'did_action' => false, - ), - ); - } - - /** - * By default, the Webfonts API should not request webfonts from - * a remote provider. Test the permissions logic works as expected. - * - * @covers WP_Webfonts_Controller::generate_and_enqueue_styles - * - * @dataProvider data_generate_and_enqueue_editor_styles - * - * @param string $stylesheet_handle Handle for the registered stylesheet. - */ - public function test_generate_and_enqueue_styles_default( $stylesheet_handle ) { - /* - * Set the stylesheet_handle property. - * This is set in WP_Webfonts_Controller::init(); however, init is not part - * of this test (as it has its own test). - */ - $property = new ReflectionProperty( $this->controller, 'stylesheet_handle' ); - $property->setAccessible( true ); - $property->setValue( $this->controller, $stylesheet_handle ); - - // Set up the provider mock. - $provider = $this->getMockBuilder( 'WP_Webfonts_Local_Provider' )->getMock(); - $providers = array( - 'local' => $provider, - ); - $this->provider_registry_mock - ->expects( $this->once() ) - ->method( 'get_all_registered' ) - ->willReturn( $providers ); - // The Local Fonts provider should never be called. - $provider - ->expects( $this->never() ) - ->method( 'set_webfonts' ); - - // Fire the method being tested. - $this->controller->generate_and_enqueue_styles(); - $this->expectOutputString( '' ); - wp_print_styles( $stylesheet_handle ); - } - - /** - * @covers WP_Webfonts_Controller::generate_and_enqueue_styles - * @covers WP_Webfonts_Controller::generate_and_enqueue_editor_styles - * - * @dataProvider data_generate_and_enqueue_editor_styles - * - * @param string $stylesheet_handle Handle for the registered stylesheet. - */ - public function test_generate_and_enqueue_styles_with_permission( $stylesheet_handle ) { - add_filter( 'has_remote_webfonts_request_permission', '__return_true' ); - - /* - * Set the stylesheet_handle property. - * This is set in WP_Webfonts_Controller::init(); however, init is not part - * of this test (as it has its own test). - */ - $property = new ReflectionProperty( $this->controller, 'stylesheet_handle' ); - $property->setAccessible( true ); - $property->setValue( $this->controller, $stylesheet_handle ); - - // Set up the provider mock. - $provider = new My_Custom_Webfonts_Provider_Mock(); - $providers = array( - 'my-custom-provider' => $provider, - ); - $this->provider_registry_mock - ->expects( $this->once() ) - ->method( 'get_all_registered' ) - ->willReturn( $providers ); - - // Set up the webfonts registry mock. - $webfonts = array( - 'source-serif-pro.normal.200 900' => array( - 'provider' => 'my-custom-provider', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - ), - 'source-serif-pro.italic.200 900' => array( - 'provider' => 'my-custom-provider', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'italic', - 'font-weight' => '200 900', - ), - ); - $this->webfont_registry_mock - ->expects( $this->once() ) - ->method( 'get_by_provider' ) - ->with( $this->equalTo( 'my-custom-provider' ) ) - ->willReturn( $webfonts ); - - // Fire the method being tested. - $this->controller->generate_and_enqueue_styles(); - - /* - * As this method adds an inline style, the test needs to print it. - * Print the webfont styles and test the output matches expectation. - */ - $expected = "\n"; - $this->expectOutputString( $expected ); - wp_print_styles( $stylesheet_handle ); - } - - /** - * Data provider. - * - * @return array - */ - public function data_generate_and_enqueue_editor_styles() { - return array( - 'for wp_enqueue_scripts' => array( 'webfonts' ), - 'for wp_print_footer_scripts' => array( 'webfonts-footer' ), - ); - } - - /** - * @covers WP_Webfonts_Controller::webfonts - */ - public function test_webfonts() { - $this->assertSame( $this->webfont_registry_mock, $this->controller->webfonts() ); - } - - /** - * @covers WP_Webfonts_Controller::providers - */ - public function test_providers() { - $this->assertSame( $this->provider_registry_mock, $this->controller->providers() ); - } -} diff --git a/phpunit/webfonts-api/class-wp-webfonts-provider-registry-test.php b/phpunit/webfonts-api/class-wp-webfonts-provider-registry-test.php deleted file mode 100644 index 7db9d4a1a4df81..00000000000000 --- a/phpunit/webfonts-api/class-wp-webfonts-provider-registry-test.php +++ /dev/null @@ -1,82 +0,0 @@ -assertSame( array(), $registry->get_all_registered() ); - } - - /** - * @covers WP_Webfonts_Provider_Registry::register - * @covers WP_Webfonts_Provider_Registry::get_all_registered - */ - public function test_register_with_invalid_class() { - $registry = new WP_Webfonts_Provider_Registry(); - $registry->register( 'DoesNotExist' ); - - $this->assertSame( array(), $registry->get_all_registered() ); - } - - /** - * @covers WP_Webfonts_Provider_Registry::register - * @covers WP_Webfonts_Provider_Registry::get_all_registered - */ - public function test_register_with_valid_class() { - $registry = new WP_Webfonts_Provider_Registry(); - $registry->register( My_Custom_Webfonts_Provider_Mock::class ); - - $providers = $registry->get_all_registered(); - - $this->assertIsArray( $providers ); - $this->assertCount( 1, $providers ); - $this->assertArrayHasKey( 'my-custom-provider', $providers ); - $this->assertInstanceOf( 'My_Custom_Webfonts_Provider_Mock', $providers['my-custom-provider'] ); - } - - /** - * @covers WP_Webfonts_Provider_Registry::init - * @covers WP_Webfonts_Provider_Registry::get_all_registered - */ - public function test_init() { - $registry = new WP_Webfonts_Provider_Registry(); - // Register the core providers. - $registry->init(); - - $providers = $registry->get_all_registered(); - - $expected = array( 'local' ); - $this->assertSame( $expected, array_keys( $providers ) ); - $this->assertInstanceOf( 'WP_Webfonts_Local_Provider', $providers['local'] ); - } - - /** - * @covers WP_Webfonts_Provider_Registry::register - * @covers WP_Webfonts_Provider_Registry::get_all_registered - */ - public function test_register_with_core_providers() { - $registry = new WP_Webfonts_Provider_Registry(); - // Register the core providers. - $registry->init(); - // Register a custom provider. - $registry->register( My_Custom_Webfonts_Provider_Mock::class ); - - $providers = $registry->get_all_registered(); - - $expected = array( 'local', 'my-custom-provider' ); - $this->assertSame( $expected, array_keys( $providers ) ); - } -} diff --git a/phpunit/webfonts-api/class-wp-webfonts-registry-test.php b/phpunit/webfonts-api/class-wp-webfonts-registry-test.php deleted file mode 100644 index 4e489fb753cf12..00000000000000 --- a/phpunit/webfonts-api/class-wp-webfonts-registry-test.php +++ /dev/null @@ -1,341 +0,0 @@ -validator_mock = $this->getMockBuilder( 'WP_Webfonts_Schema_Validator' )->getMock(); - - $this->registry = new WP_Webfonts_Registry( $this->validator_mock ); - } - - /** - * @covers WP_Webfonts_Registry::get_all_registered - */ - public function test_get_all_registered() { - $expected = array( - 'open-sans.normal.400' => array( - 'provider' => 'local', - 'font-family' => 'Open Sans', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - 'roboto.normal.900' => array( - 'provider' => 'local', - 'font-family' => 'Robot', - 'font-style' => 'normal', - 'font-weight' => '900', - 'font-display' => 'fallback', - ), - ); - - /* - * Set the registry property. - * This is set in WP_Webfonts_Registry::register(), which not part of this test. - */ - $property = new ReflectionProperty( $this->registry, 'registered' ); - $property->setAccessible( true ); - $property->setValue( $this->registry, $expected ); - - $this->assertSame( $expected, $this->registry->get_all_registered() ); - } - - /** - * @covers WP_Webfonts_Registry::register - * - * @dataProvider data_register_with_invalid_schema - * - * @param array $webfont Webfonts input. - */ - public function test_register_with_invalid_schema( array $webfont ) { - $this->validator_mock - ->expects( $this->once() ) - ->method( 'is_valid_schema' ) - ->willReturn( false ); - $this->validator_mock - ->expects( $this->never() ) - ->method( 'set_valid_properties' ); - - $this->assertSame( '', $this->registry->register( $webfont ) ); - } - - /** - * Data Provider. - * - * @return array - */ - public function data_register_with_invalid_schema() { - return array( - 'empty array - no schema' => array( - array(), - ), - 'provider: not defined' => array( - array( - 'font_family' => 'Some Font', - 'font_style' => 'normal', - 'font_weight' => '400', - ), - ), - 'provider: empty string' => array( - array( - 'provider' => '', - 'font_family' => 'Some Font', - 'font_style' => 'normal', - 'font_weight' => '400', - ), - ), - 'provider: not a string' => array( - array( - 'provider' => null, - 'font_family' => 'Some Font', - 'font_style' => 'normal', - 'font_weight' => '400', - ), - ), - 'font family: not defined' => array( - array( - 'provider' => 'local', - 'font_style' => 'normal', - 'font_weight' => '400', - ), - ), - 'font-family: not defined' => array( - array( - 'provider' => 'some-provider', - 'font_style' => 'normal', - 'font_weight' => '400', - ), - ), - 'font-family: empty string' => array( - array( - 'provider' => 'some-provider', - 'font_family' => '', - 'font_style' => 'normal', - 'font_weight' => '400', - ), - ), - 'font-family: not a string' => array( - array( - 'provider' => 'some-provider', - 'font_family' => null, - 'font_style' => 'normal', - 'font_weight' => '400', - ), - ), - ); - } - - /** - * @covers WP_Webfonts_Registry::register - * - * @dataProvider data_register_with_valid_schema - * - * @param array $webfont Webfont input. - * @param array $validated_webfont Webfont after being processed by the validator. - * @param string $expected Expected return value. - */ - public function test_register_with_valid_schema( array $webfont, array $validated_webfont, $expected ) { - $this->validator_mock - ->expects( $this->once() ) - ->method( 'is_valid_schema' ) - ->willReturn( true ); - $this->validator_mock - ->expects( $this->once() ) - ->method( 'set_valid_properties' ) - ->willReturn( $validated_webfont ); - - $this->assertSame( $expected, $this->registry->register( $webfont ) ); - } - - /** - * Data Provider. - * - * @return array - */ - public function data_register_with_valid_schema() { - return array( - 'valid schema without font-display' => array( - 'webfont' => array( - 'provider' => 'local', - 'font_family' => 'Roboto', - 'font_style' => 'normal', - 'font_weight' => 'normal', - ), - 'validated_webfont' => array( - 'provider' => 'local', - 'font-family' => 'Roboto', - 'font-style' => 'normal', - 'font-weight' => 'normal', - 'font-display' => 'fallback', - ), - 'expected' => 'roboto.normal.normal', - ), - 'valid schema with src' => array( - 'webfont' => 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', - ), - 'validated_webfont' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - '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', - ), - 'expected' => 'source-serif-pro.normal.200 900', - ), - ); - } - - /** - * @covers WP_Webfonts_Registry::get_by_provider - */ - public function test_get_by_provider_when_does_not_exist() { - /* - * Set the `registry_by_provider` property. - * This is set in WP_Webfonts_Registry::register(), which not part of this test. - */ - $property = new ReflectionProperty( $this->registry, 'registry_by_provider' ); - $property->setAccessible( true ); - $property->setValue( $this->registry, array( 'local' ) ); - - $this->assertSame( array(), $this->registry->get_by_provider( 'my-custom-provider' ) ); - } - - /** - * As there are many moving parts to getting by provider, this test is an integration - * test that does not mock. - * - * @covers WP_Webfonts_Registry::get_by_provider - * @covers WP_Webfonts_Registry::register - * - * @dataProvider data_get_by_provider_integrated - * - * @param array $webfonts Given webfont to register. - * @param string $provider_id Provider ID to query. - * @param array $expected Expected return value. - */ - public function test_get_by_provider_integrated( array $webfonts, $provider_id, array $expected ) { - $registry = new WP_Webfonts_Registry( new WP_Webfonts_Schema_Validator() ); - - foreach ( $webfonts as $webfont ) { - $registry->register( $webfont ); - } - - $this->assertSame( $expected, $registry->get_by_provider( $provider_id ) ); - } - - /** - * Data Provider. - * - * @return array - */ - public function data_get_by_provider_integrated() { - return array( - 'no webfonts for requested provider' => array( - 'webfonts' => array( - array( - 'provider' => 'local', - 'font_family' => 'Lato', - 'font_style' => 'italic', - 'font_weight' => '400', - ), - ), - 'provider_id' => 'local', - 'expected' => array(), - ), - 'with one provider' => array( - 'webfonts' => array( - array( - 'provider' => 'local', - 'font_family' => 'Lato', - 'font_style' => 'italic', - 'font_weight' => '400', - 'src' => 'https://example.com/lato-400i.woff2', - ), - array( - 'provider' => 'local', - 'font_family' => 'Roboto', - 'font_style' => 'normal', - 'font_weight' => '900', - 'src' => 'https://example.com/lato-900.woff2', - ), - ), - 'provider_id' => 'local', - 'expected' => array( - 'lato.italic.400' => array( - 'provider' => 'local', - 'font-family' => 'Lato', - 'font-style' => 'italic', - 'font-weight' => '400', - 'font-display' => 'fallback', - 'src' => 'https://example.com/lato-400i.woff2', - ), - 'roboto.normal.900' => array( - 'provider' => 'local', - 'font-family' => 'Roboto', - 'font-style' => 'normal', - 'font-weight' => '900', - 'font-display' => 'fallback', - 'src' => 'https://example.com/lato-900.woff2', - ), - ), - ), - 'with multiple providers' => array( - 'webfonts' => array( - array( - 'provider' => 'example', - 'font_family' => 'Open Sans', - 'font_style' => 'normal', - 'font_weight' => '400', - ), - 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', - ), - array( - 'provider' => 'example', - 'font_family' => 'Roboto', - 'font_style' => 'normal', - 'font_weight' => '900', - ), - ), - 'provider_id' => 'local', - 'expected' => array( - 'source-serif-pro.normal.200 900' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - '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', - ), - ), - ), - ); - } -} diff --git a/phpunit/webfonts-api/class-wp-webfonts-schema-validator-test.php b/phpunit/webfonts-api/class-wp-webfonts-schema-validator-test.php deleted file mode 100644 index 7b7d23dc564ba2..00000000000000 --- a/phpunit/webfonts-api/class-wp-webfonts-schema-validator-test.php +++ /dev/null @@ -1,463 +0,0 @@ -assertTrue( self::$validator->is_valid_schema( $webfont ) ); - } - - /** - * Data Provider. - * - * @return array - */ - public function data_is_valid_schema_with_valid() { - return array( - 'basic schema' => array( - array( - 'provider' => 'local', - 'font-family' => 'Open Sans', - 'font-style' => 'normal', - 'font-weight' => '400', - 'src' => 'https://example.com/open-sans-400.woff2', - ), - ), - ); - } - - /** - * @covers WP_Webfonts_Schema_Validator::is_valid_schema - * - * @dataProvider data_is_valid_schema_with_invalid - * - * @param array $webfont Webfont input. - */ - public function test_is_valid_schema_with_invalid( array $webfont ) { - $this->assertFalse( self::$validator->is_valid_schema( $webfont ) ); - } - - /** - * Data Provider. - * - * @return array - */ - public function data_is_valid_schema_with_invalid() { - return array( - 'empty array - no schema' => array( - 'webfont' => array(), - 'expected_message' => 'Webfont provider must be a non-empty string.', - ), - 'provider: not defined' => array( - 'webfont' => array( - 'font-family' => 'Some Font', - 'font-style' => 'normal', - 'font-weight' => '400', - ), - 'expected_message' => 'Webfont provider must be a non-empty string.', - ), - 'provider: empty string' => array( - 'webfont' => array( - 'provider' => '', - 'font-family' => 'Some Font', - 'font-style' => 'normal', - 'font-weight' => '400', - ), - 'expected_message' => 'Webfont provider must be a non-empty string.', - ), - 'provider: not a string' => array( - 'webfont' => array( - 'provider' => null, - 'font-family' => 'Some Font', - 'font-style' => 'normal', - 'font-weight' => '400', - ), - 'expected_message' => 'Webfont provider must be a non-empty string.', - ), - 'font-family: not defined' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-style' => 'normal', - 'font-weight' => '400', - ), - 'expected_message' => 'Webfont font family must be a non-empty string.', - ), - 'font-family: empty string' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-family' => '', - 'font-style' => 'normal', - 'font-weight' => '400', - ), - 'expected_message' => 'Webfont font family must be a non-empty string.', - ), - 'font-family: not a string' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-family' => null, - 'font-style' => 'normal', - 'font-weight' => '400', - ), - 'expected_message' => 'Webfont font family must be a non-empty string.', - ), - 'src: not defined' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - ), - 'expected_message' => 'Webfont src must be a non-empty string or an array of strings.', - ), - 'src: type is invalid' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'src' => null, - ), - 'expected_message' => 'Webfont src must be a non-empty string or an array of strings.', - ), - 'src: individual src is not a string' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'src' => array( null ), - ), - 'expected_message' => 'Each webfont src must be a non-empty string.', - ), - 'src: invalid url' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'src' => '/assets/fonts/font.woff2', - ), - 'expected_message' => 'Webfont src must be a valid URL or a data URI.', - ), - 'src: invalid data uri' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'src' => 'data:text/plain', - ), - 'expected_message' => 'Webfont src must be a valid URL or a data URI.', - ), - ); - } - - /** - * @covers WP_Webfonts_Schema_Validator::set_valid_properties - * - * @dataProvider data_set_valid_properties_with_valid_input - * - * @param array $webfont Webfont input. - * @param array $expected Expected updated webfont. - */ - public function test_set_valid_properties_with_valid_input( array $webfont, array $expected ) { - $this->assertSame( $expected, self::$validator->set_valid_properties( $webfont ) ); - } - - /** - * Data Provider. - * - * @return array - */ - public function data_set_valid_properties_with_valid_input() { - return array( - 'basic schema' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-family' => 'Open Sans', - 'font-style' => 'normal', - 'font-weight' => '400', - ), - 'expected' => array( - 'provider' => 'local', - 'font-family' => 'Open Sans', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - ), - 'basic schema in opposite order' => array( - 'webfont' => array( - 'font-weight' => '400', - 'font-style' => 'normal', - 'font-family' => 'Open Sans', - 'provider' => 'local', - ), - 'expected' => array( - 'provider' => 'local', - 'font-family' => 'Open Sans', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - ), - 'src: with protocol' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'src' => 'http://example.org/assets/fonts/SourceSerif4Variable-Roman.ttf.woff2', - ), - 'expected' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-display' => 'fallback', - 'src' => 'http://example.org/assets/fonts/SourceSerif4Variable-Roman.ttf.woff2', - ), - ), - 'src: without protocol' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'src' => '//example.org/assets/fonts/SourceSerif4Variable-Roman.ttf.woff2', - ), - 'expected' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-display' => 'fallback', - 'src' => '//example.org/assets/fonts/SourceSerif4Variable-Roman.ttf.woff2', - ), - ), - 'src: data:' => array( - 'webfont' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'src' => 'data:font/opentype; base64, SGVsbG8sIFdvcmxkIQ==', - ), - 'expected' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - 'font-style' => 'normal', - 'font-weight' => '200 900', - 'font-display' => 'fallback', - 'src' => 'data:font/opentype; base64, SGVsbG8sIFdvcmxkIQ==', - ), - ), - 'with font-stretch' => array( - 'webfont' => array( - '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', - 'provider' => 'local', - ), - 'expected' => array( - 'provider' => 'local', - 'font-family' => 'Source Serif Pro', - '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', - ), - ), - ); - } - - /** - * @covers WP_Webfonts_Schema_Validator::set_valid_properties - * - * @dataProvider data_set_valid_properties_with_invalid_input - * - * @param array $webfont Webfont input. - * @param array $expected Expected updated webfont. - */ - public function test_set_valid_properties_with_invalid_input( array $webfont, array $expected ) { - $this->assertSame( $expected, self::$validator->set_valid_properties( $webfont ) ); - } - - /** - * Data Provider. - * - * @return array - */ - public function data_set_valid_properties_with_invalid_input() { - return array( - 'empty array - no schema' => array( - 'webfont' => array(), - 'expected' => array( - 'provider' => 'local', - 'font-family' => '', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - ), - 'with invalid @font-face property' => array( - 'webfont' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'invalid' => 'should remove it', - ), - 'expected' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - ), - 'font-style: invalid value' => array( - 'webfont' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-style' => 'invalid', - ), - 'expected' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - ), - 'font-weight: invalid value' => array( - 'webfont' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-weight' => 'invalid', - ), - 'expected' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - ), - 'font-display: invalid value' => array( - 'webfont' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-display' => 'invalid', - ), - 'expected' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - ), - ); - } - - /** - * @covers WP_Webfonts_Schema_Validator::set_valid_properties - * - * @dataProvider data_set_valid_properties_with_invalid_and_error - * - * @param array $webfont Webfont input. - * @param array $expected Expected updated webfont. - */ - public function test_set_valid_properties_with_invalid_and_error( array $webfont, array $expected ) { - $this->assertSame( $expected, self::$validator->set_valid_properties( $webfont ) ); - } - - /** - * Data Provider. - * - * @return array - */ - public function data_set_valid_properties_with_invalid_and_error() { - return array( - 'font-style: empty value' => array( - 'webfont' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-style' => '', - ), - 'expected' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - 'expected_message' => 'Webfont font style must be a non-empty string.', - ), - 'font-style: not a string' => array( - 'webfont' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-style' => null, - ), - 'expected' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - 'expected_message' => 'Webfont font style must be a non-empty string.', - ), - 'font-weight: empty value' => array( - 'webfont' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-weight' => '', - ), - 'expected' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - 'expected_message' => 'Webfont font weight must be a non-empty string.', - ), - 'font-weight: not a string' => array( - 'webfont' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-weight' => true, - ), - 'expected' => array( - 'provider' => 'some-provider', - 'font-family' => 'Some Font', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ), - 'expected_message' => 'Webfont font weight must be a non-empty string.', - ), - ); - } -} diff --git a/phpunit/webfonts-api/mocks/class-my-custom-webfonts-provider-mock.php b/phpunit/webfonts-api/mocks/class-my-custom-webfonts-provider-mock.php deleted file mode 100644 index ac38f822a3ad03..00000000000000 --- a/phpunit/webfonts-api/mocks/class-my-custom-webfonts-provider-mock.php +++ /dev/null @@ -1,35 +0,0 @@ - array( - array( - 'href' => 'https://fonts.my-custom-api.com', - 'crossorigin' => 'anonymous', - ), - ), - ); - - public function get_css() { - return " - @font-face{ - font-family: 'Source Serif Pro'; - font-weight: 200 900; - font-style: normal; - font-stretch: normal; - src: url('https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2') format('woff2'); - } - @font-face{ - font-family: 'Source Serif Pro'; - font-weight: 200 900; - font-style: italic; - font-stretch: normal; - src: url('https://example.com/assets/fonts/source-serif-pro/SourceSerif4Variable-Italic.ttf.woff2') format('woff2'); - } - "; - } -}