Skip to content

Commit

Permalink
Font Library: font collection refactor to use the new schema (#57884)
Browse files Browse the repository at this point in the history
* google fonts collection data provisional url

* rename controller methods

* fix get_items parameters

* fix endpoint return

* rafactor font collection class

* fix tests for the refactored class

* refactor font collections rest controller

* update font collection tests

* update the frontend to use the new endpoint data schema

* format php

* adding linter line ignore rul

* replacing throwing an exception by calling doing_it_wrong

* add translation marks

Co-authored-by: Jeff Ong <jonger4@gmail.com>

* user ternary operator

* correct translation formatting and comments

* renaming function

* renaming tests

* improve url matching

Co-authored-by: Grant Kinney <creativecoder@users.noreply.github.com>

* return error without rest_ensure_response

* fix contradictory if condition

---------

Co-authored-by: Jeff Ong <jonger4@gmail.com>
Co-authored-by: Grant Kinney <creativecoder@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 19, 2024
1 parent 32689e1 commit 2aa9c64
Show file tree
Hide file tree
Showing 18 changed files with 563 additions and 411 deletions.
183 changes: 140 additions & 43 deletions lib/experimental/fonts/font-library/class-wp-font-collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,41 +21,128 @@
class WP_Font_Collection {

/**
* Font collection configuration.
* The unique slug for the font collection.
*
* @since 6.5.0
*
* @var string
*/
private $slug;

/**
* The name of the font collection.
*
* @since 6.5.0
*
* @var string
*/
private $name;

/**
* Description of the font collection.
*
* @since 6.5.0
*
* @var string
*/
private $description;

/**
* Source of the font collection.
*
* @since 6.5.0
*
* @var string
*/
private $src;

/**
* Array of font families in the collection.
*
* @since 6.5.0
*
* @var array
*/
private $config;
private $font_families;

/**
* Categories associated with the font collection.
*
* @since 6.5.0
*
* @var array
*/
private $categories;


/**
* WP_Font_Collection constructor.
*
* @since 6.5.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.
* @param array $config Font collection config options. {
* @type string $slug The font collection's unique slug.
* @type string $name The font collection's name.
* @type string $description The font collection's description.
* @type string $src The font collection's source.
* @type array $font_families An array of font families in the font collection.
* @type array $categories The font collection's categories.
* }
*/
public function __construct( $config ) {
if ( empty( $config ) || ! is_array( $config ) ) {
throw new Exception( 'Font Collection config options is required as a non-empty array.' );
}
$this->is_config_valid( $config );

$this->slug = isset( $config['slug'] ) ? $config['slug'] : '';
$this->name = isset( $config['name'] ) ? $config['name'] : '';
$this->description = isset( $config['description'] ) ? $config['description'] : '';
$this->src = isset( $config['src'] ) ? $config['src'] : '';
$this->font_families = isset( $config['font_families'] ) ? $config['font_families'] : array();
$this->categories = isset( $config['categories'] ) ? $config['categories'] : array();
}

if ( empty( $config['slug'] ) || ! is_string( $config['slug'] ) ) {
throw new Exception( 'Font Collection config slug is required as a non-empty string.' );
/**
* Checks if the font collection config is valid.
*
* @since 6.5.0
*
* @param array $config Font collection config options. {
* @type string $slug The font collection's unique slug.
* @type string $name The font collection's name.
* @type string $description The font collection's description.
* @type string $src The font collection's source.
* @type array $font_families An array of font families in the font collection.
* @type array $categories The font collection's categories.
* }
* @return bool True if the font collection config is valid and false otherwise.
*/
public static function is_config_valid( $config ) {
if ( empty( $config ) || ! is_array( $config ) ) {
_doing_it_wrong( __METHOD__, __( 'Font Collection config options are required as a non-empty array.', 'gutenberg' ), '6.5.0' );
return false;
}

if ( empty( $config['name'] ) || ! is_string( $config['name'] ) ) {
throw new Exception( 'Font Collection config name is required as a non-empty string.' );
$required_keys = array( 'slug', 'name' );
foreach ( $required_keys as $key ) {
if ( empty( $config[ $key ] ) ) {
_doing_it_wrong(
__METHOD__,
// translators: %s: Font collection config key.
sprintf( __( 'Font Collection config %s is required as a non-empty string.', 'gutenberg' ), $key ),
'6.5.0'
);
return false;
}
}

if ( ( empty( $config['src'] ) || ! is_string( $config['src'] ) ) && ( empty( $config['data'] ) ) ) {
throw new Exception( 'Font Collection config "src" option OR "data" option is required.' );
if (
( empty( $config['src'] ) && empty( $config['font_families'] ) ) ||
( ! empty( $config['src'] ) && ! empty( $config['font_families'] ) )
) {
_doing_it_wrong( __METHOD__, __( 'Font Collection config "src" option OR "font_families" option are required.', 'gutenberg' ), '6.5.0' );
return false;
}

$this->config = $config;
return true;
}

/**
Expand All @@ -73,56 +160,59 @@ public function __construct( $config ) {
*/
public function get_config() {
return array(
'slug' => $this->config['slug'],
'name' => $this->config['name'],
'description' => $this->config['description'] ?? '',
'slug' => $this->slug,
'name' => $this->name,
'description' => $this->description,
);
}

/**
* Gets the font collection config and data.
* Gets the font collection content.
*
* This function returns an array containing the font collection's unique ID,
* name, and its data as a PHP array.
* Load the font collection data from the src if it is not already loaded.
*
* @since 6.5.0
*
* @return array {
* An array of font collection config and data.
* @return array|WP_Error {
* An array of font collection contents.
*
* @type string $slug The font collection's unique ID.
* @type string $name The font collection's name.
* @type string $description The font collection's description.
* @type array $data The font collection's data as a PHP array.
* @type array $font_families The font collection's font families.
* @type string $categories The font collection's categories.
* }
*
* A WP_Error object if there was an error loading the font collection data.
*/
public function get_config_and_data() {
$config_and_data = $this->get_config();
$config_and_data['data'] = $this->load_data();
return $config_and_data;
public function get_content() {
// If the font families are not loaded, and the src is not empty, load the data from the src.
if ( empty( $this->font_families ) && ! empty( $this->src ) ) {
$data = $this->load_contents_from_src();
if ( is_wp_error( $data ) ) {
return $data;
}
}

return array(
'font_families' => $this->font_families,
'categories' => $this->categories,
);
}

/**
* Loads the font collection data.
* Loads the font collection data from the src.
*
* @since 6.5.0
*
* @return array|WP_Error An array containing the list of font families in font-collection.json format on success,
* else an instance of WP_Error on failure.
*/
public function load_data() {

if ( ! empty( $this->config['data'] ) ) {
return $this->config['data'];
}

private function load_contents_from_src() {
// If the src is a URL, fetch the data from the URL.
if ( str_contains( $this->config['src'], 'http' ) && str_contains( $this->config['src'], '://' ) ) {
if ( ! wp_http_validate_url( $this->config['src'] ) ) {
if ( preg_match( '#^https?://#', $this->src ) ) {
if ( ! wp_http_validate_url( $this->src ) ) {
return new WP_Error( 'font_collection_read_error', __( 'Invalid URL for Font Collection data.', 'gutenberg' ) );
}

$response = wp_remote_get( $this->config['src'] );
$response = wp_remote_get( $this->src );
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
return new WP_Error( 'font_collection_read_error', __( 'Error fetching the Font Collection data from a URL.', 'gutenberg' ) );
}
Expand All @@ -133,15 +223,22 @@ public function load_data() {
}
// If the src is a file path, read the data from the file.
} else {
if ( ! file_exists( $this->config['src'] ) ) {
if ( ! file_exists( $this->src ) ) {
return new WP_Error( 'font_collection_read_error', __( 'Font Collection data JSON file does not exist.', 'gutenberg' ) );
}
$data = wp_json_file_decode( $this->config['src'], array( 'associative' => true ) );
$data = wp_json_file_decode( $this->src, array( 'associative' => true ) );
if ( empty( $data ) ) {
return new WP_Error( 'font_collection_read_error', __( 'Error reading the Font Collection data JSON file contents.', 'gutenberg' ) );
}
}

if ( empty( $data['font_families'] ) ) {
return new WP_Error( 'font_collection_contents_error', __( 'Font Collection data JSON file does not contain font families.', 'gutenberg' ) );
}

$this->font_families = $data['font_families'];
$this->categories = $data['categories'] ?? array();

return $data;
}
}
12 changes: 9 additions & 3 deletions lib/experimental/fonts/font-library/class-wp-font-library.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,17 @@ public static function get_expected_font_mime_types_per_php_version( $php_versio
* @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 ) {
if ( ! WP_Font_Collection::is_config_valid( $config ) ) {
$error_message = __( 'Font collection config is invalid.', 'gutenberg' );
return new WP_Error( 'font_collection_registration_error', $error_message );
}

$new_collection = new WP_Font_Collection( $config );
if ( self::is_collection_registered( $config['slug'] ) ) {

if ( self::is_collection_registered( $new_collection->get_config()['slug'] ) ) {
$error_message = sprintf(
/* translators: %s: Font collection slug. */
__( 'Font collection with slug: "%s" is already registered.', 'default' ),
__( 'Font collection with slug: "%s" is already registered.', 'gutenberg' ),
$config['slug']
);
_doing_it_wrong(
Expand All @@ -76,7 +82,7 @@ public static function register_font_collection( $config ) {
);
return new WP_Error( 'font_collection_registration_error', $error_message );
}
self::$collections[ $config['slug'] ] = $new_collection;
self::$collections[ $new_collection->get_config()['slug'] ] = $new_collection;
return $new_collection;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ public function register_routes() {
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_font_collections' ),
'permission_callback' => array( $this, 'update_font_library_permissions_check' ),
'callback' => array( $this, 'get_items' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
),
)
);
Expand All @@ -54,13 +54,29 @@ public function register_routes() {
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_font_collection' ),
'permission_callback' => array( $this, 'update_font_library_permissions_check' ),
'callback' => array( $this, 'get_item' ),
'permission_callback' => array( $this, 'get_items_permissions_check' ),
),
)
);
}

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

return rest_ensure_response( $collections, 200 );
}

/**
* Gets a font collection.
*
Expand All @@ -69,54 +85,42 @@ public function register_routes() {
* @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 ) {
public function get_item( $request ) {
$slug = $request->get_param( 'slug' );
$collection = WP_Font_Library::get_font_collection( $slug );

// If the collection doesn't exist returns a 404.
if ( is_wp_error( $collection ) ) {
$collection->add_data( array( 'status' => 404 ) );
return $collection;
}
$config_and_data = $collection->get_config_and_data();
$collection_data = $config_and_data['data'];

// If there was an error getting the collection data, return the error.
if ( is_wp_error( $collection_data ) ) {
$collection_data->add_data( array( 'status' => 500 ) );
return $collection_data;
}

return new WP_REST_Response( $config_and_data );
}
$config = $collection->get_config();
$contents = $collection->get_content();

/**
* Gets the font collections available.
*
* @since 6.5.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_and_data();
// If there was an error getting the collection data, return the error.
if ( is_wp_error( $contents ) ) {
$contents->add_data( array( 'status' => 500 ) );
return $contents;
}

return new WP_REST_Response( $collections, 200 );
$collection_data = array_merge( $config, $contents );
return rest_ensure_response( $collection_data );
}

/**
* Checks whether the user has permissions to update the Font Library.
* Checks whether the user has permissions to use the Fonts Collections.
*
* @since 6.5.0
*
* @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise.
*/
public function update_font_library_permissions_check() {
public function get_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable

if ( ! current_user_can( 'edit_theme_options' ) ) {
return new WP_Error(
'rest_cannot_update_font_library',
__( 'Sorry, you are not allowed to update the Font Library on this site.', 'gutenberg' ),
'rest_cannot_read',
__( 'Sorry, you are not allowed to use the Font Library on this site.', 'gutenberg' ),
array(
'status' => rest_authorization_required_code(),
)
Expand Down
Loading

0 comments on commit 2aa9c64

Please sign in to comment.