mirror of
git://develop.git.wordpress.org/
synced 2025-01-19 05:38:07 +01:00
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. git-svn-id: https://develop.svn.wordpress.org/trunk@52399 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
b161cfc1ff
commit
e1f5600c15
@ -41,7 +41,14 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
|
||||
// List themes global styles.
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/themes/(?P<stylesheet>[\/\s%\w\.\(\)\[\]\@_\-]+)',
|
||||
// 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: `/:<>*?"|`.
|
||||
'[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?'
|
||||
),
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
@ -61,7 +68,7 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
|
||||
// Lists/updates a single global style variation based on the given id.
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/(?P<id>[\/\s%\w\.\(\)\[\]\@_\-]+)',
|
||||
'/' . $this->rest_base . '/(?P<id>[\/\w-]+)',
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
@ -88,8 +95,8 @@ class WP_REST_Global_Styles_Controller extends WP_REST_Controller {
|
||||
|
||||
/**
|
||||
* Sanitize the global styles ID or stylesheet to decode endpoint.
|
||||
* For example, `wp/v2/global-styles/templatetwentytwo%200.4.0`
|
||||
* would be decoded to `templatetwentytwo 0.4.0`.
|
||||
* For example, `wp/v2/global-styles/twentytwentytwo%200.4.0`
|
||||
* would be decoded to `twentytwentytwo 0.4.0`.
|
||||
*
|
||||
* @since 5.9.0
|
||||
*
|
||||
|
@ -68,7 +68,16 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
|
||||
// Lists/updates a single template based on the given id.
|
||||
register_rest_route(
|
||||
$this->namespace,
|
||||
'/' . $this->rest_base . '/(?P<id>[\/\s%\w\.\(\)\[\]\@_\-]+)',
|
||||
// The route.
|
||||
sprintf(
|
||||
'/%s/(?P<id>%s%s)',
|
||||
$this->rest_base,
|
||||
// Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
|
||||
// Excludes invalid directory name characters: `/:<>*?"|`.
|
||||
'([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)',
|
||||
// Matches the template name.
|
||||
'[\/\w-]+'
|
||||
),
|
||||
array(
|
||||
'args' => array(
|
||||
'id' => array(
|
||||
@ -149,7 +158,6 @@ class WP_REST_Templates_Controller extends WP_REST_Controller {
|
||||
* @return string Sanitized template ID.
|
||||
*/
|
||||
public function _sanitize_template_id( $id ) {
|
||||
// Decode empty space.
|
||||
$id = urldecode( $id );
|
||||
|
||||
$last_slash_pos = strrpos( $id, '/' );
|
||||
|
@ -16,7 +16,11 @@
|
||||
*/
|
||||
class WP_REST_Themes_Controller extends WP_REST_Controller {
|
||||
|
||||
const PATTERN = '[^.\/]+(?:\/[^.\/]+)?';
|
||||
/**
|
||||
* Matches theme's directory: `/themes/<subdirectory>/<theme>/` or `/themes/<theme>/`.
|
||||
* Excludes invalid directory name characters: `/:<>*?"|`.
|
||||
*/
|
||||
const PATTERN = '[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -58,6 +62,7 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
|
||||
'stylesheet' => array(
|
||||
'description' => __( "The theme's stylesheet. This uniquely identifies the theme." ),
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => array( $this, '_sanitize_stylesheet_callback' ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
@ -70,6 +75,18 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the stylesheet to decode endpoint.
|
||||
*
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $stylesheet The stylesheet name.
|
||||
* @return string Sanitized stylesheet.
|
||||
*/
|
||||
public function _sanitize_stylesheet_callback( $stylesheet ) {
|
||||
return urldecode( $stylesheet );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given request has access to read the theme.
|
||||
*
|
||||
|
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Block theme.
|
||||
*/
|
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
echo 'PHP template for page with ID 1';
|
@ -0,0 +1,3 @@
|
||||
<!-- wp:paragraph -->
|
||||
<p>Large Héader Témplaté Part</p>
|
||||
<!-- /wp:paragraph -->
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
Theme Name: Block Theme [0.4.0]
|
||||
Theme URI: https://wordpress.org/
|
||||
Description: Has different characters in theme directory name for testing purposes.
|
||||
Version: 0.4.0
|
||||
Text Domain: block-theme
|
||||
*/
|
@ -0,0 +1,9 @@
|
||||
<!-- wp:template-part {"slug":"header-large-dark","tagName":"header"} /-->
|
||||
|
||||
<!-- wp:group {"tagName":"main"} -->
|
||||
<main class="wp-block-group">
|
||||
<!-- wp:post-content {"layout":{"inherit":true}} /-->
|
||||
</main>
|
||||
<!-- /wp:group -->
|
||||
|
||||
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
|
71
tests/phpunit/data/themedir1/block_theme-[0.4.0]/theme.json
Normal file
71
tests/phpunit/data/themedir1/block_theme-[0.4.0]/theme.json
Normal file
@ -0,0 +1,71 @@
|
||||
{
|
||||
"version": 1,
|
||||
"settings": {
|
||||
"color": {
|
||||
"palette": [
|
||||
{
|
||||
"slug": "light",
|
||||
"name": "Light",
|
||||
"color": "#f5f7f9"
|
||||
},
|
||||
{
|
||||
"slug": "dark",
|
||||
"name": "Dark",
|
||||
"color": "#000"
|
||||
}
|
||||
],
|
||||
"gradients": [
|
||||
{
|
||||
"name": "Custom gradient",
|
||||
"gradient": "linear-gradient(135deg,rgba(0,0,0) 0%,rgb(0,0,0) 100%)",
|
||||
"slug": "custom-gradient"
|
||||
}
|
||||
],
|
||||
"custom": false,
|
||||
"customGradient": false
|
||||
},
|
||||
"typography": {
|
||||
"fontSizes": [
|
||||
{
|
||||
"name": "Custom",
|
||||
"slug": "custom",
|
||||
"size": "100px"
|
||||
}
|
||||
],
|
||||
"customFontSize": false,
|
||||
"customLineHeight": true
|
||||
},
|
||||
"spacing": {
|
||||
"units": [
|
||||
"rem"
|
||||
],
|
||||
"customPadding": true
|
||||
},
|
||||
"blocks": {
|
||||
"core/paragraph": {
|
||||
"color": {
|
||||
"palette": [
|
||||
{
|
||||
"slug": "light",
|
||||
"name": "Light",
|
||||
"color": "#f5f7f9"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"customTemplates": [
|
||||
{
|
||||
"name": "page-home",
|
||||
"title": "Homepage template"
|
||||
}
|
||||
],
|
||||
"templateParts": [
|
||||
{
|
||||
"name": "small-header",
|
||||
"title": "Small Header",
|
||||
"area": "header"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* Block theme.
|
||||
*/
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
Theme Name: Block Theme [1.0.0] in subdirectory
|
||||
Theme URI: https://wordpress.org/
|
||||
Description: Has different characters in theme directory name for testing purposes.
|
||||
Version: 0.4.0
|
||||
Text Domain: block-theme
|
||||
*/
|
@ -0,0 +1,71 @@
|
||||
{
|
||||
"version": 1,
|
||||
"settings": {
|
||||
"color": {
|
||||
"palette": [
|
||||
{
|
||||
"slug": "light",
|
||||
"name": "Light",
|
||||
"color": "#f5f7f9"
|
||||
},
|
||||
{
|
||||
"slug": "dark",
|
||||
"name": "Dark",
|
||||
"color": "#000"
|
||||
}
|
||||
],
|
||||
"gradients": [
|
||||
{
|
||||
"name": "Custom gradient",
|
||||
"gradient": "linear-gradient(135deg,rgba(0,0,0) 0%,rgb(0,0,0) 100%)",
|
||||
"slug": "custom-gradient"
|
||||
}
|
||||
],
|
||||
"custom": false,
|
||||
"customGradient": false
|
||||
},
|
||||
"typography": {
|
||||
"fontSizes": [
|
||||
{
|
||||
"name": "Custom",
|
||||
"slug": "custom",
|
||||
"size": "100px"
|
||||
}
|
||||
],
|
||||
"customFontSize": false,
|
||||
"customLineHeight": true
|
||||
},
|
||||
"spacing": {
|
||||
"units": [
|
||||
"rem"
|
||||
],
|
||||
"customPadding": true
|
||||
},
|
||||
"blocks": {
|
||||
"core/paragraph": {
|
||||
"color": {
|
||||
"palette": [
|
||||
{
|
||||
"slug": "light",
|
||||
"name": "Light",
|
||||
"color": "#f5f7f9"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"customTemplates": [
|
||||
{
|
||||
"name": "page-home",
|
||||
"title": "Homepage template"
|
||||
}
|
||||
],
|
||||
"templateParts": [
|
||||
{
|
||||
"name": "small-header",
|
||||
"title": "Small Header",
|
||||
"area": "header"
|
||||
}
|
||||
]
|
||||
}
|
@ -98,23 +98,23 @@ class WP_REST_Global_Styles_Controller_Test extends WP_Test_REST_Controller_Test
|
||||
public function test_register_routes() {
|
||||
$routes = rest_get_server()->get_routes();
|
||||
$this->assertArrayHasKey(
|
||||
'/wp/v2/global-styles/(?P<id>[\/\s%\w\.\(\)\[\]\@_\-]+)',
|
||||
'/wp/v2/global-styles/(?P<id>[\/\w-]+)',
|
||||
$routes,
|
||||
'Single global style based on the given ID route does not exist'
|
||||
);
|
||||
$this->assertCount(
|
||||
2,
|
||||
$routes['/wp/v2/global-styles/(?P<id>[\/\s%\w\.\(\)\[\]\@_\-]+)'],
|
||||
$routes['/wp/v2/global-styles/(?P<id>[\/\w-]+)'],
|
||||
'Single global style based on the given ID route does not have exactly two elements'
|
||||
);
|
||||
$this->assertArrayHasKey(
|
||||
'/wp/v2/global-styles/themes/(?P<stylesheet>[\/\s%\w\.\(\)\[\]\@_\-]+)',
|
||||
'/wp/v2/global-styles/themes/(?P<stylesheet>[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)',
|
||||
$routes,
|
||||
'Theme global styles route does not exist'
|
||||
);
|
||||
$this->assertCount(
|
||||
1,
|
||||
$routes['/wp/v2/global-styles/themes/(?P<stylesheet>[\/\s%\w\.\(\)\[\]\@_\-]+)'],
|
||||
$routes['/wp/v2/global-styles/themes/(?P<stylesheet>[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)'],
|
||||
'Theme global styles route does not have exactly one element'
|
||||
);
|
||||
}
|
||||
@ -164,14 +164,17 @@ class WP_REST_Global_Styles_Controller_Test extends WP_Test_REST_Controller_Test
|
||||
* @dataProvider data_get_theme_item_invalid_theme_dirname
|
||||
* @covers WP_REST_Global_Styles_Controller::get_theme_item
|
||||
* @ticket 54596
|
||||
*
|
||||
* @param string $theme_dirname Theme directory to test.
|
||||
* @param string $expected Expected error code.
|
||||
*/
|
||||
public function test_get_theme_item_invalid_theme_dirname( $theme_dirname ) {
|
||||
public function test_get_theme_item_invalid_theme_dirname( $theme_dirname, $expected ) {
|
||||
wp_set_current_user( self::$admin_id );
|
||||
switch_theme( $theme_dirname );
|
||||
|
||||
$request = new WP_REST_Request( 'GET', '/wp/v2/global-styles/themes/' . $theme_dirname );
|
||||
$response = rest_get_server()->dispatch( $request );
|
||||
$this->assertErrorResponse( 'rest_no_route', $response, 404 );
|
||||
$this->assertErrorResponse( $expected, $response, 404 );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -181,12 +184,39 @@ class WP_REST_Global_Styles_Controller_Test extends WP_Test_REST_Controller_Test
|
||||
*/
|
||||
public function data_get_theme_item_invalid_theme_dirname() {
|
||||
return array(
|
||||
'with |' => array( 'my|theme' ),
|
||||
'with +' => array( 'my+theme' ),
|
||||
'with {}' => array( 'my{theme}' ),
|
||||
'with #' => array( 'my#theme' ),
|
||||
'with !' => array( 'my!theme' ),
|
||||
'multiple invalid chars' => array( 'mytheme-[_(+@)]#! v4.0' ),
|
||||
'+' => array(
|
||||
'theme_dirname' => 'my+theme+',
|
||||
'expected' => 'rest_theme_not_found',
|
||||
),
|
||||
':' => array(
|
||||
'theme_dirname' => 'my:theme:',
|
||||
'expected' => 'rest_no_route',
|
||||
),
|
||||
'<>' => array(
|
||||
'theme_dirname' => 'my<theme>',
|
||||
'expected' => 'rest_no_route',
|
||||
),
|
||||
'*' => array(
|
||||
'theme_dirname' => 'my*theme*',
|
||||
'expected' => 'rest_no_route',
|
||||
),
|
||||
'?' => array(
|
||||
'theme_dirname' => 'my?theme?',
|
||||
'expected' => 'rest_no_route',
|
||||
),
|
||||
'"' => array(
|
||||
'theme_dirname' => 'my"theme?"',
|
||||
'expected' => 'rest_no_route',
|
||||
),
|
||||
'| (invalid on Windows)' => array(
|
||||
'theme_dirname' => 'my|theme|',
|
||||
'expected' => 'rest_no_route',
|
||||
),
|
||||
// Themes deep in subdirectories.
|
||||
'2 subdirectories deep' => array(
|
||||
'theme_dirname' => 'subdir/subsubdir/mytheme',
|
||||
'expected' => 'rest_global_styles_not_found',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -194,6 +224,8 @@ class WP_REST_Global_Styles_Controller_Test extends WP_Test_REST_Controller_Test
|
||||
* @dataProvider data_get_theme_item
|
||||
* @covers WP_REST_Global_Styles_Controller::get_theme_item
|
||||
* @ticket 54596
|
||||
*
|
||||
* @param string $theme Theme directory to test.
|
||||
*/
|
||||
public function test_get_theme_item( $theme ) {
|
||||
wp_set_current_user( self::$admin_id );
|
||||
@ -216,18 +248,34 @@ class WP_REST_Global_Styles_Controller_Test extends WP_Test_REST_Controller_Test
|
||||
*/
|
||||
public function data_get_theme_item() {
|
||||
return array(
|
||||
'alphabetic chars' => array( 'mytheme' ),
|
||||
'alphanumeric chars' => array( 'mythemev1' ),
|
||||
'alphabetic' => array( 'mytheme' ),
|
||||
'alphanumeric' => array( 'mythemev1' ),
|
||||
'àáâãäåæç' => array( 'àáâãäåæç' ),
|
||||
'space' => array( 'my theme' ),
|
||||
'-' => array( 'my-theme' ),
|
||||
'_' => array( 'my_theme' ),
|
||||
'.' => array( 'mytheme0.1' ),
|
||||
'- and .' => array( 'my-theme-0.1' ),
|
||||
'space and .' => array( 'mytheme v0.1' ),
|
||||
'space, -, _, .' => array( 'my-theme-v0.1' ),
|
||||
'-_.' => array( 'my_theme-0.1' ),
|
||||
'[]' => array( 'my[theme]' ),
|
||||
'()' => array( 'my(theme)' ),
|
||||
'@' => array( 'my@theme' ),
|
||||
'{}' => array( 'my{theme}' ),
|
||||
'&=#@!$,^~%' => array( 'theme &=#@!$,^~%' ),
|
||||
'all combined' => array( 'thémé {}&=@!$,^~%[0.1](-_-)' ),
|
||||
|
||||
// Themes in a subdirectory.
|
||||
'subdir: alphabetic' => array( 'subdir/mytheme' ),
|
||||
'subdir: alphanumeric in theme' => array( 'subdir/mythemev1' ),
|
||||
'subdir: alphanumeric in subdir' => array( 'subdirv1/mytheme' ),
|
||||
'subdir: alphanumeric in both' => array( 'subdirv1/mythemev1' ),
|
||||
'subdir: àáâãäåæç in theme' => array( 'subdir/àáâãäåæç' ),
|
||||
'subdir: àáâãäåæç in subdir' => array( 'àáâãäåæç/mythemev1' ),
|
||||
'subdir: àáâãäåæç in both' => array( 'àáâãäåæç/àáâãäåæç' ),
|
||||
'subdir: space in theme' => array( 'subdir/my theme' ),
|
||||
'subdir: space in subdir' => array( 'sub dir/mytheme' ),
|
||||
'subdir: space in both' => array( 'sub dir/my theme' ),
|
||||
'subdir: -_. in theme' => array( 'subdir/my_theme-0.1' ),
|
||||
'subdir: -_. in subdir' => array( 'sub_dir-0.1/mytheme' ),
|
||||
'subdir: -_. in both' => array( 'sub_dir-0.1/my_theme-0.1' ),
|
||||
'subdir: all combined in theme' => array( 'subdir/thémé {}&=@!$,^~%[0.1](-_-)' ),
|
||||
'subdir: all combined in subdir' => array( 'sűbdīr {}&=@!$,^~%[0.1](-_-)/mytheme' ),
|
||||
'subdir: all combined in both' => array( 'sűbdīr {}&=@!$,^~%[0.1](-_-)/thémé {}&=@!$,^~%[0.1](-_-)' ),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -135,8 +135,8 @@ class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase {
|
||||
'/wp/v2/users/(?P<user_id>(?:[\\d]+|me))/application-passwords/(?P<uuid>[\\w\\-]+)',
|
||||
'/wp/v2/comments',
|
||||
'/wp/v2/comments/(?P<id>[\\d]+)',
|
||||
'/wp/v2/global-styles/(?P<id>[\/\s%\w\.\(\)\[\]\@_\-]+)',
|
||||
'/wp/v2/global-styles/themes/(?P<stylesheet>[\/\s%\w\.\(\)\[\]\@_\-]+)',
|
||||
'/wp/v2/global-styles/(?P<id>[\/\w-]+)',
|
||||
'/wp/v2/global-styles/themes/(?P<stylesheet>[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)',
|
||||
'/wp/v2/search',
|
||||
'/wp/v2/block-renderer/(?P<name>[a-z0-9-]+/[a-z0-9-]+)',
|
||||
'/wp/v2/block-types',
|
||||
@ -144,19 +144,19 @@ class WP_Test_REST_Schema_Initialization extends WP_Test_REST_TestCase {
|
||||
'/wp/v2/block-types/(?P<namespace>[a-zA-Z0-9_-]+)/(?P<name>[a-zA-Z0-9_-]+)',
|
||||
'/wp/v2/settings',
|
||||
'/wp/v2/template-parts',
|
||||
'/wp/v2/template-parts/(?P<id>[\/\s%\w\.\(\)\[\]\@_\-]+)',
|
||||
'/wp/v2/template-parts/(?P<id>[\d]+)/autosaves',
|
||||
'/wp/v2/template-parts/(?P<id>([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w-]+)',
|
||||
'/wp/v2/template-parts/(?P<parent>[\d]+)/autosaves/(?P<id>[\d]+)',
|
||||
'/wp/v2/template-parts/(?P<parent>[\d]+)/revisions',
|
||||
'/wp/v2/template-parts/(?P<parent>[\d]+)/revisions/(?P<id>[\d]+)',
|
||||
'/wp/v2/templates',
|
||||
'/wp/v2/templates/(?P<id>[\/\s%\w\.\(\)\[\]\@_\-]+)',
|
||||
'/wp/v2/templates/(?P<id>[\d]+)/autosaves',
|
||||
'/wp/v2/templates/(?P<id>([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w-]+)',
|
||||
'/wp/v2/templates/(?P<parent>[\d]+)/autosaves/(?P<id>[\d]+)',
|
||||
'/wp/v2/templates/(?P<parent>[\d]+)/revisions',
|
||||
'/wp/v2/templates/(?P<parent>[\d]+)/revisions/(?P<id>[\d]+)',
|
||||
'/wp/v2/themes',
|
||||
'/wp/v2/themes/(?P<stylesheet>[^.\/]+(?:\/[^.\/]+)?)',
|
||||
'/wp/v2/themes/(?P<stylesheet>[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)',
|
||||
'/wp/v2/plugins',
|
||||
'/wp/v2/plugins/(?P<plugin>[^.\/]+(?:\/[^.\/]+)?)',
|
||||
'/wp/v2/block-directory/search',
|
||||
|
@ -1285,15 +1285,86 @@ class WP_Test_REST_Themes_Controller extends WP_Test_REST_Controller_Testcase {
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 54349
|
||||
* @dataProvider data_get_item_non_subdir_theme
|
||||
* @ticket 54596
|
||||
* @covers WP_REST_Themes_Controller::get_item
|
||||
*
|
||||
* @param string $theme_dir Theme directory to test.
|
||||
* @param string $expected_name Expected theme name.
|
||||
*/
|
||||
public function test_get_item_subdirectory_theme() {
|
||||
public function test_get_item_non_subdir_theme( $theme_dir, $expected_name ) {
|
||||
wp_set_current_user( self::$admin_id );
|
||||
$request = new WP_REST_Request( 'GET', self::$themes_route . '/subdir/theme2' );
|
||||
$request = new WP_REST_Request( 'GET', self::$themes_route . $theme_dir );
|
||||
$response = rest_do_request( $request );
|
||||
|
||||
$this->assertSame( 200, $response->get_status() );
|
||||
$this->assertSame( 'My Subdir Theme', $response->get_data()['name']['raw'] );
|
||||
$this->assertSame( $expected_name, $response->get_data()['name']['raw'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data_get_item_non_subdir_theme() {
|
||||
return array(
|
||||
'parent theme' => array(
|
||||
'theme_dir' => '/block-theme',
|
||||
'expected_name' => 'Block Theme',
|
||||
),
|
||||
'child theme' => array(
|
||||
'theme_dir' => '/block-theme-child',
|
||||
'expected_name' => 'Block Theme Child Theme',
|
||||
),
|
||||
'theme with _-[]. characters' => array(
|
||||
'theme_dir' => '/block_theme-[0.4.0]',
|
||||
'expected_name' => 'Block Theme [0.4.0]',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_get_item_subdirectory_theme
|
||||
* @ticket 54349
|
||||
* @ticket 54596
|
||||
* @covers WP_REST_Themes_Controller::get_item
|
||||
*
|
||||
* @param string $theme_dir Theme directory to test.
|
||||
* @param string $expected_name Expected theme name.
|
||||
*/
|
||||
public function test_get_item_subdirectory_theme( $theme_dir, $expected_name ) {
|
||||
wp_set_current_user( self::$admin_id );
|
||||
$request = new WP_REST_Request( 'GET', self::$themes_route . $theme_dir );
|
||||
$response = rest_do_request( $request );
|
||||
|
||||
$this->assertSame(
|
||||
200,
|
||||
$response->get_status(),
|
||||
'A 200 OK status was not returned.'
|
||||
);
|
||||
$this->assertSame(
|
||||
$expected_name,
|
||||
$response->get_data()['name']['raw'],
|
||||
'The actual theme name was not the expected theme name.'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data_get_item_subdirectory_theme() {
|
||||
return array(
|
||||
'theme2' => array(
|
||||
'theme_dir' => '/subdir/theme2',
|
||||
'expected_name' => 'My Subdir Theme',
|
||||
),
|
||||
'theme with _-[]. characters' => array(
|
||||
'theme_dir' => '/subdir/block_theme-[1.0.0]',
|
||||
'expected_name' => 'Block Theme [1.0.0] in subdirectory',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,7 +65,7 @@ class Tests_REST_WpRestTemplatesController extends WP_Test_REST_Controller_Testc
|
||||
'Templates route does not exist'
|
||||
);
|
||||
$this->assertArrayHasKey(
|
||||
'/wp/v2/templates/(?P<id>[\/\s%\w\.\(\)\[\]\@_\-]+)',
|
||||
'/wp/v2/templates/(?P<id>([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w-]+)',
|
||||
$routes,
|
||||
'Single template based on the given ID route does not exist'
|
||||
);
|
||||
@ -208,6 +208,119 @@ class Tests_REST_WpRestTemplatesController extends WP_Test_REST_Controller_Testc
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_get_item_with_valid_theme_dirname
|
||||
* @covers WP_REST_Templates_Controller::get_item
|
||||
* @ticket 54596
|
||||
*
|
||||
* @param string $theme_dir Theme directory to test.
|
||||
* @param string $template Template to test.
|
||||
* @param array $args Arguments to create the 'wp_template" post.
|
||||
*/
|
||||
public function test_get_item_with_valid_theme_dirname( $theme_dir, $template, array $args ) {
|
||||
wp_set_current_user( self::$admin_id );
|
||||
switch_theme( $theme_dir );
|
||||
|
||||
// Set up template post.
|
||||
$args['post_type'] = 'wp_template';
|
||||
$args['tax_input'] = array(
|
||||
'wp_theme' => array(
|
||||
get_stylesheet(),
|
||||
),
|
||||
);
|
||||
$post = self::factory()->post->create_and_get( $args );
|
||||
wp_set_post_terms( $post->ID, get_stylesheet(), 'wp_theme' );
|
||||
|
||||
$request = new WP_REST_Request( 'GET', "/wp/v2/templates/{$theme_dir}//{$template}" );
|
||||
$response = rest_get_server()->dispatch( $request );
|
||||
$data = $response->get_data();
|
||||
unset( $data['content'] );
|
||||
unset( $data['_links'] );
|
||||
|
||||
$this->assertSameSetsWithIndex(
|
||||
array(
|
||||
'id' => "{$theme_dir}//{$template}",
|
||||
'theme' => $theme_dir,
|
||||
'slug' => $template,
|
||||
'source' => 'custom',
|
||||
'origin' => null,
|
||||
'type' => 'wp_template',
|
||||
'description' => $args['post_excerpt'],
|
||||
'title' => array(
|
||||
'raw' => $args['post_title'],
|
||||
'rendered' => $args['post_title'],
|
||||
),
|
||||
'status' => 'publish',
|
||||
'wp_id' => $post->ID,
|
||||
'has_theme_file' => false,
|
||||
'is_custom' => true,
|
||||
'author' => self::$admin_id,
|
||||
),
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function data_get_item_with_valid_theme_dirname() {
|
||||
$theme_root_dir = DIR_TESTDATA . '/themedir1/';
|
||||
return array(
|
||||
'template parts: parent theme' => array(
|
||||
'theme_dir' => 'themedir1/block-theme',
|
||||
'template' => 'small-header',
|
||||
'args' => array(
|
||||
'post_name' => 'small-header',
|
||||
'post_title' => 'Small Header Template',
|
||||
'post_content' => file_get_contents( $theme_root_dir . '/block-theme/parts/small-header.html' ),
|
||||
'post_excerpt' => 'Description of small header template.',
|
||||
),
|
||||
),
|
||||
'template: parent theme' => array(
|
||||
'theme_dir' => 'themedir1/block-theme',
|
||||
'template' => 'page-home',
|
||||
'args' => array(
|
||||
'post_name' => 'page-home',
|
||||
'post_title' => 'Home Page Template',
|
||||
'post_content' => file_get_contents( $theme_root_dir . 'block-theme/templates/page-home.html' ),
|
||||
'post_excerpt' => 'Description of page home template.',
|
||||
),
|
||||
),
|
||||
'template: child theme' => array(
|
||||
'theme_dir' => 'themedir1/block-theme-child',
|
||||
'template' => 'page-1',
|
||||
'args' => array(
|
||||
'post_name' => 'page-1',
|
||||
'post_title' => 'Page 1 Template',
|
||||
'post_content' => file_get_contents( $theme_root_dir . 'block-theme-child/templates/page-1.html' ),
|
||||
'post_excerpt' => 'Description of page 1 template.',
|
||||
),
|
||||
),
|
||||
'template part: subdir with _-[]. characters' => array(
|
||||
'theme_dir' => 'themedir1/block_theme-[0.4.0]',
|
||||
'template' => 'large-header',
|
||||
'args' => array(
|
||||
'post_name' => 'large-header',
|
||||
'post_title' => 'Large Header Template Part',
|
||||
'post_content' => file_get_contents( $theme_root_dir . 'block_theme-[0.4.0]/parts/large-header.html' ),
|
||||
'post_excerpt' => 'Description of large header template.',
|
||||
),
|
||||
),
|
||||
'template: subdir with _-[]. characters' => array(
|
||||
'theme_dir' => 'themedir1/block_theme-[0.4.0]',
|
||||
'template' => 'page-large-header',
|
||||
'args' => array(
|
||||
'post_name' => 'page-large-header',
|
||||
'post_title' => 'Page Large Template',
|
||||
'post_content' => file_get_contents( $theme_root_dir . 'block_theme-[0.4.0]/templates/page-large-header.html' ),
|
||||
'post_excerpt' => 'Description of page large template.',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 54507
|
||||
* @dataProvider get_template_ids_to_sanitize
|
||||
|
@ -163,6 +163,8 @@ class Tests_Theme_ThemeDir extends WP_UnitTestCase {
|
||||
'REST Theme',
|
||||
'Block Theme',
|
||||
'Block Theme Child Theme',
|
||||
'Block Theme [0.4.0]',
|
||||
'Block Theme [1.0.0] in subdirectory',
|
||||
);
|
||||
|
||||
sort( $theme_names );
|
||||
|
@ -5140,7 +5140,7 @@ mockedApiResponse.Schema = {
|
||||
]
|
||||
}
|
||||
},
|
||||
"/wp/v2/templates/(?P<id>[\\/\\s%\\w\\.\\(\\)\\[\\]\\@_\\-]+)": {
|
||||
"/wp/v2/templates/(?P<id>([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w-]+)": {
|
||||
"namespace": "wp/v2",
|
||||
"methods": [
|
||||
"GET",
|
||||
@ -5792,7 +5792,7 @@ mockedApiResponse.Schema = {
|
||||
]
|
||||
}
|
||||
},
|
||||
"/wp/v2/template-parts/(?P<id>[\\/\\s%\\w\\.\\(\\)\\[\\]\\@_\\-]+)": {
|
||||
"/wp/v2/template-parts/(?P<id>([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w-]+)": {
|
||||
"namespace": "wp/v2",
|
||||
"methods": [
|
||||
"GET",
|
||||
@ -9424,7 +9424,7 @@ mockedApiResponse.Schema = {
|
||||
}
|
||||
]
|
||||
},
|
||||
"/wp/v2/global-styles/themes/(?P<stylesheet>[\\/\\s%\\w\\.\\(\\)\\[\\]\\@_\\-]+)": {
|
||||
"/wp/v2/global-styles/themes/(?P<stylesheet>[^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)": {
|
||||
"namespace": "wp/v2",
|
||||
"methods": [
|
||||
"GET"
|
||||
@ -9444,7 +9444,7 @@ mockedApiResponse.Schema = {
|
||||
}
|
||||
]
|
||||
},
|
||||
"/wp/v2/global-styles/(?P<id>[\\/\\s%\\w\\.\\(\\)\\[\\]\\@_\\-]+)": {
|
||||
"/wp/v2/global-styles/(?P<id>[\\/\\w-]+)": {
|
||||
"namespace": "wp/v2",
|
||||
"methods": [
|
||||
"GET",
|
||||
@ -9668,7 +9668,7 @@ mockedApiResponse.Schema = {
|
||||
"self": "http://example.org/index.php?rest_route=/wp/v2/themes"
|
||||
}
|
||||
},
|
||||
"/wp/v2/themes/(?P<stylesheet>[^.\\/]+(?:\\/[^.\\/]+)?)": {
|
||||
"/wp/v2/themes/(?P<stylesheet>[^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)": {
|
||||
"namespace": "wp/v2",
|
||||
"methods": [
|
||||
"GET"
|
||||
|
Loading…
x
Reference in New Issue
Block a user