-
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
Remove inline style colors atributes from paragraph. #3722
Conversation
Codecov Report
@@ Coverage Diff @@
## master #3722 +/- ##
==========================================
- Coverage 38.24% 37.68% -0.56%
==========================================
Files 282 280 -2
Lines 6859 6751 -108
Branches 1256 1229 -27
==========================================
- Hits 2623 2544 -79
+ Misses 3563 3544 -19
+ Partials 673 663 -10
Continue to review full report at Codecov.
|
bad8e68
to
38dc117
Compare
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.
Here we are using #ids instead of .classes so our custom attributes have higher specificity.
Which specificity are we seeking to defeat, and are we sure ID specificity is enough to do so?
lib/blocks.php
Outdated
} | ||
} | ||
if ( '' !== $rules ) { | ||
$styles .= sprintf( "\n#%1\$s { %2\$s\n}", $attributes['anchor'], $rules ); |
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.
Do we need to escape the anchor?
$rules = ''; | ||
foreach ( $map_attrs_styles as $attr_key => $css_property ) { | ||
if ( isset( $attributes[ $attr_key ] ) ) { | ||
$rules .= "\n\t" . esc_attr( sprintf( '%1$s: %2$s;', $css_property, $attributes[ $attr_key ] ) ); |
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.
Do we need to do the whitespace prettifying here?
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.
Without this whitespace prettifying when we check the source code the styles are messy and all on the same line but they work. I'm not certain what we normally do in this cases.
lib/blocks.php
Outdated
'textColor' => 'color', | ||
'backgroundColor' => 'background-color', | ||
); | ||
$styles = ''; |
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.
Minor: If we added a newline before this, we could avoid the awkward =
alignment, and more accurately associate the $styles
variable with the foreach
block where its value is accumulated.
blocks/hooks/custom-anchor-styles.js
Outdated
|
||
class AddAnchorWhenNeeded extends Component { | ||
componentWillReceiveProps( nextProps ) { | ||
if ( ! nextProps.attributes.anchor && CUSTOM_STYLE_ATTRIBUTES.some( attr => nextProps.attributes[ attr ] ) ) { |
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.
Minor: Personally I find the test within the condition to be a bit hard to read (and make the line long), vs. assigning to a separate variable e.g. hasCustomStyleAttribute = ...
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.
Yes, extracting a variable which explains the condition is always a good idea 👍
blocks/hooks/custom-anchor-styles.js
Outdated
const CUSTOM_STYLE_ATTRIBUTES = [ 'backgroundColor', 'textColor' ]; | ||
|
||
class AddAnchorWhenNeeded extends Component { | ||
componentWillReceiveProps( nextProps ) { |
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.
Are we sure this is only necessary to check when props change, not also on the initial mount? Thinking a block which is prepopulated with custom styling attributes.
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.
If a block is prepopulated with custom styles my expectation is that the anchor is already present so we don't need to add it.
Regarding posts created before this change that's problematic. This change changes the markup e.g: changes inline style attributes so, right now we display the message saying the block is invalid. I have not yet addressed the migration, as soon as #3673 or a similar approach is landed I will use the approach to migrate blocks
@@ -34,9 +34,6 @@ export function addAttribute( settings ) { | |||
settings.attributes = assign( settings.attributes, { | |||
anchor: { | |||
type: 'string', | |||
source: 'attribute', |
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.
Why is this attributes definition modified?
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.
This change allows the server to have access to anchor attribute which is required to generate the styles in the server.
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.
This change allows the server to have access to anchor attribute which is required to generate the styles in the server.
This will also mean existing blocks with anchors will lose the attribute value after this change (since it was not encoded in the comment delimiters).
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 see this was mentioned in #3722 (comment)
/** | ||
* Returns the block's default classname from its name | ||
* | ||
* @param {String} blockName The block name | ||
* @return {string} The block's default class | ||
*/ | ||
export function getBlockDefaultClassname( blockName ) { | ||
// Drop common prefixes: 'core/' or 'core-' (in 'core-embed/') | ||
return 'wp-block-' + blockName.replace( /\//, '-' ).replace( /^core-/, '' ); | ||
return `wp-block-${ friendlyBlockName( blockName ) }`; |
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.
Not sure it's worth concerning about, but there's a decent amount of redundancy between the class name and style applied to a block with custom styles, i.e.:
<p id="wp-block-paragraph-z60dssg" class="wp-block-paragraph">
</p>
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 agree the naming was redundant, I changed the id's so now they are in format 'paragraph-....'.
e4b742f
to
48771ef
Compare
Hi @aduth thank for your review, some improvements were applied based on the ideas you provided.
The original example was something like "#content p" which as you well noted in a previous talk our approach did not provide enough specificity. I made a change in all blocks with custom styles we add a "has-custom-styles" class. By default we target using .has-custom-styles#blockid. We are using a class and id specify which I think is enough the majority of cases. The fact we are using an id allows us to target from class/attribute specificity using [id=...blockid] to a hacky multiple id approach e.g: "#blockid#blockid". We will never be able to make sure our default approach for custom styles is enough so I think an option we have right now is provide a default approach that we are comfortable with and is ok for majority cases and then we can provide a way for themes/plugins to change the specificity of our custom styles between a set of allowed options. |
This would have the same specificity of |
"#content p" has one id and one element selector. Our approach ".has-custom-styles#blockid" has one id and one class selector so I think we have higher specificity against the "#content p" use case (unless I'm missing something). |
blocks/api/serializer.js
Outdated
|
||
/** | ||
* Returns a random base 36 string, 36^7 possible strings, maximum seven chars | ||
* According to the birthday paradox repetition occur after sqrt(36^7) = 279936 random strings are generated |
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.
If this is random, is it really the case that repetition could only occur after this number of strings has been generated, or is it rather there's a 1 in 279936 chance that a collision could occur? Meaning a post with two blocks could potentially share the same ID (though with a very low chance).
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.
Sorry, @aduth I missed your comment. I changed the comments to be more accurate. The number I wanted to refer is the expected number of ids we have to generate (but I used a wrong formula) to have the first collision. I added the formula to compute the probability of collision given k strings, and the correct number of expected ids we have to generate before having the first collision. Both formulas come from this page https://en.wikipedia.org/wiki/Birthday_attack. A post with two blocks can share the same id but the probability is very very low 1.27*10^-11.
@@ -34,9 +34,6 @@ export function addAttribute( settings ) { | |||
settings.attributes = assign( settings.attributes, { | |||
anchor: { | |||
type: 'string', | |||
source: 'attribute', |
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 see this was mentioned in #3722 (comment)
blocks/hooks/custom-styles.js
Outdated
} | ||
|
||
export default function customAnchorStyles( { addFilter } ) { | ||
addFilter( 'BlockEdit', 'core-anchor-inspector-control', addAnchorWhenStylesNeed ); |
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.
This implementation would need to be updated per #3827 (not yet merged)
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.
It was merged earlier today :)
Let me push fix.
Nope, you're right, I had a brain fart 😄 |
baeb280
to
b64945f
Compare
@jorgefilipecosta I rebased this PR with master and updated code to work with the latest changes around hooks. |
blocks/hooks/custom-styles.js
Outdated
} | ||
|
||
export function addAnchorWhenStylesNeed( BlockEdit ) { | ||
const WrappedBlockEdit = ( props ) => { |
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.
@jorgefilipecosta you might want to combine AddAnchorWhenNeeded
and WrappedBlockEdit
together and provide only one Component
. It looks like AddAnchorWhenNeeded
is there only for lifecycle method, so could be also a part of WrappedBlockEdit
. This would simplify render method and help keep componentWillReceiveProps
focused on logic related to anchor.
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.
Thank you for rebasing and updating this PR @gziolo. I tried to simplify things a bit following your advice :)
blocks/hooks/custom-styles.js
Outdated
|
||
const hasCustomStyles = ( attributes ) => ( | ||
CUSTOM_STYLE_ATTRIBUTES.some( attr => attributes[ attr ] ) | ||
); |
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.
This may be a bit too much magic, especially if we think outside the core block library. Why not something based on explicit support (blockType.supports.customStyles = …
, hasBlockSupport
)?
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.
Hi @mcsf, I added explicit support for custom styles, but this verification still happens, because even if blocks have support for custom styles, this function still needs to execute to check if custom styles are in fact used. I changed the name to hasCustomStyleAttributes.
lib/blocks.php
Outdated
* | ||
* @return string CSS style block or empty string | ||
*/ | ||
function compute_styles( $blocks ) { |
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.
do_blocks_styles
? gutenberg_generate_blocks_styles
?
blocks/api/serializer.js
Outdated
@@ -15,15 +15,45 @@ import { applyFilters } from '@wordpress/hooks'; | |||
*/ | |||
import { getBlockType, getUnknownTypeHandlerName } from './registration'; | |||
|
|||
/** | |||
* Returns the block's name with common prefixes: 'core/' or 'core-' (in 'core-embed/') dropped |
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'd wrap the examples with parens to make it slightly more readable: "Returns the block's name with common prefixes ('core/', 'core-') dropped".
f427d3c
to
d4b313e
Compare
! nextProps.attributes.anchor && | ||
hasCustomStyleAttributes( nextProps.attributes ) | ||
) { | ||
nextProps.setAttributes( { |
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.
Can you explain what setAttributes
is doing here? In general props
should be readonly, but it's hard to find out if this call updates props or not. Given that we check whether nextProps.attributes.anchor
is empty, I would assume this code updates this attribute. If I correctly assumed, we might want to introduce internal state here, and combine props and state when passing down to the <BlockEdit { ...this.props } />
in render method.
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.
Hi @gziolo, what we are doing here is verifying if no anchor was set yet ( by the user or automatically). If that's the case we check if attributes needing custom styles were used and if yes we set an automatically generated anchor attribute. I think it's not enough to pass a prop we really want to save the attribute for it to be serialized.
The general question here is what is our extensibility solution to allow to set an attribute depending on other. E.g: If I want to have a plugin that sets red text color attribute if the background is blue what would be the best way to do it? Right now it looks like using our hooks we can achieve this result using this solution, but maybe there is a simpler way.
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.
Okey, setAttributes
is some magic functions passed down to edit
which does all magic. It must be good 👍
It looks like it needs another rebase and final check from @mtias once he is back. |
d4b313e
to
240fd08
Compare
Would it be possible to allow a block to provide their own inline styles to be included in the style tag, rather than just the small whitelisted set included here? |
Hi @aduth, I think we can allow that by allowing blocks to provide a PHP styles render function that outputs the custom styles they want, similar to what we have for server-side blocks. |
Will it merge into master? IMO it would be a great feature to remove inline styles. |
Description
This is a second take on #3669 and tries to accomplish the first step of the tasks discussed in #2862
. The objective is to remove inline styles. Here we are using #ids instead of .classes so our custom attributes have higher specificity. The styles are not saved at all in the post content they are generated by PHP on render time.
The styles are targeted using anchor if the user set one that anchor is used, if not anchor exists, one is automatically generated when needed (and the user is able to change it, but not remove it).
The inline styles remaining in paragraph size and align will be replaced by classes.
This is a WIP in progress when adding the anchor support to paragraph (even just than change) we starting getting tinymce erros in the console, but things work as expected. This changes the markup of paragraph so some blocks may now be invalid some migration/version should be added.
How Has This Been Tested?
Add a paragraph write some text.
Add other paragraphs change text color in one, background color in other and both attributes in another. Verify HTML anchors are automatically added when the first style is chosen. Verify you can change the anchor.
Save the post and view it verify it shows as expected.
Types of changes
Added anchor support to paragraph.
Added a hook to implements automatic addition of anchors when needed.
Added a PHP mechanism to generate the styles in the server.
Remove in style colors from paragraph block saving.
Checklist: