From 657913f76da82e23192ef60fc0e5d675bbab22fe Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 27 Jul 2026 13:43:24 +0300 Subject: [PATCH 1/2] Fix template `date` return value for file templates --- .../class-wp-rest-templates-controller.php | 9 +++++++-- .../rest-api/wpRestTemplatesController.php | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) 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 b821ca09453e3..ce9fb64bcd8e2 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 @@ -780,7 +780,12 @@ public function prepare_item_for_response( $item, $request ) { } if ( rest_is_field_included( 'date', $fields ) ) { - $data['date'] = mysql_to_rfc3339( $template->date ); + /* + * File-backed templates have no date. Return `null` in that case, as + * `mysql_to_rfc3339()` would return `false` for an empty value, which + * the schema does not allow. + */ + $data['date'] = empty( $template->date ) ? null : mysql_to_rfc3339( $template->date ); } if ( rest_is_field_included( 'author_text', $fields ) ) { @@ -1177,7 +1182,7 @@ public function get_item_schema() { 'user', ), ), - 'date' => array( + 'date' => array( 'description' => __( "The date the template was published, in the site's timezone." ), 'type' => array( 'string', 'null' ), 'format' => 'date-time', diff --git a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php index 42eed8dfa9c35..05e36936ea7ce 100644 --- a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php +++ b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php @@ -638,6 +638,25 @@ public function test_get_item_from_registry() { $this->assertSame( 404, $response->get_status(), 'Fetching an unregistered template should return 404.' ); } + /** + * A file-backed template has no date, which should be exposed as `null` + * rather than the `false` returned by `mysql_to_rfc3339()`. + * + * @ticket 65728 + * @covers WP_REST_Templates_Controller::prepare_item_for_response + */ + public function test_get_item_date_is_null_for_file_backed_template() { + wp_set_current_user( self::$admin_id ); + switch_theme( 'block-theme' ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/block-theme//page-home' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + $this->assertSame( 200, $response->get_status(), 'Fetching a file-backed template should return 200.' ); + $this->assertNull( $data['date'], 'The date should be null for a file-backed template.' ); + } + /** * @ticket 54507 * @dataProvider data_sanitize_template_id From c31a40be110244da4767c4c03c2d059046df8f41 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 27 Jul 2026 18:06:15 +0300 Subject: [PATCH 2/2] include `modified` changes --- .../class-wp-rest-templates-controller.php | 21 +++++++++++++------ .../rest-api/wpRestTemplatesController.php | 7 ++++--- 2 files changed, 19 insertions(+), 9 deletions(-) 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 ce9fb64bcd8e2..b6691c588ca7d 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 @@ -668,6 +668,8 @@ protected function prepare_item_for_database( $request ) { * @since 5.9.0 Renamed `$template` to `$item` to match parent class for PHP 8 named parameter support. * @since 6.3.0 Added `modified` property to the response. * @since 7.1.0 Added `date` property to the response. + * @since 7.1.0 The `modified` property is `null` for templates that have no + * modification date. * * @param WP_Block_Template $item Template instance. * @param WP_REST_Request $request Request object. @@ -776,16 +778,23 @@ public function prepare_item_for_response( $item, $request ) { } if ( rest_is_field_included( 'modified', $fields ) ) { - $data['modified'] = mysql_to_rfc3339( $template->modified ); + /* + * File-backed templates have no modification date, and `mysql_to_rfc3339()` + * returns `false` for an empty or malformed value, which the schema does + * not allow. Return `null` in that case. + */ + $modified = mysql_to_rfc3339( $template->modified ); + $data['modified'] = false !== $modified ? $modified : null; } if ( rest_is_field_included( 'date', $fields ) ) { /* - * File-backed templates have no date. Return `null` in that case, as - * `mysql_to_rfc3339()` would return `false` for an empty value, which - * the schema does not allow. + * File-backed templates have no date, and `mysql_to_rfc3339()` returns + * `false` for an empty or malformed value, which the schema does not + * allow. Return `null` in that case. */ - $data['date'] = empty( $template->date ) ? null : mysql_to_rfc3339( $template->date ); + $date = mysql_to_rfc3339( $template->date ); + $data['date'] = false !== $date ? $date : null; } if ( rest_is_field_included( 'author_text', $fields ) ) { @@ -1159,7 +1168,7 @@ public function get_item_schema() { ), 'modified' => array( 'description' => __( "The date the template was last modified, in the site's timezone." ), - 'type' => 'string', + 'type' => array( 'string', 'null' ), 'format' => 'date-time', 'context' => array( 'view', 'edit' ), 'readonly' => true, diff --git a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php index 05e36936ea7ce..e8ff29beaac33 100644 --- a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php +++ b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php @@ -639,13 +639,13 @@ public function test_get_item_from_registry() { } /** - * A file-backed template has no date, which should be exposed as `null` - * rather than the `false` returned by `mysql_to_rfc3339()`. + * A file-backed template has no publication or modification date, which should + * be exposed as `null` rather than the `false` returned by `mysql_to_rfc3339()`. * * @ticket 65728 * @covers WP_REST_Templates_Controller::prepare_item_for_response */ - public function test_get_item_date_is_null_for_file_backed_template() { + public function test_get_item_dates_are_null_for_file_backed_template() { wp_set_current_user( self::$admin_id ); switch_theme( 'block-theme' ); @@ -655,6 +655,7 @@ public function test_get_item_date_is_null_for_file_backed_template() { $this->assertSame( 200, $response->get_status(), 'Fetching a file-backed template should return 200.' ); $this->assertNull( $data['date'], 'The date should be null for a file-backed template.' ); + $this->assertNull( $data['modified'], 'The modified date should be null for a file-backed template.' ); } /**