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

Proposal for a Webfonts collection schema #4

Open
aristath opened this issue Oct 5, 2021 · 10 comments
Open

Proposal for a Webfonts collection schema #4

aristath opened this issue Oct 5, 2021 · 10 comments

Comments

@aristath
Copy link
Owner

aristath commented Oct 5, 2021

How web fonts will be defined in a theme:

In a theme.json file:

{
	"webfonts": {
		"font-handle-1": {
			"font-family": "Open Sans",
			"font-weight": "400",
			"font-style": "normal",
			"provider": "google"
		},
		"font-handle-2": {
			"font-family": "Open Sans",
			"font-weight": "600",
			"font-style": "italic",
			"font-variant": "small-caps",
			"provider": "google"
		},
		"font-handle-3": {
			"font-family": "My Local Font",
			"font-weight": "400",
			"font-style": "normal",
			"src": [ "fonts/MyLocalFont.woff2" ],
			"provider": "local"
		}
	}
}

webfonts is an object. The key is the webfont's handle, and the value contains all the webfont's props (all valid CSS props for @font-face, plus a provider to define the type of webfont (local/google/other).

The same exact structure will be used when defining a webfont-collection from PHP instead of a theme.json file.
We may want to use fontFamily instead of font-family in theme.json... Everything else in a theme.json file uses camelCase and not kebab-case, so it would make sense to follow that same pattern. In PHP however, we may want to stick to camel-case 'cause that's what the eventual CSS will be

@hellofromtonya
Copy link
Collaborator

Start with the end in mind.

When talking about a Webfont API, I propose we start with the end in mind: how themes define the webfonts used in the theme. The future of theming will be in defining these types of assets within theme.json. Let's start by defining this schema.

Terminology for collective understanding:

  • Webfonts collection: a configuration that defines each of the fonts the theme uses
  • Schema: the structure of the webfonts collection (i.e. it's model)

Goals:

  • One schema for classic and block themes
  • Each font is a separate record in the collection
  • Ability to define third party and local fonts in the collection
  • Ability to define custom ("other") providers for custom processing needs
  • Think about theme authors => make it straightforward for them to define their font collections

Notes:

  • The data type could be different if it makes it easier for classic theme authors:
    • JSON for block theme
    • Array or JSON for classic theme
  • Let's not think too much (yet) about the implementation details of how core will parse, process, and generate CSS from this schema. Figure out the right schema first. Then the output. Then the processing.

Why use one schema?

  • One standard
  • For theme authors:
    • Less confusion of how and when to use different configuration models and entry points into the API. This can translate into less effort, time, and costs for theme authors, documentation, support, etc.
    • Makes it less effort to transition between classic and block themes
  • For Core and Gutenberg:
    • Ensures the API can be iteratively built for the future
    • Less entry points into the API means less code to build, test, maintain, and support
  • For performance:
    • Like fonts or like sources can be combined
    • Third party fetching can be optimized
    • Schema can be validated before processing to make the API more robust, stable, etc. _doing_it_wrong() can be thrown to alert theme authors of problems

@hellofromtonya
Copy link
Collaborator

hellofromtonya commented Oct 5, 2021

We may want to use fontFamily instead of font-family in theme.json... Everything else in a theme.json file uses camelCase and not kebab-case, so it would make sense to follow that same pattern. In PHP however, we may want to stick to camel-case 'cause that's what the eventual CSS will be

@aristath Is the expectation within the theme.json that these keys are in camelCase form? I assume after parsing, each becomes a variable for usage. Avoiding language reserved names then is also important.

@aristath
Copy link
Owner Author

aristath commented Oct 5, 2021

@aristath Is the expectation within the theme.json that these keys are in camelCase form?

Yes. Example: https://github.com/WordPress/gutenberg/blob/c596a61e562ba2281c1f7d960a7124670dbf54cc/docs/how-to-guides/themes/theme-json.md?plain=1#L704-L710

I assume after parsing, each becomes a variable for usage.

In the JSON parser we're converting camelCase to kebab-case: https://github.com/WordPress/gutenberg/blob/0cdcd47ee333cc64ae0c5641fd8865a8f6c3c4a5/lib/class-wp-theme-json-gutenberg.php#L514-L520 so they can be used later on in CSS generation and/or css-variable names

@hellofromtonya
Copy link
Collaborator

Will the webfont camelCase properties ever be used? Or will they always be converted to kebab-case?

If always converted during the parsing and never ever used in the camelCase format, then using the kebab-case in the schema gets rid of the added conversion processing (less code, memory, and execution time) and makes the webfont's schema more readable and understandable.

@aristath
Copy link
Owner Author

aristath commented Oct 6, 2021

Will the webfont camelCase properties ever be used? Or will they always be converted to kebab-case?

Not in the initial implementation. However, at some point, we'll definitely want to use JS to generate these styles in the editor - in which case camelCase will be used.
Using camelCase in theme.json will be consistent with the way everything else is defined in that file (including CSS props) and will future-proof the implementation editor-side.

@aristath
Copy link
Owner Author

aristath commented Oct 6, 2021

We also need to define the scope of the initial implementation...
I don't think that parsing theme.json should be a concern at this stage.
In order to implement it for theme.json, we'll need to push an initial implementation in core, then push the parser to Gutenberg, test it there, then backport that parsing to WP-Core.
For WP5.9 I think it would be beneficial to just limit our scope to the PHP implementation (keeping in mind that we'll need to implement it in Gutenberg at a later stage), but the editor & theme.json implementations should not be the primary concern.
We only have a limited window of time to get this in WordPress 5.9, and if we go wide and try to implement everything, I fear we're not going to make the date.
A theme.json implementation can come as a 2nd stage after we have the basics in core 😉

@hellofromtonya
Copy link
Collaborator

For WP5.9 I think it would be beneficial to just limit our scope to the PHP implementation (keeping in mind that we'll need to implement it in Gutenberg at a later stage), but the editor & theme.json implementations should not be the primary concern.

I agree. The implementation details for theme.json are not part of the initial (phase 1) implementation. Rather, we are "starting with the end in mind" to ensure what is built and committed in this initial phase 1 is a stepping stone towards that future vision of theme.json, etc. In doing so, we can avoid deprecations, impacts on theme authors, rework, and fragile or overly complex connections into Core's processing engine (registration through to generating the CSS). The "end in mind" helps to shine a light on what needs to built to support the future of theme.json.

What could be Phase 1?

  • Input: the webfonts collection schema in an array data type (for registration)
  • Processing:
    • Schema validation
    • Collection of like font providers to optimize fetching from external APIs
    • Registration of custom providers
    • Generation of CSS
  • Output: CSS

Most of this functionality already exists in the first PR. It can be ported over into a more modern and optimized architecture while exposing new functions for themes to register their webfonts collection and custom providers. The gathering of like font providers is a new piece, though not overly complex to build. And then a full suite of tests will be needed.

@hellofromtonya
Copy link
Collaborator

What about custom providers?

In the webfonts collection scheme, the "provider" could be the ID that is assigned when registering a custom provider through a new function like wp_register_webfont_provider() as proposed by @felixarntz. Core's built-in providers are also registered as available providers along with any custom providers.

Then the registration process for theme authors could be simplified to passing this webfonts collection schema through a function like wp_register_webfont() and any custom providers through wp_register_webfont_provider().

What do you think @aristath?

@aristath
Copy link
Owner Author

aristath commented Oct 6, 2021

What I was thinking is to allow registering a custom provider using wp_register_webfont_provider( $id, $class_name );.
The $id is what will be used as a param when registering a webfont, and a new instance of $class_namecan get created. Or perhaps we could use singletons to gather all fonts from the same provider and have a single instance of each provider's object? 🤔

@hellofromtonya
Copy link
Collaborator

hellofromtonya commented Oct 6, 2021

What I was thinking is to allow registering a custom provider using wp_register_webfont_provider( $id, $class_name );.

Yes, that makes sense.

Or perhaps we could use singletons to gather all fonts from the same provider and have a single instance of each provider's object?

I'd suggest avoiding singletons for future proofing. In the processing engine, the providers are instantiated for the collection of fonts associated with it. For those like fonts (such as Google fonts), I imagine they can use one provider object.

This brings up a good point. Making Core aware of when not to collect like fonts.

For custom providers, how will Core know whether to collect the like fonts or not? For example, let's say there's a custom provider for an external API that requires individual endpoints. How would Core know not to gather like fonts for this provider?

  • This awareness is a configuration detail.
  • The theme would need to tell Core not to include this font or fonts associated with a custom provider.

Would there ever be a use case for one or more fonts to be skipped in the collection process? Or would it be more at the custom provider level, such as for a specific third party API?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants