Implementing a Webfonts API in WordPress Core

PluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party and theme developers have been able to enqueue scripts and styles for years, but fonts have always been more complicated to enqueue. Following ticketticket Created for both bug reports and feature development on the bug tracker. #46370 and last September’s proposal to add a fonts enqueue API in WordPress Core, we now have a patch ready.

With the recent advancements in GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/, global-styles, and an effort to consolidate options and UIs in the site-editor, a Webfonts APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. is becoming a necessity as it will allow theme developers to define fonts in their theme.json files.

In this first iteration, we are mirroring the scripts & styles enqueueing functions for consistency. Since enqueueing a webfont entails enqueuing a stylesheet (or adding inline styles) to enqueue the font files themselves, the webfonts API functions act as wrappers for the stylesheets API (with the appropriate modifications where needed).

The intention for this initial iteration is to provide a basis we can build upon and improve in the future – which is why it was kept minimal. More improvements and functionality will be added in the future, but in order to improve it, it has to be there.

The patchpatch A special text file that describes changes to code, by identifying the files and lines which are added, removed, and altered. It may also be referred to as a diff. A patch can be applied to a codebase for testing. adds the following functions:

  • wp_register_webfont
  • wp_deregister_webfont
  • wp_enqueue_webfont
  • wp_dequeue_webfont
  • wp_webfont_is
  • wp_webfont_add_data

The syntax of all these functions is identical to their style counterparts, so wp_register_webfont is the same as wp_register_style and so on. The only difference is the use of $params in lieu of $deps for practical reasons.

Notes:

  • The styles registered for webfonts automatically get a webfont- prefix to avoid conflicts with any similarly named stylesheets. This provides a clear distinction between normal styles and webfonts styles, while keeping the implementation simple.
  • Since webfonts don’t have dependencies, the $deps argument was replaced with $params. These params can be used to register a webfont from local files, and auto-generate the CSSCSS Cascading Style Sheets. for @font-face.

Enqueuing a webfont from a remote URLURL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org

To use a webfonts API (Google Fonts, Adobe fonts, etc), we can use the URL provided by the API directly:

add_action( 'wp_enqueue_scripts', function() {
	wp_enqueue_webfont(
		// The handle
		'dancing-script',
		// URL to the webfont CSS - can use any public API.
		'https://fonts.googleapis.com/css2?family=Dancing+Script:wght@500;600&display=swap', 
	);
} );

This is identical to what we would previously do using the wp_enqueue_style function, but now using a more appropriately named wp_enqueue_webfont function. With the example code above, the webfont will be enqueued and the stylesheet’s handle will be webfont-dancing-script.

Generating CSS for a webfont

It is possible to generate the CSS for a webfont using the provider parameter and the wp_webfont_generate_styles function.

A provider is an object with details about the provider’s implementation and a method to get (or generate) the CSS from that API.

Generating styles for bundled font files

To generate styles for bundled font-files, set the provider to new WP_Fonts_Provider_Local().

$my_font_styles = wp_webfont_generate_styles( array(
	'provider'     => new WP_Fonts_Provider_Local(),
	'font-family'  => 'My Font',
	'font-display' => 'swap',
	'font-style'   => 'normal',
	'font-weight'  => '400',
	'src'          => array(
		get_template_directory_uri() . '/fonts/font.woff2',
		get_template_directory_uri() . '/fonts/font.woff',
	),
) );

Generating styles for Google fonts

To generate styles for a Google font, set the provider to new WP_Fonts_Provider_Google.

$roboto_styles = wp_webfont_generate_styles( array(
	'provider'    => new WP_Fonts_Provider_Google(),
	'font-family' => 'Roboto',
	'font-weight' => '400',
) );

Using the generated styles

You can attach the styles to an existing stylesheet using wp_add_inline_style:

add_action( 'wp_enqueue_scripts', function() {
	// Enqueue theme stylesheet.
	wp_enqueue_style( 'my-theme-styles', get_theme_file_uri( 'style.css' ) );
	// Get webfont styles.
	$roboto_styles = wp_webfont_generate_styles( array(
		'provider'    => new WP_Fonts_Provider_Local(),
		'font-family' => 'Roboto',
		'font-weight' => '400',
	) );
	// Add webfont styles.
	wp_add_inline_style( 'my-theme-styles', $roboto_styles );
} );

Alternatively, you can use the wp_enqueue_webfont function:

add_action( 'wp_enqueue_scripts', function() {
	wp_enqueue_webfont( 'roboto-400', '', array(
		'provider'    => new WP_Fonts_Provider_Local(),
		'font-family' => 'Roboto',
		'font-weight' => '400',
	) );
} );

This will internally call wp_enqueue_style with a blank $src, and attach the webfoot styles to the defined $handle.

Adding implementations for more 3rd-party APIs

At the moment of this writing, Google-Fonts is the most popular API for web fonts, and the only one publicly available, free, with OpenSource-compatible fonts.

Adding implementations for more APIs in the future can be done by extending the WP_Fonts_Provider class.

The $params argument

The $params argument is formatted as an array and accepts all valid CSS props of @font-face as its array keys. Any extra args are ignored. The list of valid descriptors was taken from MDN.
Defining a font-family is mandatory, and skipping that results in no CSS getting generated.

The src

If we’re enqueueing a webfoot from bundled files, then we can use the src to define the files. If we only want to define a single file for the webfont, then we can add it as a string ('src' => $url).
If we have multiple files for the webfont (different formats to support older browsers), then we can use an array ('src' => [ $url1, $url2 ]). In this case, the URLs get internally reordered for browser support (woff2, woff, ttf, eot, otf). SVG for webfonts is not supported because they have been deprecated (see caniuse.com/svg-fonts), so if provided it gets removed (like any other invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid. type).

Note: The src can also accept data-urls.

Variable fonts

The font-variation-settings property accepts either a string (normal), or an array of key/value pairs (e.g. ["wght" => 637, "wdth" => 100]) and returns a string of these values (e.g., wght 637, wdth 100).

Props @jonoaldersonwp, @sergeybiryukov for reviewing