-
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
Style Engine: add typography to backend #40082
Conversation
ebbb509
to
48e733f
Compare
} | ||
$styles[] = sprintf( 'font-family: %s;', $font_family_custom ); | ||
// Before using classes, the value was serialized as a CSS Custom Property. | ||
// We don't need to check for a preset when it lands in 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.
We don't need to check for a preset when it lands in core
TODO: check what this means
cc @ockham Do you know if this comment is still valid? Grabbed your name from 1e17b5a#diff-2c54d3c8305590cf826f83511a9fd85d5b405470addd62edc3183ff9118177fbR115
Or would we need the code permanently for backwards compatibility?
0cfe185
to
6edbfa4
Compare
@@ -109,56 +192,49 @@ public function generate( $block_styles, $options = array() ) { | |||
|
|||
$rules = array(); | |||
|
|||
// If a path to a specific block style is defined, only return rules for that style. | |||
if ( isset( $options['path'] ) && is_array( $options['path'] ) ) { |
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.
We don't actually use these feature, so I'm removing it.
* | ||
* @param string|array $style_value A single raw Gutenberg style attributes value for a CSS property. | ||
* @param string $style_property The CSS property for which we're creating a rule. | ||
* | ||
* @return array The class name for the added style. | ||
*/ | ||
public static function get_css_box_rules( $style_value, $style_property ) { | ||
public static function get_css_rules( $style_value, $style_property ) { |
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.
To match the clientside naming.
@@ -152,7 +152,7 @@ function test_margin_with_individual_skipped_serialization_block_supports() { | |||
|
|||
$actual = gutenberg_apply_spacing_support( $block_type, $block_atts ); | |||
$expected = array( | |||
'style' => 'padding-top:1px;padding-right:2px;padding-bottom:3px;padding-left:4px;', | |||
'style' => 'padding-top: 1px; padding-right: 2px; padding-bottom: 3px; padding-left: 4px;', |
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.
Updated to use spaces to improve readability.
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.
Great work @ramonjd, this is testing very nicely!
✅ Each of the Typography styles are rendered correctly on the front end
✅ The generated classnames appear to be rendered and injected correctly into the markup
I've left a few comments, I hope you don't mind — mostly poking at the idea of whether it'd be feasible for us to consolidate into a single call to generate
, move the logic of inferring classnames from attribute values to the style engine, and return an array with keys for the inline styles and classes.
It probably doesn't make a huge difference to do that at this stage, but I wondered if it'd be easier to lay the groundwork for that now, in prep for other block supports that will likely use classnames (and generated / constructed or random id classnames) more verbosely or frequently (mostly thinking of elements and layout supports).
What do you think? I can imagine there's a good argument either way for keeping separate for now / versus consolidating now.
Happy to do more testing tomorrow!
lib/block-supports/typography.php
Outdated
$style_engine = gutenberg_get_style_engine(); | ||
$inline_styles = $style_engine->generate( | ||
array( 'typography' => $styles ), | ||
array( | ||
'inline' => true, | ||
) | ||
); | ||
|
||
$classnames = $style_engine->get_classnames( | ||
array( 'typography' => $classes ), | ||
array( | ||
'use_schema' => true, | ||
) | ||
); |
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.
Seeing these two calls side-by-side, I was wondering if we should consolidate these calls so that get_classnames
becomes an implementation detail of generate
within the style engine? Then, we could adjust the return signature of generate
to be an array with keys for classes
and a key for inline_styles
(or whatever we want to name the keys).
By the time we get to refactoring the elements block support to use the style engine, we'll need to handle returning generated class names, so I wondered if it's worth factoring that in now?
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.
Seeing these two calls side-by-side, I was wondering if we should consolidate these calls so that get_classnames becomes an implementation detail of generate within the style engine?
I agree it's something we probably should do.
I spent some time thinking about this before I landed on two methods, and I got stuck on the structure of the arguments signature more than the return. That is, how show we should tell the style engine to deal with the different values?
The $block_styles
arg matches Gutenberg's style object and has a very particular structure, and I couldn't see how classname slugs would fit into that.
We could always expand the options array. I did try that but wasn't satisfied with my approach as it appeared haphazard and unintuitive, and not related at all to the main argument $block_styles
.
generate(
$block_styles,
[ classnames => $array_of_classnames ]
)
The first argument could be a collection of [ $block_styles, $block_classnames ]
I suppose.
Another thought I had was to extend the style value with metadata, which would mean the style engine had its own implementation of $block_styles
. For example:
// Classname/slug
$style['color'] = [ 'classname' => 'crimson' ];
// Regular style
$style['color'] = '#fff'; // or [ 'value' => '#fff' ];
The reason why I left it at two methods was so we could indeed have separate methods that we could ultimately call in a single generate
.
So maybe the current generate
should rather be named get_styles
or whatever, and we create a new generate
that calls get_styles
or get_classnames
accordingly. 🤷
What do you reckon
😄 ?
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, that is an interesting challenge! Thanks for explaining the logic there, and apologies when I was reading this yesterday, I totally missed that the following lines are grabbing root level attributes, not values within the style object 😅:
$classes['fontSize'] = _wp_to_kebab_case( $block_attributes['fontSize'] );
$classes['fontFamily'] = _wp_to_kebab_case( $block_attributes['fontFamily'] );
I think we're now bumping into one of the tricky areas where there's a part of the feature here that we probably need to decide between "do we change how it works now, or later?".
As in the border PR (#37770) I think there's been discussion in various places about whether these root level attributes will (long-term) better belong within the style
object. Ideally, we'd have everything we need right there in the style object, whether that style object is coming from block attributes, or global styles.
However, we're not there yet!
So in the spirit of the approach we've been taking thus far, which is — let's see if we can refactor what's currently working (pretty much as-is) and then iteratively switch over to new approaches — I reckon we go in the direction you've been exploring 👍
We could always expand the options array. I did try that but wasn't satisfied with my approach as it appeared haphazard and unintuitive, and not related at all to the main argument $block_styles.
You're right, it's tricky to come up with something that feels intuitive. I was kinda wondering if we could nearly have a value in the options array called attributes
or additionalAttributes
or something, which is a way to pass in attributes that are not part of the style
object — but that could feel a bit awkward, too...
Basically, I was thinking of something like:
$style_engine->generate(
array( 'typography' => $styles ),
array(
'inline' => true,
'attributes' => array(
'fontSize' => 'large', // just the raw attribute, let the style engine do the kebab-ing?
'fontFamily' => 'papyrus'
)
)
);
But I agree, it does feel awkward including those attributes separately in the list of options, so it might not be the right approach...
Another thought I had was to extend the style value with metadata, which would mean the style engine had its own implementation of $block_styles
That's actually not such a bad idea 🤔😀 — if we think of this as an opportunity to come up with the structure of how we long-term hope to structure the style object so that it contains those root level attributes, if we go with this approach, it might be a good way to confidence check what that shape will eventually look like.
It could also mean we kinda have an implementation which is "if the values are all in the style object, we don't need to look for anything else, otherwise, migrate over those other attributes to the style object for backwards compat" — that way we might be able to handle the desired location in the style object without ever having to worry about migrating old attributes? Just a thought....
The reason why I left it at two methods was so we could indeed have separate methods that we could ultimately call in a single generate.
So maybe the current generate should rather be named get_styles or whatever, and we create a new generate that calls get_styles or get_classnames accordingly.
I really like this idea, it means we've got two inner methods that are doing different things, and we have generate
as an abstraction that sits just above, so we can have a single entry point to generating styles 👍
} | ||
|
||
$classnames = array(); | ||
$use_schema = isset( $options['use_schema'] ) ? $options['use_schema'] : false; |
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 need to be an option, or could we infer it based on the preference within BLOCK_STYLE_DEFINITIONS_METADATA
? Because $options
is set for the overall call to generate
(or get_classnames
in this case) I was wondering if use_schema
is a little too broad, in that each property / support might need a different approach?
Or did you have in mind a use case where we really do want to be able to globally switch between the two approaches when calling the style engine? 🤔
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.
Good question.
We don't need this right now, true. I was just playing with an idea of being able to pass a custom schema to the style engine for styles that might not be defined in BLOCK_STYLE_DEFINITIONS_METADATA
, like layout container classes wp-%s
.
$options['use_schema']
is fairly generic, but it was supposed to mean "use the pattern/schema stored in the style engine if there is one".
I'm not really sure to be honest.
It's not needed for this PR, so I'll probably dump it until we have a real-world use case.
lib/block-supports/typography.php
Outdated
$has_named_font_size = array_key_exists( 'fontSize', $block_attributes ); | ||
$has_custom_font_size = isset( $block_attributes['style']['typography']['fontSize'] ); | ||
|
||
if ( $has_named_font_size ) { | ||
$classes[] = sprintf( 'has-%s-font-size', _wp_to_kebab_case( $block_attributes['fontSize'] ) ); | ||
$classes['fontSize'] = _wp_to_kebab_case( $block_attributes['fontSize'] ); |
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 was wondering if it'd be worth moving this call to convert the value to kebab case to the style engine, too, so that the caller doesn't have to worry about the detail of how the class name is ultimately constructed, and the style engine can be responsible for that?
What I have in mind, is whether it'd be feasible for the style engine to infer the class names based on the attributes passed in via the style
object handed to generate
, instead of having to call get_classnames
separately with the $classes
value 🤔
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.
convert the value to kebab case to the style engine, too, so that the caller doesn't have to worry about the detail of how the class name is ultimately constructed
It probably should, but would it need to if it's inferring classnames and building them "in house" based on attributes alone?
The tricky part of the puzzle here is building classnames based on existing patterns. For typography
only font size received the kebab case treatment. That's the reason why I left it to the block support to pass the right slug, and kept the style engine "dumb" in that regard.
I can't think of any reason not to do this - in fact I agree that we definitely should ensure that all classnames are consistent in that way - however if ever a block/block support didn't want kebab case (an extreme edge case) and something else, we might have painted ourselves into a corner too early.
Once again, I'm not sure. Maybe we'll know as we add more supports to the mix.
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.
Once again, I'm not sure. Maybe we'll know as we add more supports to the mix.
Good points! I think if we're not sure, then perhaps let's leave it in the block support so that we haven't painted ourselves into a corner, like you say. We could always move it over in a follow-up, if need be.
First stab at generating classnames based on slugs
…sing it yet. Adding a new public function to generate_classnames. Updated tests.
Remove value_func for common style definitions since I'm pretty sure we'll be using the get_css_rules method for 80%++ of cases.
6edbfa4
to
9dff885
Compare
Alternative that includes typography, but takes into account classname generation for colors here: |
I think I'll close this in favour of Since that PR takes classnames/presets into account. |
Allowing for border side styles, e.g., border.top.width et. al.
Allowing for border side styles, e.g., border.top.width et. al.
Allowing for border side styles, e.g., border.top.width et. al.
Allowing for border side styles, e.g., border.top.width et. al.
Allowing for border side styles, e.g., border.top.width et. al.
Allowing for border side styles, e.g., border.top.width et. al.
Tracking Issue: #38167
What?
Following on from #39446 that introduced spacing to the Style Engine backend, this PR takes on typography ⚔️
Why?
To introduce the Style Engine incrementally at first, and not change any output for now.
How?
generate
get_classnames
to output classnames inc. slugs.Testing Instructions
For dynamic blocks (Site Title, Navigation, Post Title, Post Date for example), check that the typography is output correctly on the frontend.
I've been testing so far with the Site Title block. To test with all controls you can update that block's JSON supports with the following:
Test:
Some test code (using TwentyTwentyTwo theme)
<!-- wp:site-title {"style":{"typography":{"lineHeight":1.7,"textTransform":"uppercase","letterSpacing":"113px","textDecoration":"line-through"},"color":{"background":"#c2c9d0"}},"fontSize":"large","fontFamily":"source-serif-pro"} /-->
Deprecated HTML with presets
Screenshots or screencast