Skip to content

Commit

Permalink
REST API: Support . in theme directory names in `WP_REST_Global_Sty…
Browse files Browse the repository at this point in the history
…les_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
  • Loading branch information
hellofromtonya committed Dec 21, 2021
1 parent b161cfc commit e1f5600
Show file tree
Hide file tree
Showing 18 changed files with 493 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,14 @@ public function register_routes() {
// 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,
Expand All @@ -61,7 +68,7 @@ public function register_routes() {
// 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,
Expand All @@ -88,8 +95,8 @@ public function register_routes() {

/**
* 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
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,16 @@ public function register_routes() {
// 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(
Expand Down Expand Up @@ -149,7 +158,6 @@ protected function permissions_check( $request ) {
* @return string Sanitized template ID.
*/
public function _sanitize_template_id( $id ) {
// Decode empty space.
$id = urldecode( $id );

$last_slash_pos = strrpos( $id, '/' );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -56,8 +60,9 @@ public function register_routes() {
array(
'args' => array(
'stylesheet' => array(
'description' => __( "The theme's stylesheet. This uniquely identifies the theme." ),
'type' => 'string',
'description' => __( "The theme's stylesheet. This uniquely identifies the theme." ),
'type' => 'string',
'sanitize_callback' => array( $this, '_sanitize_stylesheet_callback' ),
),
),
array(
Expand All @@ -70,6 +75,18 @@ public function register_routes() {
);
}

/**
* 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.
*
Expand Down
4 changes: 4 additions & 0 deletions tests/phpunit/data/themedir1/block_theme-[0.4.0]/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php
/**
* Block theme.
*/
3 changes: 3 additions & 0 deletions tests/phpunit/data/themedir1/block_theme-[0.4.0]/page-1.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php

echo 'PHP template for page with ID 1';
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<!-- wp:paragraph -->
<p>Large Héader Témplaté Part</p>
<!-- /wp:paragraph -->
7 changes: 7 additions & 0 deletions tests/phpunit/data/themedir1/block_theme-[0.4.0]/style.css
Original file line number Diff line number Diff line change
@@ -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
*/
Original file line number Diff line number Diff line change
@@ -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 changes: 71 additions & 0 deletions tests/phpunit/data/themedir1/block_theme-[0.4.0]/theme.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?php
/**
* Block theme.
*/
Original file line number Diff line number Diff line change
@@ -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
*/
71 changes: 71 additions & 0 deletions tests/phpunit/data/themedir1/subdir/block_theme-[1.0.0]/theme.json
Original file line number Diff line number Diff line change
@@ -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"
}
]
}
Loading

0 comments on commit e1f5600

Please sign in to comment.