From e690417742b42b6c65dc10810938ff2348627e2c Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Fri, 9 Sep 2022 11:10:46 +0300 Subject: [PATCH 01/20] Backport: Block template utils and rest templates controller --- src/wp-includes/block-template-utils.php | 78 ++++++++- .../class-wp-rest-templates-controller.php | 61 +++++++ tests/phpunit/tests/block-template-utils.php | 156 ++++++++++++++++++ .../rest-api/wpRestTemplatesController.php | 41 +++++ 4 files changed, 331 insertions(+), 5 deletions(-) diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index 54413d809bc78..1454a29d98d70 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -147,7 +147,7 @@ function get_default_block_template_types() { ), 'category' => array( 'title' => _x( 'Category', 'Template name' ), - 'description' => __( 'Displays latest posts in single post category.' ), + 'description' => __( 'Displays latest posts from a single post category.' ), ), 'taxonomy' => array( 'title' => _x( 'Taxonomy', 'Template name' ), @@ -555,7 +555,8 @@ function _build_block_template_result_from_post( $post ) { $template_file = _get_block_template_file( $post->post_type, $post->post_name ); $has_theme_file = wp_get_theme()->get_stylesheet() === $theme && null !== $template_file; - $origin = get_post_meta( $post->ID, 'origin', true ); + $origin = get_post_meta( $post->ID, 'origin', true ); + $is_wp_suggestion = get_post_meta( $post->ID, 'is_wp_suggestion', true ); $template = new WP_Block_Template(); $template->wp_id = $post->ID; @@ -570,7 +571,7 @@ function _build_block_template_result_from_post( $post ) { $template->title = $post->post_title; $template->status = $post->post_status; $template->has_theme_file = $has_theme_file; - $template->is_custom = true; + $template->is_custom = empty( $is_wp_suggestion ); $template->author = $post->post_author; if ( 'wp_template' === $post->post_type && $has_theme_file && isset( $template_file['postTypes'] ) ) { @@ -581,6 +582,10 @@ function _build_block_template_result_from_post( $post ) { $template->is_custom = false; } + if ( 'wp_template' === $post->post_type && $has_theme_file && isset( $template_file['postTypes'] ) ) { + $template->post_types = $template_file['postTypes']; + } + if ( 'wp_template_part' === $post->post_type ) { $type_terms = get_the_terms( $post, 'wp_template_part_area' ); if ( ! is_wp_error( $type_terms ) && false !== $type_terms ) { @@ -912,9 +917,10 @@ function block_footer_area() { * @return Bool Whether this file is in an ignored directory. */ function wp_is_theme_directory_ignored( $path ) { - $directories_to_ignore = array( '.svn', '.git', '.hg', '.bzr', 'node_modules', 'vendor' ); + $directories_to_ignore = array( '.DS_Store', '.svn', '.git', '.hg', '.bzr', 'node_modules', 'vendor' ); + foreach ( $directories_to_ignore as $directory ) { - if ( strpos( $path, $directory ) === 0 ) { + if ( str_starts_with( $path, $directory ) ) { return true; } } @@ -1023,3 +1029,65 @@ function wp_generate_block_templates_export_file() { return $filename; } + +/** + * Helper function to get the Template Hierarchy for a given slug. + * We need to Handle special cases here like `front-page`, `singular` and `archive` templates. + * + * Noting that we always add `index` as the last fallback template. + * + * @since 6.1.0 + * + * @param string $slug The template slug to be created. + * @param boolean $is_custom Indicates if a template is custom or part of the template hierarchy. + * @param string $template_prefix The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`. + * + * @return array The template hierarchy. + */ +function get_template_hierarchy( $slug, $is_custom = false, $template_prefix = '' ) { + if ( 'index' === $slug ) { + return array( 'index' ); + } + if ( $is_custom ) { + return array( 'page', 'singular', 'index' ); + } + if ( 'front-page' === $slug ) { + return array( 'front-page', 'home', 'index' ); + } + $template_hierarchy = array( $slug ); + // Most default templates don't have `$template_prefix` assigned. + if ( $template_prefix ) { + list($type) = explode( '-', $template_prefix ); + // We need these checks because we always add the `$slug` above. + if ( ! in_array( $template_prefix, array( $slug, $type ), true ) ) { + $template_hierarchy[] = $template_prefix; + } + if ( $slug !== $type ) { + $template_hierarchy[] = $type; + } + } + // Handle `archive` template. + if ( + str_starts_with( $slug, 'author' ) || + str_starts_with( $slug, 'taxonomy' ) || + str_starts_with( $slug, 'category' ) || + str_starts_with( $slug, 'tag' ) || + 'date' === $slug + ) { + $template_hierarchy[] = 'archive'; + } + // Handle `single` template. + if ( 'attachment' === $slug ) { + $template_hierarchy[] = 'single'; + } + // Handle `singular` template. + if ( + str_starts_with( $slug, 'single' ) || + str_starts_with( $slug, 'page' ) || + 'attachment' === $slug + ) { + $template_hierarchy[] = 'singular'; + } + $template_hierarchy[] = 'index'; + return $template_hierarchy; +}; 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 7e60674890646..b8292d8eb1dfa 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 @@ -42,6 +42,7 @@ public function __construct( $post_type ) { * Registers the controllers routes. * * @since 5.8.0 + * @since 6.1.0 Endpoint for fallback template content. */ public function register_routes() { // Lists all templates. @@ -115,6 +116,55 @@ public function register_routes() { 'schema' => array( $this, 'get_public_item_schema' ), ) ); + + // Get fallback template content. + register_rest_route( + $this->namespace, + '/' . $this->rest_base . '/lookup', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_template_fallback' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), + 'args' => array( + 'slug' => array( + 'description' => __( 'The slug of the template to get the fallback for' ), + 'type' => 'string', + ), + 'is_custom' => array( + 'description' => __( ' Indicates if a template is custom or part of the template hierarchy' ), + 'type' => 'boolean', + ), + 'template_prefix' => array( + 'description' => __( 'The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`' ), + 'type' => 'string', + ), + ), + ), + ) + ); + } + + /** + * Returns the fallback template for a given slug. + * + * @since 6.1.0 + * + * @param WP_REST_Request $request The request instance. + * + * @return WP_REST_Response|WP_Error + */ + public function get_template_fallback( $request ) { + if ( empty( $request['slug'] ) ) { + return new WP_Error( + 'rest_invalid_param', + __( 'Invalid slug.', 'gutenberg' ), + array( 'status' => 400 ) + ); + } + $hierarchy = get_template_hierarchy( $request['slug'], $request['is_custom'], $request['template_prefix'] ); + $fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' ); + return rest_ensure_response( $fallback_template ); } /** @@ -525,6 +575,17 @@ protected function prepare_item_for_database( $request ) { $changes->post_excerpt = $template->description; } + if ( 'wp_template' === $this->post_type ) { + if ( isset( $request['is_wp_suggestion'] ) ) { + $changes->meta_input = wp_parse_args( + array( + 'is_wp_suggestion' => $request['is_wp_suggestion'], + ), + $changes->meta_input = array() + ); + } + } + if ( 'wp_template_part' === $this->post_type ) { if ( isset( $request['area'] ) ) { $changes->tax_input['wp_template_part_area'] = _filter_block_template_part_area( $request['area'] ); diff --git a/tests/phpunit/tests/block-template-utils.php b/tests/phpunit/tests/block-template-utils.php index 7410dcaed3f68..93f155b0a7495 100644 --- a/tests/phpunit/tests/block-template-utils.php +++ b/tests/phpunit/tests/block-template-utils.php @@ -340,4 +340,160 @@ function test_wp_generate_block_templates_export_file() { } $this->assertTrue( $has_html_files, 'contains at least one html file' ); } + + /** + * Helper function to get the Template Hierarchy for a given slug. + * + * @ticket 56467 + */ + public function test_get_template_hierarchy() { + $hierarchy = get_template_hierarchy( 'front-page' ); + $this->assertEquals( array( 'front-page', 'home', 'index' ), $hierarchy ); + // Custom templates. + $hierarchy = get_template_hierarchy( 'whatever-slug', true ); + $this->assertEquals( array( 'page', 'singular', 'index' ), $hierarchy ); + // Single slug templates(ex. page, tag, author, etc.. + $hierarchy = get_template_hierarchy( 'page' ); + $this->assertEquals( array( 'page', 'singular', 'index' ), $hierarchy ); + $hierarchy = get_template_hierarchy( 'tag' ); + $this->assertEquals( array( 'tag', 'archive', 'index' ), $hierarchy ); + $hierarchy = get_template_hierarchy( 'author' ); + $this->assertEquals( array( 'author', 'archive', 'index' ), $hierarchy ); + $hierarchy = get_template_hierarchy( 'date' ); + $this->assertEquals( array( 'date', 'archive', 'index' ), $hierarchy ); + $hierarchy = get_template_hierarchy( 'taxonomy' ); + $this->assertEquals( array( 'taxonomy', 'archive', 'index' ), $hierarchy ); + $hierarchy = get_template_hierarchy( 'attachment' ); + $this->assertEquals( + array( + 'attachment', + 'single', + 'singular', + 'index', + ), + $hierarchy + ); + $hierarchy = get_template_hierarchy( 'singular' ); + $this->assertEquals( array( 'singular', 'index' ), $hierarchy ); + $hierarchy = get_template_hierarchy( 'single' ); + $this->assertEquals( array( 'single', 'singular', 'index' ), $hierarchy ); + $hierarchy = get_template_hierarchy( 'archive' ); + $this->assertEquals( array( 'archive', 'index' ), $hierarchy ); + $hierarchy = get_template_hierarchy( 'index' ); + $this->assertEquals( array( 'index' ), $hierarchy ); + + // Taxonomies. + $hierarchy = get_template_hierarchy( 'taxonomy-books', false, 'taxonomy-books' ); + $this->assertEquals( array( 'taxonomy-books', 'taxonomy', 'archive', 'index' ), $hierarchy ); + // Single word category. + $hierarchy = get_template_hierarchy( 'category-fruits', false, 'category' ); + $this->assertEquals( + array( + 'category-fruits', + 'category', + 'archive', + 'index', + ), + $hierarchy + ); + // Multi word category. + $hierarchy = get_template_hierarchy( 'category-fruits-yellow', false, 'category' ); + $this->assertEquals( + array( + 'category-fruits-yellow', + 'category', + 'archive', + 'index', + ), + $hierarchy + ); + // Single word taxonomy. + $hierarchy = get_template_hierarchy( 'taxonomy-books-action', false, 'taxonomy-books' ); + $this->assertEquals( + array( + 'taxonomy-books-action', + 'taxonomy-books', + 'taxonomy', + 'archive', + 'index', + ), + $hierarchy + ); + $hierarchy = get_template_hierarchy( 'taxonomy-books-action-adventure', false, 'taxonomy-books' ); + $this->assertEquals( + array( + 'taxonomy-books-action-adventure', + 'taxonomy-books', + 'taxonomy', + 'archive', + 'index', + ), + $hierarchy + ); + // Multi word taxonomy/terms. + $hierarchy = get_template_hierarchy( 'taxonomy-greek-books-action-adventure', false, 'taxonomy-greek-books' ); + $this->assertEquals( + array( + 'taxonomy-greek-books-action-adventure', + 'taxonomy-greek-books', + 'taxonomy', + 'archive', + 'index', + ), + $hierarchy + ); + // Post types. + $hierarchy = get_template_hierarchy( 'single-book', false, 'single-book' ); + $this->assertEquals( + array( + 'single-book', + 'single', + 'singular', + 'index', + ), + $hierarchy + ); + $hierarchy = get_template_hierarchy( 'single-art-project', false, 'single-art-project' ); + $this->assertEquals( + array( + 'single-art-project', + 'single', + 'singular', + 'index', + ), + $hierarchy + ); + $hierarchy = get_template_hierarchy( 'single-art-project-imagine', false, 'single-art-project' ); + $this->assertEquals( + array( + 'single-art-project-imagine', + 'single-art-project', + 'single', + 'singular', + 'index', + ), + $hierarchy + ); + $hierarchy = get_template_hierarchy( 'page-hi', false, 'page' ); + $this->assertEquals( + array( + 'page-hi', + 'page', + 'singular', + 'index', + ), + $hierarchy + ); + // Authors. + $hierarchy = get_template_hierarchy( 'author-rigas', false, 'author' ); + $this->assertEquals( + array( + 'author-rigas', + 'author', + 'archive', + 'index', + ), + $hierarchy + ); + } } diff --git a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php index c53701f9b6a8c..e4b865d958df6 100644 --- a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php +++ b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php @@ -56,6 +56,7 @@ public static function wpTearDownAfterClass() { /** * @covers WP_REST_Templates_Controller::register_routes * @ticket 54596 + * @ticket 56467 */ public function test_register_routes() { $routes = rest_get_server()->get_routes(); @@ -69,6 +70,11 @@ public function test_register_routes() { $routes, 'Single template based on the given ID route does not exist' ); + $this->assertArrayHasKey( + '/wp/v2/templates/lookup', + $routes, + 'Get template fallback content route does not exist' + ); } /** @@ -678,4 +684,39 @@ protected function find_and_normalize_template_by_id( $templates, $id ) { return null; } + /** + * @ticket 56467 + * @covers WP_REST_Templates_Controller::get_template_fallback + */ + // TODO: check how to make this test work.. + // https://github.com/WordPress/gutenberg/pull/42520/files#diff-5dcd7f0ba0e053098e93f6907913da73787fb7487e05d37e3249fb1c0ec434d6 + // public function test_get_template_fallback() { + // $base_path = gutenberg_dir_path() . 'test/emptytheme/block-templates/'; + // wp_set_current_user( self::$admin_id ); + // $request = new WP_REST_Request( 'GET', '/wp/v2/templates/lookup' ); + // // Should match `category.html`. + // $request->set_param( 'slug', 'category-fruits' ); + // $request->set_param( 'is_custom', false ); + // $request->set_param( 'template_prefix', 'category' ); + // $response = rest_get_server()->dispatch( $request ); + // $data = $response->get_data()->content; + // $expected = file_get_contents( $base_path . 'category.html' ); + // $this->assertEquals( $expected, $data ); + // // Should fallback to `index.html` . + // $request->set_param( 'slug', 'tag-status' ); + // $request->set_param( 'is_custom', false ); + // $request->set_param( 'template_prefix', 'tag' ); + // $response = rest_get_server()->dispatch( $request ); + // $data = $response->get_data()->content; + // $expected = file_get_contents( $base_path . 'index.html' ); + // $this->assertEquals( $expected, $data ); + // // Should fallback to `singular.html` . + // $request->set_param( 'slug', 'page-hello' ); + // $request->set_param( 'is_custom', false ); + // $request->set_param( 'template_prefix', 'page' ); + // $response = rest_get_server()->dispatch( $request ); + // $data = $response->get_data()->content; + // $expected = file_get_contents( $base_path . 'singular.html' ); + // $this->assertEquals( $expected, $data ); + // } } From a416a0aaa1cf9378cd2ac8bb86e3f406e737f54c Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Fri, 9 Sep 2022 11:32:16 +0300 Subject: [PATCH 02/20] add `icon` to types controller --- .../endpoints/class-wp-rest-post-types-controller.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php index cb2daa4b292c6..6ca4b855b06af 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php @@ -221,6 +221,10 @@ public function prepare_item_for_response( $item, $request ) { $data['slug'] = $post_type->name; } + if ( in_array( 'icon', $fields, true ) ) { + $data['icon'] = $post_type->menu_icon; + } + if ( in_array( 'supports', $fields, true ) ) { $data['supports'] = $supports; } @@ -287,6 +291,7 @@ protected function prepare_links( $post_type ) { * @since 4.7.0 * @since 4.8.0 The `supports` property was added. * @since 5.9.0 The `visibility` and `rest_namespace` properties were added. + * @since 6.1.0 The `icon` property was added. * * @return array Item schema data. */ @@ -385,6 +390,12 @@ public function get_item_schema() { ), ), ), + 'icon' => array( + 'description' => __( 'The icon for the post type.' ), + 'type' => 'string', + 'context' => array( 'view', 'edit', 'embed' ), + 'readonly' => true, + ), ), ); From f1958f43406d653de05c3c60946604532a9a5c72 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Fri, 9 Sep 2022 17:05:50 +0300 Subject: [PATCH 03/20] update tests --- src/wp-includes/block-template-utils.php | 15 +--- .../class-wp-rest-templates-controller.php | 54 ++++++------ .../rest-api/rest-post-types-controller.php | 3 +- .../tests/rest-api/rest-schema-setup.php | 2 + .../rest-api/wpRestTemplatesController.php | 48 ++++------- tests/qunit/fixtures/wp-api-generated.js | 83 +++++++++++++++++++ 6 files changed, 133 insertions(+), 72 deletions(-) diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index 1454a29d98d70..4678fce3f9cd5 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -552,8 +552,8 @@ function _build_block_template_result_from_post( $post ) { } $theme = $terms[0]->name; - $template_file = _get_block_template_file( $post->post_type, $post->post_name ); - $has_theme_file = wp_get_theme()->get_stylesheet() === $theme && null !== $template_file; + $has_theme_file = wp_get_theme()->get_stylesheet() === $theme && + null !== _get_block_template_file( $post->post_type, $post->post_name ); $origin = get_post_meta( $post->ID, 'origin', true ); $is_wp_suggestion = get_post_meta( $post->ID, 'is_wp_suggestion', true ); @@ -582,10 +582,6 @@ function _build_block_template_result_from_post( $post ) { $template->is_custom = false; } - if ( 'wp_template' === $post->post_type && $has_theme_file && isset( $template_file['postTypes'] ) ) { - $template->post_types = $template_file['postTypes']; - } - if ( 'wp_template_part' === $post->post_type ) { $type_terms = get_the_terms( $post, 'wp_template_part_area' ); if ( ! is_wp_error( $type_terms ) && false !== $type_terms ) { @@ -684,13 +680,6 @@ function get_block_templates( $query = array(), $template_type = 'wp_template' ) continue; } - if ( $post_type && - isset( $template->post_types ) && - ! in_array( $post_type, $template->post_types, true ) - ) { - continue; - } - $query_result[] = $template; } 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 b8292d8eb1dfa..24714f322caa9 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 @@ -66,6 +66,33 @@ public function register_routes() { ) ); + // Get fallback template content. + register_rest_route( + $this->namespace, + '/' . $this->rest_base . '/lookup', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_template_fallback' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), + 'args' => array( + 'slug' => array( + 'description' => __( 'The slug of the template to get the fallback for' ), + 'type' => 'string', + ), + 'is_custom' => array( + 'description' => __( ' Indicates if a template is custom or part of the template hierarchy' ), + 'type' => 'boolean', + ), + 'template_prefix' => array( + 'description' => __( 'The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`' ), + 'type' => 'string', + ), + ), + ), + ) + ); + // Lists/updates a single template based on the given id. register_rest_route( $this->namespace, @@ -116,33 +143,6 @@ public function register_routes() { 'schema' => array( $this, 'get_public_item_schema' ), ) ); - - // Get fallback template content. - register_rest_route( - $this->namespace, - '/' . $this->rest_base . '/lookup', - array( - array( - 'methods' => WP_REST_Server::READABLE, - 'callback' => array( $this, 'get_template_fallback' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), - 'args' => array( - 'slug' => array( - 'description' => __( 'The slug of the template to get the fallback for' ), - 'type' => 'string', - ), - 'is_custom' => array( - 'description' => __( ' Indicates if a template is custom or part of the template hierarchy' ), - 'type' => 'boolean', - ), - 'template_prefix' => array( - 'description' => __( 'The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`' ), - 'type' => 'string', - ), - ), - ), - ) - ); } /** diff --git a/tests/phpunit/tests/rest-api/rest-post-types-controller.php b/tests/phpunit/tests/rest-api/rest-post-types-controller.php index 0ab2a7b937005..25a89f16e69c8 100644 --- a/tests/phpunit/tests/rest-api/rest-post-types-controller.php +++ b/tests/phpunit/tests/rest-api/rest-post-types-controller.php @@ -161,7 +161,7 @@ public function test_get_item_schema() { $response = rest_get_server()->dispatch( $request ); $data = $response->get_data(); $properties = $data['schema']['properties']; - $this->assertCount( 12, $properties ); + $this->assertCount( 13, $properties ); $this->assertArrayHasKey( 'capabilities', $properties ); $this->assertArrayHasKey( 'description', $properties ); $this->assertArrayHasKey( 'hierarchical', $properties ); @@ -174,6 +174,7 @@ public function test_get_item_schema() { $this->assertArrayHasKey( 'rest_base', $properties ); $this->assertArrayHasKey( 'rest_namespace', $properties ); $this->assertArrayHasKey( 'visibility', $properties ); + $this->assertArrayHasKey( 'icon', $properties ); } public function test_get_additional_field_registration() { diff --git a/tests/phpunit/tests/rest-api/rest-schema-setup.php b/tests/phpunit/tests/rest-api/rest-schema-setup.php index a1e4330c0cc4a..afc1ebc125830 100644 --- a/tests/phpunit/tests/rest-api/rest-schema-setup.php +++ b/tests/phpunit/tests/rest-api/rest-schema-setup.php @@ -150,12 +150,14 @@ public function test_expected_routes_in_schema() { '/wp/v2/template-parts/(?P[\d]+)/autosaves/(?P[\d]+)', '/wp/v2/template-parts/(?P[\d]+)/revisions', '/wp/v2/template-parts/(?P[\d]+)/revisions/(?P[\d]+)', + '/wp/v2/template-parts/lookup', '/wp/v2/templates', '/wp/v2/templates/(?P[\d]+)/autosaves', '/wp/v2/templates/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w-]+)', '/wp/v2/templates/(?P[\d]+)/autosaves/(?P[\d]+)', '/wp/v2/templates/(?P[\d]+)/revisions', '/wp/v2/templates/(?P[\d]+)/revisions/(?P[\d]+)', + '/wp/v2/templates/lookup', '/wp/v2/themes', '/wp/v2/themes/(?P[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)', '/wp/v2/plugins', diff --git a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php index e4b865d958df6..2f61dfac36fbc 100644 --- a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php +++ b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php @@ -688,35 +688,21 @@ protected function find_and_normalize_template_by_id( $templates, $id ) { * @ticket 56467 * @covers WP_REST_Templates_Controller::get_template_fallback */ - // TODO: check how to make this test work.. - // https://github.com/WordPress/gutenberg/pull/42520/files#diff-5dcd7f0ba0e053098e93f6907913da73787fb7487e05d37e3249fb1c0ec434d6 - // public function test_get_template_fallback() { - // $base_path = gutenberg_dir_path() . 'test/emptytheme/block-templates/'; - // wp_set_current_user( self::$admin_id ); - // $request = new WP_REST_Request( 'GET', '/wp/v2/templates/lookup' ); - // // Should match `category.html`. - // $request->set_param( 'slug', 'category-fruits' ); - // $request->set_param( 'is_custom', false ); - // $request->set_param( 'template_prefix', 'category' ); - // $response = rest_get_server()->dispatch( $request ); - // $data = $response->get_data()->content; - // $expected = file_get_contents( $base_path . 'category.html' ); - // $this->assertEquals( $expected, $data ); - // // Should fallback to `index.html` . - // $request->set_param( 'slug', 'tag-status' ); - // $request->set_param( 'is_custom', false ); - // $request->set_param( 'template_prefix', 'tag' ); - // $response = rest_get_server()->dispatch( $request ); - // $data = $response->get_data()->content; - // $expected = file_get_contents( $base_path . 'index.html' ); - // $this->assertEquals( $expected, $data ); - // // Should fallback to `singular.html` . - // $request->set_param( 'slug', 'page-hello' ); - // $request->set_param( 'is_custom', false ); - // $request->set_param( 'template_prefix', 'page' ); - // $response = rest_get_server()->dispatch( $request ); - // $data = $response->get_data()->content; - // $expected = file_get_contents( $base_path . 'singular.html' ); - // $this->assertEquals( $expected, $data ); - // } + public function test_get_template_fallback() { + wp_set_current_user( self::$admin_id ); + switch_theme( 'block-theme' ); + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/lookup' ); + // Should fallback to `index.html` . + $request->set_param( 'slug', 'tag-status' ); + $request->set_param( 'is_custom', false ); + $request->set_param( 'template_prefix', 'tag' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertEquals( 'index', $response->get_data()->slug ); + // Should fallback to `page.html` . + $request->set_param( 'slug', 'page-hello' ); + $request->set_param( 'is_custom', false ); + $request->set_param( 'template_prefix', 'page' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertEquals( 'page', $response->get_data()->slug ); + } } diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js index 4020b25da844d..51375b8e97498 100644 --- a/tests/qunit/fixtures/wp-api-generated.js +++ b/tests/qunit/fixtures/wp-api-generated.js @@ -5140,6 +5140,43 @@ mockedApiResponse.Schema = { ] } }, + "/wp/v2/templates/lookup": { + "namespace": "wp/v2", + "methods": [ + "GET" + ], + "endpoints": [ + { + "methods": [ + "GET" + ], + "args": { + "slug": { + "description": "The slug of the template to get the fallback for", + "type": "string", + "required": false + }, + "is_custom": { + "description": " Indicates if a template is custom or part of the template hierarchy", + "type": "boolean", + "required": false + }, + "template_prefix": { + "description": "The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`", + "type": "string", + "required": false + } + } + } + ], + "_links": { + "self": [ + { + "href": "http://example.org/index.php?rest_route=/wp/v2/templates/lookup" + } + ] + } + }, "/wp/v2/templates/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w-]+)": { "namespace": "wp/v2", "methods": [ @@ -5792,6 +5829,43 @@ mockedApiResponse.Schema = { ] } }, + "/wp/v2/template-parts/lookup": { + "namespace": "wp/v2", + "methods": [ + "GET" + ], + "endpoints": [ + { + "methods": [ + "GET" + ], + "args": { + "slug": { + "description": "The slug of the template to get the fallback for", + "type": "string", + "required": false + }, + "is_custom": { + "description": " Indicates if a template is custom or part of the template hierarchy", + "type": "boolean", + "required": false + }, + "template_prefix": { + "description": "The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`", + "type": "string", + "required": false + } + } + } + ], + "_links": { + "self": [ + { + "href": "http://example.org/index.php?rest_route=/wp/v2/template-parts/lookup" + } + ] + } + }, "/wp/v2/template-parts/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w-]+)": { "namespace": "wp/v2", "methods": [ @@ -11591,6 +11665,7 @@ mockedApiResponse.TypesCollection = { "hierarchical": false, "name": "Posts", "slug": "post", + "icon": "dashicons-admin-post", "taxonomies": [ "category", "post_tag" @@ -11622,6 +11697,7 @@ mockedApiResponse.TypesCollection = { "hierarchical": true, "name": "Pages", "slug": "page", + "icon": "dashicons-admin-page", "taxonomies": [], "rest_base": "pages", "rest_namespace": "wp/v2", @@ -11650,6 +11726,7 @@ mockedApiResponse.TypesCollection = { "hierarchical": false, "name": "Media", "slug": "attachment", + "icon": "dashicons-admin-media", "taxonomies": [], "rest_base": "media", "rest_namespace": "wp/v2", @@ -11678,6 +11755,7 @@ mockedApiResponse.TypesCollection = { "hierarchical": false, "name": "Navigation Menu Items", "slug": "nav_menu_item", + "icon": null, "taxonomies": [ "nav_menu" ], @@ -11708,6 +11786,7 @@ mockedApiResponse.TypesCollection = { "hierarchical": false, "name": "Reusable blocks", "slug": "wp_block", + "icon": null, "taxonomies": [], "rest_base": "blocks", "rest_namespace": "wp/v2", @@ -11736,6 +11815,7 @@ mockedApiResponse.TypesCollection = { "hierarchical": false, "name": "Templates", "slug": "wp_template", + "icon": null, "taxonomies": [], "rest_base": "templates", "rest_namespace": "wp/v2", @@ -11764,6 +11844,7 @@ mockedApiResponse.TypesCollection = { "hierarchical": false, "name": "Template Parts", "slug": "wp_template_part", + "icon": null, "taxonomies": [], "rest_base": "template-parts", "rest_namespace": "wp/v2", @@ -11792,6 +11873,7 @@ mockedApiResponse.TypesCollection = { "hierarchical": false, "name": "Navigation Menus", "slug": "wp_navigation", + "icon": null, "taxonomies": [], "rest_base": "navigation", "rest_namespace": "wp/v2", @@ -11822,6 +11904,7 @@ mockedApiResponse.TypeModel = { "hierarchical": false, "name": "Posts", "slug": "post", + "icon": "dashicons-admin-post", "taxonomies": [ "category", "post_tag" From 0ae99e12df9de75ea11ecee56d00b99f194b3d1b Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Fri, 9 Sep 2022 20:10:46 +0300 Subject: [PATCH 04/20] add tests for `is_wp_suggestion` --- .../rest-api/wpRestTemplatesController.php | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php index 2f61dfac36fbc..f4897411a1354 100644 --- a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php +++ b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php @@ -684,6 +684,72 @@ protected function find_and_normalize_template_by_id( $templates, $id ) { return null; } + /** + * @ticket 56467 + * @covers WP_REST_Templates_Controller::create_item + */ + public function test_create_item_with_is_wp_suggestion() { + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'POST', '/wp/v2/templates' ); + // `is_wp_suggestion` true. + $body_params = array( + 'slug' => 'page-rigas', + 'description' => 'Just a description', + 'title' => 'My Template', + 'content' => 'Content', + 'is_wp_suggestion' => true, + 'author' => self::$admin_id, + ); + $request->set_body_params( $body_params ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + unset( $data['_links'] ); + unset( $data['wp_id'] ); + $expected = array( + 'id' => 'default//page-rigas', + 'theme' => 'default', + 'content' => array( + 'raw' => 'Content', + ), + 'slug' => 'page-rigas', + 'source' => 'custom', + 'origin' => null, + 'type' => 'wp_template', + 'description' => 'Just a description', + 'title' => array( + 'raw' => 'My Template', + 'rendered' => 'My Template', + ), + 'status' => 'publish', + 'has_theme_file' => false, + 'is_custom' => false, + 'author' => self::$admin_id, + ); + $this->assertSame( $expected, $data ); + // `is_wp_suggestion` false. + $body_params = wp_parse_args( + array( + 'slug' => 'page-hi', + 'is_wp_suggestion' => false, + ), + $body_params + ); + $request->set_body_params( $body_params ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + unset( $data['_links'] ); + unset( $data['wp_id'] ); + $expected = wp_parse_args( + array( + 'id' => 'default//page-hi', + 'slug' => 'page-hi', + 'is_custom' => true, + ), + $expected + ); + $this->assertSame( $expected, $data ); + } + /** * @ticket 56467 * @covers WP_REST_Templates_Controller::get_template_fallback From 09ec609040a768b4586b504167ba03b4d95f1727 Mon Sep 17 00:00:00 2001 From: Tonya Mork Date: Thu, 15 Sep 2022 07:49:07 -0500 Subject: [PATCH 05/20] Update docblock for coding standards --- src/wp-includes/block-template-utils.php | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index 4678fce3f9cd5..ce09e9f293ccc 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -1020,18 +1020,21 @@ function wp_generate_block_templates_export_file() { } /** - * Helper function to get the Template Hierarchy for a given slug. - * We need to Handle special cases here like `front-page`, `singular` and `archive` templates. + * Helper function to get the Template Hierarchy for the given slug. + * Handles special cases like `front-page`, `singular` and `archive` templates. * - * Noting that we always add `index` as the last fallback template. + * Note: Always add `index` as the last fallback template. * * @since 6.1.0 * - * @param string $slug The template slug to be created. - * @param boolean $is_custom Indicates if a template is custom or part of the template hierarchy. - * @param string $template_prefix The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`. - * - * @return array The template hierarchy. + * @param string $slug The template slug to be created. + * @param boolean $is_custom Optional. Indicates if a template is custom or + * part of the template hierarchy. Default false. + * @param string $template_prefix The template prefix for the created template. + * Used to extract the main template type, e.g. + * in `taxonomy-books` the `taxonomy` is extracted. + * Default empty string. + * @return string[] The template hierarchy. */ function get_template_hierarchy( $slug, $is_custom = false, $template_prefix = '' ) { if ( 'index' === $slug ) { From 1bf24b4f93beb1982be0744c7b642a6b7ba08ab2 Mon Sep 17 00:00:00 2001 From: Tonya Mork Date: Thu, 15 Sep 2022 07:49:28 -0500 Subject: [PATCH 06/20] Remove 'gutenberg' text domain --- .../rest-api/endpoints/class-wp-rest-templates-controller.php | 2 +- 1 file changed, 1 insertion(+), 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 24714f322caa9..a602089253184 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 @@ -158,7 +158,7 @@ public function get_template_fallback( $request ) { if ( empty( $request['slug'] ) ) { return new WP_Error( 'rest_invalid_param', - __( 'Invalid slug.', 'gutenberg' ), + __( 'Invalid slug.' ), array( 'status' => 400 ) ); } From adb4dcaf43bf5699ac435bf89cab020dfcb8d263 Mon Sep 17 00:00:00 2001 From: Tonya Mork Date: Thu, 15 Sep 2022 07:49:56 -0500 Subject: [PATCH 07/20] Improve docblock for coding standards --- .../rest-api/endpoints/class-wp-rest-templates-controller.php | 3 +-- 1 file changed, 1 insertion(+), 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 a602089253184..a2d7d2f59510a 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 @@ -146,12 +146,11 @@ public function register_routes() { } /** - * Returns the fallback template for a given slug. + * Returns the fallback template for the given slug. * * @since 6.1.0 * * @param WP_REST_Request $request The request instance. - * * @return WP_REST_Response|WP_Error */ public function get_template_fallback( $request ) { From d4a2bb820cddb1c32436f7bb546a994a7deb7698 Mon Sep 17 00:00:00 2001 From: Tonya Mork Date: Thu, 15 Sep 2022 07:50:45 -0500 Subject: [PATCH 08/20] Removes "we" from description --- .../rest-api/endpoints/class-wp-rest-templates-controller.php | 2 +- 1 file changed, 1 insertion(+), 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 a2d7d2f59510a..442c888489213 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 @@ -85,7 +85,7 @@ public function register_routes() { 'type' => 'boolean', ), 'template_prefix' => array( - 'description' => __( 'The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`' ), + 'description' => __( 'The template prefix for the created template. This is used to extract the main template type, e.g. in `taxonomy-books` extracts the `taxonomy`' ), 'type' => 'string', ), ), From c63eb7d3ea3218acf67cc65d13f84b6be8248e30 Mon Sep 17 00:00:00 2001 From: Tonya Mork Date: Thu, 15 Sep 2022 09:24:12 -0500 Subject: [PATCH 09/20] Auto regenerated wp-api-generated.js qunit test fixture --- tests/qunit/fixtures/wp-api-generated.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js index 51375b8e97498..89eff763a4a88 100644 --- a/tests/qunit/fixtures/wp-api-generated.js +++ b/tests/qunit/fixtures/wp-api-generated.js @@ -5162,7 +5162,7 @@ mockedApiResponse.Schema = { "required": false }, "template_prefix": { - "description": "The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`", + "description": "The template prefix for the created template. This is used to extract the main template type, e.g. in `taxonomy-books` extracts the `taxonomy`", "type": "string", "required": false } @@ -5851,7 +5851,7 @@ mockedApiResponse.Schema = { "required": false }, "template_prefix": { - "description": "The template prefix for the created template. This is used to extract the main template type ex. in `taxonomy-books` we extract the `taxonomy`", + "description": "The template prefix for the created template. This is used to extract the main template type, e.g. in `taxonomy-books` extracts the `taxonomy`", "type": "string", "required": false } From 06c008215af1ca003e1d2ae22c168b2413771f22 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 19 Sep 2022 12:43:17 +0300 Subject: [PATCH 10/20] update tests --- .../class-wp-rest-templates-controller.php | 16 ++-- tests/phpunit/tests/block-template-utils.php | 81 +++++++++++-------- .../rest-api/rest-post-types-controller.php | 26 +++--- .../rest-api/wpRestTemplatesController.php | 12 +-- 4 files changed, 72 insertions(+), 63 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 442c888489213..e2ece085ae376 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 @@ -574,15 +574,13 @@ protected function prepare_item_for_database( $request ) { $changes->post_excerpt = $template->description; } - if ( 'wp_template' === $this->post_type ) { - if ( isset( $request['is_wp_suggestion'] ) ) { - $changes->meta_input = wp_parse_args( - array( - 'is_wp_suggestion' => $request['is_wp_suggestion'], - ), - $changes->meta_input = array() - ); - } + if ( 'wp_template' === $this->post_type && isset( $request['is_wp_suggestion'] ) ) { + $changes->meta_input = wp_parse_args( + array( + 'is_wp_suggestion' => $request['is_wp_suggestion'], + ), + $changes->meta_input = array() + ); } if ( 'wp_template_part' === $this->post_type ) { diff --git a/tests/phpunit/tests/block-template-utils.php b/tests/phpunit/tests/block-template-utils.php index 93f155b0a7495..70cb78d7979c2 100644 --- a/tests/phpunit/tests/block-template-utils.php +++ b/tests/phpunit/tests/block-template-utils.php @@ -348,68 +348,71 @@ function test_wp_generate_block_templates_export_file() { */ public function test_get_template_hierarchy() { $hierarchy = get_template_hierarchy( 'front-page' ); - $this->assertEquals( array( 'front-page', 'home', 'index' ), $hierarchy ); + $this->assertSame( array( 'front-page', 'home', 'index' ), $hierarchy, 'Incorrect hierarchy for `front-page`.' ); // Custom templates. $hierarchy = get_template_hierarchy( 'whatever-slug', true ); - $this->assertEquals( array( 'page', 'singular', 'index' ), $hierarchy ); + $this->assertSame( array( 'page', 'singular', 'index' ), $hierarchy, 'Incorrect hierarchy for custom template.' ); // Single slug templates(ex. page, tag, author, etc.. $hierarchy = get_template_hierarchy( 'page' ); - $this->assertEquals( array( 'page', 'singular', 'index' ), $hierarchy ); + $this->assertSame( array( 'page', 'singular', 'index' ), $hierarchy, 'Incorrect hierarchy for `page`.' ); $hierarchy = get_template_hierarchy( 'tag' ); - $this->assertEquals( array( 'tag', 'archive', 'index' ), $hierarchy ); + $this->assertSame( array( 'tag', 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for `tag`.' ); $hierarchy = get_template_hierarchy( 'author' ); - $this->assertEquals( array( 'author', 'archive', 'index' ), $hierarchy ); + $this->assertSame( array( 'author', 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for `author`.' ); $hierarchy = get_template_hierarchy( 'date' ); - $this->assertEquals( array( 'date', 'archive', 'index' ), $hierarchy ); + $this->assertSame( array( 'date', 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for `date`.' ); $hierarchy = get_template_hierarchy( 'taxonomy' ); - $this->assertEquals( array( 'taxonomy', 'archive', 'index' ), $hierarchy ); + $this->assertSame( array( 'taxonomy', 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for `taxonomy`.' ); $hierarchy = get_template_hierarchy( 'attachment' ); - $this->assertEquals( + $this->assertSame( array( 'attachment', 'single', 'singular', 'index', ), - $hierarchy + $hierarchy, + 'Incorrect hierarchy for `attachment`.' ); $hierarchy = get_template_hierarchy( 'singular' ); - $this->assertEquals( array( 'singular', 'index' ), $hierarchy ); + $this->assertSame( array( 'singular', 'index' ), $hierarchy, 'Incorrect hierarchy for `singular`.' ); $hierarchy = get_template_hierarchy( 'single' ); - $this->assertEquals( array( 'single', 'singular', 'index' ), $hierarchy ); + $this->assertSame( array( 'single', 'singular', 'index' ), $hierarchy, 'Incorrect hierarchy for `single`.' ); $hierarchy = get_template_hierarchy( 'archive' ); - $this->assertEquals( array( 'archive', 'index' ), $hierarchy ); + $this->assertSame( array( 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for `archive`.' ); $hierarchy = get_template_hierarchy( 'index' ); - $this->assertEquals( array( 'index' ), $hierarchy ); + $this->assertSame( array( 'index' ), $hierarchy, 'Incorrect hierarchy for `index`.' ); // Taxonomies. $hierarchy = get_template_hierarchy( 'taxonomy-books', false, 'taxonomy-books' ); - $this->assertEquals( array( 'taxonomy-books', 'taxonomy', 'archive', 'index' ), $hierarchy ); + $this->assertSame( array( 'taxonomy-books', 'taxonomy', 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for specific taxonomies.' ); // Single word category. $hierarchy = get_template_hierarchy( 'category-fruits', false, 'category' ); - $this->assertEquals( + $this->assertSame( array( 'category-fruits', 'category', 'archive', 'index', ), - $hierarchy + $hierarchy, + 'Incorrect hierarchy for single word categories.' ); // Multi word category. $hierarchy = get_template_hierarchy( 'category-fruits-yellow', false, 'category' ); - $this->assertEquals( + $this->assertSame( array( 'category-fruits-yellow', 'category', 'archive', 'index', ), - $hierarchy + $hierarchy, + 'Incorrect hierarchy for multi word categories.' ); - // Single word taxonomy. + // Single word taxonomy term. $hierarchy = get_template_hierarchy( 'taxonomy-books-action', false, 'taxonomy-books' ); - $this->assertEquals( + $this->assertSame( array( 'taxonomy-books-action', 'taxonomy-books', @@ -417,10 +420,11 @@ public function test_get_template_hierarchy() { 'archive', 'index', ), - $hierarchy + $hierarchy, + 'Incorrect hierarchy for single word taxonomy and term.' ); $hierarchy = get_template_hierarchy( 'taxonomy-books-action-adventure', false, 'taxonomy-books' ); - $this->assertEquals( + $this->assertSame( array( 'taxonomy-books-action-adventure', 'taxonomy-books', @@ -428,11 +432,12 @@ public function test_get_template_hierarchy() { 'archive', 'index', ), - $hierarchy + $hierarchy, + 'Incorrect hierarchy for single word taxonomy and multi word term.' ); // Multi word taxonomy/terms. $hierarchy = get_template_hierarchy( 'taxonomy-greek-books-action-adventure', false, 'taxonomy-greek-books' ); - $this->assertEquals( + $this->assertSame( array( 'taxonomy-greek-books-action-adventure', 'taxonomy-greek-books', @@ -440,31 +445,34 @@ public function test_get_template_hierarchy() { 'archive', 'index', ), - $hierarchy + $hierarchy, + 'Incorrect hierarchy for multi word taxonomy and term.' ); // Post types. $hierarchy = get_template_hierarchy( 'single-book', false, 'single-book' ); - $this->assertEquals( + $this->assertSame( array( 'single-book', 'single', 'singular', 'index', ), - $hierarchy + $hierarchy, + 'Incorrect hierarchy for single word post type.' ); $hierarchy = get_template_hierarchy( 'single-art-project', false, 'single-art-project' ); - $this->assertEquals( + $this->assertSame( array( 'single-art-project', 'single', 'singular', 'index', ), - $hierarchy + $hierarchy, + 'Incorrect hierarchy for multi word post type.' ); $hierarchy = get_template_hierarchy( 'single-art-project-imagine', false, 'single-art-project' ); - $this->assertEquals( + $this->assertSame( array( 'single-art-project-imagine', 'single-art-project', @@ -472,28 +480,31 @@ public function test_get_template_hierarchy() { 'singular', 'index', ), - $hierarchy + $hierarchy, + 'Incorrect hierarchy for single post with multi word post type.' ); $hierarchy = get_template_hierarchy( 'page-hi', false, 'page' ); - $this->assertEquals( + $this->assertSame( array( 'page-hi', 'page', 'singular', 'index', ), - $hierarchy + $hierarchy, + 'Incorrect hierarchy for single page.' ); // Authors. $hierarchy = get_template_hierarchy( 'author-rigas', false, 'author' ); - $this->assertEquals( + $this->assertSame( array( 'author-rigas', 'author', 'archive', 'index', ), - $hierarchy + $hierarchy, + 'Incorrect hierarchy for single author.' ); } } diff --git a/tests/phpunit/tests/rest-api/rest-post-types-controller.php b/tests/phpunit/tests/rest-api/rest-post-types-controller.php index 25a89f16e69c8..447e317b7eec9 100644 --- a/tests/phpunit/tests/rest-api/rest-post-types-controller.php +++ b/tests/phpunit/tests/rest-api/rest-post-types-controller.php @@ -162,19 +162,19 @@ public function test_get_item_schema() { $data = $response->get_data(); $properties = $data['schema']['properties']; $this->assertCount( 13, $properties ); - $this->assertArrayHasKey( 'capabilities', $properties ); - $this->assertArrayHasKey( 'description', $properties ); - $this->assertArrayHasKey( 'hierarchical', $properties ); - $this->assertArrayHasKey( 'viewable', $properties ); - $this->assertArrayHasKey( 'labels', $properties ); - $this->assertArrayHasKey( 'name', $properties ); - $this->assertArrayHasKey( 'slug', $properties ); - $this->assertArrayHasKey( 'supports', $properties ); - $this->assertArrayHasKey( 'taxonomies', $properties ); - $this->assertArrayHasKey( 'rest_base', $properties ); - $this->assertArrayHasKey( 'rest_namespace', $properties ); - $this->assertArrayHasKey( 'visibility', $properties ); - $this->assertArrayHasKey( 'icon', $properties ); + $this->assertArrayHasKey( 'capabilities', $properties, '`capabilities` should be included in the schema.' ); + $this->assertArrayHasKey( 'description', $properties, '`description` should be included in the schema.' ); + $this->assertArrayHasKey( 'hierarchical', $properties, '`hierarchical` should be included in the schema.' ); + $this->assertArrayHasKey( 'viewable', $properties, '`viewable` should be included in the schema.' ); + $this->assertArrayHasKey( 'labels', $properties, '`labels` should be included in the schema.' ); + $this->assertArrayHasKey( 'name', $properties, '`name` should be included in the schema.' ); + $this->assertArrayHasKey( 'slug', $properties, '`slug` should be included in the schema.' ); + $this->assertArrayHasKey( 'supports', $properties, '`supports` should be included in the schema.' ); + $this->assertArrayHasKey( 'taxonomies', $properties, '`taxonomies` should be included in the schema.' ); + $this->assertArrayHasKey( 'rest_base', $properties, '`rest_base` should be included in the schema.' ); + $this->assertArrayHasKey( 'rest_namespace', $properties, '`rest_namespace` should be included in the schema.' ); + $this->assertArrayHasKey( 'visibility', $properties, '`visibility` should be included in the schema.' ); + $this->assertArrayHasKey( 'icon', $properties, '`icon` should be included in the schema.' ); } public function test_get_additional_field_registration() { diff --git a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php index f4897411a1354..ffccc4b55331f 100644 --- a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php +++ b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php @@ -725,7 +725,7 @@ public function test_create_item_with_is_wp_suggestion() { 'is_custom' => false, 'author' => self::$admin_id, ); - $this->assertSame( $expected, $data ); + $this->assertSame( $expected, $data, 'Incorrect response when `is_wp_suggestion:true` is set.' ); // `is_wp_suggestion` false. $body_params = wp_parse_args( array( @@ -747,7 +747,7 @@ public function test_create_item_with_is_wp_suggestion() { ), $expected ); - $this->assertSame( $expected, $data ); + $this->assertSame( $expected, $data, 'Incorrect response when `is_wp_suggestion:false` is set.' ); } /** @@ -758,17 +758,17 @@ public function test_get_template_fallback() { wp_set_current_user( self::$admin_id ); switch_theme( 'block-theme' ); $request = new WP_REST_Request( 'GET', '/wp/v2/templates/lookup' ); - // Should fallback to `index.html` . + // Should fallback to `index.html`. $request->set_param( 'slug', 'tag-status' ); $request->set_param( 'is_custom', false ); $request->set_param( 'template_prefix', 'tag' ); $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( 'index', $response->get_data()->slug ); - // Should fallback to `page.html` . + $this->assertSame( 'index', $response->get_data()->slug, 'Should fallback to `index.html`.' ); + // Should fallback to `page.html`. $request->set_param( 'slug', 'page-hello' ); $request->set_param( 'is_custom', false ); $request->set_param( 'template_prefix', 'page' ); $response = rest_get_server()->dispatch( $request ); - $this->assertEquals( 'page', $response->get_data()->slug ); + $this->assertSame( 'page', $response->get_data()->slug, 'Should fallback to `page.html`.' ); } } From 942ef322fd129b5565ebfef64f0dad033c17e42d Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Tue, 20 Sep 2022 14:48:05 +0300 Subject: [PATCH 11/20] Update src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php Co-authored-by: Jonny Harris --- .../rest-api/endpoints/class-wp-rest-templates-controller.php | 1 + 1 file changed, 1 insertion(+) 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 e2ece085ae376..1d381adcd4bf4 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 @@ -78,6 +78,7 @@ public function register_routes() { 'args' => array( 'slug' => array( 'description' => __( 'The slug of the template to get the fallback for' ), + 'required' => true, 'type' => 'string', ), 'is_custom' => array( From 2bdd39335317d6f7fbb0a0c611e253acf5e5def0 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Tue, 20 Sep 2022 14:58:56 +0300 Subject: [PATCH 12/20] address feedback --- .../class-wp-rest-templates-controller.php | 13 ++++--------- tests/phpunit/tests/block-template-utils.php | 2 ++ 2 files changed, 6 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 1d381adcd4bf4..c61be608a72ce 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 @@ -74,12 +74,13 @@ public function register_routes() { array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_template_fallback' ), - 'permission_callback' => array( $this, 'get_items_permissions_check' ), + 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'slug' => array( 'description' => __( 'The slug of the template to get the fallback for' ), 'required' => true, 'type' => 'string', + 'required' => true, ), 'is_custom' => array( 'description' => __( ' Indicates if a template is custom or part of the template hierarchy' ), @@ -155,16 +156,10 @@ public function register_routes() { * @return WP_REST_Response|WP_Error */ public function get_template_fallback( $request ) { - if ( empty( $request['slug'] ) ) { - return new WP_Error( - 'rest_invalid_param', - __( 'Invalid slug.' ), - array( 'status' => 400 ) - ); - } $hierarchy = get_template_hierarchy( $request['slug'], $request['is_custom'], $request['template_prefix'] ); $fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' ); - return rest_ensure_response( $fallback_template ); + $response = $this->prepare_item_for_response( $fallback_template, $request ); + return rest_ensure_response( $response ); } /** diff --git a/tests/phpunit/tests/block-template-utils.php b/tests/phpunit/tests/block-template-utils.php index 70cb78d7979c2..34f30bfaa5aa8 100644 --- a/tests/phpunit/tests/block-template-utils.php +++ b/tests/phpunit/tests/block-template-utils.php @@ -345,6 +345,8 @@ function test_wp_generate_block_templates_export_file() { * Helper function to get the Template Hierarchy for a given slug. * * @ticket 56467 + * + * @covers ::get_template_hierarchy */ public function test_get_template_hierarchy() { $hierarchy = get_template_hierarchy( 'front-page' ); From 2dcfe25c130787460abfd2546f82899db5f3366a Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Tue, 20 Sep 2022 15:26:35 +0300 Subject: [PATCH 13/20] feedback --- .../endpoints/class-wp-rest-post-types-controller.php | 2 +- tests/phpunit/tests/rest-api/wpRestTemplatesController.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php index 6ca4b855b06af..bfad858bcbcec 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php @@ -392,7 +392,7 @@ public function get_item_schema() { ), 'icon' => array( 'description' => __( 'The icon for the post type.' ), - 'type' => 'string', + 'type' => array( 'string', 'null' ), 'context' => array( 'view', 'edit', 'embed' ), 'readonly' => true, ), diff --git a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php index ffccc4b55331f..b66668b57c89e 100644 --- a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php +++ b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php @@ -763,12 +763,12 @@ public function test_get_template_fallback() { $request->set_param( 'is_custom', false ); $request->set_param( 'template_prefix', 'tag' ); $response = rest_get_server()->dispatch( $request ); - $this->assertSame( 'index', $response->get_data()->slug, 'Should fallback to `index.html`.' ); + $this->assertSame( 'index', $response->get_data()['slug'], 'Should fallback to `index.html`.' ); // Should fallback to `page.html`. $request->set_param( 'slug', 'page-hello' ); $request->set_param( 'is_custom', false ); $request->set_param( 'template_prefix', 'page' ); $response = rest_get_server()->dispatch( $request ); - $this->assertSame( 'page', $response->get_data()->slug, 'Should fallback to `page.html`.' ); + $this->assertSame( 'page', $response->get_data()['slug'], 'Should fallback to `page.html`.' ); } } From d0c201088eb8795efdb957aee658e5d03d2c3aa7 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Tue, 20 Sep 2022 15:37:28 +0300 Subject: [PATCH 14/20] update tests and use `rest_is_field_included` --- .../class-wp-rest-post-types-controller.php | 26 +++++++++---------- tests/qunit/fixtures/wp-api-generated.js | 4 +-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php index bfad858bcbcec..8223f1dd6f38e 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php @@ -186,58 +186,58 @@ public function prepare_item_for_response( $item, $request ) { $fields = $this->get_fields_for_response( $request ); $data = array(); - if ( in_array( 'capabilities', $fields, true ) ) { + if ( rest_is_field_included( 'capabilities', $fields ) ) { $data['capabilities'] = $post_type->cap; } - if ( in_array( 'description', $fields, true ) ) { + if ( rest_is_field_included( 'description', $fields ) ) { $data['description'] = $post_type->description; } - if ( in_array( 'hierarchical', $fields, true ) ) { + if ( rest_is_field_included( 'hierarchical', $fields ) ) { $data['hierarchical'] = $post_type->hierarchical; } - if ( in_array( 'visibility', $fields, true ) ) { + if ( rest_is_field_included( 'visibility', $fields ) ) { $data['visibility'] = array( 'show_in_nav_menus' => (bool) $post_type->show_in_nav_menus, 'show_ui' => (bool) $post_type->show_ui, ); } - if ( in_array( 'viewable', $fields, true ) ) { + if ( rest_is_field_included( 'viewable', $fields ) ) { $data['viewable'] = is_post_type_viewable( $post_type ); } - if ( in_array( 'labels', $fields, true ) ) { + if ( rest_is_field_included( 'labels', $fields ) ) { $data['labels'] = $post_type->labels; } - if ( in_array( 'name', $fields, true ) ) { + if ( rest_is_field_included( 'name', $fields ) ) { $data['name'] = $post_type->label; } - if ( in_array( 'slug', $fields, true ) ) { + if ( rest_is_field_included( 'slug', $fields ) ) { $data['slug'] = $post_type->name; } - if ( in_array( 'icon', $fields, true ) ) { + if ( rest_is_field_included( 'icon', $fields ) ) { $data['icon'] = $post_type->menu_icon; } - if ( in_array( 'supports', $fields, true ) ) { + if ( rest_is_field_included( 'supports', $fields ) ) { $data['supports'] = $supports; } - if ( in_array( 'taxonomies', $fields, true ) ) { + if ( rest_is_field_included( 'taxonomies', $fields ) ) { $data['taxonomies'] = array_values( $taxonomies ); } - if ( in_array( 'rest_base', $fields, true ) ) { + if ( rest_is_field_included( 'rest_base', $fields ) ) { $data['rest_base'] = $base; } - if ( in_array( 'rest_namespace', $fields, true ) ) { + if ( rest_is_field_included( 'rest_namespace', $fields ) ) { $data['rest_namespace'] = $namespace; } diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js index 89eff763a4a88..051f176fc4a7f 100644 --- a/tests/qunit/fixtures/wp-api-generated.js +++ b/tests/qunit/fixtures/wp-api-generated.js @@ -5154,7 +5154,7 @@ mockedApiResponse.Schema = { "slug": { "description": "The slug of the template to get the fallback for", "type": "string", - "required": false + "required": true }, "is_custom": { "description": " Indicates if a template is custom or part of the template hierarchy", @@ -5843,7 +5843,7 @@ mockedApiResponse.Schema = { "slug": { "description": "The slug of the template to get the fallback for", "type": "string", - "required": false + "required": true }, "is_custom": { "description": " Indicates if a template is custom or part of the template hierarchy", From 33a4eba1c93391916b4fb99359c8dad08f0f4339 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Tue, 20 Sep 2022 15:56:54 +0300 Subject: [PATCH 15/20] remove duplicate required --- .../rest-api/endpoints/class-wp-rest-templates-controller.php | 1 - 1 file changed, 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 c61be608a72ce..e26b4d17e5ebe 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 @@ -78,7 +78,6 @@ public function register_routes() { 'args' => array( 'slug' => array( 'description' => __( 'The slug of the template to get the fallback for' ), - 'required' => true, 'type' => 'string', 'required' => true, ), From 4ef9146da49de94b12f316c33b77b309dcc9f5ec Mon Sep 17 00:00:00 2001 From: Tonya Mork Date: Tue, 20 Sep 2022 11:35:41 -0500 Subject: [PATCH 16/20] Code review updates for get_template_hierarchy() --- src/wp-includes/block-template-utils.php | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index ce09e9f293ccc..4e7a25676086c 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -1030,7 +1030,7 @@ function wp_generate_block_templates_export_file() { * @param string $slug The template slug to be created. * @param boolean $is_custom Optional. Indicates if a template is custom or * part of the template hierarchy. Default false. - * @param string $template_prefix The template prefix for the created template. + * @param string $template_prefix Optional. The template prefix for the created template. * Used to extract the main template type, e.g. * in `taxonomy-books` the `taxonomy` is extracted. * Default empty string. @@ -1046,11 +1046,13 @@ function get_template_hierarchy( $slug, $is_custom = false, $template_prefix = ' if ( 'front-page' === $slug ) { return array( 'front-page', 'home', 'index' ); } + $template_hierarchy = array( $slug ); + // Most default templates don't have `$template_prefix` assigned. if ( $template_prefix ) { - list($type) = explode( '-', $template_prefix ); - // We need these checks because we always add the `$slug` above. + list( $type ) = explode( '-', $template_prefix ); + // These checks are needed because the `$slug` above is always added. if ( ! in_array( $template_prefix, array( $slug, $type ), true ) ) { $template_hierarchy[] = $template_prefix; } @@ -1058,6 +1060,7 @@ function get_template_hierarchy( $slug, $is_custom = false, $template_prefix = ' $template_hierarchy[] = $type; } } + // Handle `archive` template. if ( str_starts_with( $slug, 'author' ) || @@ -1072,6 +1075,7 @@ function get_template_hierarchy( $slug, $is_custom = false, $template_prefix = ' if ( 'attachment' === $slug ) { $template_hierarchy[] = 'single'; } + // Handle `singular` template. if ( str_starts_with( $slug, 'single' ) || @@ -1080,6 +1084,8 @@ function get_template_hierarchy( $slug, $is_custom = false, $template_prefix = ' ) { $template_hierarchy[] = 'singular'; } + $template_hierarchy[] = 'index'; + return $template_hierarchy; }; From 5deea6b2e659e6066136cd38ab4fef2f80fa8513 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Tue, 20 Sep 2022 12:52:04 -0500 Subject: [PATCH 17/20] Test updates get_template_hierarchy(). * Moved tests to its own test file. * Moved individual assertions to a data provider. --- phpcs.xml.dist | 1 + tests/phpunit/tests/block-template-utils.php | 169 ------------------ tests/phpunit/tests/block-templates/base.php | 85 +++++++++ .../block-templates/getTemplateHierarchy.php | 124 +++++++++++++ 4 files changed, 210 insertions(+), 169 deletions(-) create mode 100644 tests/phpunit/tests/block-templates/base.php create mode 100644 tests/phpunit/tests/block-templates/getTemplateHierarchy.php diff --git a/phpcs.xml.dist b/phpcs.xml.dist index db1a76d17e721..32c6acc06d8b1 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -237,6 +237,7 @@ + diff --git a/tests/phpunit/tests/block-template-utils.php b/tests/phpunit/tests/block-template-utils.php index 34f30bfaa5aa8..7410dcaed3f68 100644 --- a/tests/phpunit/tests/block-template-utils.php +++ b/tests/phpunit/tests/block-template-utils.php @@ -340,173 +340,4 @@ function test_wp_generate_block_templates_export_file() { } $this->assertTrue( $has_html_files, 'contains at least one html file' ); } - - /** - * Helper function to get the Template Hierarchy for a given slug. - * - * @ticket 56467 - * - * @covers ::get_template_hierarchy - */ - public function test_get_template_hierarchy() { - $hierarchy = get_template_hierarchy( 'front-page' ); - $this->assertSame( array( 'front-page', 'home', 'index' ), $hierarchy, 'Incorrect hierarchy for `front-page`.' ); - // Custom templates. - $hierarchy = get_template_hierarchy( 'whatever-slug', true ); - $this->assertSame( array( 'page', 'singular', 'index' ), $hierarchy, 'Incorrect hierarchy for custom template.' ); - // Single slug templates(ex. page, tag, author, etc.. - $hierarchy = get_template_hierarchy( 'page' ); - $this->assertSame( array( 'page', 'singular', 'index' ), $hierarchy, 'Incorrect hierarchy for `page`.' ); - $hierarchy = get_template_hierarchy( 'tag' ); - $this->assertSame( array( 'tag', 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for `tag`.' ); - $hierarchy = get_template_hierarchy( 'author' ); - $this->assertSame( array( 'author', 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for `author`.' ); - $hierarchy = get_template_hierarchy( 'date' ); - $this->assertSame( array( 'date', 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for `date`.' ); - $hierarchy = get_template_hierarchy( 'taxonomy' ); - $this->assertSame( array( 'taxonomy', 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for `taxonomy`.' ); - $hierarchy = get_template_hierarchy( 'attachment' ); - $this->assertSame( - array( - 'attachment', - 'single', - 'singular', - 'index', - ), - $hierarchy, - 'Incorrect hierarchy for `attachment`.' - ); - $hierarchy = get_template_hierarchy( 'singular' ); - $this->assertSame( array( 'singular', 'index' ), $hierarchy, 'Incorrect hierarchy for `singular`.' ); - $hierarchy = get_template_hierarchy( 'single' ); - $this->assertSame( array( 'single', 'singular', 'index' ), $hierarchy, 'Incorrect hierarchy for `single`.' ); - $hierarchy = get_template_hierarchy( 'archive' ); - $this->assertSame( array( 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for `archive`.' ); - $hierarchy = get_template_hierarchy( 'index' ); - $this->assertSame( array( 'index' ), $hierarchy, 'Incorrect hierarchy for `index`.' ); - - // Taxonomies. - $hierarchy = get_template_hierarchy( 'taxonomy-books', false, 'taxonomy-books' ); - $this->assertSame( array( 'taxonomy-books', 'taxonomy', 'archive', 'index' ), $hierarchy, 'Incorrect hierarchy for specific taxonomies.' ); - // Single word category. - $hierarchy = get_template_hierarchy( 'category-fruits', false, 'category' ); - $this->assertSame( - array( - 'category-fruits', - 'category', - 'archive', - 'index', - ), - $hierarchy, - 'Incorrect hierarchy for single word categories.' - ); - // Multi word category. - $hierarchy = get_template_hierarchy( 'category-fruits-yellow', false, 'category' ); - $this->assertSame( - array( - 'category-fruits-yellow', - 'category', - 'archive', - 'index', - ), - $hierarchy, - 'Incorrect hierarchy for multi word categories.' - ); - // Single word taxonomy term. - $hierarchy = get_template_hierarchy( 'taxonomy-books-action', false, 'taxonomy-books' ); - $this->assertSame( - array( - 'taxonomy-books-action', - 'taxonomy-books', - 'taxonomy', - 'archive', - 'index', - ), - $hierarchy, - 'Incorrect hierarchy for single word taxonomy and term.' - ); - $hierarchy = get_template_hierarchy( 'taxonomy-books-action-adventure', false, 'taxonomy-books' ); - $this->assertSame( - array( - 'taxonomy-books-action-adventure', - 'taxonomy-books', - 'taxonomy', - 'archive', - 'index', - ), - $hierarchy, - 'Incorrect hierarchy for single word taxonomy and multi word term.' - ); - // Multi word taxonomy/terms. - $hierarchy = get_template_hierarchy( 'taxonomy-greek-books-action-adventure', false, 'taxonomy-greek-books' ); - $this->assertSame( - array( - 'taxonomy-greek-books-action-adventure', - 'taxonomy-greek-books', - 'taxonomy', - 'archive', - 'index', - ), - $hierarchy, - 'Incorrect hierarchy for multi word taxonomy and term.' - ); - // Post types. - $hierarchy = get_template_hierarchy( 'single-book', false, 'single-book' ); - $this->assertSame( - array( - 'single-book', - 'single', - 'singular', - 'index', - ), - $hierarchy, - 'Incorrect hierarchy for single word post type.' - ); - $hierarchy = get_template_hierarchy( 'single-art-project', false, 'single-art-project' ); - $this->assertSame( - array( - 'single-art-project', - 'single', - 'singular', - 'index', - ), - $hierarchy, - 'Incorrect hierarchy for multi word post type.' - ); - $hierarchy = get_template_hierarchy( 'single-art-project-imagine', false, 'single-art-project' ); - $this->assertSame( - array( - 'single-art-project-imagine', - 'single-art-project', - 'single', - 'singular', - 'index', - ), - $hierarchy, - 'Incorrect hierarchy for single post with multi word post type.' - ); - $hierarchy = get_template_hierarchy( 'page-hi', false, 'page' ); - $this->assertSame( - array( - 'page-hi', - 'page', - 'singular', - 'index', - ), - $hierarchy, - 'Incorrect hierarchy for single page.' - ); - // Authors. - $hierarchy = get_template_hierarchy( 'author-rigas', false, 'author' ); - $this->assertSame( - array( - 'author-rigas', - 'author', - 'archive', - 'index', - ), - $hierarchy, - 'Incorrect hierarchy for single author.' - ); - } } diff --git a/tests/phpunit/tests/block-templates/base.php b/tests/phpunit/tests/block-templates/base.php new file mode 100644 index 0000000000000..77c66359cb31f --- /dev/null +++ b/tests/phpunit/tests/block-templates/base.php @@ -0,0 +1,85 @@ +post->create_and_get( + array( + 'post_type' => 'wp_template', + 'post_name' => 'my_template', + 'post_title' => 'My Template', + 'post_content' => 'Content', + 'post_excerpt' => 'Description of my template', + 'tax_input' => array( + 'wp_theme' => array( + 'this-theme-should-not-resolve', + ), + ), + ) + ); + + wp_set_post_terms( self::$template_post->ID, 'this-theme-should-not-resolve', 'wp_theme' ); + + // Set up template post. + self::$template_post = $factory->post->create_and_get( + array( + 'post_type' => 'wp_template', + 'post_name' => 'my_template', + 'post_title' => 'My Template', + 'post_content' => 'Content', + 'post_excerpt' => 'Description of my template', + 'tax_input' => array( + 'wp_theme' => array( + self::TEST_THEME, + ), + ), + ) + ); + + wp_set_post_terms( self::$template_post->ID, self::TEST_THEME, 'wp_theme' ); + + // Set up template part post. + self::$template_part_post = $factory->post->create_and_get( + array( + 'post_type' => 'wp_template_part', + 'post_name' => 'my_template_part', + 'post_title' => 'My Template Part', + 'post_content' => 'Content', + 'post_excerpt' => 'Description of my template part', + 'tax_input' => array( + 'wp_theme' => array( + self::TEST_THEME, + ), + 'wp_template_part_area' => array( + WP_TEMPLATE_PART_AREA_HEADER, + ), + ), + ) + ); + + wp_set_post_terms( self::$template_part_post->ID, WP_TEMPLATE_PART_AREA_HEADER, 'wp_template_part_area' ); + wp_set_post_terms( self::$template_part_post->ID, self::TEST_THEME, 'wp_theme' ); + } + + public static function wpTearDownAfterClass() { + wp_delete_post( self::$template_post->ID ); + } + + public function set_up() { + parent::set_up(); + switch_theme( self::TEST_THEME ); + } +} diff --git a/tests/phpunit/tests/block-templates/getTemplateHierarchy.php b/tests/phpunit/tests/block-templates/getTemplateHierarchy.php new file mode 100644 index 0000000000000..e550b22778417 --- /dev/null +++ b/tests/phpunit/tests/block-templates/getTemplateHierarchy.php @@ -0,0 +1,124 @@ +assertSame( $expected, get_template_hierarchy( ...$args ) ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_get_template_hierarchy() { + return array( + 'front-page' => array( + 'args' => array( 'front-page' ), + 'expected' => array( 'front-page', 'home', 'index' ), + ), + 'custom template' => array( + 'args' => array( 'whatever-slug', true ), + 'expected' => array( 'page', 'singular', 'index' ), + ), + 'page' => array( + 'args' => array( 'page' ), + 'expected' => array( 'page', 'singular', 'index' ), + ), + 'tag' => array( + 'args' => array( 'tag' ), + 'expected' => array( 'tag', 'archive', 'index' ), + ), + 'author' => array( + 'args' => array( 'author' ), + 'expected' => array( 'author', 'archive', 'index' ), + ), + 'date' => array( + 'args' => array( 'date' ), + 'expected' => array( 'date', 'archive', 'index' ), + ), + 'taxonomy' => array( + 'args' => array( 'taxonomy' ), + 'expected' => array( 'taxonomy', 'archive', 'index' ), + ), + 'attachment' => array( + 'args' => array( 'attachment' ), + 'expected' => array( 'attachment', 'single', 'singular', 'index' ), + ), + 'singular' => array( + 'args' => array( 'singular' ), + 'expected' => array( 'singular', 'index' ), + ), + 'single' => array( + 'args' => array( 'single' ), + 'expected' => array( 'single', 'singular', 'index' ), + ), + 'archive' => array( + 'args' => array( 'archive' ), + 'expected' => array( 'archive', 'index' ), + ), + 'index' => array( + 'args' => array( 'index' ), + 'expected' => array( 'index' ), + ), + 'specific taxonomies' => array( + 'args' => array( 'taxonomy-books', false, 'taxonomy-books' ), + 'expected' => array( 'taxonomy-books', 'taxonomy', 'archive', 'index' ), + ), + 'single word categories' => array( + 'args' => array( 'category-fruits', false, 'category' ), + 'expected' => array( 'category-fruits', 'category', 'archive', 'index' ), + ), + 'multi word categories' => array( + 'args' => array( 'category-fruits-yellow', false, 'category' ), + 'expected' => array( 'category-fruits-yellow', 'category', 'archive', 'index' ), + ), + 'single word taxonomy and term' => array( + 'args' => array( 'taxonomy-books-action', false, 'taxonomy-books' ), + 'expected' => array( 'taxonomy-books-action', 'taxonomy-books', 'taxonomy', 'archive', 'index' ), + ), + 'single word taxonomy and multi word term' => array( + 'args' => array( 'taxonomy-books-action-adventure', false, 'taxonomy-books' ), + 'expected' => array( 'taxonomy-books-action-adventure', 'taxonomy-books', 'taxonomy', 'archive', 'index' ), + ), + 'multi word taxonomy and term' => array( + 'args' => array( 'taxonomy-greek-books-action-adventure', false, 'taxonomy-greek-books' ), + 'expected' => array( 'taxonomy-greek-books-action-adventure', 'taxonomy-greek-books', 'taxonomy', 'archive', 'index' ), + ), + 'single word post type' => array( + 'args' => array( 'single-book', false, 'single-book' ), + 'expected' => array( 'single-book', 'single', 'singular', 'index' ), + ), + 'multi word post type' => array( + 'args' => array( 'single-art-project', false, 'single-art-project' ), + 'expected' => array( 'single-art-project', 'single', 'singular', 'index' ), + ), + 'single post with multi word post type' => array( + 'args' => array( 'single-art-project-imagine', false, 'single-art-project' ), + 'expected' => array( 'single-art-project-imagine', 'single-art-project', 'single', 'singular', 'index' ), + ), + 'single page' => array( + 'args' => array( 'page-hi', false, 'page' ), + 'expected' => array( 'page-hi', 'page', 'singular', 'index' ), + ), + 'authors' => array( + 'args' => array( 'author-rigas', false, 'author' ), + 'expected' => array( 'author-rigas', 'author', 'archive', 'index' ), + ), + ); + } +} From 5ba2daf65cf1895732d7cc3e47ddea4d9db4d761 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Tue, 20 Sep 2022 13:58:26 -0500 Subject: [PATCH 18/20] Updates to REST API tests --- .../rest-api/rest-post-types-controller.php | 34 ++++---- .../rest-api/wpRestTemplatesController.php | 80 ++++++++++++------- 2 files changed, 69 insertions(+), 45 deletions(-) diff --git a/tests/phpunit/tests/rest-api/rest-post-types-controller.php b/tests/phpunit/tests/rest-api/rest-post-types-controller.php index 447e317b7eec9..982fb4e04a23d 100644 --- a/tests/phpunit/tests/rest-api/rest-post-types-controller.php +++ b/tests/phpunit/tests/rest-api/rest-post-types-controller.php @@ -156,25 +156,31 @@ public function test_prepare_item_limit_fields() { ); } + /** + * @ticket 56467 + * + * @covers WP_REST_Post_Types_Controller::get_item_schema + */ public function test_get_item_schema() { $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/types' ); $response = rest_get_server()->dispatch( $request ); $data = $response->get_data(); $properties = $data['schema']['properties']; - $this->assertCount( 13, $properties ); - $this->assertArrayHasKey( 'capabilities', $properties, '`capabilities` should be included in the schema.' ); - $this->assertArrayHasKey( 'description', $properties, '`description` should be included in the schema.' ); - $this->assertArrayHasKey( 'hierarchical', $properties, '`hierarchical` should be included in the schema.' ); - $this->assertArrayHasKey( 'viewable', $properties, '`viewable` should be included in the schema.' ); - $this->assertArrayHasKey( 'labels', $properties, '`labels` should be included in the schema.' ); - $this->assertArrayHasKey( 'name', $properties, '`name` should be included in the schema.' ); - $this->assertArrayHasKey( 'slug', $properties, '`slug` should be included in the schema.' ); - $this->assertArrayHasKey( 'supports', $properties, '`supports` should be included in the schema.' ); - $this->assertArrayHasKey( 'taxonomies', $properties, '`taxonomies` should be included in the schema.' ); - $this->assertArrayHasKey( 'rest_base', $properties, '`rest_base` should be included in the schema.' ); - $this->assertArrayHasKey( 'rest_namespace', $properties, '`rest_namespace` should be included in the schema.' ); - $this->assertArrayHasKey( 'visibility', $properties, '`visibility` should be included in the schema.' ); - $this->assertArrayHasKey( 'icon', $properties, '`icon` should be included in the schema.' ); + + $this->assertCount( 13, $properties, 'Schema should have 13 properties' ); + $this->assertArrayHasKey( 'capabilities', $properties, '`capabilities` should be included in the schema' ); + $this->assertArrayHasKey( 'description', $properties, '`description` should be included in the schema' ); + $this->assertArrayHasKey( 'hierarchical', $properties, '`hierarchical` should be included in the schema' ); + $this->assertArrayHasKey( 'viewable', $properties, '`viewable` should be included in the schema' ); + $this->assertArrayHasKey( 'labels', $properties, '`labels` should be included in the schema' ); + $this->assertArrayHasKey( 'name', $properties, '`name` should be included in the schema' ); + $this->assertArrayHasKey( 'slug', $properties, '`slug` should be included in the schema' ); + $this->assertArrayHasKey( 'supports', $properties, '`supports` should be included in the schema' ); + $this->assertArrayHasKey( 'taxonomies', $properties, '`taxonomies` should be included in the schema' ); + $this->assertArrayHasKey( 'rest_base', $properties, '`rest_base` should be included in the schema' ); + $this->assertArrayHasKey( 'rest_namespace', $properties, '`rest_namespace` should be included in the schema' ); + $this->assertArrayHasKey( 'visibility', $properties, '`visibility` should be included in the schema' ); + $this->assertArrayHasKey( 'icon', $properties, '`icon` should be included in the schema' ); } public function test_get_additional_field_registration() { diff --git a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php index b66668b57c89e..0ddd023c012f2 100644 --- a/tests/phpunit/tests/rest-api/wpRestTemplatesController.php +++ b/tests/phpunit/tests/rest-api/wpRestTemplatesController.php @@ -685,26 +685,35 @@ protected function find_and_normalize_template_by_id( $templates, $id ) { } /** + * @dataProvider data_create_item_with_is_wp_suggestion * @ticket 56467 * @covers WP_REST_Templates_Controller::create_item + * + * @param array $body_params Data set to test. + * @param array $expected Expected results. */ - public function test_create_item_with_is_wp_suggestion() { + public function test_create_item_with_is_wp_suggestion( array $body_params, array $expected ) { + // Set up the user. + $body_params['author'] = self::$admin_id; + $expected['author'] = self::$admin_id; wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'POST', '/wp/v2/templates' ); - // `is_wp_suggestion` true. - $body_params = array( - 'slug' => 'page-rigas', - 'description' => 'Just a description', - 'title' => 'My Template', - 'content' => 'Content', - 'is_wp_suggestion' => true, - 'author' => self::$admin_id, - ); $request->set_body_params( $body_params ); $response = rest_get_server()->dispatch( $request ); $data = $response->get_data(); unset( $data['_links'] ); unset( $data['wp_id'] ); + + $this->assertSame( $expected, $data ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_create_item_with_is_wp_suggestion() { $expected = array( 'id' => 'default//page-rigas', 'theme' => 'default', @@ -723,31 +732,40 @@ public function test_create_item_with_is_wp_suggestion() { 'status' => 'publish', 'has_theme_file' => false, 'is_custom' => false, - 'author' => self::$admin_id, + 'author' => null, ); - $this->assertSame( $expected, $data, 'Incorrect response when `is_wp_suggestion:true` is set.' ); - // `is_wp_suggestion` false. - $body_params = wp_parse_args( - array( - 'slug' => 'page-hi', - 'is_wp_suggestion' => false, + + return array( + 'is_wp_suggestion: true' => array( + 'body_params' => array( + 'slug' => 'page-rigas', + 'description' => 'Just a description', + 'title' => 'My Template', + 'content' => 'Content', + 'is_wp_suggestion' => true, + 'author' => null, + ), + 'expected' => $expected, ), - $body_params - ); - $request->set_body_params( $body_params ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - unset( $data['_links'] ); - unset( $data['wp_id'] ); - $expected = wp_parse_args( - array( - 'id' => 'default//page-hi', - 'slug' => 'page-hi', - 'is_custom' => true, + 'is_wp_suggestion: false' => array( + 'body_params' => array( + 'slug' => 'page-hi', + 'description' => 'Just a description', + 'title' => 'My Template', + 'content' => 'Content', + 'is_wp_suggestion' => false, + 'author' => null, + ), + 'expected' => array_merge( + $expected, + array( + 'id' => 'default//page-hi', + 'slug' => 'page-hi', + 'is_custom' => true, + ) + ), ), - $expected ); - $this->assertSame( $expected, $data, 'Incorrect response when `is_wp_suggestion:false` is set.' ); } /** From 0d2d57ced962aacfac96ff817431c363b05f23a0 Mon Sep 17 00:00:00 2001 From: hellofromtonya Date: Tue, 20 Sep 2022 15:04:44 -0500 Subject: [PATCH 19/20] Reapply changeset 54184. After rebasing on top of trunk, the PR reverted some of the changes in wp-includes/block-template-utils.php that were added in changest 54184. This commit reapplies the code from that changeset. It also cleans up in one test. --- src/wp-includes/block-template-utils.php | 12 ++++++++++-- tests/phpunit/tests/block-templates/base.php | 1 + 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index 4e7a25676086c..369aec86506e2 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -552,8 +552,8 @@ function _build_block_template_result_from_post( $post ) { } $theme = $terms[0]->name; - $has_theme_file = wp_get_theme()->get_stylesheet() === $theme && - null !== _get_block_template_file( $post->post_type, $post->post_name ); + $template_file = _get_block_template_file( $post->post_type, $post->post_name ); + $has_theme_file = wp_get_theme()->get_stylesheet() === $theme && null !== $template_file; $origin = get_post_meta( $post->ID, 'origin', true ); $is_wp_suggestion = get_post_meta( $post->ID, 'is_wp_suggestion', true ); @@ -680,6 +680,14 @@ function get_block_templates( $query = array(), $template_type = 'wp_template' ) continue; } + if ( + $post_type && + isset( $template->post_types ) && + ! in_array( $post_type, $template->post_types, true ) + ) { + continue; + } + $query_result[] = $template; } diff --git a/tests/phpunit/tests/block-templates/base.php b/tests/phpunit/tests/block-templates/base.php index 77c66359cb31f..f6a5a9f4dfcec 100644 --- a/tests/phpunit/tests/block-templates/base.php +++ b/tests/phpunit/tests/block-templates/base.php @@ -76,6 +76,7 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { public static function wpTearDownAfterClass() { wp_delete_post( self::$template_post->ID ); + wp_delete_post( self::$template_part_post->ID ); } public function set_up() { From 4b32c1505c59747c1e45a766060941d2eca2399b Mon Sep 17 00:00:00 2001 From: Tonya Mork Date: Tue, 20 Sep 2022 15:59:57 -0500 Subject: [PATCH 20/20] Improve DocBlock. --- src/wp-includes/block-template-utils.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index 369aec86506e2..a16fe2914c821 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -1028,8 +1028,8 @@ function wp_generate_block_templates_export_file() { } /** - * Helper function to get the Template Hierarchy for the given slug. - * Handles special cases like `front-page`, `singular` and `archive` templates. + * Gets the template hierarchy for the given template slug to be created. + * * * Note: Always add `index` as the last fallback template. *