Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webfonts API - webfonts collection implementation #1736

Closed
wants to merge 94 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
cef117a
1st Webfonts API implementation - to change.
aristath Aug 6, 2021
9facf39
Register collections instead of individual fonts
aristath Oct 6, 2021
85e0fb9
New architecture scaffolding.
hellofromtonya Oct 11, 2021
5ee49bb
Add get_validated_params method
aristath Oct 11, 2021
a1f34f0
Tweak validation for local fonts
aristath Oct 11, 2021
d5ac8df
fix paths
aristath Oct 11, 2021
6531b66
typo
aristath Oct 11, 2021
f99faf4
Adds tests and fixes for WP_Webfonts_Registry.
hellofromtonya Oct 11, 2021
42bc934
Adds tests amd fixes for WP_Webfonts_Provider_Registry.
hellofromtonya Oct 11, 2021
1804d67
Adds tests and fixes for WP_Webfonts_Controller.
hellofromtonya Oct 11, 2021
a2331ae
Moved schema validator to separate class.
hellofromtonya Oct 11, 2021
ee9ea3b
Made font weight and style optional.
hellofromtonya Oct 11, 2021
0ad4f54
Fix method name
aristath Oct 12, 2021
566fea7
validation: should use kebab since it's 1 step before the CSS output
aristath Oct 12, 2021
ecfa1da
Fix styles generation
aristath Oct 12, 2021
45c6f21
remove blank line (CS)
aristath Oct 12, 2021
78812dd
Add editor styles for webfonts
aristath Oct 13, 2021
75c0bf9
Make function public. We'll need it for the theme.json implementation
aristath Oct 13, 2021
228508d
Revert "Make function public. We'll need it for the theme.json implem…
aristath Oct 13, 2021
880178d
Account for "file:./" URLs defined in a theme.json file.
aristath Oct 13, 2021
780cda6
Update docblocks and remove final for testing.
hellofromtonya Oct 13, 2021
da9ebcf
Replaces _doing_it_wrong() with trigger_error().
hellofromtonya Oct 13, 2021
a73bc1d
Moves validation from providers to Validator.
hellofromtonya Oct 14, 2021
9966b19
Adds src validation to Validator.
hellofromtonya Oct 15, 2021
56ebaa7
Remove invalid_parameters & related method
aristath Oct 18, 2021
0c0354b
Improves readability, usability, and performance.
hellofromtonya Oct 19, 2021
2e541a1
Remove file:./ implementation
aristath Oct 20, 2021
1d92844
update tests
aristath Oct 20, 2021
e5ca831
CS
aristath Oct 20, 2021
33872b8
more tests fixes
aristath Oct 20, 2021
551adee
Make links relative if URL is on-site
aristath Oct 20, 2021
846e860
Update tests for local URLs CSS generation
aristath Oct 20, 2021
dab75cc
Add check to verify the provider is registered.
aristath Oct 21, 2021
d14aa9e
This was already done
aristath Oct 21, 2021
d87a3b8
test unregistered provider
aristath Oct 21, 2021
646c9c0
cs
aristath Oct 21, 2021
fe29ea7
Trigger error when provider is not registered
aristath Oct 21, 2021
01fd844
CS fix
aristath Oct 21, 2021
27116bc
Fix some failing tests
aristath Oct 21, 2021
4be94a3
meh, copy/pasta typo-error
aristath Oct 21, 2021
d2f1474
Fix failing test for unregistered provider
aristath Oct 21, 2021
dc5ed3f
minor improvements to the validator
aristath Oct 25, 2021
291e4a8
fix docs & typos
aristath Oct 26, 2021
4b7b099
another typo fix
aristath Oct 26, 2021
88fb4af
Don't check if provider is registered
aristath Oct 26, 2021
699f96c
This is not necessary, the browser won't get a request for this URL.
aristath Oct 27, 2021
e22ed3e
CS
aristath Oct 27, 2021
4757065
simplify configuration params
aristath Oct 27, 2021
d2b2c91
Add docs to the register method
aristath Oct 27, 2021
09742ca
This was removed
aristath Oct 27, 2021
571c40d
Check if provider is a subclass of WP_Webfonts_Provider
aristath Oct 27, 2021
022467a
more docs
aristath Oct 27, 2021
68f439a
more docs
aristath Oct 27, 2021
b2aef24
rename the webfonts file.
aristath Oct 27, 2021
cf6ac7c
Remove get_by_font_family and related tests
aristath Oct 27, 2021
46c87d5
Move font-family quoting to css-generation method
aristath Oct 27, 2021
5bf5f66
Simplify the controller
aristath Oct 27, 2021
e31dee5
Move require_once to script_loader.php
aristath Oct 27, 2021
9ae7f9a
add missing "since" to classes
aristath Oct 27, 2021
0883e97
Simplify the preconnect-URLs implementation
aristath Oct 27, 2021
2d0274b
minify styles if not debugging scripts
aristath Oct 27, 2021
28445b3
Removes store by font-family during register.
hellofromtonya Oct 27, 2021
aff4233
Abstracts generating resources hints.
aristath Nov 1, 2021
1ec9d69
Fix method parameter name typo.
hellofromtonya Nov 3, 2021
6b08c0a
Fix variable name typo.
hellofromtonya Nov 3, 2021
a9c62fc
Remove unused key variable from `foreach`.
hellofromtonya Nov 3, 2021
b0e0296
Fixes to tests from code review.
hellofromtonya Nov 3, 2021
febc81b
Skip "provider" in CSS generation in the local provider.
aristath Nov 4, 2021
de65387
Update src/wp-includes/webfonts-api/class-wp-webfonts-registry.php
aristath Nov 4, 2021
00c54aa
Allow using a range of font-weights for google-fonts
aristath Nov 4, 2021
0e75bcf
provider no longer printed in the CSS
aristath Nov 4, 2021
ec7c787
Require 'is-external' => true to load external API webfonts
aristath Nov 4, 2021
2139913
fix some (not all) test failures
aristath Nov 4, 2021
4ea1f34
bugfix
aristath Nov 4, 2021
864b5d1
typecast to array
aristath Nov 4, 2021
9dd78c0
Improves the WP_Webfonts_Controller::generate_styles().
hellofromtonya Nov 4, 2021
0f89538
Require valid CSS properties for webfont schema.
hellofromtonya Nov 4, 2021
9a9f91c
Document classname needs for provider registration.
hellofromtonya Nov 4, 2021
d035860
Removes WP_Webfonts_Provider::prepare().
hellofromtonya Nov 4, 2021
3929bf9
Require CSS properties in snake_case for registration.
hellofromtonya Nov 4, 2021
125c29c
Shortens the Controller's getter names.
hellofromtonya Nov 4, 2021
1380de5
Use MINUTE_IN_SECONDS constant instead of hard coded 60.
hellofromtonya Nov 4, 2021
acde215
Type cast font weights to int for range().
hellofromtonya Nov 5, 2021
f88500c
Remove unnecessary empty line.
hellofromtonya Nov 5, 2021
6a0c723
Micro-optimizations, fixes, and comments.
hellofromtonya Nov 5, 2021
14efc74
Removes unnecessary guard clauses.
hellofromtonya Nov 5, 2021
c8ea408
Makes reflection get_webfonts_property() consistent in tests.
hellofromtonya Nov 5, 2021
d898462
Simplify wp_register_webfonts by removing the unnecessary guard clause.
hellofromtonya Nov 5, 2021
cb0c9bc
Adds tests for Google Fonts provider `get_css()`.
hellofromtonya Nov 5, 2021
81bba48
Changes the remote privacy permission logic.
hellofromtonya Nov 5, 2021
81326fd
Code review: comments, typos, micro-optimizations.
hellofromtonya Nov 6, 2021
6024894
Adds remaining class DocBlock comments.
hellofromtonya Nov 7, 2021
aa08030
typo fix
aristath Nov 8, 2021
0ce34f6
should be an instance of WP_Webfonts_Controller, not WP_Webfonts
aristath Nov 18, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/wp-includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -3268,6 +3268,7 @@ function wp_get_image_mime( $file ) {
* @since 4.2.0 Support was added for GIMP (.xcf) files.
* @since 4.9.2 Support was added for Flac (.flac) files.
* @since 4.9.6 Support was added for AAC (.aac) files.
* @since 5.9.0 Support was added for webfont (.woff2, .woff, .ttf, .eot, .otf) files.
*
* @return string[] Array of mime types keyed by the file extension regex corresponding to those types.
*/
Expand Down Expand Up @@ -3332,6 +3333,12 @@ function wp_get_mime_types() {
'wma' => 'audio/x-ms-wma',
'wax' => 'audio/x-ms-wax',
'mka' => 'audio/x-matroska',
// Webfonts formats.
'woff2' => 'font/woff2',
'woff' => 'font/woff',
'ttf' => 'font/ttf',
'eot' => 'application/vnd.ms-fontobject',
'otf' => 'application/x-font-opentype',
// Misc application formats.
'rtf' => 'application/rtf',
'js' => 'application/javascript',
Expand Down
7 changes: 7 additions & 0 deletions src/wp-includes/script-loader.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
/** WordPress Styles Functions */
require ABSPATH . WPINC . '/functions.wp-styles.php';

/** WordPress Webfonts Classes & Functions */
require_once ABSPATH . WPINC . '/webfonts-api/class-wp-webfonts-schema-validator.php';
require_once ABSPATH . WPINC . '/webfonts-api/class-wp-webfonts-registry.php';
require_once ABSPATH . WPINC . '/webfonts-api/class-wp-webfonts-provider-registry.php';
require_once ABSPATH . WPINC . '/webfonts-api/class-wp-webfonts-controller.php';
require_once ABSPATH . WPINC . '/webfonts.php';

/**
* Registers TinyMCE scripts.
*
Expand Down
276 changes: 276 additions & 0 deletions src/wp-includes/webfonts-api/class-wp-webfonts-controller.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
<?php
/**
* Webfonts API: Webfonts Controller
*
* @package WordPress
* @subpackage Webfonts
* @since 5.9.0
*/

/**
* Webfonts Controller exposes the public entry point into this API
* and coordinates the interactions between the webfonts registry,
* providers registry, and the Dependencies API.
*
* event
* ↕
* Controller
* ⤢ ⤡
* Webfonts Registry Providers Registry
* ↕ ⤢ ⤡ .. [custom providers]
* Validator Local Google Fonts
* Provider Provider
* ↕ ↕
* Filesystem Remote Font API Service
*
* The Controller receives an event such as a request to register
* a webfont or provider, print `@font-face` styles in the `<head>`
* (e.g. `'wp_enqueue_scripts'`), or print the resource `<link>`
* (`'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. 'google', to identify
* the remote webfonts service provider.
*/
true !== apply_filters( 'has_remote_webfonts_request_permission', false, $provider_id )
) {
continue;
}
Comment on lines +203 to +222
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @azaozz, here's the new filter we discussed for granting permission to do a remote request to an external webfonts service provider, such as Google Fonts. By default, it's set to false meaning the API will not do remote requests. What do you think?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huzzah


/*
* 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 `<link>` 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 ) {
hellofromtonya marked this conversation as resolved.
Show resolved Hide resolved
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;
}
}
Loading