REST API: Introduce the necessary endpoints for the font library.
This commits add three endpoints to retrieve and manipulate fonts in WordPress. This commit also means that we now have a fully functional Font Library in the site editor. Props get_dave, youknowriad, mmaattiiaass, grantmkin, swissspidy, mcsf, jorbin, ocean90. See #59166. Built from https://develop.svn.wordpress.org/trunk@57548 git-svn-id: http://core.svn.wordpress.org/trunk@57049 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
8f1ccc91ae
commit
b7725a50d3
|
@ -115,14 +115,13 @@ class WP_Font_Library {
|
|||
* @since 6.5.0
|
||||
*
|
||||
* @param string $slug Font collection slug.
|
||||
* @return WP_Font_Collection|WP_Error Font collection object,
|
||||
* or WP_Error object if the font collection doesn't exist.
|
||||
* @return WP_Font_Collection|null Font collection object, or null if the font collection doesn't exist.
|
||||
*/
|
||||
public function get_font_collection( $slug ) {
|
||||
if ( $this->is_collection_registered( $slug ) ) {
|
||||
return $this->collections[ $slug ];
|
||||
}
|
||||
return new WP_Error( 'font_collection_not_found', __( 'Font collection not found.' ) );
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -567,14 +567,14 @@ function create_initial_post_types() {
|
|||
register_post_type(
|
||||
'wp_font_family',
|
||||
array(
|
||||
'labels' => array(
|
||||
'labels' => array(
|
||||
'name' => __( 'Font Families' ),
|
||||
'singular_name' => __( 'Font Family' ),
|
||||
),
|
||||
'public' => false,
|
||||
'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
|
||||
'hierarchical' => false,
|
||||
'capabilities' => array(
|
||||
'public' => false,
|
||||
'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
|
||||
'hierarchical' => false,
|
||||
'capabilities' => array(
|
||||
'read' => 'edit_theme_options',
|
||||
'read_private_posts' => 'edit_theme_options',
|
||||
'create_posts' => 'edit_theme_options',
|
||||
|
@ -586,24 +586,28 @@ function create_initial_post_types() {
|
|||
'delete_others_posts' => 'edit_theme_options',
|
||||
'delete_published_posts' => 'edit_theme_options',
|
||||
),
|
||||
'map_meta_cap' => true,
|
||||
'query_var' => false,
|
||||
'show_in_rest' => false,
|
||||
'rewrite' => false,
|
||||
'map_meta_cap' => true,
|
||||
'query_var' => false,
|
||||
'rewrite' => false,
|
||||
'show_in_rest' => true,
|
||||
'rest_base' => 'font-families',
|
||||
'rest_controller_class' => 'WP_REST_Font_Families_Controller',
|
||||
// Disable autosave endpoints for font families.
|
||||
'autosave_rest_controller_class' => 'stdClass',
|
||||
)
|
||||
);
|
||||
|
||||
register_post_type(
|
||||
'wp_font_face',
|
||||
array(
|
||||
'labels' => array(
|
||||
'labels' => array(
|
||||
'name' => __( 'Font Faces' ),
|
||||
'singular_name' => __( 'Font Face' ),
|
||||
),
|
||||
'public' => false,
|
||||
'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
|
||||
'hierarchical' => false,
|
||||
'capabilities' => array(
|
||||
'public' => false,
|
||||
'_builtin' => true, /* internal use only. don't use this when registering your own post type. */
|
||||
'hierarchical' => false,
|
||||
'capabilities' => array(
|
||||
'read' => 'edit_theme_options',
|
||||
'read_private_posts' => 'edit_theme_options',
|
||||
'create_posts' => 'edit_theme_options',
|
||||
|
@ -615,10 +619,14 @@ function create_initial_post_types() {
|
|||
'delete_others_posts' => 'edit_theme_options',
|
||||
'delete_published_posts' => 'edit_theme_options',
|
||||
),
|
||||
'map_meta_cap' => true,
|
||||
'query_var' => false,
|
||||
'show_in_rest' => false,
|
||||
'rewrite' => false,
|
||||
'map_meta_cap' => true,
|
||||
'query_var' => false,
|
||||
'rewrite' => false,
|
||||
'show_in_rest' => true,
|
||||
'rest_base' => 'font-families/(?P<font_family_id>[\d]+)/font-faces',
|
||||
'rest_controller_class' => 'WP_REST_Font_Faces_Controller',
|
||||
// Disable autosave endpoints for font faces.
|
||||
'autosave_rest_controller_class' => 'stdClass',
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -391,6 +391,10 @@ function create_initial_rest_routes() {
|
|||
// Navigation Fallback.
|
||||
$controller = new WP_REST_Navigation_Fallback_Controller();
|
||||
$controller->register_routes();
|
||||
|
||||
// Font Collections.
|
||||
$font_collections_controller = new WP_REST_Font_Collections_Controller();
|
||||
$font_collections_controller->register_routes();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,322 @@
|
|||
<?php
|
||||
/**
|
||||
* Rest Font Collections Controller.
|
||||
*
|
||||
* This file contains the class for the REST API Font Collections Controller.
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
* @since 6.5.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Font Library Controller class.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*/
|
||||
class WP_REST_Font_Collections_Controller extends WP_REST_Controller {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->rest_base = 'font-collections';
|
||||
$this->namespace = 'wp/v2';
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the routes for the objects of the controller.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base,
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/(?P<slug>[\/\w-]+)',
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => array(
|
||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||
),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
$collections_all = WP_Font_Library::get_instance()->get_font_collections();
|
||||
|
||||
$page = $request['page'];
|
||||
$per_page = $request['per_page'];
|
||||
$total_items = count( $collections_all );
|
||||
$max_pages = ceil( $total_items / $per_page );
|
||||
|
||||
if ( $page > $max_pages && $total_items > 0 ) {
|
||||
return new WP_Error(
|
||||
'rest_post_invalid_page_number',
|
||||
__( 'The page number requested is larger than the number of pages available.' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
|
||||
$collections_page = array_slice( $collections_all, ( $page - 1 ) * $per_page, $per_page );
|
||||
|
||||
$items = array();
|
||||
foreach ( $collections_page as $collection ) {
|
||||
$item = $this->prepare_item_for_response( $collection, $request );
|
||||
|
||||
// If there's an error loading a collection, skip it and continue loading valid collections.
|
||||
if ( is_wp_error( $item ) ) {
|
||||
continue;
|
||||
}
|
||||
$item = $this->prepare_response_for_collection( $item );
|
||||
$items[] = $item;
|
||||
}
|
||||
|
||||
$response = rest_ensure_response( $items );
|
||||
|
||||
$response->header( 'X-WP-Total', (int) $total_items );
|
||||
$response->header( 'X-WP-TotalPages', (int) $max_pages );
|
||||
|
||||
$request_params = $request->get_query_params();
|
||||
$collection_url = rest_url( $this->namespace . '/' . $this->rest_base );
|
||||
$base = add_query_arg( urlencode_deep( $request_params ), $collection_url );
|
||||
|
||||
if ( $page > 1 ) {
|
||||
$prev_page = $page - 1;
|
||||
|
||||
if ( $prev_page > $max_pages ) {
|
||||
$prev_page = $max_pages;
|
||||
}
|
||||
|
||||
$prev_link = add_query_arg( 'page', $prev_page, $base );
|
||||
$response->link_header( 'prev', $prev_link );
|
||||
}
|
||||
if ( $max_pages > $page ) {
|
||||
$next_page = $page + 1;
|
||||
$next_link = add_query_arg( 'page', $next_page, $base );
|
||||
|
||||
$response->link_header( 'next', $next_link );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a font collection.
|
||||
*
|
||||
* @since 6.5.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_item( $request ) {
|
||||
$slug = $request->get_param( 'slug' );
|
||||
$collection = WP_Font_Library::get_instance()->get_font_collection( $slug );
|
||||
|
||||
if ( ! $collection ) {
|
||||
return new WP_Error( 'rest_font_collection_not_found', __( 'Font collection not found.' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
return $this->prepare_item_for_response( $collection, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a single collection output for response.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_Font_Collection $item Font collection object.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
$fields = $this->get_fields_for_response( $request );
|
||||
$data = array();
|
||||
|
||||
if ( rest_is_field_included( 'slug', $fields ) ) {
|
||||
$data['slug'] = $item->slug;
|
||||
}
|
||||
|
||||
// If any data fields are requested, get the collection data.
|
||||
$data_fields = array( 'name', 'description', 'font_families', 'categories' );
|
||||
if ( ! empty( array_intersect( $fields, $data_fields ) ) ) {
|
||||
$collection_data = $item->get_data();
|
||||
if ( is_wp_error( $collection_data ) ) {
|
||||
$collection_data->add_data( array( 'status' => 500 ) );
|
||||
return $collection_data;
|
||||
}
|
||||
|
||||
foreach ( $data_fields as $field ) {
|
||||
if ( rest_is_field_included( $field, $fields ) ) {
|
||||
$data[ $field ] = $collection_data[ $field ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response = rest_ensure_response( $data );
|
||||
|
||||
if ( rest_is_field_included( '_links', $fields ) ) {
|
||||
$links = $this->prepare_links( $item );
|
||||
$response->add_links( $links );
|
||||
}
|
||||
|
||||
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
||||
$response->data = $this->add_additional_fields_to_object( $response->data, $request );
|
||||
$response->data = $this->filter_response_by_context( $response->data, $context );
|
||||
|
||||
/**
|
||||
* Filters the font collection data for a REST API response.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_REST_Response $response The response object.
|
||||
* @param WP_Font_Collection $item The font collection object.
|
||||
* @param WP_REST_Request $request Request used to generate the response.
|
||||
*/
|
||||
return apply_filters( 'rest_prepare_font_collection', $response, $item, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the font collection's schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
if ( $this->schema ) {
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => 'font-collection',
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'slug' => array(
|
||||
'description' => __( 'Unique identifier for the font collection.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'name' => array(
|
||||
'description' => __( 'The name for the font collection.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'description' => array(
|
||||
'description' => __( 'The description for the font collection.' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'font_families' => array(
|
||||
'description' => __( 'The font families for the font collection.' ),
|
||||
'type' => 'array',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'categories' => array(
|
||||
'description' => __( 'The categories for the font collection.' ),
|
||||
'type' => 'array',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$this->schema = $schema;
|
||||
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares links for the request.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_Font_Collection $collection Font collection data
|
||||
* @return array Links for the given font collection.
|
||||
*/
|
||||
protected function prepare_links( $collection ) {
|
||||
return array(
|
||||
'self' => array(
|
||||
'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $collection->slug ) ),
|
||||
),
|
||||
'collection' => array(
|
||||
'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the search params for the font collections.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @return array Collection parameters.
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
$query_params = parent::get_collection_params();
|
||||
|
||||
$query_params['context'] = $this->get_context_param( array( 'default' => 'view' ) );
|
||||
|
||||
unset( $query_params['search'] );
|
||||
|
||||
/**
|
||||
* Filters REST API collection parameters for the font collections controller.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param array $query_params JSON Schema-formatted collection parameters.
|
||||
*/
|
||||
return apply_filters( 'rest_font_collections_collection_params', $query_params );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 get_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
if ( current_user_can( 'edit_theme_options' ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return new WP_Error(
|
||||
'rest_cannot_read',
|
||||
__( 'Sorry, you are not allowed to access font collections.' ),
|
||||
array(
|
||||
'status' => rest_authorization_required_code(),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,950 @@
|
|||
<?php
|
||||
/**
|
||||
* REST API: WP_REST_Font_Faces_Controller class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
* @since 6.5.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to access font faces through the REST API.
|
||||
*/
|
||||
class WP_REST_Font_Faces_Controller extends WP_REST_Posts_Controller {
|
||||
|
||||
/**
|
||||
* The latest version of theme.json schema supported by the controller.
|
||||
*
|
||||
* @since 6.5.0
|
||||
* @var int
|
||||
*/
|
||||
const LATEST_THEME_JSON_VERSION_SUPPORTED = 2;
|
||||
|
||||
/**
|
||||
* Whether the controller supports batching.
|
||||
*
|
||||
* @since 6.5.0
|
||||
* @var false
|
||||
*/
|
||||
protected $allow_batch = false;
|
||||
|
||||
/**
|
||||
* Registers the routes for posts.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @see register_rest_route()
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base,
|
||||
array(
|
||||
'args' => array(
|
||||
'font_family_id' => array(
|
||||
'description' => __( 'The ID for the parent font family of the font face.' ),
|
||||
'type' => 'integer',
|
||||
'required' => true,
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_items' ),
|
||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||
'args' => $this->get_collection_params(),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => array( $this, 'create_item' ),
|
||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||
'args' => $this->get_create_params(),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/(?P<id>[\d]+)',
|
||||
array(
|
||||
'args' => array(
|
||||
'font_family_id' => array(
|
||||
'description' => __( 'The ID for the parent font family of the font face.' ),
|
||||
'type' => 'integer',
|
||||
'required' => true,
|
||||
),
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the font face.' ),
|
||||
'type' => 'integer',
|
||||
'required' => true,
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_item' ),
|
||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => array( $this, 'delete_item' ),
|
||||
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
||||
'args' => array(
|
||||
'force' => array(
|
||||
'type' => 'boolean',
|
||||
'default' => false,
|
||||
'description' => __( 'Whether to bypass Trash and force deletion.', 'default' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
'schema' => array( $this, 'get_public_item_schema' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to font faces.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
$post_type = get_post_type_object( $this->post_type );
|
||||
|
||||
if ( ! current_user_can( $post_type->cap->read ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_read',
|
||||
__( 'Sorry, you are not allowed to access font faces.' ),
|
||||
array( 'status' => rest_authorization_required_code() )
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to a font face.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
$post = $this->get_post( $request['id'] );
|
||||
if ( is_wp_error( $post ) ) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'read_post', $post->ID ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_read',
|
||||
__( 'Sorry, you are not allowed to access this font face.' ),
|
||||
array( 'status' => rest_authorization_required_code() )
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates settings when creating a font face.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param string $value Encoded JSON string of font face settings.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return true|WP_Error True if the settings are valid, otherwise a WP_Error object.
|
||||
*/
|
||||
public function validate_create_font_face_settings( $value, $request ) {
|
||||
$settings = json_decode( $value, true );
|
||||
|
||||
// Check settings string is valid JSON.
|
||||
if ( null === $settings ) {
|
||||
return new WP_Error(
|
||||
'rest_invalid_param',
|
||||
__( 'font_face_settings parameter must be a valid JSON string.' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
|
||||
// Check that the font face settings match the theme.json schema.
|
||||
$schema = $this->get_item_schema()['properties']['font_face_settings'];
|
||||
$has_valid_settings = rest_validate_value_from_schema( $settings, $schema, 'font_face_settings' );
|
||||
|
||||
if ( is_wp_error( $has_valid_settings ) ) {
|
||||
$has_valid_settings->add_data( array( 'status' => 400 ) );
|
||||
return $has_valid_settings;
|
||||
}
|
||||
|
||||
// Check that none of the required settings are empty values.
|
||||
$required = $schema['required'];
|
||||
foreach ( $required as $key ) {
|
||||
if ( isset( $settings[ $key ] ) && ! $settings[ $key ] ) {
|
||||
return new WP_Error(
|
||||
'rest_invalid_param',
|
||||
/* translators: %s: Name of the missing font face settings parameter, e.g. "font_face_settings[src]". */
|
||||
sprintf( __( '%s cannot be empty.' ), "font_face_setting[ $key ]" ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$srcs = is_array( $settings['src'] ) ? $settings['src'] : array( $settings['src'] );
|
||||
$files = $request->get_file_params();
|
||||
|
||||
foreach ( $srcs as $src ) {
|
||||
// Check that each src is a non-empty string.
|
||||
$src = ltrim( $src );
|
||||
if ( empty( $src ) ) {
|
||||
return new WP_Error(
|
||||
'rest_invalid_param',
|
||||
/* translators: %s: Font face source parameter name: "font_face_settings[src]". */
|
||||
sprintf( __( '%s values must be non-empty strings.' ), 'font_face_settings[src]' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
|
||||
// Check that srcs are valid URLs or file references.
|
||||
if ( false === wp_http_validate_url( $src ) && ! isset( $files[ $src ] ) ) {
|
||||
return new WP_Error(
|
||||
'rest_invalid_param',
|
||||
/* translators: 1: Font face source parameter name: "font_face_settings[src]", 2: The invalid src value. */
|
||||
sprintf( __( '%1$s value "%2$s" must be a valid URL or file reference.' ), 'font_face_settings[src]', $src ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that each file in the request references a src in the settings.
|
||||
foreach ( array_keys( $files ) as $file ) {
|
||||
if ( ! in_array( $file, $srcs, true ) ) {
|
||||
return new WP_Error(
|
||||
'rest_invalid_param',
|
||||
/* translators: 1: File key (e.g. "file-0") in the request data, 2: Font face source parameter name: "font_face_settings[src]". */
|
||||
sprintf( __( 'File %1$s must be used in %2$s.' ), $file, 'font_face_settings[src]' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the font face settings when creating a font face.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param string $value Encoded JSON string of font face settings.
|
||||
* @return array Decoded and sanitized array of font face settings.
|
||||
*/
|
||||
public function sanitize_font_face_settings( $value ) {
|
||||
// Settings arrive as stringified JSON, since this is a multipart/form-data request.
|
||||
$settings = json_decode( $value, true );
|
||||
$schema = $this->get_item_schema()['properties']['font_face_settings']['properties'];
|
||||
|
||||
// Sanitize settings based on callbacks in the schema.
|
||||
foreach ( $settings as $key => $value ) {
|
||||
$sanitize_callback = $schema[ $key ]['arg_options']['sanitize_callback'];
|
||||
$settings[ $key ] = call_user_func( $sanitize_callback, $value );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a collection of font faces within the parent font family.
|
||||
*
|
||||
* @since 6.5.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_items( $request ) {
|
||||
$font_family = $this->get_parent_font_family_post( $request['font_family_id'] );
|
||||
if ( is_wp_error( $font_family ) ) {
|
||||
return $font_family;
|
||||
}
|
||||
|
||||
return parent::get_items( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a single font face within the parent font family.
|
||||
*
|
||||
* @since 6.5.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_item( $request ) {
|
||||
$post = $this->get_post( $request['id'] );
|
||||
if ( is_wp_error( $post ) ) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
// Check that the font face has a valid parent font family.
|
||||
$font_family = $this->get_parent_font_family_post( $request['font_family_id'] );
|
||||
if ( is_wp_error( $font_family ) ) {
|
||||
return $font_family;
|
||||
}
|
||||
|
||||
if ( (int) $font_family->ID !== (int) $post->post_parent ) {
|
||||
return new WP_Error(
|
||||
'rest_font_face_parent_id_mismatch',
|
||||
/* translators: %d: A post id. */
|
||||
sprintf( __( 'The font face does not belong to the specified font family with id of "%d".' ), $font_family->ID ),
|
||||
array( 'status' => 404 )
|
||||
);
|
||||
}
|
||||
|
||||
return parent::get_item( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a font face for the parent font family.
|
||||
*
|
||||
* @since 6.5.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 create_item( $request ) {
|
||||
$font_family = $this->get_parent_font_family_post( $request['font_family_id'] );
|
||||
if ( is_wp_error( $font_family ) ) {
|
||||
return $font_family;
|
||||
}
|
||||
|
||||
// Settings have already been decoded by ::sanitize_font_face_settings().
|
||||
$settings = $request->get_param( 'font_face_settings' );
|
||||
$file_params = $request->get_file_params();
|
||||
|
||||
// Check that the necessary font face properties are unique.
|
||||
$query = new WP_Query(
|
||||
array(
|
||||
'post_type' => $this->post_type,
|
||||
'posts_per_page' => 1,
|
||||
'title' => WP_Font_Utils::get_font_face_slug( $settings ),
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
)
|
||||
);
|
||||
if ( ! empty( $query->posts ) ) {
|
||||
return new WP_Error(
|
||||
'rest_duplicate_font_face',
|
||||
__( 'A font face matching those settings already exists.' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
|
||||
// Move the uploaded font asset from the temp folder to the fonts directory.
|
||||
if ( ! function_exists( 'wp_handle_upload' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
}
|
||||
|
||||
$srcs = is_string( $settings['src'] ) ? array( $settings['src'] ) : $settings['src'];
|
||||
$processed_srcs = array();
|
||||
$font_file_meta = array();
|
||||
|
||||
foreach ( $srcs as $src ) {
|
||||
// If src not a file reference, use it as is.
|
||||
if ( ! isset( $file_params[ $src ] ) ) {
|
||||
$processed_srcs[] = $src;
|
||||
continue;
|
||||
}
|
||||
|
||||
$file = $file_params[ $src ];
|
||||
$font_file = $this->handle_font_file_upload( $file );
|
||||
if ( is_wp_error( $font_file ) ) {
|
||||
return $font_file;
|
||||
}
|
||||
|
||||
$processed_srcs[] = $font_file['url'];
|
||||
$font_file_meta[] = $this->relative_fonts_path( $font_file['file'] );
|
||||
}
|
||||
|
||||
// Store the updated settings for prepare_item_for_database to use.
|
||||
$settings['src'] = count( $processed_srcs ) === 1 ? $processed_srcs[0] : $processed_srcs;
|
||||
$request->set_param( 'font_face_settings', $settings );
|
||||
|
||||
// Ensure that $settings data is slashed, so values with quotes are escaped.
|
||||
// WP_REST_Posts_Controller::create_item uses wp_slash() on the post_content.
|
||||
$font_face_post = parent::create_item( $request );
|
||||
|
||||
if ( is_wp_error( $font_face_post ) ) {
|
||||
return $font_face_post;
|
||||
}
|
||||
|
||||
$font_face_id = $font_face_post->data['id'];
|
||||
|
||||
foreach ( $font_file_meta as $font_file_path ) {
|
||||
add_post_meta( $font_face_id, '_wp_font_face_file', $font_file_path );
|
||||
}
|
||||
|
||||
return $font_face_post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a single font face.
|
||||
*
|
||||
* @since 6.5.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 delete_item( $request ) {
|
||||
$post = $this->get_post( $request['id'] );
|
||||
if ( is_wp_error( $post ) ) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
$font_family = $this->get_parent_font_family_post( $request['font_family_id'] );
|
||||
if ( is_wp_error( $font_family ) ) {
|
||||
return $font_family;
|
||||
}
|
||||
|
||||
if ( (int) $font_family->ID !== (int) $post->post_parent ) {
|
||||
return new WP_Error(
|
||||
'rest_font_face_parent_id_mismatch',
|
||||
/* translators: %d: A post id. */
|
||||
sprintf( __( 'The font face does not belong to the specified font family with id of "%d".' ), $font_family->ID ),
|
||||
array( 'status' => 404 )
|
||||
);
|
||||
}
|
||||
|
||||
$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
|
||||
|
||||
// We don't support trashing for font faces.
|
||||
if ( ! $force ) {
|
||||
return new WP_Error(
|
||||
'rest_trash_not_supported',
|
||||
/* translators: %s: force=true */
|
||||
sprintf( __( 'Font faces do not support trashing. Set "%s" to delete.' ), 'force=true' ),
|
||||
array( 'status' => 501 )
|
||||
);
|
||||
}
|
||||
|
||||
return parent::delete_item( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a single font face output for response.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_Post $item Post object.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return WP_REST_Response Response object.
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
$fields = $this->get_fields_for_response( $request );
|
||||
$data = array();
|
||||
|
||||
if ( rest_is_field_included( 'id', $fields ) ) {
|
||||
$data['id'] = $item->ID;
|
||||
}
|
||||
if ( rest_is_field_included( 'theme_json_version', $fields ) ) {
|
||||
$data['theme_json_version'] = static::LATEST_THEME_JSON_VERSION_SUPPORTED;
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'parent', $fields ) ) {
|
||||
$data['parent'] = $item->post_parent;
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'font_face_settings', $fields ) ) {
|
||||
$data['font_face_settings'] = $this->get_settings_from_post( $item );
|
||||
}
|
||||
|
||||
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
||||
$data = $this->add_additional_fields_to_object( $data, $request );
|
||||
$data = $this->filter_response_by_context( $data, $context );
|
||||
|
||||
$response = rest_ensure_response( $data );
|
||||
|
||||
if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
|
||||
$links = $this->prepare_links( $item );
|
||||
$response->add_links( $links );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the font face data for a REST API response.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_REST_Response $response The response object.
|
||||
* @param WP_Post $post Font face post object.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*/
|
||||
return apply_filters( 'rest_prepare_wp_font_face', $response, $item, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the post's schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
if ( $this->schema ) {
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => $this->post_type,
|
||||
'type' => 'object',
|
||||
// Base properties for every Post.
|
||||
'properties' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the post.', 'default' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'theme_json_version' => array(
|
||||
'description' => __( 'Version of the theme.json schema used for the typography settings.' ),
|
||||
'type' => 'integer',
|
||||
'default' => static::LATEST_THEME_JSON_VERSION_SUPPORTED,
|
||||
'minimum' => 2,
|
||||
'maximum' => static::LATEST_THEME_JSON_VERSION_SUPPORTED,
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'parent' => array(
|
||||
'description' => __( 'The ID for the parent font family of the font face.' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
// Font face settings come directly from theme.json schema
|
||||
// See https://schemas.wp.org/trunk/theme.json
|
||||
'font_face_settings' => array(
|
||||
'description' => __( 'font-face declaration in theme.json format.' ),
|
||||
'type' => 'object',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'properties' => array(
|
||||
'fontFamily' => array(
|
||||
'description' => __( 'CSS font-family value.' ),
|
||||
'type' => 'string',
|
||||
'default' => '',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => array( 'WP_Font_Utils', 'sanitize_font_family' ),
|
||||
),
|
||||
),
|
||||
'fontStyle' => array(
|
||||
'description' => __( 'CSS font-style value.' ),
|
||||
'type' => 'string',
|
||||
'default' => 'normal',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'fontWeight' => array(
|
||||
'description' => __( 'List of available font weights, separated by a space.' ),
|
||||
'default' => '400',
|
||||
// Changed from `oneOf` to avoid errors from loose type checking.
|
||||
// e.g. a fontWeight of "400" validates as both a string and an integer due to is_numeric check.
|
||||
'type' => array( 'string', 'integer' ),
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'fontDisplay' => array(
|
||||
'description' => __( 'CSS font-display value.' ),
|
||||
'type' => 'string',
|
||||
'default' => 'fallback',
|
||||
'enum' => array(
|
||||
'auto',
|
||||
'block',
|
||||
'fallback',
|
||||
'swap',
|
||||
'optional',
|
||||
),
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'src' => array(
|
||||
'description' => __( 'Paths or URLs to the font files.' ),
|
||||
// Changed from `oneOf` to `anyOf` due to rest_sanitize_array converting a string into an array,
|
||||
// and causing a "matches more than one of the expected formats" error.
|
||||
'anyOf' => array(
|
||||
array(
|
||||
'type' => 'string',
|
||||
),
|
||||
array(
|
||||
'type' => 'array',
|
||||
'items' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
),
|
||||
'default' => array(),
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => function ( $value ) {
|
||||
return is_array( $value ) ? array_map( array( $this, 'sanitize_src' ), $value ) : $this->sanitize_src( $value );
|
||||
},
|
||||
),
|
||||
),
|
||||
'fontStretch' => array(
|
||||
'description' => __( 'CSS font-stretch value.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'ascentOverride' => array(
|
||||
'description' => __( 'CSS ascent-override value.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'descentOverride' => array(
|
||||
'description' => __( 'CSS descent-override value.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'fontVariant' => array(
|
||||
'description' => __( 'CSS font-variant value.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'fontFeatureSettings' => array(
|
||||
'description' => __( 'CSS font-feature-settings value.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'fontVariationSettings' => array(
|
||||
'description' => __( 'CSS font-variation-settings value.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'lineGapOverride' => array(
|
||||
'description' => __( 'CSS line-gap-override value.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'sizeAdjust' => array(
|
||||
'description' => __( 'CSS size-adjust value.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'unicodeRange' => array(
|
||||
'description' => __( 'CSS unicode-range value.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'preview' => array(
|
||||
'description' => __( 'URL to a preview image of the font face.' ),
|
||||
'type' => 'string',
|
||||
'format' => 'uri',
|
||||
'default' => '',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_url',
|
||||
),
|
||||
),
|
||||
),
|
||||
'required' => array( 'fontFamily', 'src' ),
|
||||
'additionalProperties' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$this->schema = $schema;
|
||||
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the item's schema for display / public consumption purposes.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @return array Public item schema data.
|
||||
*/
|
||||
public function get_public_item_schema() {
|
||||
|
||||
$schema = parent::get_public_item_schema();
|
||||
|
||||
// Also remove `arg_options' from child font_family_settings properties, since the parent
|
||||
// controller only handles the top level properties.
|
||||
foreach ( $schema['properties']['font_face_settings']['properties'] as &$property ) {
|
||||
unset( $property['arg_options'] );
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the query params for the font face collection.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @return array Collection parameters.
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
$query_params = parent::get_collection_params();
|
||||
|
||||
// Remove unneeded params.
|
||||
unset(
|
||||
$query_params['after'],
|
||||
$query_params['modified_after'],
|
||||
$query_params['before'],
|
||||
$query_params['modified_before'],
|
||||
$query_params['search'],
|
||||
$query_params['search_columns'],
|
||||
$query_params['slug'],
|
||||
$query_params['status']
|
||||
);
|
||||
|
||||
$query_params['orderby']['default'] = 'id';
|
||||
$query_params['orderby']['enum'] = array( 'id', 'include' );
|
||||
|
||||
/**
|
||||
* Filters collection parameters for the font face controller.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param array $query_params JSON Schema-formatted collection parameters.
|
||||
*/
|
||||
return apply_filters( 'rest_wp_font_face_collection_params', $query_params );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the params used when creating a new font face.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @return array Font face create arguments.
|
||||
*/
|
||||
public function get_create_params() {
|
||||
$properties = $this->get_item_schema()['properties'];
|
||||
return array(
|
||||
'theme_json_version' => $properties['theme_json_version'],
|
||||
// When creating, font_face_settings is stringified JSON, to work with multipart/form-data used
|
||||
// when uploading font files.
|
||||
'font_face_settings' => array(
|
||||
'description' => __( 'font-face declaration in theme.json format, encoded as a string.' ),
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
'validate_callback' => array( $this, 'validate_create_font_face_settings' ),
|
||||
'sanitize_callback' => array( $this, 'sanitize_font_face_settings' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent font family, if the ID is valid.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param int $font_family_id Supplied ID.
|
||||
* @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
|
||||
*/
|
||||
protected function get_parent_font_family_post( $font_family_id ) {
|
||||
$error = new WP_Error(
|
||||
'rest_post_invalid_parent',
|
||||
__( 'Invalid post parent ID.', 'default' ),
|
||||
array( 'status' => 404 )
|
||||
);
|
||||
|
||||
if ( (int) $font_family_id <= 0 ) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
$font_family_post = get_post( (int) $font_family_id );
|
||||
|
||||
if ( empty( $font_family_post ) || empty( $font_family_post->ID )
|
||||
|| 'wp_font_family' !== $font_family_post->post_type
|
||||
) {
|
||||
return $error;
|
||||
}
|
||||
|
||||
return $font_family_post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares links for the request.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_Post $post Post object.
|
||||
* @return array Links for the given post.
|
||||
*/
|
||||
protected function prepare_links( $post ) {
|
||||
// Entity meta.
|
||||
return array(
|
||||
'self' => array(
|
||||
'href' => rest_url( $this->namespace . '/font-families/' . $post->post_parent . '/font-faces/' . $post->ID ),
|
||||
),
|
||||
'collection' => array(
|
||||
'href' => rest_url( $this->namespace . '/font-families/' . $post->post_parent . '/font-faces' ),
|
||||
),
|
||||
'parent' => array(
|
||||
'href' => rest_url( $this->namespace . '/font-families/' . $post->post_parent ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a single font face post for creation.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return stdClass Post object.
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
$prepared_post = new stdClass();
|
||||
|
||||
// Settings have already been decoded by ::sanitize_font_face_settings().
|
||||
$settings = $request->get_param( 'font_face_settings' );
|
||||
|
||||
// Store this "slug" as the post_title rather than post_name, since it uses the fontFamily setting,
|
||||
// which may contain multibyte characters.
|
||||
$title = WP_Font_Utils::get_font_face_slug( $settings );
|
||||
|
||||
$prepared_post->post_type = $this->post_type;
|
||||
$prepared_post->post_parent = $request['font_family_id'];
|
||||
$prepared_post->post_status = 'publish';
|
||||
$prepared_post->post_title = $title;
|
||||
$prepared_post->post_name = sanitize_title( $title );
|
||||
$prepared_post->post_content = wp_json_encode( $settings );
|
||||
|
||||
return $prepared_post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes a single src value for a font face.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param string $value Font face src that is a URL or the key for a $_FILES array item.
|
||||
* @return string Sanitized value.
|
||||
*/
|
||||
protected function sanitize_src( $value ) {
|
||||
$value = ltrim( $value );
|
||||
return false === wp_http_validate_url( $value ) ? (string) $value : sanitize_url( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the upload of a font file using wp_handle_upload().
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param array $file Single file item from $_FILES.
|
||||
* @return array|WP_Error Array containing uploaded file attributes on success, or WP_Error object on failure.
|
||||
*/
|
||||
protected function handle_font_file_upload( $file ) {
|
||||
add_filter( 'upload_mimes', array( 'WP_Font_Utils', 'get_allowed_font_mime_types' ) );
|
||||
add_filter( 'upload_dir', 'wp_get_font_dir' );
|
||||
|
||||
$overrides = array(
|
||||
'upload_error_handler' => array( $this, 'handle_font_file_upload_error' ),
|
||||
// Arbitrary string to avoid the is_uploaded_file() check applied
|
||||
// when using 'wp_handle_upload'.
|
||||
'action' => 'wp_handle_font_upload',
|
||||
// Not testing a form submission.
|
||||
'test_form' => false,
|
||||
// Seems mime type for files that are not images cannot be tested.
|
||||
// See wp_check_filetype_and_ext().
|
||||
'test_type' => true,
|
||||
// Only allow uploading font files for this request.
|
||||
'mimes' => WP_Font_Utils::get_allowed_font_mime_types(),
|
||||
);
|
||||
|
||||
$uploaded_file = wp_handle_upload( $file, $overrides );
|
||||
|
||||
remove_filter( 'upload_dir', 'wp_get_font_dir' );
|
||||
remove_filter( 'upload_mimes', array( 'WP_Font_Utils', 'get_allowed_font_mime_types' ) );
|
||||
|
||||
return $uploaded_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles file upload error.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param array $file File upload data.
|
||||
* @param string $message Error message from wp_handle_upload().
|
||||
* @return WP_Error WP_Error object.
|
||||
*/
|
||||
public function handle_font_file_upload_error( $file, $message ) {
|
||||
$status = 500;
|
||||
$code = 'rest_font_upload_unknown_error';
|
||||
|
||||
if ( __( 'Sorry, you are not allowed to upload this file type.' ) === $message ) {
|
||||
$status = 400;
|
||||
$code = 'rest_font_upload_invalid_file_type';
|
||||
}
|
||||
|
||||
return new WP_Error( $code, $message, array( 'status' => $status ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns relative path to an uploaded font file.
|
||||
*
|
||||
* The path is relative to the current fonts directory.
|
||||
*
|
||||
* @since 6.5.0
|
||||
* @access private
|
||||
*
|
||||
* @param string $path Full path to the file.
|
||||
* @return string Relative path on success, unchanged path on failure.
|
||||
*/
|
||||
protected function relative_fonts_path( $path ) {
|
||||
$new_path = $path;
|
||||
|
||||
$fonts_dir = wp_get_font_dir();
|
||||
if ( str_starts_with( $new_path, $fonts_dir['path'] ) ) {
|
||||
$new_path = str_replace( $fonts_dir, '', $new_path );
|
||||
$new_path = ltrim( $new_path, '/' );
|
||||
}
|
||||
|
||||
return $new_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the font face's settings from the post.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_Post $post Font face post object.
|
||||
* @return array Font face settings array.
|
||||
*/
|
||||
protected function get_settings_from_post( $post ) {
|
||||
$settings = json_decode( $post->post_content, true );
|
||||
$properties = $this->get_item_schema()['properties']['font_face_settings']['properties'];
|
||||
|
||||
// Provide required, empty settings if needed.
|
||||
if ( null === $settings ) {
|
||||
$settings = array(
|
||||
'fontFamily' => '',
|
||||
'src' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
// Only return the properties defined in the schema.
|
||||
return array_intersect_key( $settings, $properties );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,564 @@
|
|||
<?php
|
||||
/**
|
||||
* REST API: WP_REST_Font_Families_Controller class
|
||||
*
|
||||
* @package WordPress
|
||||
* @subpackage REST_API
|
||||
* @since 6.5.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Font Families Controller class.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*/
|
||||
class WP_REST_Font_Families_Controller extends WP_REST_Posts_Controller {
|
||||
|
||||
/**
|
||||
* The latest version of theme.json schema supported by the controller.
|
||||
*
|
||||
* @since 6.5.0
|
||||
* @var int
|
||||
*/
|
||||
const LATEST_THEME_JSON_VERSION_SUPPORTED = 2;
|
||||
|
||||
/**
|
||||
* Whether the controller supports batching.
|
||||
*
|
||||
* @since 6.5.0
|
||||
* @var false
|
||||
*/
|
||||
protected $allow_batch = false;
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to font families.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_items_permissions_check( $request ) {
|
||||
$post_type = get_post_type_object( $this->post_type );
|
||||
|
||||
if ( ! current_user_can( $post_type->cap->read ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_read',
|
||||
__( 'Sorry, you are not allowed to access font families.' ),
|
||||
array( 'status' => rest_authorization_required_code() )
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to a font family.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
|
||||
*/
|
||||
public function get_item_permissions_check( $request ) {
|
||||
$post = $this->get_post( $request['id'] );
|
||||
if ( is_wp_error( $post ) ) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'read_post', $post->ID ) ) {
|
||||
return new WP_Error(
|
||||
'rest_cannot_read',
|
||||
__( 'Sorry, you are not allowed to access this font family.' ),
|
||||
array( 'status' => rest_authorization_required_code() )
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates settings when creating or updating a font family.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param string $value Encoded JSON string of font family settings.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return true|WP_Error True if the settings are valid, otherwise a WP_Error object.
|
||||
*/
|
||||
public function validate_font_family_settings( $value, $request ) {
|
||||
$settings = json_decode( $value, true );
|
||||
|
||||
// Check settings string is valid JSON.
|
||||
if ( null === $settings ) {
|
||||
return new WP_Error(
|
||||
'rest_invalid_param',
|
||||
/* translators: %s: Parameter name: "font_family_settings". */
|
||||
sprintf( __( '%s parameter must be a valid JSON string.' ), 'font_family_settings' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
|
||||
$schema = $this->get_item_schema()['properties']['font_family_settings'];
|
||||
$required = $schema['required'];
|
||||
|
||||
if ( isset( $request['id'] ) ) {
|
||||
// Allow sending individual properties if we are updating an existing font family.
|
||||
unset( $schema['required'] );
|
||||
|
||||
// But don't allow updating the slug, since it is used as a unique identifier.
|
||||
if ( isset( $settings['slug'] ) ) {
|
||||
return new WP_Error(
|
||||
'rest_invalid_param',
|
||||
/* translators: %s: Name of parameter being updated: font_family_settings[slug]". */
|
||||
sprintf( __( '%s cannot be updated.' ), 'font_family_settings[slug]' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the font face settings match the theme.json schema.
|
||||
$has_valid_settings = rest_validate_value_from_schema( $settings, $schema, 'font_family_settings' );
|
||||
|
||||
if ( is_wp_error( $has_valid_settings ) ) {
|
||||
$has_valid_settings->add_data( array( 'status' => 400 ) );
|
||||
return $has_valid_settings;
|
||||
}
|
||||
|
||||
// Check that none of the required settings are empty values.
|
||||
foreach ( $required as $key ) {
|
||||
if ( isset( $settings[ $key ] ) && ! $settings[ $key ] ) {
|
||||
return new WP_Error(
|
||||
'rest_invalid_param',
|
||||
/* translators: %s: Name of the empty font family setting parameter, e.g. "font_family_settings[slug]". */
|
||||
sprintf( __( '%s cannot be empty.' ), "font_family_settings[ $key ]" ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the font family settings when creating or updating a font family.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param string $value Encoded JSON string of font family settings.
|
||||
* @return array Decoded array of font family settings.
|
||||
*/
|
||||
public function sanitize_font_family_settings( $value ) {
|
||||
// Settings arrive as stringified JSON, since this is a multipart/form-data request.
|
||||
$settings = json_decode( $value, true );
|
||||
$schema = $this->get_item_schema()['properties']['font_family_settings']['properties'];
|
||||
|
||||
// Sanitize settings based on callbacks in the schema.
|
||||
foreach ( $settings as $key => $value ) {
|
||||
$sanitize_callback = $schema[ $key ]['arg_options']['sanitize_callback'];
|
||||
$settings[ $key ] = call_user_func( $sanitize_callback, $value );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single font family.
|
||||
*
|
||||
* @since 6.5.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 create_item( $request ) {
|
||||
$settings = $request->get_param( 'font_family_settings' );
|
||||
|
||||
// Check that the font family slug is unique.
|
||||
$query = new WP_Query(
|
||||
array(
|
||||
'post_type' => $this->post_type,
|
||||
'posts_per_page' => 1,
|
||||
'name' => $settings['slug'],
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
)
|
||||
);
|
||||
if ( ! empty( $query->posts ) ) {
|
||||
return new WP_Error(
|
||||
'rest_duplicate_font_family',
|
||||
/* translators: %s: Font family slug. */
|
||||
sprintf( __( 'A font family with slug "%s" already exists.' ), $settings['slug'] ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
|
||||
return parent::create_item( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a single font family.
|
||||
*
|
||||
* @since 6.5.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 delete_item( $request ) {
|
||||
$force = isset( $request['force'] ) ? (bool) $request['force'] : false;
|
||||
|
||||
// We don't support trashing for font families.
|
||||
if ( ! $force ) {
|
||||
return new WP_Error(
|
||||
'rest_trash_not_supported',
|
||||
/* translators: %s: force=true */
|
||||
sprintf( __( 'Font faces do not support trashing. Set "%s" to delete.' ), 'force=true' ),
|
||||
array( 'status' => 501 )
|
||||
);
|
||||
}
|
||||
|
||||
return parent::delete_item( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a single font family output for response.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_Post $item Post object.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return WP_REST_Response Response object.
|
||||
*/
|
||||
public function prepare_item_for_response( $item, $request ) {
|
||||
$fields = $this->get_fields_for_response( $request );
|
||||
$data = array();
|
||||
|
||||
if ( rest_is_field_included( 'id', $fields ) ) {
|
||||
$data['id'] = $item->ID;
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'theme_json_version', $fields ) ) {
|
||||
$data['theme_json_version'] = static::LATEST_THEME_JSON_VERSION_SUPPORTED;
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'font_faces', $fields ) ) {
|
||||
$data['font_faces'] = $this->get_font_face_ids( $item->ID );
|
||||
}
|
||||
|
||||
if ( rest_is_field_included( 'font_family_settings', $fields ) ) {
|
||||
$data['font_family_settings'] = $this->get_settings_from_post( $item );
|
||||
}
|
||||
|
||||
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
||||
$data = $this->add_additional_fields_to_object( $data, $request );
|
||||
$data = $this->filter_response_by_context( $data, $context );
|
||||
|
||||
$response = rest_ensure_response( $data );
|
||||
|
||||
if ( rest_is_field_included( '_links', $fields ) ) {
|
||||
$links = $this->prepare_links( $item );
|
||||
$response->add_links( $links );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the font family data for a REST API response.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_REST_Response $response The response object.
|
||||
* @param WP_Post $post Font family post object.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
*/
|
||||
return apply_filters( 'rest_prepare_wp_font_family', $response, $item, $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the post's schema, conforming to JSON Schema.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @return array Item schema data.
|
||||
*/
|
||||
public function get_item_schema() {
|
||||
if ( $this->schema ) {
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
$schema = array(
|
||||
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
||||
'title' => $this->post_type,
|
||||
'type' => 'object',
|
||||
// Base properties for every Post.
|
||||
'properties' => array(
|
||||
'id' => array(
|
||||
'description' => __( 'Unique identifier for the post.', 'default' ),
|
||||
'type' => 'integer',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'theme_json_version' => array(
|
||||
'description' => __( 'Version of the theme.json schema used for the typography settings.' ),
|
||||
'type' => 'integer',
|
||||
'default' => static::LATEST_THEME_JSON_VERSION_SUPPORTED,
|
||||
'minimum' => 2,
|
||||
'maximum' => static::LATEST_THEME_JSON_VERSION_SUPPORTED,
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
),
|
||||
'font_faces' => array(
|
||||
'description' => __( 'The IDs of the child font faces in the font family.' ),
|
||||
'type' => 'array',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'items' => array(
|
||||
'type' => 'integer',
|
||||
),
|
||||
),
|
||||
// Font family settings come directly from theme.json schema
|
||||
// See https://schemas.wp.org/trunk/theme.json
|
||||
'font_family_settings' => array(
|
||||
'description' => __( 'font-face definition in theme.json format.' ),
|
||||
'type' => 'object',
|
||||
'context' => array( 'view', 'edit', 'embed' ),
|
||||
'properties' => array(
|
||||
'name' => array(
|
||||
'description' => __( 'Name of the font family preset, translatable.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
),
|
||||
),
|
||||
'slug' => array(
|
||||
'description' => __( 'Kebab-case unique identifier for the font family preset.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_title',
|
||||
),
|
||||
),
|
||||
'fontFamily' => array(
|
||||
'description' => __( 'CSS font-family value.' ),
|
||||
'type' => 'string',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => array( 'WP_Font_Utils', 'sanitize_font_family' ),
|
||||
),
|
||||
),
|
||||
'preview' => array(
|
||||
'description' => __( 'URL to a preview image of the font family.' ),
|
||||
'type' => 'string',
|
||||
'format' => 'uri',
|
||||
'default' => '',
|
||||
'arg_options' => array(
|
||||
'sanitize_callback' => 'sanitize_url',
|
||||
),
|
||||
),
|
||||
),
|
||||
'required' => array( 'name', 'slug', 'fontFamily' ),
|
||||
'additionalProperties' => false,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$this->schema = $schema;
|
||||
|
||||
return $this->add_additional_fields_schema( $this->schema );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the item's schema for display / public consumption purposes.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @return array Public item schema data.
|
||||
*/
|
||||
public function get_public_item_schema() {
|
||||
|
||||
$schema = parent::get_public_item_schema();
|
||||
|
||||
// Also remove `arg_options' from child font_family_settings properties, since the parent
|
||||
// controller only handles the top level properties.
|
||||
foreach ( $schema['properties']['font_family_settings']['properties'] as &$property ) {
|
||||
unset( $property['arg_options'] );
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the query params for the font family collection.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @return array Collection parameters.
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
$query_params = parent::get_collection_params();
|
||||
|
||||
// Remove unneeded params.
|
||||
unset(
|
||||
$query_params['after'],
|
||||
$query_params['modified_after'],
|
||||
$query_params['before'],
|
||||
$query_params['modified_before'],
|
||||
$query_params['search'],
|
||||
$query_params['search_columns'],
|
||||
$query_params['status']
|
||||
);
|
||||
|
||||
$query_params['orderby']['default'] = 'id';
|
||||
$query_params['orderby']['enum'] = array( 'id', 'include' );
|
||||
|
||||
/**
|
||||
* Filters collection parameters for the font family controller.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param array $query_params JSON Schema-formatted collection parameters.
|
||||
*/
|
||||
return apply_filters( 'rest_wp_font_family_collection_params', $query_params );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the arguments used when creating or updating a font family.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @return array Font family create/edit arguments.
|
||||
*/
|
||||
public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
|
||||
if ( WP_REST_Server::CREATABLE === $method || WP_REST_Server::EDITABLE === $method ) {
|
||||
$properties = $this->get_item_schema()['properties'];
|
||||
return array(
|
||||
'theme_json_version' => $properties['theme_json_version'],
|
||||
// When creating or updating, font_family_settings is stringified JSON, to work with multipart/form-data.
|
||||
// Font families don't currently support file uploads, but may accept preview files in the future.
|
||||
'font_family_settings' => array(
|
||||
'description' => __( 'font-family declaration in theme.json format, encoded as a string.' ),
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
'validate_callback' => array( $this, 'validate_font_family_settings' ),
|
||||
'sanitize_callback' => array( $this, 'sanitize_font_family_settings' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return parent::get_endpoint_args_for_item_schema( $method );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the child font face post IDs.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param int $font_family_id Font family post ID.
|
||||
* @return int[] Array of child font face post IDs.
|
||||
*/
|
||||
protected function get_font_face_ids( $font_family_id ) {
|
||||
$query = new WP_Query(
|
||||
array(
|
||||
'fields' => 'ids',
|
||||
'post_parent' => $font_family_id,
|
||||
'post_type' => 'wp_font_face',
|
||||
'posts_per_page' => 99,
|
||||
'order' => 'ASC',
|
||||
'orderby' => 'id',
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
)
|
||||
);
|
||||
|
||||
return $query->posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares font family links for the request.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_Post $post Post object.
|
||||
* @return array Links for the given post.
|
||||
*/
|
||||
protected function prepare_links( $post ) {
|
||||
// Entity meta.
|
||||
$links = parent::prepare_links( $post );
|
||||
|
||||
return array(
|
||||
'self' => $links['self'],
|
||||
'collection' => $links['collection'],
|
||||
'font_faces' => $this->prepare_font_face_links( $post->ID ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares child font face links for the request.
|
||||
*
|
||||
* @param int $font_family_id Font family post ID.
|
||||
* @return array Links for the child font face posts.
|
||||
*/
|
||||
protected function prepare_font_face_links( $font_family_id ) {
|
||||
$font_face_ids = $this->get_font_face_ids( $font_family_id );
|
||||
$links = array();
|
||||
foreach ( $font_face_ids as $font_face_id ) {
|
||||
$links[] = array(
|
||||
'embeddable' => true,
|
||||
'href' => rest_url( sprintf( '%s/%s/%s/font-faces/%s', $this->namespace, $this->rest_base, $font_family_id, $font_face_id ) ),
|
||||
);
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares a single font family post for create or update.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @return stdClass|WP_Error Post object or WP_Error.
|
||||
*/
|
||||
protected function prepare_item_for_database( $request ) {
|
||||
$prepared_post = new stdClass();
|
||||
// Settings have already been decoded by ::sanitize_font_family_settings().
|
||||
$settings = $request->get_param( 'font_family_settings' );
|
||||
|
||||
// This is an update and we merge with the existing font family.
|
||||
if ( isset( $request['id'] ) ) {
|
||||
$existing_post = $this->get_post( $request['id'] );
|
||||
if ( is_wp_error( $existing_post ) ) {
|
||||
return $existing_post;
|
||||
}
|
||||
|
||||
$prepared_post->ID = $existing_post->ID;
|
||||
$existing_settings = $this->get_settings_from_post( $existing_post );
|
||||
$settings = array_merge( $existing_settings, $settings );
|
||||
}
|
||||
|
||||
$prepared_post->post_type = $this->post_type;
|
||||
$prepared_post->post_status = 'publish';
|
||||
$prepared_post->post_title = $settings['name'];
|
||||
$prepared_post->post_name = sanitize_title( $settings['slug'] );
|
||||
|
||||
// Remove duplicate information from settings.
|
||||
unset( $settings['name'] );
|
||||
unset( $settings['slug'] );
|
||||
|
||||
$prepared_post->post_content = wp_json_encode( $settings );
|
||||
|
||||
return $prepared_post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the font family's settings from the post.
|
||||
*
|
||||
* @since 6.5.0
|
||||
*
|
||||
* @param WP_Post $post Font family post object.
|
||||
* @return array Font family settings array.
|
||||
*/
|
||||
protected function get_settings_from_post( $post ) {
|
||||
$settings_json = json_decode( $post->post_content, true );
|
||||
|
||||
// Default to empty strings if the settings are missing.
|
||||
return array(
|
||||
'name' => isset( $post->post_title ) && $post->post_title ? $post->post_title : '',
|
||||
'slug' => isset( $post->post_name ) && $post->post_name ? $post->post_name : '',
|
||||
'fontFamily' => isset( $settings_json['fontFamily'] ) && $settings_json['fontFamily'] ? $settings_json['fontFamily'] : '',
|
||||
'preview' => isset( $settings_json['preview'] ) && $settings_json['preview'] ? $settings_json['preview'] : '',
|
||||
);
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '6.5-alpha-57547';
|
||||
$wp_version = '6.5-alpha-57548';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
|
|
|
@ -310,6 +310,9 @@ require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-widgets-controller.
|
|||
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-templates-controller.php';
|
||||
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-url-details-controller.php';
|
||||
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-navigation-fallback-controller.php';
|
||||
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-font-families-controller.php';
|
||||
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-font-faces-controller.php';
|
||||
require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-font-collections-controller.php';
|
||||
require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php';
|
||||
require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-comment-meta-fields.php';
|
||||
require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php';
|
||||
|
|
Loading…
Reference in New Issue