Skip to content
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

Site Title: Add support settings for colors, fonts, and line height #23007

Merged
merged 49 commits into from
Jul 13, 2020

Conversation

apeatling
Copy link
Contributor

@apeatling apeatling commented Jun 8, 2020

Part of #21087

Description

Adds block level support for colors, fonts, and line height to the Site Title block.

Adds server side block style support via a function on the render_block filter to apply styles set for all blocks supporting __experimentalColor, __experimentalFontSize, and __experimentalLineHeight.

How has this been tested?

  • Local dev environment
  • New PHP unit tests

Testing instructions

  • Open the site editor
  • Add a site title block if it doesn't already exist
  • Modify the alignment, colors, font sizes and line height.
  • Add a custom CSS class
  • Save, and confirm that all of these changes are represented in the front end.

TODO

  • Support line height and font size styles and classnames on server side
  • Adjust the colors array to merge together text and background class and style data
  • Add __experimental* checks before rendering classnames and styles
  • Look at supporting __experimentalPadding classes/styles (This looks too influx to support in this PR).
  • Write some PHP unit tests for all the new server side code
  • Update documentation

Screenshots

Screen Shot 2020-06-08 at 10 58 54 AM

Types of changes

New feature.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.
  • I've included developer documentation if appropriate.
  • I've updated all React Native files affected by any refactorings/renamings in this PR.

@apeatling apeatling added the [Block] Site Title Affects the Site Title Block label Jun 8, 2020
@apeatling apeatling self-assigned this Jun 8, 2020
@apeatling apeatling marked this pull request as draft June 8, 2020 18:01
@github-actions
Copy link

github-actions bot commented Jun 8, 2020

Size Change: +22 B (0%)

Total Size: 1.13 MB

Filename Size Change
build/block-library/index.js 129 kB +22 B (0%)
ℹ️ View Unchanged
Filename Size Change
build/a11y/index.js 1.14 kB 0 B
build/annotations/index.js 3.62 kB 0 B
build/api-fetch/index.js 3.4 kB 0 B
build/autop/index.js 2.82 kB 0 B
build/blob/index.js 620 B 0 B
build/block-directory/index.js 7.42 kB 0 B
build/block-directory/style-rtl.css 941 B 0 B
build/block-directory/style.css 942 B 0 B
build/block-editor/index.js 109 kB 0 B
build/block-editor/style-rtl.css 10.7 kB 0 B
build/block-editor/style.css 10.7 kB 0 B
build/block-library/editor-rtl.css 7.44 kB 0 B
build/block-library/editor.css 7.44 kB 0 B
build/block-library/style-rtl.css 8.04 kB 0 B
build/block-library/style.css 8.05 kB 0 B
build/block-library/theme-rtl.css 730 B 0 B
build/block-library/theme.css 732 B 0 B
build/block-serialization-default-parser/index.js 1.88 kB 0 B
build/block-serialization-spec-parser/index.js 3.1 kB 0 B
build/blocks/index.js 48.2 kB 0 B
build/components/index.js 198 kB 0 B
build/components/style-rtl.css 15.9 kB 0 B
build/components/style.css 15.9 kB 0 B
build/compose/index.js 9.65 kB 0 B
build/core-data/index.js 11.4 kB 0 B
build/data-controls/index.js 1.29 kB 0 B
build/data/index.js 8.44 kB 0 B
build/date/index.js 5.47 kB 0 B
build/deprecated/index.js 772 B 0 B
build/dom-ready/index.js 569 B 0 B
build/dom/index.js 3.19 kB 0 B
build/edit-navigation/index.js 9.88 kB 0 B
build/edit-navigation/style-rtl.css 1.02 kB 0 B
build/edit-navigation/style.css 1.02 kB 0 B
build/edit-post/index.js 304 kB 0 B
build/edit-post/style-rtl.css 5.51 kB 0 B
build/edit-post/style.css 5.51 kB 0 B
build/edit-site/index.js 16.6 kB 0 B
build/edit-site/style-rtl.css 3 kB 0 B
build/edit-site/style.css 3 kB 0 B
build/edit-widgets/index.js 9.32 kB 0 B
build/edit-widgets/style-rtl.css 2.42 kB 0 B
build/edit-widgets/style.css 2.42 kB 0 B
build/editor/editor-styles-rtl.css 537 B 0 B
build/editor/editor-styles.css 539 B 0 B
build/editor/index.js 44.9 kB 0 B
build/editor/style-rtl.css 3.85 kB 0 B
build/editor/style.css 3.86 kB 0 B
build/element/index.js 4.65 kB 0 B
build/escape-html/index.js 733 B 0 B
build/format-library/index.js 7.72 kB 0 B
build/format-library/style-rtl.css 547 B 0 B
build/format-library/style.css 548 B 0 B
build/hooks/index.js 2.13 kB 0 B
build/html-entities/index.js 622 B 0 B
build/i18n/index.js 3.56 kB 0 B
build/is-shallow-equal/index.js 710 B 0 B
build/keyboard-shortcuts/index.js 2.52 kB 0 B
build/keycodes/index.js 1.94 kB 0 B
build/list-reusable-blocks/index.js 3.12 kB 0 B
build/list-reusable-blocks/style-rtl.css 450 B 0 B
build/list-reusable-blocks/style.css 451 B 0 B
build/media-utils/index.js 5.29 kB 0 B
build/notices/index.js 1.79 kB 0 B
build/nux/index.js 3.4 kB 0 B
build/nux/style-rtl.css 671 B 0 B
build/nux/style.css 668 B 0 B
build/plugins/index.js 2.56 kB 0 B
build/primitives/index.js 1.5 kB 0 B
build/priority-queue/index.js 788 B 0 B
build/redux-routine/index.js 2.85 kB 0 B
build/rich-text/index.js 14 kB 0 B
build/server-side-render/index.js 2.67 kB 0 B
build/shortcode/index.js 1.69 kB 0 B
build/token-list/index.js 1.28 kB 0 B
build/url/index.js 4.06 kB 0 B
build/viewport/index.js 1.85 kB 0 B
build/warning/index.js 1.14 kB 0 B
build/wordcount/index.js 1.17 kB 0 B

compressed-size-action

@apeatling
Copy link
Contributor Author

This PR will need server side logic, possibly relevant: #21420

@apeatling
Copy link
Contributor Author

apeatling commented Jun 11, 2020

I've added some initial work to support rendering classNames and inline styles for server side rendered blocks. This works for the Site Title block included in this PR as a test block. Would love some feedback on this, is this heading in the right direction?

A few thoughts:

  • Where should this code live? It's in lib/blocks.php right now.
  • This needs to support global styles variables. I'm not clear on how to support them yet, still reading the relevant issues.
  • Need to check for supports and the experimental flags. Although -- this will check for duplicate classes and styles and merge them, so technically it shouldn't matter?
  • Still need to add code to support font-size and line-height.

/cc @Addison-Stavlo @youknowriad @gziolo @nosolosw

@Addison-Stavlo
Copy link
Contributor

This is looking great so far! I'm hoping this method is favorable as its nice to not have to deal with the regex.

Where should this code live? It's in lib/blocks.php right now.

maybe lib/global-styles.php makes sense (at least if this interacts with that the way I am thinking it may)? I'm sure some of the other's that have been pinged may be able to supply more clarity on that.

Need to check for supports and the experimental flags. Although -- this will check for duplicate classes and styles and merge them, so technically it shouldn't matter?

I was wondering about this too. Maybe some of the unsupported ones are set up to apply some of these classes or styles to specific elements interior to the block wrapper... in which case this would then apply those same classes or styles to the block wrapper redundantly.

lib/blocks.php Outdated Show resolved Hide resolved
lib/blocks.php Outdated Show resolved Hide resolved
lib/blocks.php Outdated Show resolved Hide resolved
Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great start here.

@oandregal
Copy link
Member

This needs to support global styles variables. I'm not clear on how to support them yet, still reading the relevant issues.

So far, the things blocks need to play nicely with the block style system (both block-level & global-level) are:

  1. Declare its style attributes via the support keys (__experimentalColors, __experimentalFontSize, etc).
  2. If they use a class such as wp-block-{block-name} at the top-level element, nothing else is required. Otherwise, they have to add the __experimentalSelector key with a selector to match the block (see examples for paragraph and heading).

This PR checks both boxes so nothing else is required for it to work.

This sort of work is tracked at #22700 and documented in the handbook at docs/designers-developers/developers/themes/theme-json.md. It'd be great if this PR could update the docs with the style properties it adds.

@Addison-Stavlo Addison-Stavlo self-assigned this Jun 12, 2020
@apeatling
Copy link
Contributor Author

Great work on this PR @Addison-Stavlo!

@apeatling apeatling marked this pull request as ready for review June 16, 2020 16:47
@apeatling
Copy link
Contributor Author

I've noticed that editing and saving the site title value does not seem to work, however it's also not working in master so seems unrelated to the changes in this PR.

@apeatling
Copy link
Contributor Author

@Addison-Stavlo I think we should also support link color? Although the site title block does not contain a link, I expect it will in the future because users will want the title to link back to their homepage.

@Addison-Stavlo
Copy link
Contributor

Addison-Stavlo commented Jun 16, 2020

@Addison-Stavlo I think we should also support link color? Although the site title block does not contain a link, I expect it will in the future because users will want the title to link back to their homepage.

I think supporting link color at this point would be meaningless since we cannot apply a link to the Site Title. Since we cannot use the rich text for the site title to apply a link that way, we would need to add a savable attribute to the block and some case specific tools to its edit.js and index.php to set/apply/render the link?

It probably doesn't make sense to add the supports flag for link color unless that other stuff to support the link here is also put in place. That could be a good followup after this PR to improve the block if that link functionality for the site title is desired.

I've noticed that editing and saving the site title value does not seem to work, however it's also not working in master so seems unrelated to the changes in this PR.

Thats probably some functionality we will also want to add. Id say that would go well as a follow-up, but maybe we could squeeze that in here.

@apeatling
Copy link
Contributor Author

I think supporting link color at this point would be meaningless since we cannot apply a link to the Site Title. Since we cannot use the rich text for the site title to apply a link that way, we would need to add a savable attribute to the block and some case specific tools to its edit.js and index.php to set/apply/render the link?

Yes good point on RichText, I'd completely forgotten that we can't support a link in the same way. Agreed we should hold off until we know a link will be supported.

Thats probably some functionality we will also want to add. Id say that would go well as a follow-up, but maybe we could squeeze that in here.

I think this is a regression, it was working previously if I'm not mistaken. I think we should deal with that in a follow up.

lib/blocks.php Outdated
$colors['css_classes'],
$typography['css_classes'],
isset( $block['attrs']['className'] ) ? array( $block['attrs']['className'] ) : array(),
isset( $block['attrs']['align'] ) ? array( 'has-text-align-' . $block['attrs']['align'] ) : array()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@youknowriad - I'm wondering if it makes sense for us to add the text alignment and className here?

If it does, should we skip the early return for no support flags and apply align and className for all blocks that have those attributes saved? Or should we only apply these attrs if the block is using one of the experimental support flags? (or not at all?)


Other than that, this PR should be ready for another look over once you get a chance. 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My feeling is that this function knows too much about what each support flag (align, classnames, experimental ones)... does.

Ideally it's written in a generic way where we'd have a clear "interface" if want to add a new support flag. Doest that make sense?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i seem something like

$attributes =  array();
$attributes = gutenberg_experimental_apply_colors_flag(  $attributes, $block['attrs'], $supports  );
$attributes = gutenberg_experimental_apply_lineheight_flag(  $attributes, $block['attrs'], $supports  );
$attributes = gutenberg_experimental_apply-align_flag(  $attributes, $block['attrs'], $supports  );
$attributes = gutenberg_experimental_apply_custom_classname_flag(  $attributes, $block['attrs'], $supports  );


if ( ! count( $attributes ) ) {
     return $post_content;
} 

// Do the magic to parse the html and add  the extra attributes (we could start by supporting class and style).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that makes sense.

However, Im not currently seeing any of the similar experimental supports flags for the text alignment and class name. Should we leave these out for now and expect them to be handled elsewhere for the time being (index.php I'm guessing for these blocks)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have the customClassName for the custom classname, classname for the generated classname (which can also be handled similarly) and align for text alligment. I'm fine leaving them for dedicated PRs though and just get the API right in this initial PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine leaving them for dedicated PRs though and just get the API right in this initial PR.

Sounds good.

We have the customClassName for the custom classname, classname for the generated classname (which can also be handled similarly) and align for text alignment.

I saw these, but the reasons I am confused is that they don't have support keys defined for them like the others (font-size, line-height, colors, etc.) do. Similarly, they aren't checked for in the gutenberg_experimental_global_styles_get_supported_styles function:

$style_features = array(
'color' => array( '__experimentalColor' ),
'background-color' => array( '__experimentalColor' ),
'background' => array( '__experimentalColor', 'gradients' ),
'line-height' => array( '__experimentalLineHeight' ),
'font-size' => array( '__experimentalFontSize' ),
);

So I was a bit confused about how they are supposed to be handled compared to the ones we have here that require the support flags, and if they are intended to be added here or elsewhere.

Are we to assume these ones without support keys are supported by default if the corresponding attributes are saved and present? If that is the case we can handle them that way here.

align for text alignment

I was assuming this is for block alignment since it has settings like 'wide' and 'full' width. Or does this combine both text alignment and block/element alignment?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right "align" is for block alignment my bad but it's also a good candidate for server-side generation.

customClassName and className are more "historical" and not part of the global styles project but their behavior is very close. and yes, they are opt-out and I believe className can also receive a string to be used as class (need confirmation)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i seem something like

Updated to adopt this pattern instead. Let me know if this isn't what you had in mind.

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work here 👍

lib/blocks.php Outdated
$colors['css_classes'],
$typography['css_classes'],
isset( $block['attrs']['className'] ) ? array( $block['attrs']['className'] ) : array(),
isset( $block['attrs']['align'] ) ? array( 'has-text-align-' . $block['attrs']['align'] ) : array()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My feeling is that this function knows too much about what each support flag (align, classnames, experimental ones)... does.

Ideally it's written in a generic way where we'd have a clear "interface" if want to add a new support flag. Doest that make sense?

lib/blocks.php Outdated
$colors['css_classes'],
$typography['css_classes'],
isset( $block['attrs']['className'] ) ? array( $block['attrs']['className'] ) : array(),
isset( $block['attrs']['align'] ) ? array( 'has-text-align-' . $block['attrs']['align'] ) : array()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i seem something like

$attributes =  array();
$attributes = gutenberg_experimental_apply_colors_flag(  $attributes, $block['attrs'], $supports  );
$attributes = gutenberg_experimental_apply_lineheight_flag(  $attributes, $block['attrs'], $supports  );
$attributes = gutenberg_experimental_apply-align_flag(  $attributes, $block['attrs'], $supports  );
$attributes = gutenberg_experimental_apply_custom_classname_flag(  $attributes, $block['attrs'], $supports  );


if ( ! count( $attributes ) ) {
     return $post_content;
} 

// Do the magic to parse the html and add  the extra attributes (we could start by supporting class and style).

return $block_content;
}

$xpath = new DOMXPath( $dom );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if regex is more performant. This is definitely stronger and safer but in the long run, performance is important for the frontend. I'm happy starting with this and monitor impact

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a similar thought about performance, but attempting to parse HTML with a regex gets messy really quickly.

FWIW, I found myself in a similar situation a while ago, when adding a new sniff to WPCS. I ended up using XMLReader which out of a number of options seemed to have the smallest resource footprint. However, I only needed parsing at the time -- I didn't have to write HTML.

For writing, there's however XMLWriter -- maybe it could be used in combination with XMLReader.

Here's a StackOverflow post listing PHP's built-in (and external) HTML parsing options.

Here's some more background on RegEx-based parsing (and why it's messy) and alternatives.

* @param array $block Block Object.
* @return string New block output.
*/
function gutenberg_experimental_apply_classnames_and_styles( $block_content, $block ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens with existing blocks that already apply these flags on the frontend on their "save" function? how can we exclude them from this behavior?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens with existing blocks that already apply these flags on the frontend on their "save" function?

They go through this function unnecessarily. They do 'play nice', although this function handling them as well is a bit redundant.

how can we exclude them from this behavior?

Im not sure. There doesn't seem to be anything on the block object passed into the function that signifies anything special about this case. Maybe we can add an extra property on the block object or an attr to signal that it should be ignored by this function? Im open to ideas...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't testing for the presence of "render_callback" enough maybe?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems to do the trick! Thank you 😄 - 7c17c76

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is looking good and could land but since we're getting close to 5.5 beta1, I'd prefer if we hold on merging this as it can be impactful and merge it once Gutenberg 8.5 is released.

@ockham
Copy link
Contributor

ockham commented Jul 1, 2020

Should we at least rebase to get tests to pass and resolve the conflict? (Happy to do it if people don't mind me squashing commits.)

@Addison-Stavlo
Copy link
Contributor

@youknowriad - just double checking to see if you think this is safe to merge now that 8.5 just launched? If so I will circle back and merge Monday morning if no one has beat me to it.

@youknowriad
Copy link
Contributor

Yep, it should be good to go.

Comment on lines +248 to +252
$dom = new DOMDocument( '1.0', 'utf-8' );

// Suppress warnings from this method from polluting the front-end.
// @codingStandardsIgnoreStart
if ( ! @$dom->loadHTML( $block_content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_COMPACT ) ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for reference: this introduced #24445, with a likely fix in #24447. I don't find it surprising that we discover quirks in these PHP interfaces as we start doing more server-side manipulation of content. :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for catching it. 👍

$classes_to_add = esc_attr( implode( ' ', array_key_exists( 'css_classes', $attributes ) ? $attributes['css_classes'] : array() ) );
$styles_to_add = esc_attr( implode( ' ', array_key_exists( 'inline_styles', $attributes ) ? $attributes['inline_styles'] : array() ) );
$new_classes = implode( ' ', array_unique( explode( ' ', ltrim( $block_root->getAttribute( 'class' ) . ' ' ) . $classes_to_add ) ) );
$new_styles = implode( ' ', array_unique( explode( ' ', $current_styles . ' ' . $styles_to_add ) ) );
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I am reading this correctly, the separator for implode and explode should be ';' instead of ' ', otherwise array_unique doesn't have much to trim.

Same for two lines above at the assignment of $styles_to_add.

Using a print_r and a die on my env:

INPUT:
background-color:#b44343;min-height:244px;

OUTPUT:
Array
(
    [0] => background-color:#b44343;min-height:244px;
    [1] => 
)

Copy link
Contributor

@Addison-Stavlo Addison-Stavlo Aug 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the styles in $current_styles never have spaces between them like in your example input? or could they be either case? Input: background-color:#b44343;min-height:244px; vs Input: background-color:#b44343; min-height:244px;

It does look like we need to update these so that they are more consistent with each other and can properly remove the duplicates. We can implode $styles_to_add with no spacing (since ';' is already added to the values in the array), and explode/implode $new_styles on ';' if there are never spaces. If there can be I guess we need an extra step to trim whitespace for the array_unique to compare properly? 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the styles in $current_styles never have spaces between them like in your example input? or could they be either case?

I didn't check to see if this was guaranteeable, but those are the styles I got after using the actual user-facing tools. I'd look at the framework to make sure. If it seems like spaces could make their way in, you can always use preg_split:

php > var_dump( preg_split( '/; ?/', 'color:red;color:green; color:blue' ) );
array(3) {
  [0]=>
  string(9) "color:red"
  [1]=>
  string(11) "color:green"
  [2]=>
  string(10) "color:blue"
}

Of course, you can take it as far as you like:

php > var_dump( preg_split( '/ *; */', 'color:red   ; color:green; color:blue' ) );
array(3) {
  [0]=>
  string(9) "color:red"
  [1]=>
  string(11) "color:green"
  [2]=>
  string(10) "color:blue"
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can implode $styles_to_add with no spacing (since ';' is already added to the values in the array)

I'm not sure what you mean here. When wouldn't explode/preg_split strip semi-colons from the captured styles?

Copy link
Contributor

@Addison-Stavlo Addison-Stavlo Aug 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah preg_split could be the way to go then.

I'm not sure what you mean here. When wouldn't explode/preg_split strip semi-colons from the captured styles?

I just mean that currently the values added to $attributes['inline-styles'] all currently have the semicolons at the end of the string already. So that array looks something like [ '--wp--style--color--link: #fff;', 'background: #000;' ] etc. So when implode happens on the line with $styles_to_add that turns into '--wp--style--color--link: #fff; background: #000;' etc, even though we are just imploding with ' ' as the separator. It looks like with those internal spaces in the values that the explode by ' ' is even more problematic than noted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out by the way. I hope to address this relatively shortly but have been preoccupied so far today.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I proposed a fix in #24486

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Site Title Affects the Site Title Block
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants