From 60edf363944a7267cdfef5e3e0e83a7a9e188729 Mon Sep 17 00:00:00 2001 From: Timothy Jacobs Date: Thu, 12 Mar 2020 02:40:29 +0000 Subject: [PATCH] REST API: Introduce "hex-color" JSON Schema format. Props spacedmonkey, chrisvanpatten. Fixes #49270. git-svn-id: https://develop.svn.wordpress.org/trunk@47450 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/rest-api.php | 26 +++++++++++++++++++ .../tests/rest-api/rest-controller.php | 21 +++++++++++++++ .../rest-api/rest-schema-sanitization.php | 13 ++++++++++ .../tests/rest-api/rest-schema-validation.php | 13 ++++++++++ .../tests/rest-api/rest-test-controller.php | 5 ++++ 5 files changed, 78 insertions(+) diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index bdfd8fac42..9f63b87f93 100644 --- a/src/wp-includes/rest-api.php +++ b/src/wp-includes/rest-api.php @@ -970,6 +970,23 @@ function rest_parse_date( $date, $force_utc = false ) { return strtotime( $date ); } +/** + * Parses a 3 or 6 digit hex color (with #). + * + * @since 5.4.0 + * + * @param string $color 3 or 6 digit hex color (with #). + * @return string|false + */ +function rest_parse_hex_color( $color ) { + $regex = '|^#([A-Fa-f0-9]{3}){1,2}$|'; + if ( ! preg_match( $regex, $color, $matches ) ) { + return false; + } + + return $color; +} + /** * Parses a date into both its local and UTC equivalent, in MySQL datetime format. * @@ -1327,6 +1344,12 @@ function rest_validate_value_from_schema( $value, $args, $param = '' ) { if ( isset( $args['format'] ) ) { switch ( $args['format'] ) { + case 'hex-color': + if ( ! rest_parse_hex_color( $value ) ) { + return new WP_Error( 'rest_invalid_hex_color', __( 'Invalid hex color.' ) ); + } + break; + case 'date-time': if ( ! rest_parse_date( $value ) ) { return new WP_Error( 'rest_invalid_date', __( 'Invalid date.' ) ); @@ -1485,6 +1508,9 @@ function rest_sanitize_value_from_schema( $value, $args ) { if ( isset( $args['format'] ) ) { switch ( $args['format'] ) { + case 'hex-color': + return (string) sanitize_hex_color( $value ); + case 'date-time': return sanitize_text_field( $value ); diff --git a/tests/phpunit/tests/rest-api/rest-controller.php b/tests/phpunit/tests/rest-api/rest-controller.php index 6de5cf5482..0fa98078b5 100644 --- a/tests/phpunit/tests/rest-api/rest-controller.php +++ b/tests/phpunit/tests/rest-api/rest-controller.php @@ -27,6 +27,10 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase { 'somestring' => array( 'type' => 'string', ), + 'somehex' => array( + 'type' => 'string', + 'format' => 'hex-color', + ), 'someenum' => array( 'type' => 'string', 'enum' => array( 'a' ), @@ -166,6 +170,21 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase { ); } + /** + * @ticket 49270 + */ + public function test_validate_schema_format_hex_color() { + + $this->assertTrue( + rest_validate_request_arg( '#000000', $this->request, 'somehex' ) + ); + + $this->assertErrorResponse( + 'rest_invalid_hex_color', + rest_validate_request_arg( 'wibble', $this->request, 'somehex' ) + ); + } + public function test_validate_schema_format_date_time() { $this->assertTrue( @@ -218,6 +237,7 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase { 'someurl', 'somedate', 'someemail', + 'somehex', 'someenum', 'someargoptions', 'somedefault', @@ -247,6 +267,7 @@ class WP_Test_REST_Controller extends WP_Test_REST_TestCase { 'someurl', 'somedate', 'someemail', + 'somehex', 'someenum', 'someargoptions', 'somedefault', diff --git a/tests/phpunit/tests/rest-api/rest-schema-sanitization.php b/tests/phpunit/tests/rest-api/rest-schema-sanitization.php index fc100f7b2b..29fa6b5362 100644 --- a/tests/phpunit/tests/rest-api/rest-schema-sanitization.php +++ b/tests/phpunit/tests/rest-api/rest-schema-sanitization.php @@ -77,6 +77,19 @@ class WP_Test_REST_Schema_Sanitization extends WP_UnitTestCase { $this->assertEquals( '2001:DB8:0:0:8:800:200C:417A', rest_sanitize_value_from_schema( '2001:DB8:0:0:8:800:200C:417A', $schema ) ); } + /** + * @ticket 49270 + */ + public function test_format_hex_color() { + $schema = array( + 'type' => 'string', + 'format' => 'hex-color', + ); + $this->assertEquals( '#000000', rest_sanitize_value_from_schema( '#000000', $schema ) ); + $this->assertEquals( '#FFF', rest_sanitize_value_from_schema( '#FFF', $schema ) ); + $this->assertEquals( '', rest_sanitize_value_from_schema( 'WordPress', $schema ) ); + } + public function test_type_array() { $schema = array( 'type' => 'array', diff --git a/tests/phpunit/tests/rest-api/rest-schema-validation.php b/tests/phpunit/tests/rest-api/rest-schema-validation.php index a6722d42a7..dd338f5068 100644 --- a/tests/phpunit/tests/rest-api/rest-schema-validation.php +++ b/tests/phpunit/tests/rest-api/rest-schema-validation.php @@ -72,6 +72,19 @@ class WP_Test_REST_Schema_Validation extends WP_UnitTestCase { $this->assertWPError( rest_validate_value_from_schema( 'email', $schema ) ); } + /** + * @ticket 49270 + */ + public function test_format_hex_color() { + $schema = array( + 'type' => 'string', + 'format' => 'hex-color', + ); + $this->assertTrue( rest_validate_value_from_schema( '#000000', $schema ) ); + $this->assertTrue( rest_validate_value_from_schema( '#FFF', $schema ) ); + $this->assertWPError( rest_validate_value_from_schema( 'WordPress', $schema ) ); + } + public function test_format_date_time() { $schema = array( 'type' => 'string', diff --git a/tests/phpunit/tests/rest-api/rest-test-controller.php b/tests/phpunit/tests/rest-api/rest-test-controller.php index b79e7cf59b..a06800c3ce 100644 --- a/tests/phpunit/tests/rest-api/rest-test-controller.php +++ b/tests/phpunit/tests/rest-api/rest-test-controller.php @@ -64,6 +64,11 @@ class WP_REST_Test_Controller extends WP_REST_Controller { 'format' => 'email', 'context' => array( 'view' ), ), + 'somehex' => array( + 'type' => 'string', + 'format' => 'hex-color', + 'context' => array( 'view' ), + ), 'someenum' => array( 'type' => 'string', 'enum' => array( 'a', 'b', 'c' ),