-
-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Overview
Enable WordPress Font Collections in the block plugin scaffold using the JSON registration method introduced in WordPress 6.5. This feature allows plugins to provide curated sets of fonts that users can install and manage through the Font Library in the Site Editor.
Resources
- WordPress Documentation: How to register custom font collections
- JSON Schema: font-collection.json
- WordPress Schema URL:
https://schemas.wp.org/trunk/font-collection.json
Implementation Requirements
1. Create Font Collection JSON Files
Location: assets/fonts/
Create placeholder/template JSON files following the WordPress font collection schema:
{
"$schema": "https://schemas.wp.org/trunk/font-collection.json",
"font_families": [
{
"font_family_settings": {
"name": "{{font_family_name}}",
"fontFamily": "{{font_family_stack}}",
"slug": "{{font_family_slug}}",
"fontFace": [
{
"src": "{{font_src_url}}",
"fontWeight": "{{font_weight}}",
"fontStyle": "{{font_style}}",
"fontFamily": "{{font_family_name}}",
"preview": "{{preview_image_url}}"
}
],
"preview": "{{family_preview_url}}"
},
"categories": ["{{font_category}}"]
}
]
}Suggested Collections:
assets/fonts/{{slug}}-system-fonts.json- System font stacks (no files required)assets/fonts/{{slug}}-custom-fonts.json- Plugin-specific custom fonts (optional)
2. Update Plugin Main File
File: {{slug}}.php
Add font collection registration method to the Core class or as a standalone function:
/**
* Register plugin font collections.
*
* @since {{version}}
*/
public function register_font_collections() {
// Register system fonts collection (if exists)
$system_fonts_path = plugin_dir_path( __FILE__ ) . 'assets/fonts/{{slug}}-system-fonts.json';
if ( file_exists( $system_fonts_path ) ) {
wp_register_font_collection(
'{{slug}}-system-fonts',
array(
'name' => __( '{{plugin_name}} System Fonts', '{{text_domain}}' ),
'description' => __( 'A curated collection of system fonts optimized for {{plugin_name}}.', '{{text_domain}}' ),
'font_families' => $system_fonts_path,
'categories' => array(
array(
'name' => __( 'Sans Serif', '{{text_domain}}' ),
'slug' => 'sans-serif',
),
array(
'name' => __( 'Serif', '{{text_domain}}' ),
'slug' => 'serif',
),
array(
'name' => __( 'Monospace', '{{text_domain}}' ),
'slug' => 'monospace',
),
array(
'name' => __( 'Handwriting', '{{text_domain}}' ),
'slug' => 'handwriting',
),
),
)
);
}
// Register custom fonts collection (if exists)
$custom_fonts_path = plugin_dir_path( __FILE__ ) . 'assets/fonts/{{slug}}-custom-fonts.json';
if ( file_exists( $custom_fonts_path ) ) {
wp_register_font_collection(
'{{slug}}-custom-fonts',
array(
'name' => __( '{{plugin_name}} Custom Fonts', '{{text_domain}}' ),
'description' => __( 'Custom font families designed for {{plugin_name}}.', '{{text_domain}}' ),
'font_families' => $custom_fonts_path,
'categories' => array(
array(
'name' => __( 'Display', '{{text_domain}}' ),
'slug' => 'display',
),
),
)
);
}
}Hook to init:
add_action( 'init', array( $this, 'register_font_collections' ) );3. Update Mustache Variables Registry
File: scripts/mustache-variables-registry.json
Add new font collection variables to track:
{
"font_collection_name": {
"name": "font_collection_name",
"category": "typography",
"type": "string",
"description": "Name of the font collection"
},
"font_collection_slug": {
"name": "font_collection_slug",
"category": "typography",
"type": "slug",
"description": "Slug for the font collection"
},
"font_collection_description": {
"name": "font_collection_description",
"category": "typography",
"type": "string",
"description": "Description of the font collection"
},
"font_family_name": {
"name": "font_family_name",
"category": "typography",
"type": "string",
"description": "Font family display name"
},
"font_family_slug": {
"name": "font_family_slug",
"category": "typography",
"type": "slug",
"description": "Font family slug"
},
"font_family_stack": {
"name": "font_family_stack",
"category": "typography",
"type": "string",
"description": "CSS font-family value with fallbacks"
},
"font_src_url": {
"name": "font_src_url",
"category": "typography",
"type": "url",
"description": "URL to font file"
},
"font_weight": {
"name": "font_weight",
"category": "typography",
"type": "string",
"description": "Font weight value"
},
"font_style": {
"name": "font_style",
"category": "typography",
"type": "string",
"description": "Font style (normal, italic)"
},
"font_category": {
"name": "font_category",
"category": "typography",
"type": "string",
"description": "Font category slug"
},
"preview_image_url": {
"name": "preview_image_url",
"category": "typography",
"type": "url",
"description": "URL to font preview image"
},
"family_preview_url": {
"name": "family_preview_url",
"category": "typography",
"type": "url",
"description": "URL to font family preview image"
}
}4. Update Plugin Generation Script
File: scripts/generate-plugin.js
Add font collection handling:
- Create
assets/fonts/directory during generation - Process font collection JSON template files
- Replace mustache variables in JSON files
- Validate generated JSON against schema
Implementation additions:
// After plugin directory creation
const fontCollectionsDir = path.join(outputDir, 'assets/fonts');
fs.mkdirSync(fontCollectionsDir, { recursive: true });
// Process font collection templates
const fontCollectionFiles = [
'assets/fonts/{{slug}}-system-fonts.json',
'assets/fonts/{{slug}}-custom-fonts.json'
];
fontCollectionFiles.forEach(file => {
const templatePath = path.join(scaffoldDir, file);
if (fs.existsSync(templatePath)) {
const content = fs.readFileSync(templatePath, 'utf8');
const processed = replaceMustacheVariables(content, placeholders);
const outputPath = path.join(outputDir, file.replace('{{slug}}', placeholders.slug));
fs.writeFileSync(outputPath, processed);
// Validate JSON
try {
JSON.parse(processed);
logger.log('success', `Generated and validated: ${outputPath}`);
} catch (error) {
logger.log('error', `Invalid JSON in ${outputPath}: ${error.message}`);
}
}
});5. Update Plugin Config Schema
File: .github/schemas/plugin-config.schema.json
Add font collection configuration options:
{
"enable_font_collections": {
"type": "boolean",
"description": "Enable custom font collections for the plugin",
"default": false
},
"font_collections": {
"type": "array",
"description": "Array of font collections to include",
"items": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Display name of the font collection"
},
"slug": {
"type": "string",
"description": "Unique identifier for the collection",
"pattern": "^[a-z0-9-]+$"
},
"description": {
"type": "string",
"description": "Description of the font collection"
},
"type": {
"type": "string",
"enum": ["system", "custom", "google"],
"description": "Type of font collection"
}
},
"required": ["name", "slug"]
},
"default": []
}
}6. Update Generation Agent
File: .github/agents/generate-plugin.agent.md
Add instructions for font collection generation:
## Font Collections
When generating plugins with font collections:
1. Check if `enable_font_collections` is true in config
2. Create `assets/fonts/` directory
3. Generate font collection JSON files based on `font_collections` array
4. For system fonts: use Modern Font Stacks as examples
5. For custom fonts: create placeholder structure
6. Validate all JSON against WordPress font collection schema
7. Add registration method to Core class or plugin main file
8. Include translatable strings for collection names and categories
9. Hook registration to `init` action7. Update Core Class
File: inc/class-core.php
Add font collection registration method if using class-based structure:
/**
* Register font collections.
*
* @since {{version}}
*/
public function register_font_collections() {
// Registration code from section 2
}Add to __construct() or init hooks:
add_action( 'init', array( $this, 'register_font_collections' ) );8. Documentation Updates
Files to update:
docs/GENERATE_PLUGIN.md- Add font collections sectionREADME.md- Mention font collections featureUSAGE.md- Add usage instructions for font collections- Create
docs/FONT_COLLECTIONS.md- Detailed guide on:- Using font collections in plugins
- Customizing font families
- Schema validation
- Examples (system fonts, web fonts)
- Limitations and best practices
- Plugin vs Theme considerations
9. Create Directory Structure
assets/
fonts/
.gitkeep
{{slug}}-system-fonts.json (template)
{{slug}}-custom-fonts.json (template)
10. Unit Tests
File: tests/test-font-collections.php
Add PHPUnit tests:
<?php
/**
* Tests for font collection registration.
*
* @package {{slug}}
*/
class Test_Font_Collections extends WP_UnitTestCase {
public function test_system_fonts_registered() {
$collections = WP_Font_Library::get_instance()->get_font_collections();
$this->assertArrayHasKey( '{{slug}}-system-fonts', $collections );
}
public function test_font_collection_has_valid_structure() {
$collection = WP_Font_Library::get_instance()->get_font_collection( '{{slug}}-system-fonts' );
$this->assertNotNull( $collection );
$this->assertIsString( $collection->get_name() );
$this->assertIsString( $collection->get_description() );
}
public function test_font_collection_json_valid() {
$json_path = plugin_dir_path( dirname( __FILE__ ) ) . 'assets/fonts/{{slug}}-system-fonts.json';
$this->assertFileExists( $json_path );
$json_content = file_get_contents( $json_path );
$this->assertJson( $json_content );
$data = json_decode( $json_content, true );
$this->assertArrayHasKey( 'font_families', $data );
$this->assertIsArray( $data['font_families'] );
}
public function test_font_collection_slug_prefixed() {
$collections = WP_Font_Library::get_instance()->get_font_collections();
foreach ( $collections as $slug => $collection ) {
if ( strpos( $slug, '{{slug}}-' ) === 0 ) {
$this->assertStringStartsWith( '{{slug}}-', $slug );
}
}
}
}11. Example System Fonts Collection
Create a default example using Modern Font Stacks:
{
"$schema": "https://schemas.wp.org/trunk/font-collection.json",
"font_families": [
{
"font_family_settings": {
"fontFamily": "system-ui, sans-serif",
"slug": "system-ui",
"name": "System UI"
},
"categories": ["sans-serif"]
},
{
"font_family_settings": {
"fontFamily": "Charter, 'Bitstream Charter', 'Sitka Text', Cambria, serif",
"slug": "transitional",
"name": "Transitional"
},
"categories": ["serif"]
},
{
"font_family_settings": {
"fontFamily": "'Nimbus Mono PS', 'Courier New', monospace",
"slug": "monospace-slab-serif",
"name": "Monospace Slab Serif"
},
"categories": ["monospace", "serif"]
},
{
"font_family_settings": {
"fontFamily": "'Segoe Print', 'Bradley Hand', Chilanka, TSCu_Comic, casual, cursive",
"slug": "handwritten",
"name": "Handwritten"
},
"categories": ["handwriting"]
}
]
}12. Plugin-Specific Considerations
Namespace Conflicts:
- Ensure font collection slugs are prefixed with plugin slug
- Example:
my-plugin-system-fontsnot justsystem-fonts
Plugin Deactivation:
- Consider unregistering collections on deactivation
- Add uninstall cleanup in
uninstall.phporuninstall-{{slug}}.php
Uninstall Cleanup:
// In uninstall-{{slug}}.php
if ( function_exists( 'wp_unregister_font_collection' ) ) {
wp_unregister_font_collection( '{{slug}}-system-fonts' );
wp_unregister_font_collection( '{{slug}}-custom-fonts' );
}Checklist
- Create
assets/fonts/directory structure - Create font collection JSON template files with mustache placeholders
- Add font collection registration to Core class or plugin main file
- Update mustache variables registry
- Update plugin generation script to process font collections
- Update plugin config schema with font collection options
- Update generate-plugin agent instructions
- Create documentation (FONT_COLLECTIONS.md)
- Update existing docs (GENERATE_PLUGIN.md, README.md, USAGE.md)
- Add PHPUnit tests
- Add generation script tests
- Add uninstall cleanup
- Test with wp-env
- Validate JSON against schema
- Test with basic and advanced wizard modes
- Add examples for both system and custom fonts
- Ensure proper plugin slug prefixing
- Test plugin activation/deactivation
Notes
- JSON Method Only: We're using the JSON method exclusively as it's cleaner for templates and follows best practices
- Placeholders: All files use mustache variables for plugin-specific values
- Validation: All generated JSON must be validated against the WordPress schema
- Optional Feature: Font collections should be optional in the wizard (default: disabled for plugins)
- System Fonts First: Prioritize system fonts as they don't require file hosting
- Plugin Review Compliance: Be mindful of WordPress.org Plugin Review guidelines regarding external resources
- Translation Ready: All collection names and descriptions must be translatable
- Slug Prefixing: Always prefix font collection slugs with plugin slug to avoid conflicts
- Cleanup: Provide proper uninstall cleanup for font collections
- Plugin vs Theme: Unlike themes, plugins should use
plugin_dir_path()instead ofget_theme_file_path() - Class-Based Structure: If using the Core class pattern, add as a method; otherwise add as function in main plugin file
- Init Hook: Always hook font collection registration to
initaction with appropriate priority
Related Issues
- Relates to typography features in block patterns
- May impact block editor font controls
- Consider integration with SCF JSON for font metadata
- Consider relationship with pattern typography settings
Plugin-Specific Use Cases
- Form Builders: Custom fonts for form typography
- Page Builders: Font collections for design systems
- E-commerce: Brand-specific font collections
- Membership Sites: Exclusive font collections for members
- LMS Plugins: Educational content typography
- Portfolio Plugins: Designer-curated font sets