2021-11-08 22:00:07 +01:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* REST API: WP_REST_Global_Styles_Controller class
|
|
|
|
*
|
|
|
|
* @package WordPress
|
|
|
|
* @subpackage REST_API
|
|
|
|
* @since 5.9.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Base Global Styles REST API Controller.
|
|
|
|
*/
|
|
|
|
class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
|
2021-12-07 21:58:00 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Post type.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $post_type;
|
|
|
|
|
2021-11-08 22:00:07 +01:00
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
* @since 5.9.0
|
|
|
|
*/
|
|
|
|
public function __construct() {
|
|
|
|
$this->namespace = 'wp/v2';
|
|
|
|
$this->rest_base = 'global-styles';
|
2021-12-07 21:58:00 +01:00
|
|
|
$this->post_type = 'wp_global_styles';
|
2021-11-08 22:00:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Registers the controllers routes.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function register_routes() {
|
2022-04-05 11:52:02 +02:00
|
|
|
register_rest_route(
|
|
|
|
$this->namespace,
|
|
|
|
'/' . $this->rest_base . '/themes/(?P<stylesheet>[\/\s%\w\.\(\)\[\]\@_\-]+)/variations',
|
|
|
|
array(
|
|
|
|
array(
|
|
|
|
'methods' => WP_REST_Server::READABLE,
|
|
|
|
'callback' => array( $this, 'get_theme_items' ),
|
|
|
|
'permission_callback' => array( $this, 'get_theme_items_permissions_check' ),
|
|
|
|
'args' => array(
|
|
|
|
'stylesheet' => array(
|
|
|
|
'description' => __( 'The theme identifier' ),
|
|
|
|
'type' => 'string',
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
2021-11-08 22:00:07 +01:00
|
|
|
// List themes global styles.
|
|
|
|
register_rest_route(
|
|
|
|
$this->namespace,
|
REST API: Support `.` in theme directory names in `WP_REST_Global_Styles_Controller`, `WP_REST_Templates_Controller`, and `WP_REST_Themes_Controller`.
Regex changes from [52376] are reverted to restore the original regex patterns. Why? [52376] used an include characters pattern, which was too limiting. It did not account for localized characters, such as `é`, or other valid directory name characters.
The original theme directory regex pattern, i.e. `[^.\/]+(?:\/[^.\/]+)?` excluded the period `.` character. Removing the `.` character resolves the reported issue by allowing matching for `themes/theme-dirname-1.0/` or `themes/<subdirname>/theme-dirname-1.0/`.
As the pattern used an exclude approach, all characters are valid for matching except for `/`. However, not all characters are cross-platform valid for directory names. For example, the characters `/:<>*?"|` are not valid on Windows OS. The pattern now excludes those characters.
The theme's directory (or subdirectory) name pattern matching is now used in `WP_REST_Global_Styles_Controller`, `WP_REST_Templates_Controller`, and `WP_REST_Themes_Controller`.
Follow-up to [51003], [52051], [52275], [52376].
Props costdev, hellofromTonya, spacedmonkey, TimothyBlynJacobs, bijayyadav, kafleg.
Fixes #54596.
Built from https://develop.svn.wordpress.org/trunk@52399
git-svn-id: http://core.svn.wordpress.org/trunk@51991 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2021-12-21 05:14:00 +01:00
|
|
|
// The route.
|
|
|
|
sprintf(
|
|
|
|
'/%s/themes/(?P<stylesheet>%s)',
|
|
|
|
$this->rest_base,
|
|
|
|
// Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
|
|
|
|
// Excludes invalid directory name characters: `/:<>*?"|`.
|
|
|
|
'[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?'
|
|
|
|
),
|
2021-11-08 22:00:07 +01:00
|
|
|
array(
|
|
|
|
array(
|
|
|
|
'methods' => WP_REST_Server::READABLE,
|
|
|
|
'callback' => array( $this, 'get_theme_item' ),
|
|
|
|
'permission_callback' => array( $this, 'get_theme_item_permissions_check' ),
|
|
|
|
'args' => array(
|
|
|
|
'stylesheet' => array(
|
REST API: Add block theme support for valid non-alphanumeric characters in theme's directory name.
Themes whose `wp-content/themes/<dirname>` include valid non-alphanumeric (cross-platform) characters work for non-block themes, but did not previously resolve for block themes. For example, a block theme in `wp-content/themes/twentytwentytwo-0.4.0/` directory resulted a 404 "No route was found matching the URL and request method" response when attempting to customize it in the Site Editor.
This commit adds support for the following characters in a theme's root directory: `_`, `.`, `@`, `[`, `]`, `(`, and `)`. Subdirectory themes and `-` are already supported.
Follow-up to [51003], [52051], [52275].
Props mkaz, costdev, hellofromTonya, jffng, justinahinon, peterwilsoncc, spacedmonkey, TimothyBlynJacobs.
Fixes #54596.
Built from https://develop.svn.wordpress.org/trunk@52376
git-svn-id: http://core.svn.wordpress.org/trunk@51968 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2021-12-14 19:24:01 +01:00
|
|
|
'description' => __( 'The theme identifier' ),
|
|
|
|
'type' => 'string',
|
|
|
|
'sanitize_callback' => array( $this, '_sanitize_global_styles_callback' ),
|
2021-11-08 22:00:07 +01:00
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
REST API: Add block theme support for valid non-alphanumeric characters in theme's directory name.
Themes whose `wp-content/themes/<dirname>` include valid non-alphanumeric (cross-platform) characters work for non-block themes, but did not previously resolve for block themes. For example, a block theme in `wp-content/themes/twentytwentytwo-0.4.0/` directory resulted a 404 "No route was found matching the URL and request method" response when attempting to customize it in the Site Editor.
This commit adds support for the following characters in a theme's root directory: `_`, `.`, `@`, `[`, `]`, `(`, and `)`. Subdirectory themes and `-` are already supported.
Follow-up to [51003], [52051], [52275].
Props mkaz, costdev, hellofromTonya, jffng, justinahinon, peterwilsoncc, spacedmonkey, TimothyBlynJacobs.
Fixes #54596.
Built from https://develop.svn.wordpress.org/trunk@52376
git-svn-id: http://core.svn.wordpress.org/trunk@51968 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2021-12-14 19:24:01 +01:00
|
|
|
// Lists/updates a single global style variation based on the given id.
|
2021-11-08 22:00:07 +01:00
|
|
|
register_rest_route(
|
|
|
|
$this->namespace,
|
REST API: Support `.` in theme directory names in `WP_REST_Global_Styles_Controller`, `WP_REST_Templates_Controller`, and `WP_REST_Themes_Controller`.
Regex changes from [52376] are reverted to restore the original regex patterns. Why? [52376] used an include characters pattern, which was too limiting. It did not account for localized characters, such as `é`, or other valid directory name characters.
The original theme directory regex pattern, i.e. `[^.\/]+(?:\/[^.\/]+)?` excluded the period `.` character. Removing the `.` character resolves the reported issue by allowing matching for `themes/theme-dirname-1.0/` or `themes/<subdirname>/theme-dirname-1.0/`.
As the pattern used an exclude approach, all characters are valid for matching except for `/`. However, not all characters are cross-platform valid for directory names. For example, the characters `/:<>*?"|` are not valid on Windows OS. The pattern now excludes those characters.
The theme's directory (or subdirectory) name pattern matching is now used in `WP_REST_Global_Styles_Controller`, `WP_REST_Templates_Controller`, and `WP_REST_Themes_Controller`.
Follow-up to [51003], [52051], [52275], [52376].
Props costdev, hellofromTonya, spacedmonkey, TimothyBlynJacobs, bijayyadav, kafleg.
Fixes #54596.
Built from https://develop.svn.wordpress.org/trunk@52399
git-svn-id: http://core.svn.wordpress.org/trunk@51991 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2021-12-21 05:14:00 +01:00
|
|
|
'/' . $this->rest_base . '/(?P<id>[\/\w-]+)',
|
2021-11-08 22:00:07 +01:00
|
|
|
array(
|
|
|
|
array(
|
|
|
|
'methods' => WP_REST_Server::READABLE,
|
|
|
|
'callback' => array( $this, 'get_item' ),
|
|
|
|
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
|
|
|
'args' => array(
|
|
|
|
'id' => array(
|
REST API: Add block theme support for valid non-alphanumeric characters in theme's directory name.
Themes whose `wp-content/themes/<dirname>` include valid non-alphanumeric (cross-platform) characters work for non-block themes, but did not previously resolve for block themes. For example, a block theme in `wp-content/themes/twentytwentytwo-0.4.0/` directory resulted a 404 "No route was found matching the URL and request method" response when attempting to customize it in the Site Editor.
This commit adds support for the following characters in a theme's root directory: `_`, `.`, `@`, `[`, `]`, `(`, and `)`. Subdirectory themes and `-` are already supported.
Follow-up to [51003], [52051], [52275].
Props mkaz, costdev, hellofromTonya, jffng, justinahinon, peterwilsoncc, spacedmonkey, TimothyBlynJacobs.
Fixes #54596.
Built from https://develop.svn.wordpress.org/trunk@52376
git-svn-id: http://core.svn.wordpress.org/trunk@51968 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2021-12-14 19:24:01 +01:00
|
|
|
'description' => __( 'The id of a template' ),
|
|
|
|
'type' => 'string',
|
|
|
|
'sanitize_callback' => array( $this, '_sanitize_global_styles_callback' ),
|
2021-11-08 22:00:07 +01:00
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
array(
|
|
|
|
'methods' => WP_REST_Server::EDITABLE,
|
|
|
|
'callback' => array( $this, 'update_item' ),
|
|
|
|
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
|
|
|
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
|
|
|
),
|
|
|
|
'schema' => array( $this, 'get_public_item_schema' ),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
REST API: Add block theme support for valid non-alphanumeric characters in theme's directory name.
Themes whose `wp-content/themes/<dirname>` include valid non-alphanumeric (cross-platform) characters work for non-block themes, but did not previously resolve for block themes. For example, a block theme in `wp-content/themes/twentytwentytwo-0.4.0/` directory resulted a 404 "No route was found matching the URL and request method" response when attempting to customize it in the Site Editor.
This commit adds support for the following characters in a theme's root directory: `_`, `.`, `@`, `[`, `]`, `(`, and `)`. Subdirectory themes and `-` are already supported.
Follow-up to [51003], [52051], [52275].
Props mkaz, costdev, hellofromTonya, jffng, justinahinon, peterwilsoncc, spacedmonkey, TimothyBlynJacobs.
Fixes #54596.
Built from https://develop.svn.wordpress.org/trunk@52376
git-svn-id: http://core.svn.wordpress.org/trunk@51968 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2021-12-14 19:24:01 +01:00
|
|
|
/**
|
|
|
|
* Sanitize the global styles ID or stylesheet to decode endpoint.
|
REST API: Support `.` in theme directory names in `WP_REST_Global_Styles_Controller`, `WP_REST_Templates_Controller`, and `WP_REST_Themes_Controller`.
Regex changes from [52376] are reverted to restore the original regex patterns. Why? [52376] used an include characters pattern, which was too limiting. It did not account for localized characters, such as `é`, or other valid directory name characters.
The original theme directory regex pattern, i.e. `[^.\/]+(?:\/[^.\/]+)?` excluded the period `.` character. Removing the `.` character resolves the reported issue by allowing matching for `themes/theme-dirname-1.0/` or `themes/<subdirname>/theme-dirname-1.0/`.
As the pattern used an exclude approach, all characters are valid for matching except for `/`. However, not all characters are cross-platform valid for directory names. For example, the characters `/:<>*?"|` are not valid on Windows OS. The pattern now excludes those characters.
The theme's directory (or subdirectory) name pattern matching is now used in `WP_REST_Global_Styles_Controller`, `WP_REST_Templates_Controller`, and `WP_REST_Themes_Controller`.
Follow-up to [51003], [52051], [52275], [52376].
Props costdev, hellofromTonya, spacedmonkey, TimothyBlynJacobs, bijayyadav, kafleg.
Fixes #54596.
Built from https://develop.svn.wordpress.org/trunk@52399
git-svn-id: http://core.svn.wordpress.org/trunk@51991 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2021-12-21 05:14:00 +01:00
|
|
|
* For example, `wp/v2/global-styles/twentytwentytwo%200.4.0`
|
|
|
|
* would be decoded to `twentytwentytwo 0.4.0`.
|
REST API: Add block theme support for valid non-alphanumeric characters in theme's directory name.
Themes whose `wp-content/themes/<dirname>` include valid non-alphanumeric (cross-platform) characters work for non-block themes, but did not previously resolve for block themes. For example, a block theme in `wp-content/themes/twentytwentytwo-0.4.0/` directory resulted a 404 "No route was found matching the URL and request method" response when attempting to customize it in the Site Editor.
This commit adds support for the following characters in a theme's root directory: `_`, `.`, `@`, `[`, `]`, `(`, and `)`. Subdirectory themes and `-` are already supported.
Follow-up to [51003], [52051], [52275].
Props mkaz, costdev, hellofromTonya, jffng, justinahinon, peterwilsoncc, spacedmonkey, TimothyBlynJacobs.
Fixes #54596.
Built from https://develop.svn.wordpress.org/trunk@52376
git-svn-id: http://core.svn.wordpress.org/trunk@51968 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2021-12-14 19:24:01 +01:00
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @param string $id_or_stylesheet Global styles ID or stylesheet.
|
|
|
|
* @return string Sanitized global styles ID or stylesheet.
|
|
|
|
*/
|
|
|
|
public function _sanitize_global_styles_callback( $id_or_stylesheet ) {
|
|
|
|
return urldecode( $id_or_stylesheet );
|
|
|
|
}
|
|
|
|
|
2022-07-19 18:22:09 +02:00
|
|
|
/**
|
|
|
|
* Get the post, if the ID is valid.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @param int $id Supplied ID.
|
|
|
|
* @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
|
|
|
|
*/
|
|
|
|
protected function get_post( $id ) {
|
|
|
|
$error = new WP_Error(
|
|
|
|
'rest_global_styles_not_found',
|
|
|
|
__( 'No global styles config exist with that id.' ),
|
|
|
|
array( 'status' => 404 )
|
|
|
|
);
|
|
|
|
|
|
|
|
$id = (int) $id;
|
|
|
|
if ( $id <= 0 ) {
|
|
|
|
return $error;
|
|
|
|
}
|
|
|
|
|
|
|
|
$post = get_post( $id );
|
|
|
|
if ( empty( $post ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
|
|
|
|
return $error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $post;
|
|
|
|
}
|
|
|
|
|
2021-11-08 22:00:07 +01:00
|
|
|
/**
|
2021-12-07 21:58:00 +01:00
|
|
|
* Checks if a given request has access to read a single global style.
|
2021-11-08 22:00:07 +01:00
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
2021-12-07 21:58:00 +01:00
|
|
|
* @param WP_REST_Request $request Full details about the request.
|
2021-11-08 22:00:07 +01:00
|
|
|
* @return true|WP_Error True if the request has read access, WP_Error object otherwise.
|
|
|
|
*/
|
2021-12-07 21:58:00 +01:00
|
|
|
public function get_item_permissions_check( $request ) {
|
|
|
|
$post = $this->get_post( $request['id'] );
|
|
|
|
if ( is_wp_error( $post ) ) {
|
|
|
|
return $post;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( 'edit' === $request['context'] && $post && ! $this->check_update_permission( $post ) ) {
|
2021-11-08 22:00:07 +01:00
|
|
|
return new WP_Error(
|
2021-12-07 21:58:00 +01:00
|
|
|
'rest_forbidden_context',
|
|
|
|
__( 'Sorry, you are not allowed to edit this global style.' ),
|
|
|
|
array( 'status' => rest_authorization_required_code() )
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! $this->check_read_permission( $post ) ) {
|
|
|
|
return new WP_Error(
|
|
|
|
'rest_cannot_view',
|
|
|
|
__( 'Sorry, you are not allowed to view this global style.' ),
|
|
|
|
array( 'status' => rest_authorization_required_code() )
|
2021-11-08 22:00:07 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2021-12-07 21:58:00 +01:00
|
|
|
* Checks if a global style can be read.
|
2021-11-08 22:00:07 +01:00
|
|
|
*
|
2021-12-07 21:58:00 +01:00
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @param WP_Post $post Post object.
|
|
|
|
* @return bool Whether the post can be read.
|
2021-11-08 22:00:07 +01:00
|
|
|
*/
|
2021-12-07 21:58:00 +01:00
|
|
|
protected function check_read_permission( $post ) {
|
|
|
|
return current_user_can( 'read_post', $post->ID );
|
2021-11-08 22:00:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the given global styles config.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @param WP_REST_Request $request The request instance.
|
|
|
|
*
|
|
|
|
* @return WP_REST_Response|WP_Error
|
|
|
|
*/
|
|
|
|
public function get_item( $request ) {
|
2021-12-07 21:58:00 +01:00
|
|
|
$post = $this->get_post( $request['id'] );
|
|
|
|
if ( is_wp_error( $post ) ) {
|
|
|
|
return $post;
|
2021-11-08 22:00:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $this->prepare_item_for_response( $post, $request );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if a given request has access to write a single global styles config.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @param WP_REST_Request $request Full details about the request.
|
|
|
|
* @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise.
|
|
|
|
*/
|
|
|
|
public function update_item_permissions_check( $request ) {
|
2021-12-07 21:58:00 +01:00
|
|
|
$post = $this->get_post( $request['id'] );
|
|
|
|
if ( is_wp_error( $post ) ) {
|
|
|
|
return $post;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( $post && ! $this->check_update_permission( $post ) ) {
|
|
|
|
return new WP_Error(
|
|
|
|
'rest_cannot_edit',
|
|
|
|
__( 'Sorry, you are not allowed to edit this global style.' ),
|
|
|
|
array( 'status' => rest_authorization_required_code() )
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if a global style can be edited.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @param WP_Post $post Post object.
|
|
|
|
* @return bool Whether the post can be edited.
|
|
|
|
*/
|
|
|
|
protected function check_update_permission( $post ) {
|
|
|
|
return current_user_can( 'edit_post', $post->ID );
|
2021-11-08 22:00:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates a single global style config.
|
|
|
|
*
|
|
|
|
* @since 5.9.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 update_item( $request ) {
|
2021-12-07 21:58:00 +01:00
|
|
|
$post_before = $this->get_post( $request['id'] );
|
|
|
|
if ( is_wp_error( $post_before ) ) {
|
|
|
|
return $post_before;
|
2021-11-08 22:00:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$changes = $this->prepare_item_for_database( $request );
|
Editor: Add support for custom CSS in global styles.
This changeset introduces functions `wp_get_global_styles_custom_css()` and `wp_enqueue_global_styles_custom_css()`, which allow accessing and enqueuing custom CSS added via global styles.
Custom CSS via global styles is handled separately from custom CSS via the Customizer. If a site uses both features, the custom CSS from both sources will be loaded. The global styles custom CSS is then loaded after the Customizer custom CSS, so if there are any conflicts between the rules, the global styles take precedence.
Similarly to e.g. [55185], the result is cached in a non-persistent cache, except when `WP_DEBUG` is on to avoid interrupting the theme developer's workflow.
Props glendaviesnz, oandregal, ntsekouras, mamaduka, davidbaumwald, hellofromtonya, flixos90.
Fixes #57536.
Built from https://develop.svn.wordpress.org/trunk@55192
git-svn-id: http://core.svn.wordpress.org/trunk@54725 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-02-02 19:52:17 +01:00
|
|
|
if ( is_wp_error( $changes ) ) {
|
|
|
|
return $changes;
|
|
|
|
}
|
|
|
|
|
2021-11-30 02:10:08 +01:00
|
|
|
$result = wp_update_post( wp_slash( (array) $changes ), true, false );
|
2021-11-08 22:00:07 +01:00
|
|
|
if ( is_wp_error( $result ) ) {
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
$post = get_post( $request['id'] );
|
|
|
|
$fields_update = $this->update_additional_fields_for_object( $post, $request );
|
|
|
|
if ( is_wp_error( $fields_update ) ) {
|
|
|
|
return $fields_update;
|
|
|
|
}
|
|
|
|
|
2021-11-30 02:10:08 +01:00
|
|
|
wp_after_insert_post( $post, true, $post_before );
|
|
|
|
|
|
|
|
$response = $this->prepare_item_for_response( $post, $request );
|
|
|
|
|
|
|
|
return rest_ensure_response( $response );
|
2021-11-08 22:00:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepares a single global styles config for update.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
Editor: Add support for custom CSS in global styles.
This changeset introduces functions `wp_get_global_styles_custom_css()` and `wp_enqueue_global_styles_custom_css()`, which allow accessing and enqueuing custom CSS added via global styles.
Custom CSS via global styles is handled separately from custom CSS via the Customizer. If a site uses both features, the custom CSS from both sources will be loaded. The global styles custom CSS is then loaded after the Customizer custom CSS, so if there are any conflicts between the rules, the global styles take precedence.
Similarly to e.g. [55185], the result is cached in a non-persistent cache, except when `WP_DEBUG` is on to avoid interrupting the theme developer's workflow.
Props glendaviesnz, oandregal, ntsekouras, mamaduka, davidbaumwald, hellofromtonya, flixos90.
Fixes #57536.
Built from https://develop.svn.wordpress.org/trunk@55192
git-svn-id: http://core.svn.wordpress.org/trunk@54725 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-02-02 19:52:17 +01:00
|
|
|
* @since 6.2.0 Added validation of styles.css property.
|
2021-11-08 22:00:07 +01:00
|
|
|
*
|
|
|
|
* @param WP_REST_Request $request Request object.
|
Editor: Add support for custom CSS in global styles.
This changeset introduces functions `wp_get_global_styles_custom_css()` and `wp_enqueue_global_styles_custom_css()`, which allow accessing and enqueuing custom CSS added via global styles.
Custom CSS via global styles is handled separately from custom CSS via the Customizer. If a site uses both features, the custom CSS from both sources will be loaded. The global styles custom CSS is then loaded after the Customizer custom CSS, so if there are any conflicts between the rules, the global styles take precedence.
Similarly to e.g. [55185], the result is cached in a non-persistent cache, except when `WP_DEBUG` is on to avoid interrupting the theme developer's workflow.
Props glendaviesnz, oandregal, ntsekouras, mamaduka, davidbaumwald, hellofromtonya, flixos90.
Fixes #57536.
Built from https://develop.svn.wordpress.org/trunk@55192
git-svn-id: http://core.svn.wordpress.org/trunk@54725 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-02-02 19:52:17 +01:00
|
|
|
* @return stdClass|WP_Error Prepared item on success. WP_Error on when the custom CSS is not valid.
|
2021-11-08 22:00:07 +01:00
|
|
|
*/
|
|
|
|
protected function prepare_item_for_database( $request ) {
|
|
|
|
$changes = new stdClass();
|
|
|
|
$changes->ID = $request['id'];
|
|
|
|
|
|
|
|
$post = get_post( $request['id'] );
|
|
|
|
$existing_config = array();
|
|
|
|
if ( $post ) {
|
|
|
|
$existing_config = json_decode( $post->post_content, true );
|
|
|
|
$json_decoding_error = json_last_error();
|
|
|
|
if ( JSON_ERROR_NONE !== $json_decoding_error || ! isset( $existing_config['isGlobalStylesUserThemeJSON'] ) ||
|
|
|
|
! $existing_config['isGlobalStylesUserThemeJSON'] ) {
|
|
|
|
$existing_config = array();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( isset( $request['styles'] ) || isset( $request['settings'] ) ) {
|
|
|
|
$config = array();
|
|
|
|
if ( isset( $request['styles'] ) ) {
|
Editor: Add support for custom CSS in global styles.
This changeset introduces functions `wp_get_global_styles_custom_css()` and `wp_enqueue_global_styles_custom_css()`, which allow accessing and enqueuing custom CSS added via global styles.
Custom CSS via global styles is handled separately from custom CSS via the Customizer. If a site uses both features, the custom CSS from both sources will be loaded. The global styles custom CSS is then loaded after the Customizer custom CSS, so if there are any conflicts between the rules, the global styles take precedence.
Similarly to e.g. [55185], the result is cached in a non-persistent cache, except when `WP_DEBUG` is on to avoid interrupting the theme developer's workflow.
Props glendaviesnz, oandregal, ntsekouras, mamaduka, davidbaumwald, hellofromtonya, flixos90.
Fixes #57536.
Built from https://develop.svn.wordpress.org/trunk@55192
git-svn-id: http://core.svn.wordpress.org/trunk@54725 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-02-02 19:52:17 +01:00
|
|
|
if ( isset( $request['styles']['css'] ) ) {
|
|
|
|
$css_validation_result = $this->validate_custom_css( $request['styles']['css'] );
|
|
|
|
if ( is_wp_error( $css_validation_result ) ) {
|
|
|
|
return $css_validation_result;
|
|
|
|
}
|
|
|
|
}
|
2021-11-08 22:00:07 +01:00
|
|
|
$config['styles'] = $request['styles'];
|
|
|
|
} elseif ( isset( $existing_config['styles'] ) ) {
|
|
|
|
$config['styles'] = $existing_config['styles'];
|
|
|
|
}
|
|
|
|
if ( isset( $request['settings'] ) ) {
|
|
|
|
$config['settings'] = $request['settings'];
|
|
|
|
} elseif ( isset( $existing_config['settings'] ) ) {
|
|
|
|
$config['settings'] = $existing_config['settings'];
|
|
|
|
}
|
|
|
|
$config['isGlobalStylesUserThemeJSON'] = true;
|
|
|
|
$config['version'] = WP_Theme_JSON::LATEST_SCHEMA;
|
|
|
|
$changes->post_content = wp_json_encode( $config );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Post title.
|
|
|
|
if ( isset( $request['title'] ) ) {
|
|
|
|
if ( is_string( $request['title'] ) ) {
|
|
|
|
$changes->post_title = $request['title'];
|
|
|
|
} elseif ( ! empty( $request['title']['raw'] ) ) {
|
|
|
|
$changes->post_title = $request['title']['raw'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $changes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepare a global styles config output for response.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @param WP_Post $post Global Styles post object.
|
|
|
|
* @param WP_REST_Request $request Request object.
|
2021-12-07 13:20:02 +01:00
|
|
|
* @return WP_REST_Response Response object.
|
2021-11-08 22:00:07 +01:00
|
|
|
*/
|
|
|
|
public function prepare_item_for_response( $post, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
2021-11-30 01:24:27 +01:00
|
|
|
$raw_config = json_decode( $post->post_content, true );
|
|
|
|
$is_global_styles_user_theme_json = isset( $raw_config['isGlobalStylesUserThemeJSON'] ) && true === $raw_config['isGlobalStylesUserThemeJSON'];
|
|
|
|
$config = array();
|
|
|
|
if ( $is_global_styles_user_theme_json ) {
|
|
|
|
$config = ( new WP_Theme_JSON( $raw_config, 'custom' ) )->get_raw_data();
|
|
|
|
}
|
2021-11-10 07:01:30 +01:00
|
|
|
|
|
|
|
// Base fields for every post.
|
2021-11-30 01:24:27 +01:00
|
|
|
$data = array();
|
|
|
|
$fields = $this->get_fields_for_response( $request );
|
2021-11-10 07:01:30 +01:00
|
|
|
|
|
|
|
if ( rest_is_field_included( 'id', $fields ) ) {
|
|
|
|
$data['id'] = $post->ID;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( rest_is_field_included( 'title', $fields ) ) {
|
|
|
|
$data['title'] = array();
|
|
|
|
}
|
|
|
|
if ( rest_is_field_included( 'title.raw', $fields ) ) {
|
|
|
|
$data['title']['raw'] = $post->post_title;
|
|
|
|
}
|
|
|
|
if ( rest_is_field_included( 'title.rendered', $fields ) ) {
|
|
|
|
add_filter( 'protected_title_format', array( $this, 'protected_title_format' ) );
|
|
|
|
|
|
|
|
$data['title']['rendered'] = get_the_title( $post->ID );
|
|
|
|
|
|
|
|
remove_filter( 'protected_title_format', array( $this, 'protected_title_format' ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( rest_is_field_included( 'settings', $fields ) ) {
|
|
|
|
$data['settings'] = ! empty( $config['settings'] ) && $is_global_styles_user_theme_json ? $config['settings'] : new stdClass();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( rest_is_field_included( 'styles', $fields ) ) {
|
|
|
|
$data['styles'] = ! empty( $config['styles'] ) && $is_global_styles_user_theme_json ? $config['styles'] : new stdClass();
|
|
|
|
}
|
|
|
|
|
|
|
|
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
|
|
|
$data = $this->add_additional_fields_to_object( $data, $request );
|
|
|
|
$data = $this->filter_response_by_context( $data, $context );
|
|
|
|
|
|
|
|
// Wrap the data in a response object.
|
|
|
|
$response = rest_ensure_response( $data );
|
|
|
|
|
2022-07-22 16:00:12 +02:00
|
|
|
if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
|
|
|
|
$links = $this->prepare_links( $post->ID );
|
|
|
|
$response->add_links( $links );
|
|
|
|
if ( ! empty( $links['self']['href'] ) ) {
|
|
|
|
$actions = $this->get_available_actions();
|
|
|
|
$self = $links['self']['href'];
|
|
|
|
foreach ( $actions as $rel ) {
|
|
|
|
$response->add_link( $rel, $self );
|
|
|
|
}
|
2021-11-08 22:00:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepares links for the request.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @param integer $id ID.
|
|
|
|
* @return array Links for the given post.
|
|
|
|
*/
|
|
|
|
protected function prepare_links( $id ) {
|
|
|
|
$base = sprintf( '%s/%s', $this->namespace, $this->rest_base );
|
|
|
|
|
|
|
|
$links = array(
|
2021-12-14 17:31:00 +01:00
|
|
|
'self' => array(
|
2021-11-08 22:00:07 +01:00
|
|
|
'href' => rest_url( trailingslashit( $base ) . $id ),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
return $links;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the link relations available for the post and current user.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
2023-02-01 19:38:14 +01:00
|
|
|
* @since 6.2.0 Added 'edit-css' action.
|
2021-11-08 22:00:07 +01:00
|
|
|
*
|
|
|
|
* @return array List of link relations.
|
|
|
|
*/
|
|
|
|
protected function get_available_actions() {
|
|
|
|
$rels = array();
|
|
|
|
|
2021-12-07 21:58:00 +01:00
|
|
|
$post_type = get_post_type_object( $this->post_type );
|
2021-11-08 22:00:07 +01:00
|
|
|
if ( current_user_can( $post_type->cap->publish_posts ) ) {
|
|
|
|
$rels[] = 'https://api.w.org/action-publish';
|
|
|
|
}
|
|
|
|
|
2023-02-01 19:38:14 +01:00
|
|
|
if ( current_user_can( 'edit_css' ) ) {
|
|
|
|
$rels[] = 'https://api.w.org/action-edit-css';
|
|
|
|
}
|
|
|
|
|
2021-11-08 22:00:07 +01:00
|
|
|
return $rels;
|
|
|
|
}
|
|
|
|
|
2021-11-10 07:01:30 +01:00
|
|
|
/**
|
|
|
|
* Overwrites the default protected title format.
|
|
|
|
*
|
|
|
|
* By default, WordPress will show password protected posts with a title of
|
|
|
|
* "Protected: %s", as the REST API communicates the protected status of a post
|
|
|
|
* in a machine readable format, we remove the "Protected: " prefix.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @return string Protected title format.
|
|
|
|
*/
|
|
|
|
public function protected_title_format() {
|
|
|
|
return '%s';
|
|
|
|
}
|
|
|
|
|
2021-11-08 22:00:07 +01:00
|
|
|
/**
|
|
|
|
* Retrieves the query params for the global styles collection.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @return array Collection parameters.
|
|
|
|
*/
|
|
|
|
public function get_collection_params() {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieves the global styles type' schema, conforming to JSON Schema.
|
|
|
|
*
|
|
|
|
* @since 5.9.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#',
|
2021-12-07 21:58:00 +01:00
|
|
|
'title' => $this->post_type,
|
2021-11-08 22:00:07 +01:00
|
|
|
'type' => 'object',
|
|
|
|
'properties' => array(
|
|
|
|
'id' => array(
|
|
|
|
'description' => __( 'ID of global styles config.' ),
|
|
|
|
'type' => 'string',
|
|
|
|
'context' => array( 'embed', 'view', 'edit' ),
|
|
|
|
'readonly' => true,
|
|
|
|
),
|
|
|
|
'styles' => array(
|
|
|
|
'description' => __( 'Global styles.' ),
|
|
|
|
'type' => array( 'object' ),
|
|
|
|
'context' => array( 'view', 'edit' ),
|
|
|
|
),
|
|
|
|
'settings' => array(
|
|
|
|
'description' => __( 'Global settings.' ),
|
|
|
|
'type' => array( 'object' ),
|
|
|
|
'context' => array( 'view', 'edit' ),
|
|
|
|
),
|
|
|
|
'title' => array(
|
|
|
|
'description' => __( 'Title of the global styles variation.' ),
|
|
|
|
'type' => array( 'object', 'string' ),
|
|
|
|
'default' => '',
|
|
|
|
'context' => array( 'embed', 'view', 'edit' ),
|
|
|
|
'properties' => array(
|
|
|
|
'raw' => array(
|
|
|
|
'description' => __( 'Title for the global styles variation, as it exists in the database.' ),
|
|
|
|
'type' => 'string',
|
|
|
|
'context' => array( 'view', 'edit', 'embed' ),
|
|
|
|
),
|
|
|
|
'rendered' => array(
|
|
|
|
'description' => __( 'HTML title for the post, transformed for display.' ),
|
|
|
|
'type' => 'string',
|
|
|
|
'context' => array( 'view', 'edit', 'embed' ),
|
|
|
|
'readonly' => true,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
$this->schema = $schema;
|
|
|
|
|
|
|
|
return $this->add_additional_fields_schema( $this->schema );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if a given request has access to read a single theme global styles config.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @param WP_REST_Request $request Full details about the request.
|
|
|
|
* @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
|
|
|
|
*/
|
|
|
|
public function get_theme_item_permissions_check( $request ) {
|
2021-12-07 21:58:00 +01:00
|
|
|
// Verify if the current user has edit_theme_options capability.
|
|
|
|
// This capability is required to edit/view/delete templates.
|
|
|
|
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
|
|
|
return new WP_Error(
|
|
|
|
'rest_cannot_manage_global_styles',
|
|
|
|
__( 'Sorry, you are not allowed to access the global styles on this site.' ),
|
|
|
|
array(
|
|
|
|
'status' => rest_authorization_required_code(),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2021-11-08 22:00:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the given theme global styles config.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
|
|
|
* @param WP_REST_Request $request The request instance.
|
|
|
|
* @return WP_REST_Response|WP_Error
|
|
|
|
*/
|
|
|
|
public function get_theme_item( $request ) {
|
2022-11-11 17:26:12 +01:00
|
|
|
if ( get_stylesheet() !== $request['stylesheet'] ) {
|
2021-11-08 22:00:07 +01:00
|
|
|
// This endpoint only supports the active theme for now.
|
|
|
|
return new WP_Error(
|
|
|
|
'rest_theme_not_found',
|
|
|
|
__( 'Theme not found.' ),
|
|
|
|
array( 'status' => 404 )
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-12-14 17:31:00 +01:00
|
|
|
$theme = WP_Theme_JSON_Resolver::get_merged_data( 'theme' );
|
|
|
|
$data = array();
|
|
|
|
$fields = $this->get_fields_for_response( $request );
|
|
|
|
|
|
|
|
if ( rest_is_field_included( 'settings', $fields ) ) {
|
|
|
|
$data['settings'] = $theme->get_settings();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( rest_is_field_included( 'styles', $fields ) ) {
|
2022-04-17 17:07:08 +02:00
|
|
|
$raw_data = $theme->get_raw_data();
|
2022-04-05 13:49:08 +02:00
|
|
|
$data['styles'] = isset( $raw_data['styles'] ) ? $raw_data['styles'] : array();
|
2021-12-14 17:31:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$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 );
|
|
|
|
|
2022-07-22 16:00:12 +02:00
|
|
|
if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
|
|
|
|
$links = array(
|
|
|
|
'self' => array(
|
|
|
|
'href' => rest_url( sprintf( '%s/%s/themes/%s', $this->namespace, $this->rest_base, $request['stylesheet'] ) ),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
$response->add_links( $links );
|
|
|
|
}
|
2021-11-08 22:00:07 +01:00
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
2022-04-05 11:52:02 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if a given request has access to read a single theme global styles config.
|
|
|
|
*
|
|
|
|
* @since 6.0.0
|
|
|
|
*
|
|
|
|
* @param WP_REST_Request $request Full details about the request.
|
|
|
|
* @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise.
|
|
|
|
*/
|
|
|
|
public function get_theme_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
|
|
|
// Verify if the current user has edit_theme_options capability.
|
|
|
|
// This capability is required to edit/view/delete templates.
|
|
|
|
if ( ! current_user_can( 'edit_theme_options' ) ) {
|
|
|
|
return new WP_Error(
|
|
|
|
'rest_cannot_manage_global_styles',
|
|
|
|
__( 'Sorry, you are not allowed to access the global styles on this site.' ),
|
|
|
|
array(
|
|
|
|
'status' => rest_authorization_required_code(),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the given theme global styles variations.
|
|
|
|
*
|
|
|
|
* @since 6.0.0
|
|
|
|
*
|
|
|
|
* @param WP_REST_Request $request The request instance.
|
|
|
|
*
|
|
|
|
* @return WP_REST_Response|WP_Error
|
|
|
|
*/
|
|
|
|
public function get_theme_items( $request ) {
|
2022-11-11 17:26:12 +01:00
|
|
|
if ( get_stylesheet() !== $request['stylesheet'] ) {
|
2022-04-05 11:52:02 +02:00
|
|
|
// This endpoint only supports the active theme for now.
|
|
|
|
return new WP_Error(
|
|
|
|
'rest_theme_not_found',
|
|
|
|
__( 'Theme not found.' ),
|
|
|
|
array( 'status' => 404 )
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$variations = WP_Theme_JSON_Resolver::get_style_variations();
|
|
|
|
$response = rest_ensure_response( $variations );
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
Editor: Add support for custom CSS in global styles.
This changeset introduces functions `wp_get_global_styles_custom_css()` and `wp_enqueue_global_styles_custom_css()`, which allow accessing and enqueuing custom CSS added via global styles.
Custom CSS via global styles is handled separately from custom CSS via the Customizer. If a site uses both features, the custom CSS from both sources will be loaded. The global styles custom CSS is then loaded after the Customizer custom CSS, so if there are any conflicts between the rules, the global styles take precedence.
Similarly to e.g. [55185], the result is cached in a non-persistent cache, except when `WP_DEBUG` is on to avoid interrupting the theme developer's workflow.
Props glendaviesnz, oandregal, ntsekouras, mamaduka, davidbaumwald, hellofromtonya, flixos90.
Fixes #57536.
Built from https://develop.svn.wordpress.org/trunk@55192
git-svn-id: http://core.svn.wordpress.org/trunk@54725 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-02-02 19:52:17 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Validate style.css as valid CSS.
|
|
|
|
*
|
|
|
|
* Currently just checks for invalid markup.
|
|
|
|
*
|
|
|
|
* @since 6.2.0
|
|
|
|
*
|
|
|
|
* @param string $css CSS to validate.
|
|
|
|
* @return true|WP_Error True if the input was validated, otherwise WP_Error.
|
|
|
|
*/
|
|
|
|
private function validate_custom_css( $css ) {
|
|
|
|
if ( preg_match( '#</?\w+#', $css ) ) {
|
|
|
|
return new WP_Error(
|
|
|
|
'rest_custom_css_illegal_markup',
|
|
|
|
__( 'Markup is not allowed in CSS.' ),
|
|
|
|
array( 'status' => 400 )
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2021-11-08 22:00:07 +01:00
|
|
|
}
|