Skip to content

Commit

Permalink
wp_print_webfonts() et al plus tests
Browse files Browse the repository at this point in the history
  • Loading branch information
hellofromtonya committed Aug 22, 2022
1 parent 549908c commit f91d4bb
Show file tree
Hide file tree
Showing 11 changed files with 835 additions and 85 deletions.
35 changes: 34 additions & 1 deletion lib/experimental/class-wp-webfonts-provider-local.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -81,7 +108,7 @@ class WP_Webfonts_Provider_Local extends WP_Webfonts_Provider {
* }
* </code>
*
* @since 6.0.0
* @since X.X.X
*
* @return string The `@font-face` CSS.
*/
Expand All @@ -96,6 +123,12 @@ public function get_css() {
$css .= '@font-face{' . $this->build_font_face_css( $webfont ) . '}';
}

$css = sprintf(
"<style id='wp-webfonts-local'%s>\n%s\n</style>\n",
$this->type_attr,
$css
);

return $css;
}

Expand Down
19 changes: 14 additions & 5 deletions lib/experimental/class-wp-webfonts-provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*
* @package WordPress
* @subpackage WebFonts
* @since 6.0.0
* @since X.X.X
*/

if ( class_exists( 'WP_Webfonts_Provider' ) ) {
Expand All @@ -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[]
*/
Expand All @@ -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.
*/
Expand All @@ -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();
}
}
195 changes: 142 additions & 53 deletions lib/experimental/class-wp-webfonts.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -291,97 +311,166 @@ 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. */
trigger_error( sprintf( __( 'Webfont provider "%s" is not registered.', 'gutenberg' ), $provider_id ) );
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;
}
}
Loading

0 comments on commit f91d4bb

Please sign in to comment.