Skip to content

Conversation

@youknowriad
Copy link
Contributor

closes #11392

At the moment, registering blockStyle variations is very fragile because you have to register it before the block registers itself and at the same time the block registers itself before the dom is ready which makes it very hard to do properly.

In this PR, I'm updating the block styles registration:

  • Moving away from filters
  • Using a separate reducer to keep track of block styles
  • Instead of relying on getBlockType to fetch the styles, rely on a selector (reactive)

This way we can register/unregister block styles at any moment.


I'd also argue that we should stop using getBlockType and getBlockTypes entirely and try to refactor our code to use the selectors instead. So any change that would happen to the block settings after the initial registration would be taken into consideration in the UI.

Testing instructions

  • Open the console and register a style variation: wp.blocks.registerBlockStyle( 'core/image', { name: 'fancy' } )
  • Insert an image, you should see the block style variation in the block switcher menu.

@youknowriad youknowriad added [Feature] Extensibility The ability to extend blocks or the editing experience [Type] Code Quality Issues or PRs that relate to code quality labels Nov 6, 2018
@youknowriad youknowriad self-assigned this Nov 6, 2018
@youknowriad youknowriad requested a review from a team November 6, 2018 09:41
@youknowriad youknowriad added this to the 4.3 milestone Nov 7, 2018
Copy link
Member

@jorgefilipecosta jorgefilipecosta 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 seems to work correctly. I left some improvements I think should be made before the merge.

I understand the reason for this change and it works well 👍 But I would prefer if blockStyles appeared under blockTypes.[blockName].blockStyles instead of blockStyles[blockName] in the state structure.
Would force the addBlockStyles call to be made after the block being registered to be an option?
If not would the concept of temporaryBlockType be an option? When calling addBlockStyles in a non-existing block it would add the style part in temporaryBlockType a sibling blockTypes of when registering the block if the block contains properties in temporaryBlockType these properties would be moved. This would be a totally generic solution, and in the future, if we have other need to dynamically manage or add block properties this system would work.

This last part is just a personal option regarding the state structure, it is a non-blocker at all.

*/
export function blockStyles( state = {}, action ) {
switch ( action.type ) {
case 'ADD_BLOCK_TYPES':
Copy link
Member

Choose a reason for hiding this comment

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

I think we also should handle the REMOVE_BLOCK_TYPES action.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't explicitly because the registration of styles can happen even before the block exists or after, that's one of the main ideas of this PR. You can register your styles and your block whenever you want, the styles will always be there.

For example, a plugin author could unregister a block type, register it back slightly modified and the styles will still be there.

Copy link
Member

Choose a reason for hiding this comment

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

Interesting way of thinking. The issue I see here is that you could add styles with block X and then remove it but its styles will be still there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this really an issue? I mean aside some state being there and not really useful.

Copy link
Member

@gziolo gziolo Nov 9, 2018

Choose a reason for hiding this comment

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

It would be an issue if you reuse the same block name to register your own version of the block, it would have also styles from the old block. Not a big deal in my opinion, but it raises a flag if you would scale the pattern for other parts of the block settings. I'm thinking how to turn block.registerBlockType hook into a self-dispatching action which does the same what you did here :)

return state;
}

/**
Copy link
Member

Choose a reason for hiding this comment

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

I think we also need to change blockTypes to remove styles from the blockTypes, right now they are duplicated in blockTypes and blockStyes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about it. I actually even had it implemented, but decided to revert. The idea is that, this could serve as a way to differentiate which styles are custom and which are defined in the block settings. But I don't have strong opinions though, I'm fine omitting them.

@youknowriad
Copy link
Contributor Author

Would force the addBlockStyles call to be made after the block being registered to be an option?

That's not an option, the idea of this PR is to allow plugins to register styles whenever they want regardless of existance of blocks or not. Because the loading order of JS scripts is very fragile if we can avoid it being an issue, then it's better for everyone.

@youknowriad
Copy link
Contributor Author

But I would prefer if blockStyles appeared under blockTypes.[blockName].blockStyles instead of blockStyles[blockName]

I don't have strong opinion on the state shape, it's just implementation detail for me as the most important part is the selectors. Changing as you suggest means I have to also refactor the block types to be something like blockTypes.[blockName].types, I just think it's not necessary now.

Copy link
Member

@jorgefilipecosta jorgefilipecosta left a comment

Choose a reason for hiding this comment

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

This seems to work correctly on my tests. Thank @youknowriad for clarifying my questions. I understood the rationale behind the decisions taken here and this looks ready to go 👍

onHoverClassName = noop,
} ) {
if ( ! styles ) {
if ( ! styles || styles.length === 0 ) {
Copy link
Member

Choose a reason for hiding this comment

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

Even if the block has no styles at all, it contains an empty array of styles. Should we continue to check for the length?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, the idea is that we don't show this panel at all if there's no styles.

@swissspidy
Copy link
Member

Seems like one still has to use wp.domReady in order to (un)register styles...

@youknowriad
Copy link
Contributor Author

@swissspidy Yes probably because if you unregister a style and then a code runs later and register it back, it will be there.

@erikjoling
Copy link

Seems like one still has to use wp.domReady in order to (un)register styles...

Registering custom styles works fine for me. Unregistering core/block styles is another story.

...state,
...keyBy( action.blockTypes, 'name' ),
...keyBy(
map( action.blockTypes, ( blockType ) => omit( blockType, 'styles ' ) ),
Copy link
Member

Choose a reason for hiding this comment

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

@youknowriad This looks like a typo, should 'styles ' be 'styles'?

It's present in current releases:

omit( blockType, 'styles ' )

It looks like this was intended to exclude the styles property in blockTypes state (it's moved to blockStyles), but it's present:

wp.data.select('core/blocks').getBlockType("core/image").styles.length
// 2

Copy link
Contributor Author

Choose a reason for hiding this comment

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

definitely looks like a typo yes, do you know what concrete impact this has?

Copy link
Member

Choose a reason for hiding this comment

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

I noticed it when inspecting some code, I don't have much idea of the impact it has.

It does appear to duplicate the state stored in blockStyles:

wp.data.select('core/blocks').getBlockType("core/image").styles
// [{"name":"default","label":"Default","isDefault":true},{"name":"rounded","label":"Rounded"}]

// Gives same result
wp.data.select('core/blocks').getBlockStyles("core/image")
// [{"name":"default","label":"Default","isDefault":true},{"name":"rounded","label":"Rounded"}]

// But not referential equality
wp.data.select('core/blocks').getBlockType("core/image").styles === wp.data.select('core/blocks').getBlockStyles("core/image")
// false

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Extensibility The ability to extend blocks or the editing experience [Type] Code Quality Issues or PRs that relate to code quality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Where to add JavaScript code for registerBlockStyle()

7 participants