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

Font Library: Font Collection backend #53816

Closed
wants to merge 52 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
79d6af7
Adding Font Collection class
matiasbenedetto Aug 18, 2023
fd1c967
php formatting and linting
matiasbenedetto Aug 18, 2023
0cfac6c
Adding tests for collections routes
matiasbenedetto Aug 18, 2023
6bb2f8b
Adding tests for WP_Font_Collection constructor
matiasbenedetto Aug 18, 2023
4a67d0b
adding tests for WP_Font_Collection get_data()
matiasbenedetto Aug 18, 2023
b26cb63
adding tests for WP_Font_Library register_font_collection()
matiasbenedetto Aug 18, 2023
0cfddb2
get font collection tests
matiasbenedetto Aug 21, 2023
7ba6f61
adding 'wp_' prefix to the 'register_font_collection' filter name
matiasbenedetto Aug 21, 2023
454f9a5
fix callback name
matiasbenedetto Aug 21, 2023
932064f
making class property private
matiasbenedetto Aug 21, 2023
b184398
registering filter from font-library.php file
matiasbenedetto Aug 21, 2023
6a2dfa0
Merge branch 'trunk' into try/font-collections
matiasbenedetto Aug 22, 2023
36ab188
removing superfluous comment
matiasbenedetto Aug 22, 2023
ac938c9
moving files to according changes in trunk
matiasbenedetto Aug 22, 2023
a9c7b6a
config without a json file should fail
matiasbenedetto Aug 22, 2023
b2deb14
fix property name in tests
matiasbenedetto Aug 22, 2023
4765538
name fix
matiasbenedetto Aug 23, 2023
3fb8b0a
comment update
matiasbenedetto Aug 23, 2023
3fadd9d
Adds WP_Error to return type
hellofromtonya Aug 23, 2023
bdaacf8
Improves contructor error handling.
hellofromtonya Aug 23, 2023
85fe753
FontCollection::get_data(): Improves error handling
hellofromtonya Aug 23, 2023
4ae9af6
Removes empty space for wpcs
hellofromtonya Aug 23, 2023
de053da
adding filter in a simpler way
matiasbenedetto Aug 23, 2023
21dfbe3
micro-optimization
matiasbenedetto Aug 23, 2023
fb913af
reuse WP_Error response instead of creating a new one
matiasbenedetto Aug 23, 2023
0e6c026
Eliminates try/catch
hellofromtonya Aug 23, 2023
f79212d
Revert "Eliminates try/catch" commit
hellofromtonya Aug 23, 2023
4e952e3
Remove wp_register_font_collection and replace it by a global functio…
matiasbenedetto Aug 24, 2023
196459a
adding function comment and guard agains re-declaration
matiasbenedetto Aug 24, 2023
a76d943
php format
matiasbenedetto Aug 24, 2023
c15b5ae
fixing docblock coments
matiasbenedetto Aug 24, 2023
85261b3
removing param comment
matiasbenedetto Aug 24, 2023
ad52829
re-adding parameter comment removed by mistake
matiasbenedetto Aug 24, 2023
7161ba1
format php
matiasbenedetto Aug 24, 2023
8402b91
updating WP_Font_Collection __construct tests
matiasbenedetto Aug 24, 2023
e0947c9
updating WP_Font_Collection get_data tests
matiasbenedetto Aug 24, 2023
98d52ad
updating tests
matiasbenedetto Aug 24, 2023
a6ed145
php format
matiasbenedetto Aug 24, 2023
f8dc1a0
array check
matiasbenedetto Aug 24, 2023
4cb5c77
Documents config array structure
hellofromtonya Aug 24, 2023
4b7e5e3
adding tests for /fonts/collections endpoint
matiasbenedetto Aug 24, 2023
56607c9
adding /fonts/collections/<id> endpoint test
matiasbenedetto Aug 24, 2023
c928ebe
format
matiasbenedetto Aug 24, 2023
aeb42cf
format
matiasbenedetto Aug 24, 2023
0a98de6
add test for missing collection
matiasbenedetto Aug 24, 2023
46f9fde
removing not needed variables
matiasbenedetto Aug 24, 2023
785262b
Add more tests and split the test for WP_REST_Font_Library_Controller
matiasbenedetto Aug 25, 2023
de12fe7
lint
matiasbenedetto Aug 25, 2023
dc560b8
try to create dir for tests in CI
matiasbenedetto Aug 25, 2023
60997e9
Merge branch 'trunk' into try/font-collections
matiasbenedetto Aug 25, 2023
803a1d1
Tests: Core prep
hellofromtonya Aug 31, 2023
d3935e3
Doh I changed the wrong assertion
hellofromtonya Aug 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
/**
* Font Collection class.
*
* This file contains the Font Collection class definition.
*
* @package WordPress
* @subpackage Font Library
* @since 6.4.0
*/

if ( class_exists( 'WP_Font_Collection' ) ) {
return;
}

/**
* Font Collection class.
*
* @since 6.4.0
*/
class WP_Font_Collection {

/**
* Font collection configuration.
*
* @since 6.4.0
*
* @var array
*/
private $config;

/**
* WP_Font_Collection constructor.
*
* @since 6.4.0
*
* @param array $config Font collection config options.
* See {@see wp_register_font_collection()} for the supported fields.
* @throws Exception If the required parameters are missing.
*/
public function __construct( $config ) {
if ( empty( $config ) || ! is_array( $config ) ) {
throw new Exception( 'Font Collection config options is required as a non-empty array.' );
}

if ( empty( $config['id'] ) || ! is_string( $config['id'] ) ) {
throw new Exception( 'Font Collection config ID is required as a non-empty string.' );
}

if ( empty( $config['name'] ) || ! is_string( $config['name'] ) ) {
throw new Exception( 'Font Collection config name is required as a non-empty string.' );
}

if ( empty( $config['data_json_file'] ) || ! is_string( $config['data_json_file'] ) ) {
throw new Exception( 'Font Collection config "data_json_file" option is required as a non-empty string.' );
}

$this->config = $config;
}

/**
* Gets the font collection config.
*
* @since 6.4.0
*
* @return array An array containing the font collection config.
*/
public function get_config() {
return $this->config;
}

/**
* Gets the font collection data.
*
* @since 6.4.0
*
* @return array|WP_Error An array containing the list of font families in theme.json format on success,
* else an instance of WP_Error on failure.
*/
public function get_data() {
if ( ! file_exists( $this->config['data_json_file'] ) ) {
return new WP_Error( 'font_collection_file_error', __( 'Font Collection data JSON file does not exist.', 'gutenberg' ) );
}

$data = file_get_contents( $this->config['data_json_file'] );
if ( empty( $data ) ) {
return new WP_Error( 'font_collection_read_error', __( 'Error reading the Font Collection data JSON file contents.', 'gutenberg' ) );
}

$collection_data = $this->get_config();
$collection_data['data'] = $data;
unset( $collection_data['data_json_file'] );
return $collection_data;
}
}
55 changes: 55 additions & 0 deletions lib/experimental/fonts/font-library/class-wp-font-library.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,61 @@ class WP_Font_Library {
'woff2' => 'font/woff2',
);

/**
* Font collections.
*
* @since 6.4.0
*
* @var array
*/
private static $collections = array();

/**
* Register a new font collection.
*
* @since 6.4.0
*
* @param array $config Font collection config options.
* See {@see wp_register_font_collection()} for the supported fields.
* @return WP_Font_Collection|WP_Error A font collection is it was registered successfully and a WP_Error otherwise.
*/
public static function register_font_collection( $config ) {
$new_collection = new WP_Font_Collection( $config );

if ( isset( self::$collections[ $config['id'] ] ) ) {
return new WP_Error( 'font_collection_registration_error', 'Font collection already registered.' );
}

self::$collections[ $config['id'] ] = $new_collection;
return $new_collection;
}

/**
* Gets all the font collections available.
*
* @since 6.4.0
*
* @return array List of font collections.
*/
public static function get_font_collections() {
return self::$collections;
}

/**
* Gets a font collection.
*
* @since 6.4.0
*
* @param string $id Font collection id.
* @return array List of font collections.
*/
public static function get_font_collection( $id ) {
if ( array_key_exists( $id, self::$collections ) ) {
return self::$collections[ $id ];
}
return new WP_Error( 'font_collection_not_found', 'Font collection not found.' );
}

/**
* Gets the upload directory for fonts.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,66 @@ public function register_routes() {
),
)
);

register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/collections',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_font_collections' ),
'permission_callback' => array( $this, 'update_font_library_permissions_check' ),
),
)
);

register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/collections' . '/(?P<id>[\/\w-]+)',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_font_collection' ),
'permission_callback' => array( $this, 'update_font_library_permissions_check' ),
),
)
);
}

/**
* Gets a font collection.
*
* @since 6.4.0
*
* @param WP_REST_Request $request Full details about the request.
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_font_collection( $request ) {
$id = $request->get_param( 'id' );
$collection = WP_Font_Library::get_font_collection( $id );

if ( is_wp_error( $collection ) ) {
$collection->add_data( array( 'status' => 404 ) );
return $collection;
}

return new WP_REST_Response( $collection->get_data() );
}

/**
* Gets the font collections available.
*
* @since 6.4.0
*
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_font_collections() {
$collections = array();
foreach ( WP_Font_Library::get_font_collections() as $collection ) {
$collections[] = $collection->get_config();
}

return new WP_REST_Response( $collections, 200 );
}

/**
Expand Down
24 changes: 22 additions & 2 deletions lib/experimental/fonts/font-library/font-library.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*
* @since 6.4.0
*/
function gutenberg_init_font_library() {
function gutenberg_init_font_library_routes() {
// @core-merge: This code will go into Core's `create_initial_post_types()`.
$args = array(
'public' => true,
Expand All @@ -33,5 +33,25 @@ function gutenberg_init_font_library() {
$font_library_controller->register_routes();
}

add_action( 'rest_api_init', 'gutenberg_init_font_library' );
add_action( 'rest_api_init', 'gutenberg_init_font_library_routes' );


if ( ! function_exists( 'wp_register_font_collection' ) ) {
/**
* Registers a new Font Collection in the Font Library.
*
* @since 6.4.0
*
* @param string[] $config {
* Font collection associative array of configuration options.
*
* @type string $id The font collection's unique ID.
* @type string $data_json_file The font collection's data JSON file.
* }
* @return WP_Font_Collection|WP_Error A font collection is it was registered
* successfully, else WP_Error.
*/
function wp_register_font_collection( $config ) {
return WP_Font_Library::register_font_collection( $config );
}
}
1 change: 1 addition & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ function gutenberg_is_experiment_enabled( $name ) {
( defined( 'FONTS_LIBRARY_ENABLE' ) && FONTS_LIBRARY_ENABLE )
) {
// Loads the Font Library.
require __DIR__ . '/experimental/fonts/font-library/class-wp-font-collection.php';
require __DIR__ . '/experimental/fonts/font-library/class-wp-font-library.php';
require __DIR__ . '/experimental/fonts/font-library/class-wp-font-family-utils.php';
require __DIR__ . '/experimental/fonts/font-library/class-wp-font-family.php';
Expand Down
92 changes: 92 additions & 0 deletions phpunit/tests/fonts/font-library/wpFontCollection/__construct.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php
/**
* Test WP_Font_Collection::__construct().
*
* @package WordPress
* @subpackage Font Library
*
* @group fonts
* @group font-library
*
* @covers WP_Font_Collection::__construct
*/
class Tests_Fonts_WpFontCollection_Construct extends WP_UnitTestCase {

public function test_should_initialize_data() {
$property = new ReflectionProperty( WP_Font_Collection::class, 'config' );
$property->setAccessible( true );

$config = array(
'id' => 'my-collection',
'name' => 'My Collection',
'description' => 'My collection description',
'data_json_file' => 'my-collection-data.json',
);
$font_collection = new WP_Font_Collection( $config );

$actual = $property->getValue( $font_collection );
$property->setAccessible( false );

$this->assertSame( $config, $actual );
}

/**
* @dataProvider data_should_throw_exception
*
* @param mixed $config Config of the font collection.
* @param string $expected_exception_message Expected exception message.
*/
public function test_should_throw_exception( $config, $expected_exception_message ) {
$this->expectException( 'Exception' );
$this->expectExceptionMessage( $expected_exception_message );
new WP_Font_Collection( $config );
}

/**
* Data provider.
*
* @return array
*/
public function data_should_throw_exception() {
return array(
'no id' => array(
array(
'name' => 'My Collection',
'description' => 'My collection description',
'data_json_file' => 'my-collection-data.json',
),
'Font Collection config ID is required as a non-empty string.',
),

'no config' => array(
'',
'Font Collection config options is required as a non-empty array.',
),

'empty array' => array(
array(),
'Font Collection config options is required as a non-empty array.',
),

'boolean instead of config array' => array(
false,
'Font Collection config options is required as a non-empty array.',
),

'null instead of config array' => array(
null,
'Font Collection config options is required as a non-empty array.',
),

'missing data_json_file' => array(
array(
'id' => 'my-collection',
'name' => 'My Collection',
'description' => 'My collection description',
),
'Font Collection config "data_json_file" option is required as a non-empty string.',
),

);
}
}
Loading