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 ecc3407079c1ae..4ec5bdae15098b 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',
@@ -291,28 +311,31 @@ 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 array[] $webfonts_by_provider Webfonts organized by provider.
- * @return string $styles Generated styles.
+ * @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).
+ *
+ * @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;
- }
-
- $styles = '';
- $providers = $this->get_providers();
-
- $obj = $this->registered[ $handle ];
-
+ public function do_items( $handles = false, $group = false ) {
/*
- * Loop through each of the providers to get the CSS for their respective webfonts
- * to incrementally generate the collective styles for all of them.
+ * If nothing is passed, print the queue. If a string is passed,
+ * print that item. If an array is passed, print those items.
*/
- foreach ( $providers as $provider_id => $provider ) {
+ $handles = false === $handles ? $this->queue : (array) $handles;
+ $this->all_deps( $handles );
+
+ $this->to_do_keyed_handles = array_flip( $this->to_do );
+
+ foreach ( $this->get_providers() as $provider_id => $provider ) {
// Bail out if the provider class does not exist.
if ( ! class_exists( $provider['class'] ) ) {
/* translators: %s is the provider name. */
@@ -320,68 +343,134 @@ public function do_item( $handle, $group = false ) {
continue;
}
- $fonts = $this->get_enqueued_fonts_for_provider( $provider_id );
-
- // If there are no registered webfonts for this provider, skip it.
- 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_fonts );
- $styles .= $provider->get_css();
+ $this->do_item( $provider_id, $group );
}
- return $styles;
+ return $this->done;
}
/**
- * 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 adc824e8044317..1fd651990adbc7 100644
--- a/lib/experimental/webfonts.php
+++ b/lib/experimental/webfonts.php
@@ -259,16 +259,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;
}
@@ -285,14 +289,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..dc351625dcadf7 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';
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..ed8f8b2e2c04b4 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,26 @@ 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 $provider_id Provider's unique ID to set up.
+ * @param array $font_handles Optional. Font handles for this provider.
+ */
+ protected function setup_provider_property_mock( WP_Webfonts $wp_webfonts, $provider_id, array $font_handles = array() ) {
+ $property = $this->setup_property( WP_Webfonts::class, 'providers' );
+ $providers = $property->getValue( $wp_webfonts );
+ $value = isset( $providers[ $provider_id ] )
+ ? array_merge( $font_handles, $providers[ $provider_id ]['fonts'] )
+ : array(
+ $provider_id => array(
+ 'class' => 'local' === $provider_id ? WP_Webfonts_Provider_Local::class : Mock_Provider::class,
+ 'fonts' => $font_handles,
+ ),
+ );
+
+ $property->setValue( $wp_webfonts, $value );
+ }
}
diff --git a/phpunit/webfonts/wp-webfonts-tests-dataset.php b/phpunit/webfonts/wp-webfonts-tests-dataset.php
index 70a4326a6c1c15..b9f0af4ca0dcc9 100644
--- a/phpunit/webfonts/wp-webfonts-tests-dataset.php
+++ b/phpunit/webfonts/wp-webfonts-tests-dataset.php
@@ -552,4 +552,98 @@ protected function get_data_registry() {
),
);
}
+
+ protected function get_registered_fonts() {
+ return array_merge(
+ $this->get_registered_local_fonts(),
+ $this->get_registered_mock_fonts()
+ );
+ }
+
+ 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',
+ ),
+ ),
+ );
+ }
+
+ 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..ec2a4ea6dbb66f
--- /dev/null
+++ b/phpunit/webfonts/wpPrintWebfonts-test.php
@@ -0,0 +1,56 @@
+assertSame( array(), wp_print_webfonts() );
+ $this->assertNotInstanceOf( WP_Webfonts::class, $wp_webfonts );
+ }
+
+ /**
+ * @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 );
+ }
+
+ 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' ),
+ ),
+ );
+ }
+}
diff --git a/phpunit/webfonts/wpWebfonts/doItem-test.php b/phpunit/webfonts/wpWebfonts/doItem-test.php
new file mode 100644
index 00000000000000..7b4832d8c67029
--- /dev/null
+++ b/phpunit/webfonts/wpWebfonts/doItem-test.php
@@ -0,0 +1,370 @@
+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_id
+ *
+ * @param string $provider_id Provider to mock.
+ */
+ public function test_should_return_false_when_no_fonts_enqueued_for_provider( $provider_id ) {
+ $this->setup_provider_property_mock( $this->wp_webfonts, $provider_id );
+ $this->assertFalse( $this->wp_webfonts->do_item( $provider_id ) );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_provider_id() {
+ return array(
+ 'mock' => array( 'mock' ),
+ 'local' => array( '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, '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.
+ $method = new ReflectionMethod( $this->wp_webfonts, 'get_enqueued_fonts_for_provider' );
+ $method->setAccessible( true );
+
+ // Mock the WP_Webfonts::$property to set up the test.
+ $this->setup_provider_property_mock( $this->wp_webfonts, 'mock', $font_handles );
+
+ $actual = $method->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, '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 ) {
+ $provider_id = $provider['id'];
+ $provider_class = $provider['class'];
+ $this->setup_print_deps( $provider_id, $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 ) {
+ $provider_id = $provider['id'];
+
+ $this->setup_print_deps( $provider_id, $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();
+
+ return array(
+ 'mock' => array(
+ 'provider' => array(
+ 'id' => 'mock',
+ 'class' => Mock_Provider::class,
+ ),
+ 'fonts' => $mock,
+ 'expected' => array(
+ 'set_webfonts' => array_merge( $mock['font1'], $mock['font2'], $mock['font3'] ),
+ 'printed_output' => 'font1-300-normal; font1-300-italic; font1-900-normal; font2-200-900-normal; font2-200-900-italic; font3-bold-normal',
+ ),
+ ),
+ 'local' => array(
+ 'provider' => array(
+ 'id' => 'local',
+ 'class' => WP_Webfonts_Provider_Local::class,
+ ),
+ 'fonts' => $local,
+ 'expected' => array(
+ 'set_webfonts' => array_merge( $local['merriweather'], $local['Source Serif Pro'] ),
+ 'printed_output' => <<
+@font-face{font-family:Merriweather;font-style:normal;font-weight:200 900;font-display:fallback;font-stretch:normal;src:local(Merriweather), url('https://example.com/assets/fonts/merriweather.ttf.woff2') format('woff2');}@font-face{font-family:"Source Serif Pro";font-style:normal;font-weight:300;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: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');}
+
+
+CSS
+ ,
+ ),
+ ),
+ );
+ }
+
+ /**
+ * 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 ) {
+ $provider_id = $provider['id'];
+
+ $this->setup_print_deps( $provider_id, $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' => array(
+ 'id' => 'mock',
+ 'class' => Mock_Provider::class,
+ ),
+ 'fonts' => $mock,
+ 'expected' => array(),
+ 'to_do_queue' => array(),
+ ),
+ 'local provider when to_do queue is empty' => array(
+ 'provider' => array(
+ 'id' => 'local',
+ 'class' => WP_Webfonts_Provider_Local::class,
+ ),
+ 'fonts' => $local,
+ 'expected' => array(),
+ 'to_do_queue' => array(),
+ ),
+ 'fonts not in to_do queue' => array(
+ 'provider' => array(
+ 'id' => 'mock',
+ 'class' => Mock_Provider::class,
+ ),
+ 'fonts' => $mock,
+ 'expected' => array(),
+ 'to_do_queue' => array(),
+ ),
+ );
+
+ 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' ),
+ ),
+ );
+ }
+
+ /**
+ * Sets up the print dependencies.
+ *
+ * @param string $provider_id Provider ID.
+ * @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_id, $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_id, $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..330c6ab7255a2b
--- /dev/null
+++ b/phpunit/webfonts/wpWebfonts/doItems-test.php
@@ -0,0 +1,28 @@
+setup_mock_provider( $wp_webfonts );
+ $this->assertFalse( $wp_webfonts->do );
+ }
+
+ public function test_do_items() {
+ $wp_webfonts = new WP_Webfonts();
+ $this->setup_mock_provider( $wp_webfonts );
+ $this->assertTrue( true );
+ }
+}
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;