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

Patterns API for blocks #16283

Open
youknowriad opened this issue Jun 25, 2019 · 21 comments

Comments

@youknowriad
Copy link
Contributor

commented Jun 25, 2019

A lot of block use the "setup state" pattern where some options/layouts are shown to the block user while inserterting the block:

  • The Columns block shows a number of layouts
  • The table block shows a setup state to choose rows and columns
  • The Cover block could benefit from a similar "initial layouts" state
  • A number of third party blocks use that pattern as well.

Capture d’écran 2019-06-25 à 2 41 47 PM

All these are similar in behavior. The user picks a pattern and this patterns applies initial attributes and innerBlocks content to the selected block.

The idea of this issue is to generalize that concept. Similarily to how we define block style variations, a block type should be able to define Block Patterns the user could pick from.

API

The API could look something like this:

const blockTypeSettings = {
   // ...
   patterns: [
       { name: __( 'Two columns; equal split' ), innerBlocks: [ ['core/column'], ['core/column'] ] },
       { name: __( 'Three columns; equal split' ), innerBlocks: [ ['core/column'], ['core/column'], ['core/column'] ] },
   ]

The patterns can also define just attributes

 // ...
   patterns: [
       { name: __( 'Big Quote' ), attributes: { size:'big' } },
       { name: __( 'Small Quote' ), attributes: { size:'small' } },
   ]

These are just examples to illustrate the API and not a final design.

We'd also probably need APIs to register/unregister these patterns (similar to the style variations).

UI

In terms of UI, we could explore different possibilities:

  • Offer these patterns as a setup state (Like a placeholder that shows up when you insert the block)
  • Offer these patterns in the "Block Switcher" dropdown
  • Offer these patterns in the inspector panel

Related #16129

@klihelp

This comment has been minimized.

Copy link

commented Jun 25, 2019

Good idea the initial "setup state". Thank you for the grat setup state on the columns block.

@kjellr

This comment has been minimized.

Copy link
Contributor

commented Jul 3, 2019

👋 I'd like to get the design leg of this started with a few thoughts, examples, and questions.

As Riad noted above, this is an expansion of the columns work added in #15663:

Frame 2

Here are a handful of potential use cases for this same pattern in core blocks:

Example - Cover

Example - Latest Posts

Example - Media Text

Example - Table

This isn't necessarily limited to layout though — theoretically, blocks could use this to allow users to choose any sort of default state for their block. A couple possible ideas:

Example - Map

Example - Form

In many cases, it'll make sense to include these options in the setup state. Beyond that, they'll likely also need to live in either the Block Switcher menu, or in the Sidebar:

Layout Options in the Sidebar:
03

Layout Options in the Block Switcher:
Frame 2 1

Questions

  1. From a user perspective, how are these different from Block Styles? Depending on the treatment and placement of these options, I could see many of them being analogous: The two Quote block styles for instance feel very much like layouts. Should blocks be able to present Block Styles in the placeholder state?
  2. In the placeholder state, should we include the option of a multi-step process? In #15663, we opted to keep the layout options confined to a single screen. I'm of the mind that this is generally the best approach for simplicity's sake, but we know some 3rd party blocks have found uses for multi-step placeholders (I'd love to hear thoughts from @richtabor here, since I know CoBlocks makes use of this pattern).
  3. In addition to the placeholder, does it make sense to include these options in the Sidebar, or in the Block Switcher dropdown (or both)? I think the sidebar makes more sense personally. In the case of the columns block for instance, the sidebar allows for there to be separate controls for number of columns and column layout.
  4. You'll note in the comps above, one of the options is highlighted with darker, thicker border. This is to denote the default/suggested state. This may not be 100% necessary, but I do think it helps direct the user a little bit. The visual treatment is something that's being explored in #15906 (comment), as it has broader implications for other areas of the UI. Please weigh in there with any thoughts.

Anything I'm missing? Looking forward to discussion around this. 🙂

@youknowriad

This comment has been minimized.

Copy link
Contributor Author

commented Jul 3, 2019

I love those explorations ❤️

From a user perspective, how are these different from Block Styles? Depending on the treatment and placement of these options, I could see many of them being analogous: The two Quote block styles for instance feel very much like layouts. Should blocks be able to present Block Styles in the placeholder state?

I think the main difference is that a block style is never a destructive change. All content/attributes/options are there while choosing a different pattern can result in sub-blocks being removed, content being changed...

@kjellr

This comment has been minimized.

Copy link
Contributor

commented Jul 3, 2019

I think the main difference is that a block style is never a destructive change. All content/attributes/options are there while choosing a different pattern can result in sub-blocks being removed, content being changed...

That's a good point. It makes me think that these will need a really clear name, to differentiate them from Block Styles... We'll have to think through that a bit too.

@mtias

This comment has been minimized.

Copy link
Contributor

commented Jul 5, 2019

This is great, thanks for exploring the variations. The transforms menu is potentially becoming a bit unwieldy: it includes block transforms, block styles, and now these new layout options. How can we make it more clear and functional? Should we split things out of it?

@karmatosed

This comment has been minimized.

Copy link
Member

commented Jul 5, 2019

This is great, thanks for exploring the variations. The transforms menu is potentially becoming a bit unwieldy: it includes block transforms, block styles, and now these new layout options. How can we make it more clear and functional? Should we split things out of it?

This is a really key point to me, right now they are being hidden. I have found so many people don't even notice there are styles. Hiding layout under this could lead to yet another really powerful feature being hidden.

Out there idea, are these all 3 separate enough to want different locations? I can see perhaps styling and layout being 'similar' but I do come back to maybe they just are all separate actions that need to be ensured to be surfaced.

@richtabor

This comment has been minimized.

Copy link

commented Jul 6, 2019

2. In the placeholder state, should we include the option of a multi-step process? In #15663, we opted to keep the layout options confined to a single screen. I'm of the mind that this is generally the best approach for simplicity's sake, but we know some 3rd party blocks have found uses for multi-step placeholders (I'd love to hear thoughts from @richtabor here, since I know CoBlocks makes use of this pattern).

I'd say having something in place for folks who need multi-step would be nice to have, further encouraging developers to utilize core components and patterns. I don't think we should back ourselves into a corner for simplicity's sake, as we know blocks will continue to get more and more advanced as Gutenberg, and more importantly JS WordPress developers, mature.

@chrisvanpatten

This comment has been minimized.

Copy link
Member

commented Jul 6, 2019

I really like the look in the startup state, but have some doubts about putting these options in the block switcher, or allowing them in general after a block is set up. The idea that these could be destructive is a bit concerning. Even with a robust undo system, it seems like this could create more problems than it solves, and make people inherently less likely to use the feature.

@kjellr

This comment has been minimized.

Copy link
Contributor

commented Jul 8, 2019

The transforms menu is potentially becoming a bit unwieldy: it includes block transforms, block styles, and now these new layout options.

This is a really key point to me, right now they are being hidden. I have found so many people don't even notice there are styles. Hiding layout under this could lead to yet another really powerful feature being hidden.

Yeah — I mocked it up, but I don't think it makes sense for these to live in the block switcher, for many of the reasons above. The Block Switcher menu is becoming a bit of a "Junk drawer" of features: Switch to a different type of block, create a group, switch styles, etc. If blocks want to include the ability to adjust these layouts after the setup state (more on that below), I think the sidebar is the place for it.

The idea that these could be destructive is a bit concerning. Even with a robust undo system, it seems like this could create more problems than it solves, and make people inherently less likely to use the feature.

I think it's important to note that the ability to change layout post-placeholder state should be up to the block. For some (like media + text for instance), it makes sense to allow it. But for other blocks (like the form block example above), it won't. Block authors should be able to opt-out as needed.

@mtias

This comment has been minimized.

Copy link
Contributor

commented Jul 8, 2019

Block transformations are already lossy, so in that sense I don't see layout transformations as that different.

One thing I'd also like to consider in the exploration is how to surface certain layout / pattern configurations before you insert a block, to help with discovery. For example, a "Form" block could have pre-defined sets using this new API for "Contact Us", "Feedback", and so on. Can you discover these by searching? Would a two step-insertion make sense in the inserter (so first click is on "Form" and second is on one of the pre-arranged templates).

@kjellr

This comment has been minimized.

Copy link
Contributor

commented Jul 8, 2019

One thing I'd also like to consider in the exploration is how to surface certain layout / pattern configurations before you insert a block, to help with discovery. For example, a "Form" block could have pre-defined sets using this new API for "Contact Us", "Feedback", and so on. Can you discover these by searching? Would a two step-insertion make sense in the inserter (so first click is on "Form" and second is on one of the pre-arranged templates).

Interesting. I can mock that up to see how it feels. 👍

@kjellr

This comment has been minimized.

Copy link
Contributor

commented Jul 9, 2019

For example, a "Form" block could have pre-defined sets using this new API for "Contact Us", "Feedback", and so on. Can you discover these by searching?

When there's a matching layout/pattern, a simple option would be to simply write out the template name underneath the block name. Then, if a user selects that item, we could serve up the matching template by default, and they could skip the layout-picking step:

Opt1-A

This still keeps it a one-step process when coming from a matching search.

Would a two step-insertion make sense in the inserter (so first click is on "Form" and second is on one of the pre-arranged templates).

One way to do this would be to swap out the entire panel to show the patterns after you select the main block:

2step-1

... or to have some sort of expanded drawer:

2step-2

Either of those two-step processes could also work well in the context of search, using the dark border to show the matching pattern result.

@chrisvanpatten

This comment has been minimized.

Copy link
Member

commented Jul 9, 2019

Block transformations are already lossy, so in that sense I don't see layout transformations as that different.

I would challenge this a bit — when transforming a block to another type of block, I think the idea of data loss is intuitive and implicit. One block behaves differently from another block, with different properties and interfaces.

This feature is different: describing it as a 'template' implies that it's primarily a visual change, which will have little impact on the data of the block, just how it's visualized.

Now that said, @kjellr's examples in the above mocks are super interesting, and has me wondering… what if these patterns were simply treated in the block transform UI equally to any other transformations?

Really, what's the difference between transforming a block to another block and changing the 'pattern' of a block? To the end user, the effect is the same, and explaining the distinction between a block template/pattern and a separate block could be tricky, especially when the line is kind of fuzzy. A block pattern change that effectively resets the block (e.g. a change from 6 columns to 2 columns, which would likely lead to some major data loss) is hardly any different than changing a block anyway.

@kjellr

This comment has been minimized.

Copy link
Contributor

commented Jul 10, 2019

Really, what's the difference between transforming a block to another block and changing the 'pattern' of a block? To the end user, the effect is the same, and explaining the distinction between a block template/pattern and a separate block could be tricky, especially when the line is kind of fuzzy. A block pattern change that effectively resets the block (e.g. a change from 6 columns to 2 columns, which would likely lead to some major data loss) is hardly any different than changing a block anyway.

Yes, this is an interesting point. I'm thinking this may rely a bit on the way these "patterns" are described to the user. If they're presented as "layouts", I wouldn't expect data loss. But if they're presented as different "types" of a block for instance, that might make sense.

One thing I'm repeatedly realizing is that some of these examples are relatively simple (a pattern that changes the column measurements of a Media & Text block for instance), while others are more broader structural changes (like the Form examples above). Even within the Columns block, there could theoretically be patterns that merely adjust the width of existing columns, and others that add or remove columns entirely. These sort of feel like they're the same thing, but the latter is much more consequential.

@chrisvanpatten

This comment has been minimized.

Copy link
Member

commented Jul 10, 2019

One thing I'm repeatedly realizing is that some of these examples are relatively simple (a pattern that changes the column measurements of a Media & Text block for instance), while others are more broader structural changes (like the Form examples above).

The Form example is the one that jumped out at me as well. At a certain point, you get into a "Ship of Theseus" debate — if you're effectively rebuilding the block, is it really the same block?

@jorgefilipecosta

This comment has been minimized.

Copy link
Member

commented Jul 11, 2019

Really important discussion happening here, full of awesome ideas ❤️
It seems we did not arrive yet on the UI to use, would having a branch with a prototype help make the decision in this phase or it is still too soon? If yes, any thoughts on the first approach to try?

@mapk

This comment has been minimized.

Copy link
Contributor

commented Jul 11, 2019

Lot's of great work happening here! I love the consistent setup screen for the blocks.

To get a v1 implemented is a consistent way, I'm suggesting...

  1. Provide setup screen for blocks that will not lose content if the layout is changed (ie. Media+Text, Columns, Cover, Latest Posts). Yes, I believe we can get the Columns block to work this way.
  2. Layout options should be duplicated in the Block Inspector sidebar.
  3. For each of those blocks, I believe "Layout" works well for the term used.

When thinking about more complex blocks like a Form block, I believe the setup screen works best for selecting a "type" of form, keeping the Inserter free of these things. In these cases where a change of form would most likely cause a loss of content, it would be best to not include the different forms in the Inspector sidebar. If the user wants a different form, they would insert another Form block from the Inserter.

This begins to get a bit foggy for me though in terms of Style variations and Layouts. Style variations are found in the block's transform tool, while Layouts would be found in the sidebar. The separation makes sense symantically, but currently the transform tool offers layout variants as well. How would these resolve?

With this fogginess, I question whether other blocks would also follow this pattern? ie. Quote block, Gallery block, etc.

@kjellr

This comment has been minimized.

Copy link
Contributor

commented Jul 12, 2019

To get a v1 implemented is a consistent way, I'm suggesting...

  1. Provide setup screen for blocks that will not lose content if the layout is changed (ie. Media+Text, Columns, Cover, Latest Posts). Yes, I believe we can get the Columns block to work this way.
  2. Layout options should be duplicated in the Block Inspector sidebar.
  3. For each of those blocks, I believe "Layout" works well for the term used.

This makes sense. All of these are fairly non-controversial, and it makes sense to display these options in both the placeholder and the sidebar.

This begins to get a bit foggy for me though in terms of Style variations and Layouts. Style variations are found in the block's transform tool, while Layouts would be found in the sidebar. The separation makes sense symantically, but currently the transform tool offers layout variants as well. How would these resolve?

One quick clarificaion: Block Styles actually appear in both the transform menu and the sidebar. I'm not sure how that effects our direction here.

@mtias

This comment has been minimized.

Copy link
Contributor

commented Jul 14, 2019

@kjellr these two-step inserter interactions are interesting, I think there is something to it to continue exploring as it addresses the main issue of discoverability, which none of the in-block solutions do.

Let's not get too caught up in the data portability issues, these templates / layouts / patterns are always going to be changing attributes or inner block content. They are less useful as a transformation, and more useful as initial setup conditions, but can work in both. This is also the case with the larger full page templates we support for CPTs and such.

Columns always had this issue — if you switched from 4 columns down to 2, we need to make a decision on what happens with the content of the 3rd and 4th columns. The same applies to many other attributes you could set that depend on other attributes.

@klihelp

This comment has been minimized.

Copy link

commented Jul 15, 2019

Could be the data stored for until the edit page closed or the page save/update action?
If deciding to restore the 4 columns before saving the page the lost data would be restored.

Columns always had this issue — if you switched from 4 columns down to 2, we need to make a decision on what happens with the content of the 3rd and 4th columns. The same applies to many other attributes you could set that depend on other attributes.

@kjellr

This comment has been minimized.

Copy link
Contributor

commented Aug 8, 2019

I think some of the Form examples above pushed us a little too far into the weeds, and I'd ❤️ to get this moving again. Would it make sense to start building an MVP that works as @mapk described above?

  • Start with Media+Text, Columns, Cover, and Latest Posts
  • Call it "Layout" to begin with, since that tends to cover the use cases for all of those ones.
  • Include these options in the placeholder (like we already do for the Columns block), and in the block sidebar, since those seem to be straightforward and non-controversial.

Those blocks Mark mentioned have a clear need for this API right now, and seem like a generally strong place to start. Ideas like the two-step inserter seem like they can be explored after that core functionality is in place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.