From c6b83c17110628d452fcfba4908afa8181e71f9f Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 25 Nov 2021 12:39:54 +0100 Subject: [PATCH] Update the block theme folders to templates and parts (#36647) --- .../themes/block-theme-overview.md | 6 +-- .../themes/create-block-theme.md | 28 +++++------ docs/how-to-guides/themes/theme-json.md | 4 +- .../wordpress-5.9/block-template-utils.php | 47 ++++++++++++++----- lib/compat/wordpress-5.9/edit-site-export.php | 8 ++-- lib/full-site-editing/full-site-editing.php | 3 +- .../block-library/src/template-part/index.php | 3 +- phpunit/class-edit-site-export-test.php | 8 ++-- phpunit/class-template-loader-test.php | 8 ++-- .../page-1.html | 0 .../{block-templates => templates}/index.html | 0 .../page-home.html | 0 .../{block-templates => templates}/page.html | 0 schemas/json/theme.json | 8 ++-- 14 files changed, 74 insertions(+), 49 deletions(-) rename phpunit/fixtures/themes/test-theme-child/{block-templates => templates}/page-1.html (100%) rename phpunit/fixtures/themes/test-theme/{block-templates => templates}/index.html (100%) rename phpunit/fixtures/themes/test-theme/{block-templates => templates}/page-home.html (100%) rename phpunit/fixtures/themes/test-theme/{block-templates => templates}/page.html (100%) diff --git a/docs/how-to-guides/themes/block-theme-overview.md b/docs/how-to-guides/themes/block-theme-overview.md index 4a8e109639c00..9c5806d37e17f 100644 --- a/docs/how-to-guides/themes/block-theme-overview.md +++ b/docs/how-to-guides/themes/block-theme-overview.md @@ -19,12 +19,12 @@ theme |__ style.css |__ theme.json |__ functions.php -|__ block-templates +|__ templates |__ index.html |__ single.html |__ archive.html |__ ... -|__ block-template-parts +|__ parts |__ header.html |__ footer.html |__ sidebar.html @@ -78,7 +78,7 @@ Please note that the "Templates" admin menu under "Appearance" will _not_ list t ### Edit Templates within the Full-site Editor -To begin, create a blank template file within your theme. For example: `mytheme/block-templates/index.html`. Afterwards, open the Full-site editor. Your new template should appear as the active template, and should be blank. Add blocks as you normally would using Gutenberg. You can add and create template parts directly using the "Template Parts" block. +To begin, create a blank template file within your theme. For example: `mytheme/templates/index.html`. Afterwards, open the Full-site editor. Your new template should appear as the active template, and should be blank. Add blocks as you normally would using Gutenberg. You can add and create template parts directly using the "Template Parts" block. Repeat for any additional templates you'd like to bundle with your theme. diff --git a/docs/how-to-guides/themes/create-block-theme.md b/docs/how-to-guides/themes/create-block-theme.md index 3002e245b69eb..8ba9de733a144 100644 --- a/docs/how-to-guides/themes/create-block-theme.md +++ b/docs/how-to-guides/themes/create-block-theme.md @@ -26,10 +26,10 @@ To use a block theme, you first need to activate the Gutenberg plugin. There are two files that are required to activate any theme: `index.php` and `style.css`. For the plugin to recognize that a block theme is active, the theme must also include an `index.html` template -inside a folder called `block-templates`. +inside a folder called `templates`. The theme may optionally include a `functions.php` file and a [theme.json file](/docs/how-to-guides/themes/theme-json.md) to manage global styles. -Template parts are optional. If they are included they must be placed inside a `block-template-parts` folder. +Template parts are optional. If they are included they must be placed inside a `parts` folder. File structure: ``` @@ -38,10 +38,10 @@ theme |__ functions.php |__ index.php |__ theme.json -|__ block-templates +|__ templates |__ index.html |__ ... -|__ block-template-parts +|__ parts |__ header.html |__ footer.html |__ ... @@ -52,7 +52,7 @@ theme Create a new folder for your theme in `/wp-content/themes/`. In this example, the folder name is `fse-tutorial`. -Inside the theme folder, create the `block-templates` and `block-template-parts` folders. +Inside the theme folder, create the `templates` and `parts` folders. Create a `style.css` file. The file header in the `style.css` file has [the same items you would use in a classic theme](https://developer.wordpress.org/themes/basics/main-stylesheet-style-css/#explanations). @@ -79,7 +79,7 @@ Use it to make something cool, have fun, and share what you've learned with othe Create a blank `index.php` file. This file is used as a fallback if the theme is activated without Gutenberg. -Inside the `block-templates` folder, create a blank `index.html` file. +Inside the `templates` folder, create a blank `index.html` file. Optionally, create a `functions.php` file. In this file, you can enqueue `style.css`, include additional files, enable an editor stylesheet and add theme support. @@ -132,9 +132,9 @@ theme |__ style.css |__ functions.php (optional) |__ index.php - |__ block-templates + |__ templates |__ index.html - |__ block-template-parts + |__ parts |__ (empty folder) ``` @@ -151,7 +151,7 @@ The fourth way is temporary and involves going to the Appearance menu > Template ### Manual template creation -Create two template part files called `header.html` and `footer.html` and place them inside the `block-template-parts` folder. +Create two template part files called `header.html` and `footer.html` and place them inside the `parts` folder. When you add blocks manually to your HTML files, start with an HTML comment that includes the block name prefixed with `wp:`. There are both self-closing and multi-line blocks as shown in the example below. @@ -240,8 +240,8 @@ are saved to the database as custom post types. To export them as theme files, f - In the site editor, open the **More tools and options** menu. - Select the **Export** option to download a zip file containing the files. Unpack the files. -- Copy the updated `index.html` file from `theme/block-templates/` to your theme's `block-templates` folder. -- Copy template part one and two from `theme/block-template-parts/` to your theme's `block-template-parts` folder. +- Copy the updated `index.html` file from `theme/templates/` to your theme's `templates` folder. +- Copy template part one and two from `theme/parts/` to your theme's `parts` folder. - Rename the template parts to `header.html` and `footer.html`, respectively. - Open `index.html` and update the template part slugs in the block markup. @@ -319,7 +319,7 @@ The query pagination block can only be used inside the query loop. Place it insi #### Posts and pages Next, create a new template for displaying single posts. -If you are editing theme files directly, create a file called `single.html` inside the block-templates folder. +If you are editing theme files directly, create a file called `single.html` inside the templates folder. Add the site header and site footer template parts: @@ -353,7 +353,7 @@ Add your preferred blocks inside the group block. Some new blocks that are avail Save the HTML file, or save and export the post template if you are working in the site editor. Copy all the blocks and create a template for displaying pages. -Optionally, save a copy of `single.html` as `page.html` inside the block-templates folder. +Optionally, save a copy of `single.html` as `page.html` inside the templates folder. Adjust the blocks for the page template, and save. #### Archives @@ -805,7 +805,7 @@ There are three template areas to choose from: Header, footer, and general. ## Custom templates Custom templates for posts, pages, and custom post types are created by adding additional HTML files inside the -`block-templates` folder. +`templates` folder. In a classic theme, templates are identified with a file header. In a block theme, you list templates in the `theme.json` file. All templates that are listed in the `customTemplates` section of `theme.json` are selectable in the site editor. diff --git a/docs/how-to-guides/themes/theme-json.md b/docs/how-to-guides/themes/theme-json.md index b20dffc8ca5db..53000383039cd 100644 --- a/docs/how-to-guides/themes/theme-json.md +++ b/docs/how-to-guides/themes/theme-json.md @@ -941,7 +941,7 @@ h3 { This field is only allowed when the Gutenberg plugin is active. In WordPress 5.8 will be ignored. -Within this field themes can list the custom templates present in the `block-templates` folder. For example, for a custom template named `my-custom-template.html`, the `theme.json` can declare what post types can use it and what's the title to show the user: +Within this field themes can list the custom templates present in the `templates` folder. For example, for a custom template named `my-custom-template.html`, the `theme.json` can declare what post types can use it and what's the title to show the user: - name: mandatory. - title: mandatory, translatable. @@ -970,7 +970,7 @@ Within this field themes can list the custom templates present in the `block-tem This field is only allowed when the Gutenberg plugin is active. In WordPress 5.8 will be ignored. -Within this field themes can list the template parts present in the `block-template-parts` folder. For example, for a template part named `my-template-part.html`, the `theme.json` can declare the area term for the template part entity which is responsible for rendering the corresponding block variation (Header block, Footer block, etc.) in the editor. Defining this area term in the json will allow the setting to persist across all uses of that template part entity, as opposed to a block attribute that would only affect one block. Defining area as a block attribute is not recommended as this is only used 'behind the scenes' to aid in bridging the gap between placeholder flows and entity creation. +Within this field themes can list the template parts present in the `parts` folder. For example, for a template part named `my-template-part.html`, the `theme.json` can declare the area term for the template part entity which is responsible for rendering the corresponding block variation (Header block, Footer block, etc.) in the editor. Defining this area term in the json will allow the setting to persist across all uses of that template part entity, as opposed to a block attribute that would only affect one block. Defining area as a block attribute is not recommended as this is only used 'behind the scenes' to aid in bridging the gap between placeholder flows and entity creation. Currently block variations exist for "header" and "footer" values of the area term, any other values and template parts not defined in the json will default to the general template part block. Variations will be denoted by specific icons within the editor's interface, will default to the corresponding semantic HTML element for the wrapper (this can also be overridden by the `tagName` attribute set on the template part block), and will contextualize the template part allowing more custom flows in future editor improvements. diff --git a/lib/compat/wordpress-5.9/block-template-utils.php b/lib/compat/wordpress-5.9/block-template-utils.php index 16a56d8230171..690fae6a16a46 100644 --- a/lib/compat/wordpress-5.9/block-template-utils.php +++ b/lib/compat/wordpress-5.9/block-template-utils.php @@ -21,6 +21,36 @@ define( 'WP_TEMPLATE_PART_AREA_UNCATEGORIZED', 'uncategorized' ); } + +if ( ! function_exists( 'get_block_theme_folders' ) ) { + /** + * For backward compatibility reasons, + * block themes might be using block-templates or block-template-parts, + * this function ensures we fallback to these folders properly. + * + * @param string $theme_stylesheet The stylesheet. Default is to leverage the main theme root. + * + * @return array Folder names used by block themes. + */ + function get_block_theme_folders( $theme_stylesheet = null ) { + $theme_name = null === $theme_stylesheet ? get_stylesheet() : $theme_stylesheet; + $root_dir = get_theme_root( $theme_name ); + $theme_dir = "$root_dir/$theme_name"; + + if ( is_readable( $theme_dir . '/block-templates/index.html' ) ) { + return array( + 'wp_template' => 'block-templates', + 'wp_template_part' => 'block-template-parts', + ); + } + + return array( + 'wp_template' => 'templates', + 'wp_template_part' => 'parts', + ); + } +} + if ( ! function_exists( 'get_allowed_block_template_part_areas' ) ) { /** * Returns a filtered list of allowed area values for template parts. @@ -222,16 +252,13 @@ function _get_block_template_file( $template_type, $slug ) { return null; } - $template_base_paths = array( - 'wp_template' => 'block-templates', - 'wp_template_part' => 'block-template-parts', - ); - $themes = array( + $themes = array( get_stylesheet() => get_stylesheet_directory(), get_template() => get_template_directory(), ); foreach ( $themes as $theme_slug => $theme_dir ) { - $file_path = $theme_dir . '/' . $template_base_paths[ $template_type ] . '/' . $slug . '.html'; + $template_base_paths = get_block_theme_folders( $theme_slug ); + $file_path = $theme_dir . '/' . $template_base_paths[ $template_type ] . '/' . $slug . '.html'; if ( file_exists( $file_path ) ) { $new_template_item = array( 'slug' => $slug, @@ -272,17 +299,13 @@ function _get_block_templates_files( $template_type ) { return null; } - $template_base_paths = array( - 'wp_template' => 'block-templates', - 'wp_template_part' => 'block-template-parts', - ); - $themes = array( + $themes = array( get_stylesheet() => get_stylesheet_directory(), get_template() => get_template_directory(), ); - $template_files = array(); foreach ( $themes as $theme_slug => $theme_dir ) { + $template_base_paths = get_block_theme_folders( $theme_slug ); $theme_template_files = _get_block_templates_paths( $theme_dir . '/' . $template_base_paths[ $template_type ] ); foreach ( $theme_template_files as $template_file ) { $template_base_path = $template_base_paths[ $template_type ]; diff --git a/lib/compat/wordpress-5.9/edit-site-export.php b/lib/compat/wordpress-5.9/edit-site-export.php index 825766cffcab7..6c5380b1ded73 100644 --- a/lib/compat/wordpress-5.9/edit-site-export.php +++ b/lib/compat/wordpress-5.9/edit-site-export.php @@ -27,8 +27,8 @@ function wp_generate_edit_site_export_file() { } $zip->addEmptyDir( 'theme' ); - $zip->addEmptyDir( 'theme/block-templates' ); - $zip->addEmptyDir( 'theme/block-template-parts' ); + $zip->addEmptyDir( 'theme/templates' ); + $zip->addEmptyDir( 'theme/parts' ); // Load templates into the zip file. $templates = gutenberg_get_block_templates(); @@ -36,7 +36,7 @@ function wp_generate_edit_site_export_file() { $template->content = _remove_theme_attribute_in_block_template_content( $template->content ); $zip->addFromString( - 'theme/block-templates/' . $template->slug . '.html', + 'theme/templates/' . $template->slug . '.html', $template->content ); } @@ -45,7 +45,7 @@ function wp_generate_edit_site_export_file() { $template_parts = gutenberg_get_block_templates( array(), 'wp_template_part' ); foreach ( $template_parts as $template_part ) { $zip->addFromString( - 'theme/block-template-parts/' . $template_part->slug . '.html', + 'theme/parts/' . $template_part->slug . '.html', $template_part->content ); } diff --git a/lib/full-site-editing/full-site-editing.php b/lib/full-site-editing/full-site-editing.php index a9dd85fb2f9c2..8320d1b32ccb3 100644 --- a/lib/full-site-editing/full-site-editing.php +++ b/lib/full-site-editing/full-site-editing.php @@ -11,7 +11,8 @@ * @return boolean Whether the current theme is an FSE theme or not. */ function gutenberg_is_fse_theme() { - return is_readable( get_theme_file_path( '/block-templates/index.html' ) ); + return is_readable( get_theme_file_path( '/block-templates/index.html' ) ) || + is_readable( get_theme_file_path( '/templates/index.html' ) ); } /** diff --git a/packages/block-library/src/template-part/index.php b/packages/block-library/src/template-part/index.php index 9f28002b32571..fe16679a1f318 100644 --- a/packages/block-library/src/template-part/index.php +++ b/packages/block-library/src/template-part/index.php @@ -53,7 +53,8 @@ function render_block_core_template_part( $attributes ) { } else { // Else, if the template part was provided by the active theme, // render the corresponding file content. - $template_part_file_path = get_theme_file_path( '/block-template-parts/' . $attributes['slug'] . '.html' ); + $theme_folders = get_block_theme_folders(); + $template_part_file_path = get_theme_file_path( '/' . $theme_folders['wp_template_part'] . '/' . $attributes['slug'] . '.html' ); if ( 0 === validate_file( $attributes['slug'] ) && file_exists( $template_part_file_path ) ) { $content = file_get_contents( $template_part_file_path ); $content = is_string( $content ) && '' !== $content diff --git a/phpunit/class-edit-site-export-test.php b/phpunit/class-edit-site-export-test.php index ae56f11f283de..72355ecec34d9 100644 --- a/phpunit/class-edit-site-export-test.php +++ b/phpunit/class-edit-site-export-test.php @@ -15,11 +15,11 @@ function test_wp_generate_edit_site_export_file() { $zip = new ZipArchive(); $zip->open( $filename, ZipArchive::RDONLY ); $has_theme_dir = $zip->locateName( 'theme/' ) !== false; - $has_block_templates_dir = $zip->locateName( 'theme/block-templates/' ) !== false; - $has_block_template_parts_dir = $zip->locateName( 'theme/block-template-parts/' ) !== false; + $has_block_templates_dir = $zip->locateName( 'theme/templates/' ) !== false; + $has_block_template_parts_dir = $zip->locateName( 'theme/parts/' ) !== false; $this->assertTrue( $has_theme_dir, 'theme directory exists' ); - $this->assertTrue( $has_block_templates_dir, 'theme/block-templates directory exists' ); - $this->assertTrue( $has_block_template_parts_dir, 'theme/block-template-parts directory exists' ); + $this->assertTrue( $has_block_templates_dir, 'theme/templates directory exists' ); + $this->assertTrue( $has_block_template_parts_dir, 'theme/parts directory exists' ); // ZIP file contains at least one HTML file. $has_html_files = false; diff --git a/phpunit/class-template-loader-test.php b/phpunit/class-template-loader-test.php index 5532c97015403..cb26c59db837a 100644 --- a/phpunit/class-template-loader-test.php +++ b/phpunit/class-template-loader-test.php @@ -64,7 +64,7 @@ function test_gutenberg_page_home_block_template_takes_precedence_over_less_spec ); $resolved_template_path = gutenberg_override_query_template( get_stylesheet_directory() . '/page-home.php', $type, $templates ); $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); - $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page-home.html', $_wp_current_template_content ); + $this->assertStringEqualsFile( get_stylesheet_directory() . '/templates/page-home.html', $_wp_current_template_content ); } function test_gutenberg_page_block_template_takes_precedence() { @@ -77,7 +77,7 @@ function test_gutenberg_page_block_template_takes_precedence() { ); $resolved_template_path = gutenberg_override_query_template( get_stylesheet_directory() . '/page.php', $type, $templates ); $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); - $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page.html', $_wp_current_template_content ); + $this->assertStringEqualsFile( get_stylesheet_directory() . '/templates/page.html', $_wp_current_template_content ); } function test_gutenberg_block_template_takes_precedence_over_equally_specific_php_template() { @@ -88,7 +88,7 @@ function test_gutenberg_block_template_takes_precedence_over_equally_specific_ph ); $resolved_template_path = gutenberg_override_query_template( get_stylesheet_directory() . '/index.php', $type, $templates ); $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); - $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/index.html', $_wp_current_template_content ); + $this->assertStringEqualsFile( get_stylesheet_directory() . '/templates/index.html', $_wp_current_template_content ); } /** @@ -149,7 +149,7 @@ function test_gutenberg_child_theme_block_template_takes_precedence_over_equally ); $resolved_template_path = gutenberg_override_query_template( $parent_theme_page_template_path, $type, $templates ); $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); - $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page-1.html', $_wp_current_template_content ); + $this->assertStringEqualsFile( get_stylesheet_directory() . '/templates/page-1.html', $_wp_current_template_content ); switch_theme( 'test-theme' ); } diff --git a/phpunit/fixtures/themes/test-theme-child/block-templates/page-1.html b/phpunit/fixtures/themes/test-theme-child/templates/page-1.html similarity index 100% rename from phpunit/fixtures/themes/test-theme-child/block-templates/page-1.html rename to phpunit/fixtures/themes/test-theme-child/templates/page-1.html diff --git a/phpunit/fixtures/themes/test-theme/block-templates/index.html b/phpunit/fixtures/themes/test-theme/templates/index.html similarity index 100% rename from phpunit/fixtures/themes/test-theme/block-templates/index.html rename to phpunit/fixtures/themes/test-theme/templates/index.html diff --git a/phpunit/fixtures/themes/test-theme/block-templates/page-home.html b/phpunit/fixtures/themes/test-theme/templates/page-home.html similarity index 100% rename from phpunit/fixtures/themes/test-theme/block-templates/page-home.html rename to phpunit/fixtures/themes/test-theme/templates/page-home.html diff --git a/phpunit/fixtures/themes/test-theme/block-templates/page.html b/phpunit/fixtures/themes/test-theme/templates/page.html similarity index 100% rename from phpunit/fixtures/themes/test-theme/block-templates/page.html rename to phpunit/fixtures/themes/test-theme/templates/page.html diff --git a/schemas/json/theme.json b/schemas/json/theme.json index cbdda0cc7632e..42053a01e752a 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -1130,13 +1130,13 @@ ] }, "customTemplates": { - "description": "Additional metadata for custom templates defined in the block-templates folder.\nGutenberg plugin required.", + "description": "Additional metadata for custom templates defined in the templates folder.\nGutenberg plugin required.", "type": "array", "items": { "type": "object", "properties": { "name": { - "description": "Filename, without extension, of the template in the block-templates folder.\nGutenberg plugin required.", + "description": "Filename, without extension, of the template in the templates folder.\nGutenberg plugin required.", "type": "string" }, "title": { @@ -1157,13 +1157,13 @@ } }, "templateParts": { - "description": "Additional metadata for template parts defined in the block-template-parts folder.\nGutenberg plugin required.", + "description": "Additional metadata for template parts defined in the parts folder.\nGutenberg plugin required.", "type": "array", "items": { "type": "object", "properties": { "name": { - "description": "Filename, without extension, of the template in the block-template-parts folder.\nGutenberg plugin required.", + "description": "Filename, without extension, of the template in the parts folder.\nGutenberg plugin required.", "type": "string" }, "title": {