From 0b16d7a71acef1222d08c114adddb0766f3261bc Mon Sep 17 00:00:00 2001 From: wppoland Date: Sun, 3 May 2026 16:58:44 +0200 Subject: [PATCH] REST API: Allow `null` `origin` in the templates schema. `WP_REST_Templates_Controller::prepare_item_for_response()` can return `origin: null` for templates that do not come from a customizer/theme/plugin source. The schema previously declared `origin` as `string`, so responses with `origin: null` failed schema validation under strict-mode REST clients. This commit widens the schema to match the runtime behavior: * `origin` becomes `[ string, null ]`. Adds tests covering: * The `origin` schema accepts `null`. * A theme template returns `null` for `origin` against the new schema. (Note: `modified` returning `null` was separately resolved in [62941] / #65728). See #64168. --- .../class-wp-rest-templates-controller.php | 2 +- .../rest-api/wpRestTemplatesController.php | 32 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php index 190eea6b203bb..eabf907590b99 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php @@ -1106,7 +1106,7 @@ public function get_item_schema() { ), 'origin' => array( 'description' => __( 'Source of a customized template' ), - 'type' => 'string', + 'type' => array( 'string', 'null' ), 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), diff --git a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php index 3eee1426ecb87..0f1fd1f5928ad 100644 --- a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php +++ b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php @@ -1039,6 +1039,38 @@ public function test_get_item_schema() { $this->assertArrayHasKey( 'plugin', $properties ); } + /** + * @ticket 64168 + * @covers WP_REST_Templates_Controller::get_item_schema + */ + public function test_get_item_schema_origin_allows_null() { + $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/templates' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + $properties = $data['schema']['properties']; + + $this->assertArrayHasKey( 'origin', $properties ); + $this->assertSame( + array( 'string', 'null' ), + $properties['origin']['type'], + 'The origin property type should allow string and null.' + ); + } + + + /** + * @ticket 64168 + * @covers WP_REST_Templates_Controller::prepare_item_for_response + */ + public function test_get_item_with_theme_template_returns_null_origin() { + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/default//my_template' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + $this->assertNull( $data['origin'], 'Theme template origin should be null.' ); + } + protected function find_and_normalize_template_by_id( $templates, $id ) { foreach ( $templates as $template ) { if ( $template['id'] === $id ) {