Skip to content

Commit

Permalink
Improves webfonts registry and providers.
Browse files Browse the repository at this point in the history
Readability improvements:
- Renamed `get_registry()` to `get_all_registered()`
- Added and refined comments
- Moved the organizational logic in Google Fonts Provider to private method
- Moved the store in "query by" containers to a private method

Performance:
Changed `get_by_font_family()` query to use the same registered key
strategy as the `get_by_provider()`. Both are now a O(1) lookup.
  • Loading branch information
hellofromtonya committed Oct 19, 2021
1 parent 0b3179a commit 2de948d
Show file tree
Hide file tree
Showing 10 changed files with 338 additions and 180 deletions.
32 changes: 16 additions & 16 deletions src/wp-includes/webfonts-api/class-wp-webfonts-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@ class WP_Webfonts_Controller {
private $webfonts_registry;

/**
* Instance of the provider registry.
* Instance of the provider's registry.
*
* @since 5.9.0
*
* @var WP_Webfonts_Provider_Registry
*/
private $providers_registry;
private $providers;

/**
* Stylesheet handle.
Expand All @@ -53,8 +53,8 @@ public function __construct(
WP_Webfonts_Registry $webfonts_registry,
WP_Webfonts_Provider_Registry $provider_registry
) {
$this->webfonts_registry = $webfonts_registry;
$this->providers_registry = $provider_registry;
$this->webfonts_registry = $webfonts_registry;
$this->providers = $provider_registry;
}

/**
Expand All @@ -63,7 +63,7 @@ public function __construct(
* @since 5.9.0
*/
public function init() {
$this->providers_registry->init();
$this->providers->init();

// Register callback to generate and enqueue styles.
if ( did_action( 'wp_enqueue_scripts' ) ) {
Expand Down Expand Up @@ -111,19 +111,19 @@ public function register_webfont( array $webfont ) {
*
* @since 5.9.0
*
* @return string[][] Registered webfonts.
* @return array[] Registered webfonts.
*/
public function get_webfonts() {
return $this->webfonts_registry->get_registry();
return $this->webfonts_registry->get_all_registered();
}

/**
* Gets the registered webfonts for the given provider.
* Gets the registered webfonts for the given provider organized by font-family.
*
* @since 5.9.0
*
* @param string $provider_id Provider ID to fetch.
* @return string[][] Registered webfonts.
* @return array[] Registered webfonts.
*/
public function get_webfonts_by_provider( $provider_id ) {
return $this->webfonts_registry->get_by_provider( $provider_id );
Expand All @@ -135,7 +135,7 @@ public function get_webfonts_by_provider( $provider_id ) {
* @since 5.9.0
*
* @param string $font_family Family font to fetch.
* @return string[][] Registered webfonts.
* @return array[] Registered webfonts.
*/
public function get_webfonts_by_font_family( $font_family ) {
return $this->webfonts_registry->get_by_font_family( $font_family );
Expand All @@ -149,7 +149,7 @@ public function get_webfonts_by_font_family( $font_family ) {
* @return WP_Webfonts_Provider[] Registered providers.
*/
public function get_registered_providers() {
return $this->providers_registry->get_registry();
return $this->providers->get_all_registered();
}

/**
Expand All @@ -161,7 +161,7 @@ public function get_registered_providers() {
* @return bool True when registered. False when provider does not exist.
*/
public function register_provider( $classname ) {
return $this->providers_registry->register( $classname );
return $this->providers->register( $classname );
}

/**
Expand Down Expand Up @@ -206,7 +206,7 @@ private function generate_styles() {
continue;
}

add_action( 'wp_head', array( $this, 'render_preconnect_links' ) );
add_action( 'wp_head', array( $this, 'render_links' ) );

$provider->set_webfonts( $registered_webfonts );
$styles .= $provider->get_css();
Expand All @@ -215,11 +215,11 @@ private function generate_styles() {
}

/**
* Renders preconnect links to <head> for enqueued webfonts.
* Renders the HTML `<link>` for each provider into `<head>` for enqueued webfonts.
*
* @since 5.9.0
*/
public function render_preconnect_links() {
echo $this->providers_registry->get_preconnect_links();
public function render_links() {
echo $this->providers->get_links();
}
}
153 changes: 111 additions & 42 deletions src/wp-includes/webfonts-api/class-wp-webfonts-provider-registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,41 @@

/**
* Provider Registry.
*
* This registry exists to handle all providers.
*
* It handles the following within the API:
* - loads the bundled provider files into memory;
* - registers each provider with the API by:
* 1. creating an instance (object);
* 2. storing it in-memory (by its unique provider ID) for use with the API;
* - handles generating the linked resources `<link>` for all providers.
*/
class WP_Webfonts_Provider_Registry {

/**
* Registered providers.
* An in-memory storage container that holds all registered providers
* for use within the API.
*
* Keyed by the respective provider's unique provider ID:
*
* @type string $provider_id => @type WP_Webfonts_Provider Provider instance.
*
* @since 5.9.0
*
* @var WP_Webfonts_Provider[]
*/
private $registry = array();
private $registered = array();

/**
* Gets the provider registry.
* Gets all registered providers.
*
* @since 5.9.0
*
* @return WP_Webfonts_Provider[] Registered providers.
* @return WP_Webfonts_Provider[] All registered providers each keyed by their unique provider ID.
*/
public function get_registry() {
return $this->registry;
public function get_all_registered() {
return $this->registered;
}

/**
Expand All @@ -44,6 +58,9 @@ public function init() {
/**
* 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() {
Expand All @@ -64,77 +81,129 @@ private function register_core_providers() {
*
* @since 5.9.0
*
* @param string $classname The provider class name.
* @param string $classname The provider's class name.
* @return bool True when registered. False when provider does not exist.
*/
public function register( $classname ) {
// If the class does not exist in memory, bail out.
if ( ! class_exists( $classname ) ) {
return '';
return false;
}

/*
* Create an instance of the provider.
* This API uses one instance of each provider.
*/
$provider = new $classname;
$id = $provider->get_id();

if ( ! isset( $this->providers[ $id ] ) ) {
$this->registry[ $id ] = $provider;
// Store the provider's instance by its unique provider ID.
if ( ! isset( $this->registered[ $id ] ) ) {
$this->registered[ $id ] = $provider;
}

return $id;
return true;
}

/**
* Get the preconnect links HTML.
* Gets the HTML `<link>` for each provider.
*
* @since 5.9.0
*
* @return string Preconnect links HTML.
* @return string HTML links for each provider.
*/
public function get_preconnect_links() {
// Store a static var to avoid adding the same preconnect links multiple times.
static $generated = array();

$links = '';

foreach ( $this->registry as $provider_id => $provider ) {
// Skip if the provider already added preconnect links.
if ( isset( $generated[ $provider_id ] ) ) {
public function get_links() {
/*
* Store each `<link>` by its provider ID. Why?
* To ensure only one link is created per provider.
*/
static $links = array();

foreach ( $this->get_all_registered() as $provider_id => $provider ) {
// Skip if the provider already added the link.
if ( isset( $links[ $provider_id ] ) ) {
continue;
}

$links .= $this->generate_preconnect_link( $provider );

$added[ $provider_id ] = true;
$links[ $provider_id ] = $this->generate_links( $provider );
}

return $links;
// Put each `<link>` on a newline and then return them as a string.
return implode( '', $links );
}

/**
* Generate the preconnect links HTML for the given provider.
* Generate the `<link> element(s) for the given provider.
*
* @since 5.9.0
*
* @param WP_Webfonts_Provider $provider Instance of the provider.
* @return string Preconnect links HTML for the provider.
* @return string The `<link>` element(s).
*/
private function generate_preconnect_link( WP_Webfonts_Provider $provider ) {
private function generate_links( WP_Webfonts_Provider $provider ) {
$link_attributes = $provider->get_link_attributes();

/*
* Bail out if there are no attributes for this provider
* (i.e. no `<link>` is needed).
*/
if ( ! is_array( $link_attributes ) || empty( $link_attributes ) ) {
return '';
}

/*
* This provider needs multiple `<link>` elements.
* Loop through each array and pass its attributes
* to create each of its `<link>` elements.
*/
if ( is_array( current( $link_attributes ) ) ) {
$links = '';
foreach ( $link_attributes as $attributes ) {
$links .= $this->create_link_element( $attributes );
}

return $links;
}

/*
* This provider needs one `<link>` element.
* Pass its attributes to create its `<link>` element.
*/
return $this->create_link_element( $link_attributes );
}

/**
* Creates the `<link>` element and populates with the given attributes.
*
* @since 5.9.0
*
* @param string[] $attributes An array of attributes => values.
* @return string The `<link>` element.
*/
private function create_link_element( array $attributes ) {
$link = '';

foreach ( $provider->get_preconnect_urls() as $preconnection ) {
$link .= '<link rel="preconnect"';

foreach ( $preconnection as $key => $value ) {
if ( 'href' === $key ) {
$link .= ' href="' . esc_url( $value ) . '"';
} elseif ( true === $value || false === $value ) {
$link .= $value ? ' ' . esc_attr( $key ) : '';
} else {
$link .= ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
}
foreach ( $attributes as $attribute => $value ) {
// Checks if attribute is a nonempty string. If no, skip it.
if ( ! is_string( $attribute ) || '' === $attribute ) {
continue;
}

if ( 'href' === $attribute ) {
$link .= ' href="' . esc_url( $value ) . '"';
} elseif ( is_bool( $value ) ) {
$link .= $value
? ' ' . esc_attr( $attribute )
: '';
} else {
$link .= ' ' . esc_attr( $attribute ) . '="' . esc_attr( $value ) . '"';
}
$link .= '>' . PHP_EOL;
}

return $link;
if ( '' === $link ) {
return '';
}

return '<link rel="preconnect"' . $link . '>' . "\n";
}
}
Loading

0 comments on commit 2de948d

Please sign in to comment.