Skip to content

Commit

Permalink
Update the block theme folders to templates and parts (#36647)
Browse files Browse the repository at this point in the history
  • Loading branch information
youknowriad committed Nov 25, 2021
1 parent 4a23beb commit c6b83c1
Show file tree
Hide file tree
Showing 14 changed files with 74 additions and 49 deletions.
6 changes: 3 additions & 3 deletions docs/how-to-guides/themes/block-theme-overview.md
Expand Up @@ -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
Expand Down Expand Up @@ -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.

Expand Down
28 changes: 14 additions & 14 deletions docs/how-to-guides/themes/create-block-theme.md
Expand Up @@ -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:
```
Expand All @@ -38,10 +38,10 @@ theme
|__ functions.php
|__ index.php
|__ theme.json
|__ block-templates
|__ templates
|__ index.html
|__ ...
|__ block-template-parts
|__ parts
|__ header.html
|__ footer.html
|__ ...
Expand All @@ -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).

Expand All @@ -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.
Expand Down Expand Up @@ -132,9 +132,9 @@ theme
|__ style.css
|__ functions.php (optional)
|__ index.php
|__ block-templates
|__ templates
|__ index.html
|__ block-template-parts
|__ parts
|__ (empty folder)
```

Expand All @@ -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.
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions docs/how-to-guides/themes/theme-json.md
Expand Up @@ -941,7 +941,7 @@ h3 {
This field is only allowed when the Gutenberg plugin is active. In WordPress 5.8 will be ignored.
</div>

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.
Expand Down Expand Up @@ -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.
</div>

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.

Expand Down
47 changes: 35 additions & 12 deletions lib/compat/wordpress-5.9/block-template-utils.php
Expand Up @@ -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.
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 ];
Expand Down
8 changes: 4 additions & 4 deletions lib/compat/wordpress-5.9/edit-site-export.php
Expand Up @@ -27,16 +27,16 @@ 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();
foreach ( $templates as $template ) {
$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
);
}
Expand All @@ -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
);
}
Expand Down
3 changes: 2 additions & 1 deletion lib/full-site-editing/full-site-editing.php
Expand Up @@ -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' ) );
}

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/block-library/src/template-part/index.php
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions phpunit/class-edit-site-export-test.php
Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions phpunit/class-template-loader-test.php
Expand Up @@ -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() {
Expand All @@ -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() {
Expand All @@ -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 );
}

/**
Expand Down Expand Up @@ -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' );
}
Expand Down
8 changes: 4 additions & 4 deletions schemas/json/theme.json
Expand Up @@ -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": {
Expand All @@ -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": {
Expand Down

0 comments on commit c6b83c1

Please sign in to comment.