Skip to content

Commit

Permalink
Add a layout config to the group and theme.json and make alignments d…
Browse files Browse the repository at this point in the history
…eclarative. (#29335)

Co-authored-by: jasmussen <[email protected]>
  • Loading branch information
youknowriad and jasmussen authored Mar 18, 2021
1 parent e8e951e commit 50cdfbe
Show file tree
Hide file tree
Showing 55 changed files with 953 additions and 322 deletions.
76 changes: 36 additions & 40 deletions docs/how-to-guides/themes/block-based-themes.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ theme
|__ ...
```

The difference with existing WordPress themes is that the different templates in the template hierarchy, and template parts, are block templates instead of php files. In addition, this example includes an [`experimental-theme.json`](/docs/how-to-guides/themes/theme-json.md) file for some styles.
The difference with existing WordPress themes is that the different templates in the template hierarchy, and template parts, are block templates instead of php files. In addition, this example includes an [`experimental-theme.json`](/docs/how-to-guides/themes/theme-json.md) file for some styles.

## What is a block template?

Expand All @@ -50,20 +50,16 @@ Here's an example of a block template:

<!-- wp:group -->
<div class="wp-block-group">
<div class="wp-block-group__inner-container">
<!-- wp:post-title /-->
<!-- wp:post-content /-->
</div>
<!-- wp:post-title /-->
<!-- wp:post-content /-->
</div>
<!-- /wp:group -->

<!-- wp:group -->
<div class="wp-block-group">
<div class="wp-block-group__inner-container">
<!-- wp:heading -->
<h2>Footer</h2>
<!-- /wp:heading -->
</div>
<!-- wp:heading -->
<h2>Footer</h2>
<!-- /wp:heading -->
</div>
<!-- /wp:group -->
```
Expand All @@ -72,23 +68,23 @@ Here's an example of a block template:

Ultimately, any WordPress user with the correct capabilities (example: `administrator` WordPress role) will be able to access these templates in the WordPress admin, edit them in dedicated views and potentially export them as a theme.

As of Gutenberg 8.5, there are two ways to create and edit templates within Gutenberg.
As of Gutenberg 8.5, there are two ways to create and edit templates within Gutenberg.

### Edit templates within The "Appearance" section of WP-Admin

You can navigate to the temporary "Templates" admin menu under "Appearance" `wp-admin/edit.php?post_type=wp_template` and use this as a playground to edit your templates. Add blocks here and switch to the code editor mode to grab the HTML of the template when you are done. Afterwards, you can paste that markup into a file in your theme directory.

Please note that the "Templates" admin menu under "Appearance" will _not_ list templates that are bundled with your theme. It only lists new templates created by the specific WordPress site you're working on.
Please note that the "Templates" admin menu under "Appearance" will _not_ list templates that are bundled with your theme. It only lists new templates created by the specific WordPress site you're working on.

### 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/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.

Repeat for any additional templates you'd like to bundle with your theme.
Repeat for any additional templates you'd like to bundle with your theme.

When you're done, click the "Export Theme" option in the "Tools" (ellipsis) menu of the site editor. This will provide you with a ZIP download of all the templates and template parts you've created in the site editor. These new HTML files can be placed directly into your theme.
When you're done, click the "Export Theme" option in the "Tools" (ellipsis) menu of the site editor. This will provide you with a ZIP download of all the templates and template parts you've created in the site editor. These new HTML files can be placed directly into your theme.

Note that when you export template parts this way, the template part block markup will include a `postID` attribute that can be safely removed when distributing your theme.
Note that when you export template parts this way, the template part block markup will include a `postID` attribute that can be safely removed when distributing your theme.

## Templates CPT

Expand All @@ -102,33 +98,33 @@ Note that it won't take precedence over any of your theme's templates with highe

Some blocks have been made specifically for block-based themes. For example, you'll most likely use the **Site Title** block in your site's header while your **single** block template will most likely include a **Post Title** and a **Post Content** block.

As we're still early in the process, the number of blocks specifically dedicated to these block templates is relatively small but more will be added as we move forward with the project. As of Gutenberg 8.5, the following blocks are currently available:

- Site Title
- Template Part
- Query
- Query Loop
- Query Pagination
- Post Title
- Post Content
- Post Author
- Post Comment
- Post Comment Author
- Post Comment Date
- Post Comments
- Post Comments Count
- Post Comments Form
- Post Date
- Post Excerpt
- Post Featured Image
- Post Hierarchical Terms
- Post Tags
As we're still early in the process, the number of blocks specifically dedicated to these block templates is relatively small but more will be added as we move forward with the project. As of Gutenberg 8.5, the following blocks are currently available:

- Site Title
- Template Part
- Query
- Query Loop
- Query Pagination
- Post Title
- Post Content
- Post Author
- Post Comment
- Post Comment Author
- Post Comment Date
- Post Comments
- Post Comments Count
- Post Comments Form
- Post Date
- Post Excerpt
- Post Featured Image
- Post Hierarchical Terms
- Post Tags

## Styling

One of the most important aspects of themes (if not the most important) is the styling. While initially you'll be able to provide styles and enqueue them using the same hooks themes have always used, the [Global Styles](/docs/how-to-guides/themes/theme-json.md) effort will provide a scaffolding for adding many theme styles in the future.
One of the most important aspects of themes (if not the most important) is the styling. While initially you'll be able to provide styles and enqueue them using the same hooks themes have always used, the [Global Styles](/docs/how-to-guides/themes/theme-json.md) effort will provide a scaffolding for adding many theme styles in the future.

## Resources

- [Full Site Editing](https://github.com/WordPress/gutenberg/labels/%5BFeature%5D%20Full%20Site%20Editing) label.
- [Theme Experiments](https://github.com/WordPress/theme-experiments) repository, full of block-based theme examples created by the WordPress community.
- [Full Site Editing](https://github.com/WordPress/gutenberg/labels/%5BFeature%5D%20Full%20Site%20Editing) label.
- [Theme Experiments](https://github.com/WordPress/theme-experiments) repository, full of block-based theme examples created by the WordPress community.
15 changes: 13 additions & 2 deletions docs/how-to-guides/themes/theme-json.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,16 @@ The Block Editor API has evolved at different velocities and there are some grow

This describes the current efforts to consolidate the various APIs related to styles into a single point – a `experimental-theme.json` file that should be located inside the root of the theme directory.

### Global settings for the block editor

Instead of the proliferation of theme support flags or alternative methods, the `experimental-theme.json` files provides a canonical way to define the settings of the block editor. These settings includes things like:

- What customization options should be made available or hidden from the user.
- What are the default colors, font sizes... available to the user.
- Defines the default layout of the editor. (widths and available alignments).
### Settings can be controlled per block

The Block Editor already allows the control of specific settings such as alignment, drop cap, presets available, etc. All of these work at the block level. By using the `experimental-theme.json` we aim to allow themes to control these at a block level.
For more granularity, these settings also work at the block level in `experimental-theme.json`.

Examples of what can be achieved are:

Expand Down Expand Up @@ -156,7 +163,11 @@ The settings section has the following structure and default values:
```
{
"settings": {
"some/block": {
"defaults": {
"layout": { /* Default layout to be used in the post editor */
"contentSize": "800px",
"wideSize": "1000px",
}
"border": {
"customRadius": false /* true to opt-in */
},
Expand Down
150 changes: 150 additions & 0 deletions lib/block-supports/layout.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<?php
/**
* Layout block support flag.
*
* @package gutenberg
*/

/**
* Registers the layout block attribute for block types that support it.
*
* @param WP_Block_Type $block_type Block Type.
*/
function gutenberg_register_layout_support( $block_type ) {
$support_layout = false;
if ( property_exists( $block_type, 'supports' ) ) {
$support_layout = _wp_array_get( $block_type->supports, array( '__experimentalLayout' ), false );
}
if ( $support_layout ) {
if ( ! $block_type->attributes ) {
$block_type->attributes = array();
}

if ( ! array_key_exists( 'layout', $block_type->attributes ) ) {
$block_type->attributes['layout'] = array(
'type' => 'object',
);
}
}
}

/**
* Renders the layout config to the block wrapper.
*
* @param string $block_content Rendered block content.
* @param array $block Block object.
* @return string Filtered block content.
*/
function gutenberg_render_layout_support_flag( $block_content, $block ) {
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
$support_layout = false;
if ( $block_type && property_exists( $block_type, 'supports' ) ) {
$support_layout = _wp_array_get( $block_type->supports, array( '__experimentalLayout' ), false );
}
if ( ! $support_layout || ! isset( $block['attrs']['layout'] ) ) {
return $block_content;
}

$used_layout = $block['attrs']['layout'];
if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] ) {
$tree = WP_Theme_JSON_Resolver::get_merged_data( array(), 'theme' );
$default_layout = _wp_array_get( $tree->get_settings(), array( 'defaults', 'layout' ) );
if ( ! $default_layout ) {
return $block_content;
}
$used_layout = $default_layout;
}

$id = uniqid();
$content_size = isset( $used_layout['contentSize'] ) ? $used_layout['contentSize'] : null;
$wide_size = isset( $used_layout['wideSize'] ) ? $used_layout['wideSize'] : null;

$style = '';
if ( $content_size || $wide_size ) {
ob_start();
?>
<?php echo '.wp-container-' . $id; ?> > * {
max-width: <?php echo $content_size ? $content_size : $wide_size; ?>;
margin-left: auto;
margin-right: auto;
}

<?php echo '.wp-container-' . $id; ?> > .alignwide {
max-width: <?php echo $wide_size ? $wide_size : $content_size; ?>;
}

<?php echo '.wp-container-' . $id; ?> .alignfull {
max-width: none;
}
<?php
$style = ob_get_clean();
}

ob_start();
?>
<?php echo '.wp-container-' . $id; ?> .alignleft {
float: left;
margin-right: 2em;
}

<?php echo '.wp-container-' . $id; ?> .alignright {
float: right;
margin-left: 2em;
}
<?php
$style .= ob_get_clean();

// This assumes the hook only applys to blocks with a single wrapper.
// I think this is a reasonable limitation for that particular hoook.
$content = preg_replace(
'/' . preg_quote( 'class="', '/' ) . '/',
'class="wp-container-' . $id . ' ',
$block_content,
1
);

return $content . '<style>' . $style . '</style>';
}

// Register the block support.
WP_Block_Supports::get_instance()->register(
'layout',
array(
'register_attribute' => 'gutenberg_register_layout_support',
)
);
add_filter( 'render_block', 'gutenberg_render_layout_support_flag', 10, 2 );

/**
* For themes without theme.json file, make sure
* to restore the inner div for the group block
* to avoid breaking styles relying on that div.
*
* @param string $block_content Rendered block content.
* @param array $block Block object.
* @return string Filtered block content.
*/
function gutenberg_restore_group_inner_container( $block_content, $block ) {
$group_with_inner_container_regex = '/(^(\s|\S)*<div\b[^>]*wp-block-group(\s|")[^>]*>)(([\s]|\S)*<div\b[^>]*wp-block-group__inner-container(\s|")[^>]*>)((.|\S|\s)*)/';

if (
'core/group' !== $block['blockName'] ||
WP_Theme_JSON_Resolver::theme_has_support() ||
1 === preg_match( $group_with_inner_container_regex, $block_content )
) {
return $block_content;
}

$replace_regex = '/(^(\s|\S)*<div\b[^>]*wp-block-group[^>]*>)((.|\S|\s)*)(<\/div>(\s|\S)*$)/m';
$updated_content = preg_replace_callback(
$replace_regex,
function( $matches ) {
return $matches[1] . '<div class="wp-block-group__inner-container">' . $matches[3] . '</div>' . $matches[5];
},
$block_content
);

return $updated_content;
}

add_filter( 'render_block', 'gutenberg_restore_group_inner_container', 10, 2 );
1 change: 1 addition & 0 deletions lib/class-wp-theme-json.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ class WP_Theme_JSON {
'customTextTransforms' => null,
),
'custom' => null,
'layout' => null,
),
);

Expand Down
4 changes: 4 additions & 0 deletions lib/client-assets.php
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,10 @@ function gutenberg_extend_block_editor_settings_with_default_editor_styles( $set
*/
function gutenberg_extend_block_editor_settings_with_fse_theme_flag( $settings ) {
$settings['isFSETheme'] = gutenberg_is_fse_theme();

// Enable the new layout options for themes with a theme.json file.
$settings['supportsLayout'] = WP_Theme_JSON_Resolver::theme_has_support();

return $settings;
}
add_filter( 'block_editor_settings', 'gutenberg_extend_block_editor_settings_with_fse_theme_flag' );
Expand Down
1 change: 1 addition & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,4 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/block-supports/typography.php';
require __DIR__ . '/block-supports/custom-classname.php';
require __DIR__ . '/block-supports/border.php';
require __DIR__ . '/block-supports/layout.php';
18 changes: 0 additions & 18 deletions packages/base-styles/_mixins.scss
Original file line number Diff line number Diff line change
Expand Up @@ -698,21 +698,3 @@
}
/* stylelint-enable function-comma-space-after */
}

/**
* These are default block editor widths in case the theme doesn't provide them.
*/
@mixin default-block-widths {

.wp-block {
max-width: $content-width;

&[data-align="wide"] {
max-width: $wide-content-width;
}

&[data-align="full"] {
max-width: none;
}
}
}
1 change: 1 addition & 0 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ _Type Definition_
_Properties_

- _alignWide_ `boolean`: Enable/Disable Wide/Full Alignments
- _supportsLayout_ `boolean`: Enable/disable layouts support in container blocks.
- _availableLegacyWidgets_ `Array`: Array of objects representing the legacy widgets available.
- _imageEditing_ `boolean`: Image Editing settings set to false to disable.
- _imageSizes_ `Array`: Available image sizes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
/**
* Internal dependencies
*/
import { useLayout } from '../inner-blocks/layout';
import { useLayout } from '../block-list/layout';
import { store as blockEditorStore } from '../../store';

const BLOCK_ALIGNMENTS_CONTROLS = {
Expand Down Expand Up @@ -70,11 +70,12 @@ function BlockAlignmentUI( {
if ( ! supportsAlignments ) {
return null;
}

const { alignments: availableAlignments = DEFAULT_CONTROLS } = layout;
const enabledControls = controls.filter(
( control ) =>
( wideControlsEnabled || ! WIDE_CONTROLS.includes( control ) ) &&
( layout.alignments || // Ignore the global wideAlignment check if the layout explicitely defines alignments.
wideControlsEnabled ||
! WIDE_CONTROLS.includes( control ) ) &&
availableAlignments.includes( control )
);

Expand Down
Loading

0 comments on commit 50cdfbe

Please sign in to comment.