Skip to content

Commit 607ef90

Browse files
Font Library: Font Collection backend (#54098)
Add extensibility capabilities to the Font Library. Provides a way to provide collections of typographic fonts by code. --------- Co-authored-by: Tonya Mork <[email protected]>
1 parent 8cd5bff commit 607ef90

File tree

17 files changed

+806
-76
lines changed

17 files changed

+806
-76
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
/**
3+
* Font Collection class.
4+
*
5+
* This file contains the Font Collection class definition.
6+
*
7+
* @package WordPress
8+
* @subpackage Font Library
9+
* @since 6.4.0
10+
*/
11+
12+
if ( class_exists( 'WP_Font_Collection' ) ) {
13+
return;
14+
}
15+
16+
/**
17+
* Font Collection class.
18+
*
19+
* @since 6.4.0
20+
*/
21+
class WP_Font_Collection {
22+
23+
/**
24+
* Font collection configuration.
25+
*
26+
* @since 6.4.0
27+
*
28+
* @var array
29+
*/
30+
private $config;
31+
32+
/**
33+
* WP_Font_Collection constructor.
34+
*
35+
* @since 6.4.0
36+
*
37+
* @param array $config Font collection config options.
38+
* See {@see wp_register_font_collection()} for the supported fields.
39+
* @throws Exception If the required parameters are missing.
40+
*/
41+
public function __construct( $config ) {
42+
if ( empty( $config ) || ! is_array( $config ) ) {
43+
throw new Exception( 'Font Collection config options is required as a non-empty array.' );
44+
}
45+
46+
if ( empty( $config['id'] ) || ! is_string( $config['id'] ) ) {
47+
throw new Exception( 'Font Collection config ID is required as a non-empty string.' );
48+
}
49+
50+
if ( empty( $config['name'] ) || ! is_string( $config['name'] ) ) {
51+
throw new Exception( 'Font Collection config name is required as a non-empty string.' );
52+
}
53+
54+
if ( empty( $config['data_json_file'] ) || ! is_string( $config['data_json_file'] ) ) {
55+
throw new Exception( 'Font Collection config "data_json_file" option is required as a non-empty string.' );
56+
}
57+
58+
$this->config = $config;
59+
}
60+
61+
/**
62+
* Gets the font collection config.
63+
*
64+
* @since 6.4.0
65+
*
66+
* @return array An array containing the font collection config.
67+
*/
68+
public function get_config() {
69+
return $this->config;
70+
}
71+
72+
/**
73+
* Gets the font collection data.
74+
*
75+
* @since 6.4.0
76+
*
77+
* @return array|WP_Error An array containing the list of font families in theme.json format on success,
78+
* else an instance of WP_Error on failure.
79+
*/
80+
public function get_data() {
81+
if ( ! file_exists( $this->config['data_json_file'] ) ) {
82+
return new WP_Error( 'font_collection_file_error', __( 'Font Collection data JSON file does not exist.', 'gutenberg' ) );
83+
}
84+
85+
$data = file_get_contents( $this->config['data_json_file'] );
86+
if ( empty( $data ) ) {
87+
return new WP_Error( 'font_collection_read_error', __( 'Error reading the Font Collection data JSON file contents.', 'gutenberg' ) );
88+
}
89+
90+
$collection_data = $this->get_config();
91+
$collection_data['data'] = $data;
92+
unset( $collection_data['data_json_file'] );
93+
return $collection_data;
94+
}
95+
}

lib/experimental/fonts/font-library/class-wp-font-library.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,61 @@ class WP_Font_Library {
2727
'woff2' => 'font/woff2',
2828
);
2929

30+
/**
31+
* Font collections.
32+
*
33+
* @since 6.4.0
34+
*
35+
* @var array
36+
*/
37+
private static $collections = array();
38+
39+
/**
40+
* Register a new font collection.
41+
*
42+
* @since 6.4.0
43+
*
44+
* @param array $config Font collection config options.
45+
* See {@see wp_register_font_collection()} for the supported fields.
46+
* @return WP_Font_Collection|WP_Error A font collection is it was registered successfully and a WP_Error otherwise.
47+
*/
48+
public static function register_font_collection( $config ) {
49+
$new_collection = new WP_Font_Collection( $config );
50+
51+
if ( isset( self::$collections[ $config['id'] ] ) ) {
52+
return new WP_Error( 'font_collection_registration_error', 'Font collection already registered.' );
53+
}
54+
55+
self::$collections[ $config['id'] ] = $new_collection;
56+
return $new_collection;
57+
}
58+
59+
/**
60+
* Gets all the font collections available.
61+
*
62+
* @since 6.4.0
63+
*
64+
* @return array List of font collections.
65+
*/
66+
public static function get_font_collections() {
67+
return self::$collections;
68+
}
69+
70+
/**
71+
* Gets a font collection.
72+
*
73+
* @since 6.4.0
74+
*
75+
* @param string $id Font collection id.
76+
* @return array List of font collections.
77+
*/
78+
public static function get_font_collection( $id ) {
79+
if ( array_key_exists( $id, self::$collections ) ) {
80+
return self::$collections[ $id ];
81+
}
82+
return new WP_Error( 'font_collection_not_found', 'Font collection not found.' );
83+
}
84+
3085
/**
3186
* Gets the upload directory for fonts.
3287
*

lib/experimental/fonts/font-library/class-wp-rest-font-library-controller.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,66 @@ public function register_routes() {
6767
),
6868
)
6969
);
70+
71+
register_rest_route(
72+
$this->namespace,
73+
'/' . $this->rest_base . '/collections',
74+
array(
75+
array(
76+
'methods' => WP_REST_Server::READABLE,
77+
'callback' => array( $this, 'get_font_collections' ),
78+
'permission_callback' => array( $this, 'update_font_library_permissions_check' ),
79+
),
80+
)
81+
);
82+
83+
register_rest_route(
84+
$this->namespace,
85+
'/' . $this->rest_base . '/collections' . '/(?P<id>[\/\w-]+)',
86+
array(
87+
array(
88+
'methods' => WP_REST_Server::READABLE,
89+
'callback' => array( $this, 'get_font_collection' ),
90+
'permission_callback' => array( $this, 'update_font_library_permissions_check' ),
91+
),
92+
)
93+
);
94+
}
95+
96+
/**
97+
* Gets a font collection.
98+
*
99+
* @since 6.4.0
100+
*
101+
* @param WP_REST_Request $request Full details about the request.
102+
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
103+
*/
104+
public function get_font_collection( $request ) {
105+
$id = $request->get_param( 'id' );
106+
$collection = WP_Font_Library::get_font_collection( $id );
107+
108+
if ( is_wp_error( $collection ) ) {
109+
$collection->add_data( array( 'status' => 404 ) );
110+
return $collection;
111+
}
112+
113+
return new WP_REST_Response( $collection->get_data() );
114+
}
115+
116+
/**
117+
* Gets the font collections available.
118+
*
119+
* @since 6.4.0
120+
*
121+
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
122+
*/
123+
public function get_font_collections() {
124+
$collections = array();
125+
foreach ( WP_Font_Library::get_font_collections() as $collection ) {
126+
$collections[] = $collection->get_config();
127+
}
128+
129+
return new WP_REST_Response( $collections, 200 );
70130
}
71131

72132
/**

lib/experimental/fonts/font-library/font-library.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
*
2020
* @since 6.4.0
2121
*/
22-
function gutenberg_init_font_library() {
22+
function gutenberg_init_font_library_routes() {
2323
// @core-merge: This code will go into Core's `create_initial_post_types()`.
2424
$args = array(
2525
'public' => true,
@@ -33,5 +33,25 @@ function gutenberg_init_font_library() {
3333
$font_library_controller->register_routes();
3434
}
3535

36-
add_action( 'rest_api_init', 'gutenberg_init_font_library' );
36+
add_action( 'rest_api_init', 'gutenberg_init_font_library_routes' );
3737

38+
39+
if ( ! function_exists( 'wp_register_font_collection' ) ) {
40+
/**
41+
* Registers a new Font Collection in the Font Library.
42+
*
43+
* @since 6.4.0
44+
*
45+
* @param string[] $config {
46+
* Font collection associative array of configuration options.
47+
*
48+
* @type string $id The font collection's unique ID.
49+
* @type string $data_json_file The font collection's data JSON file.
50+
* }
51+
* @return WP_Font_Collection|WP_Error A font collection is it was registered
52+
* successfully, else WP_Error.
53+
*/
54+
function wp_register_font_collection( $config ) {
55+
return WP_Font_Library::register_font_collection( $config );
56+
}
57+
}

lib/load.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ function gutenberg_is_experiment_enabled( $name ) {
165165
( defined( 'FONTS_LIBRARY_ENABLE' ) && FONTS_LIBRARY_ENABLE )
166166
) {
167167
// Loads the Font Library.
168+
require __DIR__ . '/experimental/fonts/font-library/class-wp-font-collection.php';
168169
require __DIR__ . '/experimental/fonts/font-library/class-wp-font-library.php';
169170
require __DIR__ . '/experimental/fonts/font-library/class-wp-font-family-utils.php';
170171
require __DIR__ . '/experimental/fonts/font-library/class-wp-font-family.php';
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
/**
3+
* Test WP_Font_Collection::__construct().
4+
*
5+
* @package WordPress
6+
* @subpackage Font Library
7+
*
8+
* @group fonts
9+
* @group font-library
10+
*
11+
* @covers WP_Font_Collection::__construct
12+
*/
13+
class Tests_Fonts_WpFontCollection_Construct extends WP_UnitTestCase {
14+
15+
public function test_should_initialize_data() {
16+
$property = new ReflectionProperty( WP_Font_Collection::class, 'config' );
17+
$property->setAccessible( true );
18+
19+
$config = array(
20+
'id' => 'my-collection',
21+
'name' => 'My Collection',
22+
'description' => 'My collection description',
23+
'data_json_file' => 'my-collection-data.json',
24+
);
25+
$font_collection = new WP_Font_Collection( $config );
26+
27+
$actual = $property->getValue( $font_collection );
28+
$property->setAccessible( false );
29+
30+
$this->assertSame( $config, $actual );
31+
}
32+
33+
/**
34+
* @dataProvider data_should_throw_exception
35+
*
36+
* @param mixed $config Config of the font collection.
37+
* @param string $expected_exception_message Expected exception message.
38+
*/
39+
public function test_should_throw_exception( $config, $expected_exception_message ) {
40+
$this->expectException( 'Exception' );
41+
$this->expectExceptionMessage( $expected_exception_message );
42+
new WP_Font_Collection( $config );
43+
}
44+
45+
/**
46+
* Data provider.
47+
*
48+
* @return array
49+
*/
50+
public function data_should_throw_exception() {
51+
return array(
52+
'no id' => array(
53+
array(
54+
'name' => 'My Collection',
55+
'description' => 'My collection description',
56+
'data_json_file' => 'my-collection-data.json',
57+
),
58+
'Font Collection config ID is required as a non-empty string.',
59+
),
60+
61+
'no config' => array(
62+
'',
63+
'Font Collection config options is required as a non-empty array.',
64+
),
65+
66+
'empty array' => array(
67+
array(),
68+
'Font Collection config options is required as a non-empty array.',
69+
),
70+
71+
'boolean instead of config array' => array(
72+
false,
73+
'Font Collection config options is required as a non-empty array.',
74+
),
75+
76+
'null instead of config array' => array(
77+
null,
78+
'Font Collection config options is required as a non-empty array.',
79+
),
80+
81+
'missing data_json_file' => array(
82+
array(
83+
'id' => 'my-collection',
84+
'name' => 'My Collection',
85+
'description' => 'My collection description',
86+
),
87+
'Font Collection config "data_json_file" option is required as a non-empty string.',
88+
),
89+
90+
);
91+
}
92+
}

0 commit comments

Comments
 (0)