From 5564c705b1e0827563a1fb4ec38377105782cdfd Mon Sep 17 00:00:00 2001
From: George Mamadashvili <mamaduka@git.wordpress.org>
Date: Tue, 11 Mar 2025 06:13:47 +0000
Subject: [PATCH] REST API: Add additional default template data fields for the
 active theme.

The active theme(s) now return two additional properties, `default_template_types` and `default_template_part_areas`, in the REST response.

Props mamaduka, joemcgill, timothyblynjacobs, audrasjb, gigitux, peterwilsoncc, youknowriad, jorbin.
Fixes #62574.

git-svn-id: https://develop.svn.wordpress.org/trunk@59965 602fd350-edb4-49c9-b593-d223f7449a82
---
 .../class-wp-rest-themes-controller.php       | 93 +++++++++++++++----
 .../tests/rest-api/rest-themes-controller.php | 35 ++++++-
 2 files changed, 109 insertions(+), 19 deletions(-)

diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php
index be12707b3c..a1203f2364 100644
--- a/src/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php
@@ -348,6 +348,19 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
 			}
 		}
 
+		if ( rest_is_field_included( 'default_template_types', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) {
+			$default_template_types = array();
+			foreach ( get_default_block_template_types() as $slug => $template_type ) {
+				$template_type['slug']    = (string) $slug;
+				$default_template_types[] = $template_type;
+			}
+			$data['default_template_types'] = $default_template_types;
+		}
+
+		if ( rest_is_field_included( 'default_template_part_areas', $fields ) && $this->is_same_theme( $theme, $current_theme ) ) {
+			$data['default_template_part_areas'] = get_allowed_block_template_part_areas();
+		}
+
 		$data = $this->add_additional_fields_to_object( $data, $request );
 
 		// Wrap the data in a response object.
@@ -459,29 +472,29 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
 			'title'      => 'theme',
 			'type'       => 'object',
 			'properties' => array(
-				'stylesheet'     => array(
+				'stylesheet'                  => array(
 					'description' => __( 'The theme\'s stylesheet. This uniquely identifies the theme.' ),
 					'type'        => 'string',
 					'readonly'    => true,
 				),
-				'stylesheet_uri' => array(
+				'stylesheet_uri'              => array(
 					'description' => __( 'The uri for the theme\'s stylesheet directory.' ),
 					'type'        => 'string',
 					'format'      => 'uri',
 					'readonly'    => true,
 				),
-				'template'       => array(
+				'template'                    => array(
 					'description' => __( 'The theme\'s template. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet.' ),
 					'type'        => 'string',
 					'readonly'    => true,
 				),
-				'template_uri'   => array(
+				'template_uri'                => array(
 					'description' => __( 'The uri for the theme\'s template directory. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet directory.' ),
 					'type'        => 'string',
 					'format'      => 'uri',
 					'readonly'    => true,
 				),
-				'author'         => array(
+				'author'                      => array(
 					'description' => __( 'The theme author.' ),
 					'type'        => 'object',
 					'readonly'    => true,
@@ -496,7 +509,7 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
 						),
 					),
 				),
-				'author_uri'     => array(
+				'author_uri'                  => array(
 					'description' => __( 'The website of the theme author.' ),
 					'type'        => 'object',
 					'readonly'    => true,
@@ -513,7 +526,7 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
 						),
 					),
 				),
-				'description'    => array(
+				'description'                 => array(
 					'description' => __( 'A description of the theme.' ),
 					'type'        => 'object',
 					'readonly'    => true,
@@ -528,12 +541,12 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
 						),
 					),
 				),
-				'is_block_theme' => array(
+				'is_block_theme'              => array(
 					'description' => __( 'Whether the theme is a block-based theme.' ),
 					'type'        => 'boolean',
 					'readonly'    => true,
 				),
-				'name'           => array(
+				'name'                        => array(
 					'description' => __( 'The name of the theme.' ),
 					'type'        => 'object',
 					'readonly'    => true,
@@ -548,23 +561,23 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
 						),
 					),
 				),
-				'requires_php'   => array(
+				'requires_php'                => array(
 					'description' => __( 'The minimum PHP version required for the theme to work.' ),
 					'type'        => 'string',
 					'readonly'    => true,
 				),
-				'requires_wp'    => array(
+				'requires_wp'                 => array(
 					'description' => __( 'The minimum WordPress version required for the theme to work.' ),
 					'type'        => 'string',
 					'readonly'    => true,
 				),
-				'screenshot'     => array(
+				'screenshot'                  => array(
 					'description' => __( 'The theme\'s screenshot URL.' ),
 					'type'        => 'string',
 					'format'      => 'uri',
 					'readonly'    => true,
 				),
-				'tags'           => array(
+				'tags'                        => array(
 					'description' => __( 'Tags indicating styles and features of the theme.' ),
 					'type'        => 'object',
 					'readonly'    => true,
@@ -582,18 +595,18 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
 						),
 					),
 				),
-				'textdomain'     => array(
+				'textdomain'                  => array(
 					'description' => __( 'The theme\'s text domain.' ),
 					'type'        => 'string',
 					'readonly'    => true,
 				),
-				'theme_supports' => array(
+				'theme_supports'              => array(
 					'description' => __( 'Features supported by this theme.' ),
 					'type'        => 'object',
 					'readonly'    => true,
 					'properties'  => array(),
 				),
-				'theme_uri'      => array(
+				'theme_uri'                   => array(
 					'description' => __( 'The URI of the theme\'s webpage.' ),
 					'type'        => 'object',
 					'readonly'    => true,
@@ -610,16 +623,60 @@ class WP_REST_Themes_Controller extends WP_REST_Controller {
 						),
 					),
 				),
-				'version'        => array(
+				'version'                     => array(
 					'description' => __( 'The theme\'s current version.' ),
 					'type'        => 'string',
 					'readonly'    => true,
 				),
-				'status'         => array(
+				'status'                      => array(
 					'description' => __( 'A named status for the theme.' ),
 					'type'        => 'string',
 					'enum'        => array( 'inactive', 'active' ),
 				),
+				'default_template_types'      => array(
+					'description' => __( 'A list of default template types.' ),
+					'type'        => 'array',
+					'readonly'    => true,
+					'items'       => array(
+						'type'       => 'object',
+						'properties' => array(
+							'slug'        => array(
+								'type' => 'string',
+							),
+							'title'       => array(
+								'type' => 'string',
+							),
+							'description' => array(
+								'type' => 'string',
+							),
+						),
+					),
+				),
+				'default_template_part_areas' => array(
+					'description' => __( 'A list of allowed area values for template parts.' ),
+					'type'        => 'array',
+					'readonly'    => true,
+					'items'       => array(
+						'type'       => 'object',
+						'properties' => array(
+							'area'        => array(
+								'type' => 'string',
+							),
+							'label'       => array(
+								'type' => 'string',
+							),
+							'description' => array(
+								'type' => 'string',
+							),
+							'icon'        => array(
+								'type' => 'string',
+							),
+							'area_tag'    => array(
+								'type' => 'string',
+							),
+						),
+					),
+				),
 			),
 		);
 
diff --git a/tests/phpunit/tests/rest-api/rest-themes-controller.php b/tests/phpunit/tests/rest-api/rest-themes-controller.php
index d1ebb5b8ba..923e7cda27 100644
--- a/tests/phpunit/tests/rest-api/rest-themes-controller.php
+++ b/tests/phpunit/tests/rest-api/rest-themes-controller.php
@@ -163,6 +163,7 @@ class WP_Test_REST_Themes_Controller extends WP_Test_REST_Controller_Testcase {
 	 *
 	 * @ticket 45016
 	 * @ticket 61021
+	 * @ticket 62574.
 	 */
 	public function test_get_items() {
 		$response = self::perform_active_theme_request();
@@ -175,6 +176,8 @@ class WP_Test_REST_Themes_Controller extends WP_Test_REST_Controller_Testcase {
 			'_links',
 			'author',
 			'author_uri',
+			'default_template_part_areas',
+			'default_template_types',
 			'description',
 			'is_block_theme',
 			'name',
@@ -354,12 +357,13 @@ class WP_Test_REST_Themes_Controller extends WP_Test_REST_Controller_Testcase {
 	 *
 	 * @ticket 45016
 	 * @ticket 61021
+	 * @ticket 62574
 	 */
 	public function test_get_item_schema() {
 		$response   = self::perform_active_theme_request( 'OPTIONS' );
 		$data       = $response->get_data();
 		$properties = $data['schema']['properties'];
-		$this->assertCount( 18, $properties );
+		$this->assertCount( 20, $properties );
 
 		$this->assertArrayHasKey( 'author', $properties );
 		$this->assertArrayHasKey( 'raw', $properties['author']['properties'] );
@@ -373,6 +377,9 @@ class WP_Test_REST_Themes_Controller extends WP_Test_REST_Controller_Testcase {
 		$this->assertArrayHasKey( 'raw', $properties['description']['properties'] );
 		$this->assertArrayHasKey( 'rendered', $properties['description']['properties'] );
 
+		$this->assertArrayHasKey( 'default_template_part_areas', $properties );
+		$this->assertArrayHasKey( 'default_template_types', $properties );
+
 		$this->assertArrayHasKey( 'is_block_theme', $properties );
 
 		$this->assertArrayHasKey( 'name', $properties );
@@ -472,6 +479,32 @@ class WP_Test_REST_Themes_Controller extends WP_Test_REST_Controller_Testcase {
 		);
 	}
 
+	/**
+	 * @ticket 62574
+	 */
+	public function test_theme_default_template_part_areas() {
+		$response = self::perform_active_theme_request();
+		$result   = $response->get_data();
+		$this->assertArrayHasKey( 'default_template_part_areas', $result[0] );
+		$this->assertSame( get_allowed_block_template_part_areas(), $result[0]['default_template_part_areas'] );
+	}
+
+	/**
+	 * @ticket 62574
+	 */
+	public function test_theme_default_template_types() {
+		$response = self::perform_active_theme_request();
+		$result   = $response->get_data();
+		$expected = array();
+		foreach ( get_default_block_template_types() as $slug => $template_type ) {
+			$template_type['slug'] = (string) $slug;
+			$expected[]            = $template_type;
+		}
+
+		$this->assertArrayHasKey( 'default_template_types', $result[0] );
+		$this->assertSame( $expected, $result[0]['default_template_types'] );
+	}
+
 	/**
 	 * @ticket 49906
 	 */