WordPress Developer Blog

How to register custom font collections for the Font Library

How to register custom font collections for the Font Library

WordPress 6.5 will ship the long-awaited Font Library, a feature that lets you manage fonts directly from the Site Editor. On the surface, this might primarily seem like a user-facing tool, but there are several developer goodies in the mix too.

In this post, you will learn how to register a custom font collection. This is a sub-feature of the Font Library that lets you define sets of fonts that your theme or plugin users can install on their site. Then they can further customize their typography by using these fonts via the Styles panel or directly in posts, templates, and patterns.

By default, WordPress ships with a single collection that lets you install fonts from the Google Fonts library. But as a developer, you can offer a more curated experience by building custom collections.

How font collections work

To find the Font Library in WordPress 6.5, you must go to Appearance > Editor in the admin. Then, select the Styles panel (half circle icon). Within that panel, select Typography and you should see a new settings icon, which has a tooltip of Manage fonts:

It can feel a little hidden if you’re not familiar with navigating the interface yet. But it’s located alongside all the other typography settings.

Once you click the Manage fonts button, a new Fonts modal will appear that shows a few tabs, as in the screenshot below:

The three tabs shown are:

  • Library: This will display all of the fonts from your theme and those installed via the Font Library.
  • Upload: Allows you to upload font files directly from your computer.
  • Google Fonts: This is the default font collection that ships with WordPress, letting you install any Google Font.

When you select a font from the Google Fonts collection, a new panel will appear that lets you install variants of the font that you want for your website:

It’s important to note that these fonts are stored locally in the user’s /wp-content/uploads/fonts folder. This process works the same with the default collection and any custom collections that you register in your theme.

Registering font collections

There are two methods for registering fonts. The first method uses only PHP to define the collection and its font families. The second method uses PHP to register the collection but JSON to define the font families. We’ll walk through both of these methods in this tutorial.

For this tutorial, I will focus on registering custom collections via a theme. But you can certainly register collections from plugins—you’ll just need to change any file paths to point to your plugin folder.

The registration function

WordPress provides a helper function for registering font collections named wp_register_font_collection(). Take a look at its signature:

wp_register_font_collection( string $slug, array $args );

The function accepts two parameters:

  • $slug: A unique identifier for your collection, which should only contain alphanumeric characters, dashes, and underscores. It’s best practice to prefix this with your theme or plugin slug.
  • $args: An array of arguments for defining your font collection:
    • name: The human-readable label for the collection, which should be internationalized.
    • description: An internationalized description for the collection, which is shown in the UI.
    • font_families: An array of font family definitions or a string containing the file path or URL to a JSON file containing the collection (you’ll learn how to define the families below).
    • categories: An array of categories. Each category should be an array that contains:
      • name: An internationalized label for the category.
      • slug: A unique slug containing only alphanumeric characters, dashes, and underscores.

To register a font collection, you should do so on the init hook. For the remainder of this tutorial, you will work from a single function named themeslug_font_collections(), which is an action on this hook.

Go ahead and add this code to your theme’s functions.php file to set everything up:

add_action( 'init', 'themeslug_font_collections' );

function themeslug_font_collections() {
	// Register or unregister font collections here.
}

Font family definitions

Before moving forward, it’s important to understand how to define a font family in WordPress. If you’re familiar with the format for defining font families in theme.json, this will feel similar.

The following is an example of an array of font families. The first is of a system font, and the second is a web font:

$font_families = [
	[
		'font_family_settings' => [
			'fontFamily' => 'system-ui, sans-serif',
			'slug'       => 'system-ui',
			'name'       => __( 'System UI', 'themeslug' ),
		],
		'categories' => [ 'sans-serif' ]
	],
	[
		'font_family_settings' => [
			'name'       => __( 'Roboto Flex', 'themeslug' ),
			'slug'       => 'roboto-flex',
			'fontFamily' => 'Roboto Flex, sans-serif',
			'fontFace'   => [
				[
					'src'        => 'https://fonts.gstatic.com/s/robotoflex/v9/NaN4epOXO_NexZs0b5QrzlOHb8wCikXpYqmZsWI-__OGfttPZktqc2VdZ80KvCLZaPcSBZtOx2MifRuWR28sPJtUMbsFEK6cRrleUx9Xgbm3WLHa_F4Ep4Fm0PN19Ik5Dntczx0wZGzhPlL1YNMYKbv9_1IQXOw7AiUJVXpRJ6cXW4O8TNGoXjC79QRyaLshNDUf3e0O-gn5rrZCu20YNYG0EACUTNK-QKavMlxGJI8dxef0jQ.woff2',
					'fontWeight' => '400',
					'fontStyle'  => 'normal',
					'fontFamily' => 'Roboto Flex',
					'preview'    => 'https://s.w.org/images/fonts/17.7/previews/roboto-flex/roboto-flex-400-normal.svg'
				]
			]
		],
		'categories' => [ 'sans-serif' ]
	]
];

A font family definition consists of the following arguments:

  • font_family_settings: An array of settings for defining the font family, which adheres to the standard theme.json format for defining font families:
    • name: The human-readable title for the font family.
    • slug: A unique slug for the family, which should contain only alphanumeric characters, dashes, and underscores.
    • fontFamily: A valid value that will map to the CSS font-family value. Generally, this will be a font stack of families with fallbacks.
    • fontFace:(Optional) An array of font faces that are mapped to the @font-face CSS at-rule. This is necessary to include web fonts from a URL. The format of the individual faces (variants) should be:
      • fontFamily: A valid CSS font-family descriptor.
      • fontWeight: A valid CSS font-weight value.
      • fontStyle: A valid CSS font-style value.
      • fontStretch: A valid CSS font-stretch value.
      • src: A file URL pointing to the font file.
      • preview: (Optional) A file URL that points to an image for previewing the specific font face. If not defined, the src asset is loaded in the browser to render the preview.
    • preview: (Optional) A file URL that points to an image for previewing the font family. If not defined, the src asset closest to the normal 400 font face is loaded in the browser to render the preview.
  • categories: An array of category slugs (registered for the collection) for the font family.

When registering a web font and a preview image is neither provided under font_family_settings nor fontFace, WordPress will automatically load the font via the fontFace.src file. This could have a performance impact with large collections, so it’s recommended to include a preview image for web fonts.

At this point, you’ve learned the foundational parts that make up both a collection and the font families within that collection. It can be a lot of information to consume at once. So let’s look at a real-world example and put what we’ve learned into practice.

Registering a font collection via PHP

The most straightforward way of registering a font collection is via PHP. You can do everything from within one file, and this is ideal if you just have a few fonts for your collection. If you have many fonts, you might want to use the JSON method described in the next section.

One of my favorite typography-related sites is Modern Font Stacks, which has a well-rounded list of system fonts. I thought it’d be a great idea to take some of the font stacks from that site and bring them to the WordPress Font Library. This also makes for an easier first example because system fonts don’t require font files.

Inside the themeslug_fonts_collection() function that you added to functions.php earlier, paste this code:

wp_register_font_collection( 'modern-stacks', [
	'name'          => __( 'Modern Stacks', 'themeslug' ),
	'description'   => __( 'A collection of modern system fonts.', 'themeslug' ),
	'font_families' => [
		[
			'font_family_settings' => [
				'fontFamily' => 'system-ui, sans-serif',
				'slug'       => 'system-ui',
				'name'       => __( 'System UI', 'themeslug' ),
			],
			'categories' => [ 'sans-serif' ]
		],
		[
			'font_family_settings' => [
				'fontFamily' => "Charter, 'Bitstream Charter', 'Sitka Text', Cambria, serif",
				'slug'       => 'transitional',
				'name'       => __( 'Transitional', 'themeslug' ),
			],
			'categories' => [ 'serif' ]
		],
		[
			'font_family_settings' => [
				'fontFamily' => "'Nimbus Mono PS', 'Courier New', monospace",
				'slug'       => 'monospace-slab-serif',
				'name'       => __( 'Monospace Slab Serif', 'themeslug' ),
			],
			'categories' => [ 'monospace', 'serif' ]
		],
		[
			'font_family_settings' => [
				'fontFamily' => "'Segoe Print', 'Bradley Hand', Chilanka, TSCu_Comic, casual, cursive",
				'slug'       => 'handwritten',
				'name'       => __( 'Handwritten', 'themeslug' ),
			],
			'categories' => [ 'handwriting' ]
		]
	],
	'categories' => [
		[
			'name' => __( 'Handwriting', 'themeslug' ),
			'slug' => 'handwriting'
		],
		[
			'name' => __( 'Monospace', 'themeslug' ),
			'slug' => 'monospace'
		],
		[
			'name' => __( 'Sans Serif', 'themeslug' ),
			'slug' => 'sans-serif'
		],
		[
			'name' => __( 'Serif', 'themeslug' ),
			'slug' => 'serif'
		]
	]
] );

Once you save your file and refresh your browser, you should see the Modern Stacks tab when reopening the Fonts modal:

At this point, if you want to test installing one of these fonts, just follow the same procedure as earlier.

Because System fonts don’t have font files associated with them, there are no files to install in the /wp-content/uploads/fonts directory.

Registering a font collection via JSON

It may become a little unwieldy to manage font families from PHP as you add more to your collection. JSON is usually a preferred format for storing these larger collections of data, and WordPress supports adding the font families for your collection out of the box.

Let’s mix it up a bit and add a new collection of fantasy web fonts. Unlike the system fonts from the previous section, these will have physical files that will be installed.

First, add this code inside your themeslug_font_collections() function that you’ve already created in functions.php:

wp_register_font_collection( 'fantasy', [
	'name'          => __( 'Fantasy', 'themeslug' ),
	'description'   => __( 'A collection of fantasy fonts.', 'themeslug' ),
	'font_families' => get_theme_file_path( 'assets/fonts/fantasy.json' ),
	'categories' => [
		[
			'name' => __( 'Display', 'themeslug' ),
			'slug' => 'display'
		]
	]
] );

Take note that the font_families argument is very different from the PHP example in the previous section. Instead of passing an array of font family definitions, you are passing a file path to a JSON file.

Now add a new /assets/fonts/fantasy.json file in your theme. You will use this to register the font families in your collection.

For your JSON file, there are two top-level properties that you can set:

  • $schema:  A reference to the WordPress font collection JSON schema, which can add hints in most modern code editors.
  • font_families: An array of font family definitions. The difference from the PHP method is that you must now use JSON formatting.

For this exercise, I am referencing URLs from Google Fonts and WordPress.org for the src and preview arguments. You can see a full example via the WordPress font-collection.json file. You may also choose to use custom URLs where these resources are hosted, such as GitHub. 

Now add the following code to your fantasy.json file:

{
	"$schema": "https://schemas.wp.org/trunk/font-collection.json",
	"font_families": [
		{
			"font_family_settings": {
				"name": "Henny Penny",
				"fontFamily": "Henny Penny, system-ui",
				"slug": "henny-penny",
				"fontFace": [
					{
						"src": "https://fonts.gstatic.com/s/hennypenny/v17/wXKvE3UZookzsxz_kjGSfMQvt3M7tMDT.woff2",
						"fontWeight": "400",
						"fontStyle": "normal",
						"fontFamily": "Henny Penny",
						"preview": "https://s.w.org/images/fonts/17.7/previews/henny-penny/henny-penny-400-normal.svg"
					}
				],
				"preview": "https://s.w.org/images/fonts/17.7/previews/henny-penny/henny-penny.svg"
			},
			"categories": [ "display" ]
		},
		{
			"font_family_settings": {
				"name": "MedievalSharp",
				"fontFamily": "MedievalSharp, system-ui",
				"slug": "medievalsharp",
				"fontFace": [
					{
						"src": "https://fonts.gstatic.com/s/medievalsharp/v26/EvOJzAlL3oU5AQl2mP5KdgptAqp6MwvXLDk.woff2",
						"fontWeight": "400",
						"fontStyle": "normal",
						"fontFamily": "MedievalSharp",
						"preview": "https://s.w.org/images/fonts/17.7/previews/medievalsharp/medievalsharp-400-normal.svg"
					}
				],
				"preview": "https://s.w.org/images/fonts/17.7/previews/medievalsharp/medievalsharp.svg"
			},
			"categories": [ "display" ]
		},
		{
			"font_family_settings": {
				"name": "Metamorphous",
				"fontFamily": "Metamorphous, system-ui",
				"slug": "metamorphous",
				"fontFace": [
					{
						"src": "https://fonts.gstatic.com/s/metamorphous/v20/Wnz8HA03aAXcC39ZEX5y1330OSCthTsmaQ.woff2",
						"fontWeight": "400",
						"fontStyle": "normal",
						"fontFamily": "Metamorphous",
						"preview": "https://s.w.org/images/fonts/17.7/previews/metamorphous/metamorphous-400-normal.svg"
					}
				],
				"preview": "https://s.w.org/images/fonts/17.7/previews/metamorphous/metamorphous.svg"
			},
			"categories": [ "display" ]
		}
	]
}

Once you’ve saved the file and refreshed your browser window, you should see a new Fantasy tab with your registered fonts in the Fonts modal:

As before, these can be installed and used just like any other fonts.

The downside of registering font families for the collection via JSON is that there is no way to reference a dynamic URL, such as a theme folder, for the font file source and preview images. And hosting these assets via a third-party site could run afoul of the Theme Review guidelines (only the Google Fonts CDN is allowed). In some cases, you may have no choice but to use the PHP method.

Unregistering font collections

To unregister a font collection, you must use the wp_unregister_font_collection() function, which accepts a single $slug parameter from a previously registered font collection:

wp_unregister_font_collection( string $slug );

You can use this function to unregister collections that have been registered by third-party plugins, a parent theme (if you’re building a child theme), or even WordPress. So let’s dive into a real-world example of how it works.

Unregistering the Google Fonts collection

If you’ve been around theming as long as I have, you probably know by now that opening the entire Google Fonts library to end-users is a recipe for breaking your theme’s carefully crafted typography. Not all fonts are made the same.

If you want a more curated experience, I recommend disabling the default Google Fonts collection, offering only the fonts that you know work well enough with your theme.

To unregister the Google Fonts collection, add this code inside your themeslug_font_collections() function in functions.php:

wp_unregister_font_collection( 'google-fonts' );

When you open the Fonts modal, you should only see the Modern Stacks and Fantasy collections that you registered earlier:

Limitations for themes

The biggest limitation of custom font collections (and the Font Library feature overall) is that there is no way to map uploaded fonts to semantically named font definitions in your theme.json file. This is the recommended practice defined in the Theme Handbook and the naming convention that the default Twenty Twenty-Four theme uses.

On a practical level, this means that users must define how each uploaded font is used under the Styles panel in the Site Editor. With semantic names and a method for mapping the uploading fonts, they would be automatically applied to the design, but this is not currently supported.

For theme builders who enable the Font Library or define custom font collections, make sure to note in your user documentation how installed fonts are applied.

Even with this limitation, font collections are really cool and open a lot of flexibility for users who want to control their typography.

Props to @bph and @ndiego for feedback and review.

Categories: ,

4 responses to “How to register custom font collections for the Font Library”

  1. Vasily Avatar
    Vasily

    Font library is a great feature, although the UX will be much nicer, if the Elements box indicator will show the actual font names instead of just Aa. It was suggested in Github a month ago. Here is the direct link: https://github.com/WordPress/gutenberg/issues/59345

  2. NICHOLAS AMOL GOMES Avatar
    NICHOLAS AMOL GOMES

    Thank you for your article work

  3. Christopher Avatar
    Christopher

    Any example of how to programmatically install (not register) a font?

    1. Justin Tadlock Avatar

      I don’t know if there’s an API for that. I would just use the theme.json method for adding custom font families in that case anyway. It would essentially be the same. It would be automatically loaded, and the user could still manage it.

Leave a Reply