-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Layout: Use semantic classnames, centralize layout definitions, reduce duplication, and fix blockGap in theme.json #40875
Changes from all commits
60a8018
eee8666
fc311d6
52aa4ca
428b996
0b18460
d6ea6dc
3df57a0
0438461
0d540f4
56dc493
78f5c48
422f665
b3f8ba8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,16 +64,14 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support | |
$style .= "$selector .alignfull { max-width: none; }"; | ||
} | ||
|
||
$style .= "$selector > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }"; | ||
$style .= "$selector > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }"; | ||
$style .= "$selector > .aligncenter { margin-left: auto !important; margin-right: auto !important; }"; | ||
if ( $has_block_gap_support ) { | ||
if ( is_array( $gap_value ) ) { | ||
$gap_value = isset( $gap_value['top'] ) ? $gap_value['top'] : null; | ||
} | ||
$gap_style = $gap_value && ! $should_skip_gap_serialization ? $gap_value : 'var( --wp--style--block-gap )'; | ||
$style .= "$selector > * { margin-block-start: 0; margin-block-end: 0; }"; | ||
$style .= "$selector > * + * { margin-block-start: $gap_style; margin-block-end: 0; }"; | ||
if ( $gap_value && ! $should_skip_gap_serialization ) { | ||
$style .= "$selector > * { margin-block-start: 0; margin-block-end: 0; }"; | ||
$style .= "$selector > * + * { margin-block-start: $gap_value; margin-block-end: 0; }"; | ||
} | ||
} | ||
} elseif ( 'flex' === $layout_type ) { | ||
$layout_orientation = isset( $layout['orientation'] ) ? $layout['orientation'] : 'horizontal'; | ||
|
@@ -94,52 +92,50 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support | |
$justify_content_options += array( 'space-between' => 'space-between' ); | ||
} | ||
|
||
$flex_wrap_options = array( 'wrap', 'nowrap' ); | ||
$flex_wrap = ! empty( $layout['flexWrap'] ) && in_array( $layout['flexWrap'], $flex_wrap_options, true ) ? | ||
$layout['flexWrap'] : | ||
'wrap'; | ||
if ( ! empty( $layout['flexWrap'] ) && 'nowrap' === $layout['flexWrap'] ) { | ||
$style .= "$selector { flex-wrap: nowrap; }"; | ||
} | ||
|
||
$style = "$selector {"; | ||
$style .= 'display: flex;'; | ||
if ( $has_block_gap_support ) { | ||
if ( is_array( $gap_value ) ) { | ||
$gap_row = isset( $gap_value['top'] ) ? $gap_value['top'] : $fallback_gap_value; | ||
$gap_column = isset( $gap_value['left'] ) ? $gap_value['left'] : $fallback_gap_value; | ||
$gap_value = $gap_row === $gap_column ? $gap_row : $gap_row . ' ' . $gap_column; | ||
} | ||
$gap_style = $gap_value && ! $should_skip_gap_serialization ? $gap_value : "var( --wp--style--block-gap, $fallback_gap_value )"; | ||
$style .= "gap: $gap_style;"; | ||
} else { | ||
$style .= "gap: $fallback_gap_value;"; | ||
if ( $gap_value && ! $should_skip_gap_serialization ) { | ||
$style .= "$selector {"; | ||
$style .= "gap: $gap_value;"; | ||
$style .= '}'; | ||
} | ||
} | ||
|
||
$style .= "flex-wrap: $flex_wrap;"; | ||
if ( 'horizontal' === $layout_orientation ) { | ||
/** | ||
* Add this style only if is not empty for backwards compatibility, | ||
* since we intend to convert blocks that had flex layout implemented | ||
* by custom css. | ||
*/ | ||
if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { | ||
$style .= "$selector {"; | ||
$style .= "justify-content: {$justify_content_options[ $layout['justifyContent'] ]};"; | ||
$style .= '}'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I believe for the moment we do. Those other styles are coming from the Buttons block's hard-coded The existing semantic classnames that get added are only adding the classnames but not the values associated with them. (The semantic classnames were added back in, in #41487) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I see! That makes sense. I so look forward to getting rid of those container classes 😄 |
||
} | ||
|
||
if ( ! empty( $layout['verticalAlignment'] ) && array_key_exists( $layout['verticalAlignment'], $vertical_alignment_options ) ) { | ||
$style .= "$selector {"; | ||
$style .= "align-items: {$vertical_alignment_options[ $layout['verticalAlignment'] ]};"; | ||
} else { | ||
$style .= 'align-items: center;'; | ||
$style .= '}'; | ||
} | ||
} else { | ||
$style .= "$selector {"; | ||
$style .= 'flex-direction: column;'; | ||
if ( ! empty( $layout['justifyContent'] ) && array_key_exists( $layout['justifyContent'], $justify_content_options ) ) { | ||
$style .= "align-items: {$justify_content_options[ $layout['justifyContent'] ]};"; | ||
} else { | ||
$style .= 'align-items: flex-start;'; | ||
} | ||
$style .= '}'; | ||
} | ||
$style .= '}'; | ||
|
||
$style .= "$selector > * { margin: 0; }"; | ||
} | ||
|
||
return $style; | ||
|
@@ -160,21 +156,23 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { | |
return $block_content; | ||
} | ||
|
||
$block_gap = gutenberg_get_global_settings( array( 'spacing', 'blockGap' ) ); | ||
$default_layout = gutenberg_get_global_settings( array( 'layout' ) ); | ||
$has_block_gap_support = isset( $block_gap ) ? null !== $block_gap : false; | ||
$default_block_layout = _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() ); | ||
$used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : $default_block_layout; | ||
$block_gap = gutenberg_get_global_settings( array( 'spacing', 'blockGap' ) ); | ||
$global_layout_settings = gutenberg_get_global_settings( array( 'layout' ) ); | ||
$has_block_gap_support = isset( $block_gap ) ? null !== $block_gap : false; | ||
$default_block_layout = _wp_array_get( $block_type->supports, array( '__experimentalLayout', 'default' ), array() ); | ||
$used_layout = isset( $block['attrs']['layout'] ) ? $block['attrs']['layout'] : $default_block_layout; | ||
if ( isset( $used_layout['inherit'] ) && $used_layout['inherit'] ) { | ||
if ( ! $default_layout ) { | ||
if ( ! $global_layout_settings ) { | ||
return $block_content; | ||
} | ||
$used_layout = $default_layout; | ||
$used_layout = $global_layout_settings; | ||
} | ||
|
||
$class_names = array(); | ||
$container_class = wp_unique_id( 'wp-container-' ); | ||
$class_names[] = $container_class; | ||
$class_names = array(); | ||
$layout_definitions = _wp_array_get( $global_layout_settings, array( 'definitions' ), array() ); | ||
$block_classname = wp_get_block_default_classname( $block['blockName'] ); | ||
$container_class = wp_unique_id( 'wp-container-' ); | ||
$layout_classname = ''; | ||
|
||
// The following section was added to reintroduce a small set of layout classnames that were | ||
// removed in the 5.9 release (https://github.com/WordPress/gutenberg/issues/38719). It is | ||
|
@@ -192,6 +190,17 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { | |
$class_names[] = 'is-nowrap'; | ||
} | ||
|
||
// Get classname for layout type. | ||
if ( isset( $used_layout['type'] ) ) { | ||
$layout_classname = _wp_array_get( $layout_definitions, array( $used_layout['type'], 'className' ), '' ); | ||
} else { | ||
$layout_classname = _wp_array_get( $layout_definitions, array( 'default', 'className' ), '' ); | ||
} | ||
|
||
if ( $layout_classname && is_string( $layout_classname ) ) { | ||
$class_names[] = sanitize_title( $layout_classname ); | ||
} | ||
|
||
$gap_value = _wp_array_get( $block, array( 'attrs', 'style', 'spacing', 'blockGap' ) ); | ||
// Skip if gap value contains unsupported characters. | ||
// Regex for CSS value borrowed from `safecss_filter_attr`, and used here | ||
|
@@ -209,7 +218,14 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { | |
// If a block's block.json skips serialization for spacing or spacing.blockGap, | ||
// don't apply the user-defined value to the styles. | ||
$should_skip_gap_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); | ||
$style = gutenberg_get_layout_style( ".$container_class", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value ); | ||
$style = gutenberg_get_layout_style( ".$block_classname.$container_class", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization, $fallback_gap_value ); | ||
andrewserong marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Only add container class and enqueue block support styles if unique styles were generated. | ||
if ( ! empty( $style ) ) { | ||
$class_names[] = $container_class; | ||
wp_enqueue_block_support_styles( $style ); | ||
} | ||
|
||
// This assumes the hook only applies to blocks with a single wrapper. | ||
// I think this is a reasonable limitation for that particular hook. | ||
$content = preg_replace( | ||
|
@@ -219,8 +235,6 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { | |
1 | ||
); | ||
|
||
wp_enqueue_block_support_styles( $style ); | ||
|
||
return $content; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,26 @@ | |
* @package gutenberg | ||
*/ | ||
|
||
/** | ||
* Update allowed inline style attributes list. | ||
* | ||
* Note: This should be removed when the minimum required WP version is >= 6.1. | ||
* | ||
* @param string[] $attrs Array of allowed CSS attributes. | ||
* @return string[] CSS attributes. | ||
*/ | ||
function gutenberg_safe_style_attrs_6_1( $attrs ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To see if there are any blockers with adding in support for these properties, I've opened up a Trac ticket here: https://core.trac.wordpress.org/ticket/56122#ticket and a corresponding PR: WordPress/wordpress-develop#2928 |
||
$attrs[] = 'flex-wrap'; | ||
$attrs[] = 'gap'; | ||
$attrs[] = 'margin-block-start'; | ||
$attrs[] = 'margin-block-end'; | ||
$attrs[] = 'margin-inline-start'; | ||
$attrs[] = 'margin-inline-end'; | ||
|
||
return $attrs; | ||
} | ||
add_filter( 'safe_style_css', 'gutenberg_safe_style_attrs_6_1' ); | ||
|
||
/** | ||
* Registers view scripts for core blocks if handling is missing in WordPress core. | ||
* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might have lost some context on this issue. When testing the fallback value for the Columns block, I noticed that it wasn't making it through the conditions.
Should we be setting
$gap_value
when it'snull
? Something like this?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, thanks @ramonjd, I forgot about that one. This is a tricky part of the problem, and I'm not quite sure what the right solution is. We can't use the fallback value here, or it'll overwrite the root gap value so that if a base
blockGap
value exists then the fallback would take precedence. The objective in this function should be "if there is no gap value at the block level, do not output a rule", and a solution for fallback probably needs to be handled elsewhere, I think?There's separate handling in this PR for Classic themes and the Columns block fallback value, but I couldn't quite work out a good solution for blocks-based themes and still respecting the fallback value. Let me know if you can think of any other ways of handling it, and I'll do some more 🤔 too!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh dang, thanks for the explainer. I thought I was missing something. I'll have a think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean we need to be consistent in the above condition (. 🤔is_array( $gap_value )
) and check that at least one vertical value set by the block exists? Otherwise the fallback would take precedence as wellOh wait, sorry. We're still expecting a single string value in theme.json. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@andrewserong
This seems to work for me (so far). Still testing.
Diff to check for block.json default values in layout
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for re-testing!
That's the one that gets attached to
body .is-layout-flex
, so it's the root default gap that is used by Buttons and Social Icons blocks (or any of the blocks that use the Flex layout). They don't need an explicit__experimentalDefault
since they're happy using the common base fallback gap. In this PR, rather than always outputting that0.5em
value at render time of the individual block, we use this root rule so we can avoid duplication.I liked your idea in one of the other comments of a follow-up PR to remove the tie to the
body
element for generating the base layout styles, though, it might make the relationship here a little clearer 🙂 (in effect, we're currently using thebody
element as a "please only output this rule once and at the root" piece of logic, which could be abstracted in a clearer way, potentially)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, looking at the other blocks with flex layout,
0.5em
seems to work for them. I'd thought Navigation might be an exception, but since nav items already have a fair bit of padding around them, it works well 😄Yeah, we're using it to add global rules that don't need to be attached to any particular block/HTML element. Good thing to look at in a follow-up!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Nice work.
It took me a while to realize that I had to remove blockGap block support from theme.json (even though I don't know why?) After that it tests very well!
I think my assumptions must be wrong on this issue: isn't the point of the columns default fallback to provide a fallback if there is no blockGap value set anywhere, regardless of whether a theme has opted into
spacing.blockGap
or not?If not, and I'm way off, then it seems like a good approach!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for taking another look at this! 🙇
It's a good question of what the desired behaviour is here, but in principle the behaviour in this PR should now match
trunk
. Because Gutenberg/core'stheme.json
provides a basespacing.blockGap
value, the fallback gap will never be reached unless gap support is completely switched off. My current thinking is that if a theme uses gap support (which is opt-in), then it is the theme that's responsible for determining its own Columns spacing, rather than relying on a fallback value.Or to put it slightly differently, the columns default fallback value is for backwards compatibility, and as of this PR, with the ability to set gap at the block-level in theme.json, if a theme uses
blockGap
then (ideally 😅) it should use the appropriatecore/columns
block instyles.blocks
rather than depending on fallback styles, if the theme needs to have a particular value for the gap.It's totally worth re-examining those assumptions if they're incorrect, though! I suppose my preference would be to see if a) the mechanism in this PR is viable, so that b) we feel comfortable enough that we can tweak the behaviour in follow-up PRs if need be 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah thanks for setting me straight (again 😄)
That makes total sense.