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

Pattern Overrides epic (WordPress 6.5) #53705

Closed
36 of 49 tasks
glendaviesnz opened this issue Aug 16, 2023 · 94 comments
Closed
36 of 49 tasks

Pattern Overrides epic (WordPress 6.5) #53705

glendaviesnz opened this issue Aug 16, 2023 · 94 comments
Labels
[Feature] Patterns A collection of blocks that can be synced (previously reusable blocks) or unsynced [Feature] Synced Patterns Related to synced patterns (formerly reusable blocks) [Type] Enhancement A suggestion for improvement. [Type] Iteration Scoped iteration of an effort from a tracking issue or overview issue ideally for a major release.

Comments

@glendaviesnz
Copy link
Contributor

glendaviesnz commented Aug 16, 2023


N.B. Previously referred to as partially synced patterns.

What problem does this address?

Currently when adding a synced pattern all parts of that pattern are synced across every instance, so changes in any part of the pattern are reflected across as instances of the pattern.

It has been discussed in a number of places (#48458, #50456 ) that patterns would be much more useful/flexible if parts of them, particularly the layout and styling components, could be locked and synced across instances while allowing parts of the content to be updated independently.

An example workflow for a user could be a partially synced 'Recipe' pattern. A user could insert this pattern into multiple posts and any content (Ingredients, Steps) would be local to the post rather than synced in the pattern itself. The user would also be able to go back and modify the design of the recipe pattern, and this should have no effect on their content.

What is your proposed solution?

A number of potential solutions were discussed here with a few proofs of concepts. The current thinking is to use of the proposed block bindings api to implement partial syncing, since there's some overlap in requirements. The block bindings API mostly describes a way to use external data for a block attribute value (e.g. using a custom field for paragraph content). For patterns, child blocks of a pattern block could get and set their attribute values to the pattern block instance itself. This way, different instances of patterns could inject different data into the same pattern.

See the current prototype in #56235.

Tasks

V1 (Completed)

Pattern override tasks

Block Binding Intergration

Bugs

Follow Ups

Suggested enhancements/explorations

  • Consider how future features like shuffling might work
  • Reconsider using Ids to bind blocks, the data stored in the pattern block should be more readable/interpretable - draft PR using name instead of id
  • When a pattern is redesigned, there's a chance a user will modify blocks/attributes in a way that they become disconnected from the instances of a pattern (e.g. renaming the block to something different). Explore ways to prevent/warn a user about these risks.
  • Change the override attribute name to content - (PR - #58596)
  • Patterns: change info to "Overrides enabled"
  • Look into storing the block name as metadata in the overrides data (PR - #58715)

Block specific issues

Image Block

Supported attributes: url, id, title, alt

Button Block

Supported attributes: text, url

Heading block

Supported attributes: content

  • Heading level isn't supported, could/should it be?

Paragraph block

Supported attributes: content
No known issues

General Bugs

Code quality

Future

  • Features like pattern overrides and block bindings have limited control over block UI
  • As part of the block binding API, users can denote connections to different sources (e.g. custom fields, other post values, custom data sources). To declare a pattern override, the user also defines connections. Given they're separate UIs, some thought needs to go into what happens when a user attempts to connect a pattern override on a block that's already connected to a custom field—should it overwrite it, should it be prevented, how is the user made aware of the risk/outcome.
  • At the moment the API will work for one block at a time. A solution will be needed for lists, galleries or anything that requires a series/array of bound blocks. (see Add new mode to contentOnly locking to allow insertion of new inner blocks #52018 for similar challenges with contentOnly mode). One solution explored here [PoC] Patterns: try partial syncing of inner blocks #56348
  • Some exploration might be need around how block deprecations will work (i.e. if a block attribute name changes)
  • If a user completely deletes a source pattern, they will potentially lose content everywhere the pattern is used. Are there ways to restore this content, maybe offering a flow similar to block recovery?
@glendaviesnz glendaviesnz added [Type] Enhancement A suggestion for improvement. [Feature] Synced Patterns Related to synced patterns (formerly reusable blocks) [Type] Tracking Issue Tactical breakdown of efforts across the codebase and/or tied to Overview issues. [Feature] Patterns A collection of blocks that can be synced (previously reusable blocks) or unsynced labels Aug 16, 2023
@SantosGuillamot
Copy link
Contributor

Thanks for exploring this! It looks great so far 👏

One thing that could be relevant here: In the custom fields experiment, we are connecting block attributes to custom fields, but it was designed to be connected to any other source. This means that, whenever it is needed, support for other sources could be added.

I say this because we might want to consider "partial_synced_pattern" as a new source, and the values wouldn't need to be stored in the custom fields. Bear in mind that I am unfamiliar with patterns so this might not make sense, but this is an idea of how it could work:

Imagine we have a pattern block with an image and a paragraph. We could store the values in the pattern block attributes and "connect" the inner blocks to that. Something like this:

<! wp:pattern { "dynamic_content": {...} } -->
   <!-- wp:image { "uniqueID": "1234", "connections": {}  }-->
   <!-- wp:paragraph { "uniqueID": "ABCD", "connections": {} } -->
<!-- wp:pattern -->

Being the dynamic_content like this:

"dynamic_content: {
  "1234": {
    "url": {
      "value": "<https://test.local/image.png>"
    },
    "styles": {
      "color": {
        "value": "#fff"
      }
    }
  }
}

And the connections of the inner blocks:

"connections: {
  "url": {
    "source": "pattern",
    "fallback": "https://mysite.com/image.png"
  },
  "styles": {
    "color": {
      "source": "pattern"
    }
  }
}

Keep in mind that I am just making the APIs to show an example, they don't exist and they might look different if we pursue this approach.

This way, each time the user modifies the content of a partially synced pattern, they would modify the wp:pattern block attributes. And the inner blocks would remain the same in all instances where this pattern is used.

Additionally, the attributes included in the "connections" could be used to define the editable parts of the pattern.

Add support for a fallback property in case the custom field doesn’t exist.

I believe this could be easily supported by adding a fallback property to the current API. Something like:

"content": {
    "source": "meta",
    "value": "my_custom_field",
    "fallback": "Placeholder Text"
}

Add the ability for custom field keys to be generated automatically and dynamically on a pattern instance basis in order to allow the same pattern to be edited independently more than once in the same post.

Regarding this, exploring the possibility of using the Custom naming of blocks to use unique ids: link was suggested. If I am correct, there is a proposal for that. Maybe the partial syncing could generate a unique hash until that is ready.

cc: @michalczaplinski

@annezazu
Copy link
Contributor

With four weeks left until 6.4, let's punt this to a future release as there's not enough time to reasonably get this in. This was a stretch goal to begin with 😄 so great job continuing to explore and try to make something happen.

@gziolo gziolo mentioned this issue Sep 5, 2023
69 tasks
@gziolo gziolo changed the title Patterns: partial syncing Patterns: Partial syncing Sep 5, 2023
@unscripted
Copy link
Member

Thank you for putting this together, @glendaviesnz. While I'm bummed this didn't make it into 6.4, I'm glad to see it on the list for 6.5.

Our team just migrated a 400+ post/page site to a block theme, and our number one pain point was having to manually update pattern styles across all posts when a design change was made. We have several site migrations coming up for 100+ post sites, and the lack of a partially synced pattern has us exploring other options for converting large sites to FSE.

My team and I are following this closely and look forward to contributing.

@glendaviesnz
Copy link
Contributor Author

thanks @unscripted, are you able to provide a more detailed description of how you would see partially synced patterns working in your perfect world? Obviously, the world isn't perfect so there are no guarantees we can meet all your requirements, but it would help to flesh out exactly how we approach this if we have as much understanding as possible of the potential real-world use cases.

@ridinghoodmedia
Copy link

Our use case is similar and the lack of this feature is holding us back a ton.

thanks @unscripted, are you able to provide a more detailed description of how you would see partially synced patterns working in your perfect world?

We want a set of section template parts with certain parts of the layout locked, but the actual content editable. This would allow us to create pages rapidly and update and debug the design over time since the template is separate from its contents.

This already works really well with ACF blocks, but those blocks have limitations. When trying to do the same thing with Gutenberg the closest thing is a global pattern.

A concrete example of this is a large hero template where the background image, form, title, etc. can be changed. We'd like to lock the layout of the template and its inner blocks while keeping the content of those blocks editable. That way, all the hero headers throughout the site would use a single template and we could update it in the future e.g. add buttons below the title and set them to be visible by default on all heroes. This small change would take hours updating 100+ heroes individually.

We will also use dynamic blocks so that the templates can be updated without editor errors. This concept works really well with ACF, but ACF lacks the granular composability and block editing experience we need.

@unscripted
Copy link
Member

@ridinghoodmedia - It sounds like we have encountered some of the same ACF limitations.

are you able to provide a more detailed description of how you would see partially synced patterns working in your perfect world.

TBH, I think it may take a few iterations to identify my perfect world solution, but my MVP goals are below. I should say these come from the mindset of a developer/agency building sites for a client (end-user).

MVP

Issue

A user must manually edit and update each post to apply design or settings changes to every instance of a standard pattern within the site. While a minor inconvenience on a small site, this results in extensive work on 100+ page websites.

Objective

Enhance the block editor by introducing the concept of "Partially Synced Patterns" to maintain a consistent design across various pages and posts by controlling block settings and styles from a centralized pattern library.

Feature Description

New Pattern Type: Develop a new type of syncing available to patterns in the block editor that allows for partial synchronization with the pattern library. This means that while certain stylistic and structural elements of the pattern are controlled and updated via the pattern library, the content within the pattern can be edited by the end user at the post level. This pattern type could be a new top-level type or could be a subgroup of the Synced type. Locking should be synced so that the developer or designer can prevent items such as the h1 from being removed from the block.

Pattern Library Integration: The pattern library will house these partially synced patterns and manage the style updates. When a pattern’s style is updated in the library, it automatically propagates to all instances of that pattern across posts without altering the unique content added by the post author.

Block Editor: End users can apply these patterns to their pages and have the freedom to edit the content within the blocks while the overall style and structure of the blocks are maintained from the pattern library. I see the block editor output similar to how the "templateLock": "contentOnly" attribute still allows content to be edited by the end user, but in this instance, the user can't use the "modify" action to change block settings or styles at the post level.

The user should have the ability to remove non-locked blocks from the pattern but not add new blocks. An example is a page header pattern that may utilize a cover block with a heading, paragraph, default image and a button. While the default pattern is created in the pattern library, the end user can remove the heading, paragraph, default image or button if they are not needed for that page.

Benefits:

Consistency in Design: Maintain a consistent design across various pages and posts by controlling block settings and styles from a centralized pattern library.

Flexibility in Content: Allow the end user to focus on their unique content as opposed to being concerned with style tweaks on a per-post basis.

Efficiency: Streamline the content management and design update process by allowing admins, developers or designers to make block-style updates in one place (the pattern library) that automatically reflect wherever the pattern is utilized.

@ridinghoodmedia
Copy link

ridinghoodmedia commented Oct 12, 2023

@unscripted great description, that sounds like our use case exactly. Import/export patterns would be important too.

I think the use case for this is a lot more in demand than it seems since people don't even know how to describe this feature. I had a developer working on an internal workaround before he found this thread and we decided to wait since a solution in core would be a lot better.

@annezazu
Copy link
Contributor

Import/export patterns would be important too.

On that front, that's coming to WordPress 6.4: #53288

@glendaviesnz
Copy link
Contributor Author

Thanks @unscripted, @ridinghoodmedia, what you have outlined matches exactly with what we are hoping to achieve 🤞 with the partially synced patterns work, which is good to know. Thanks for taking the time to flesh out your requirements.

@gziolo
Copy link
Member

gziolo commented Nov 2, 2023

@talldan updated the description of the issue to reflect the current state of the project based on the prototyping work done in the past weeks (months already? 😄). The most up to date prototype can be found in #55807. The next step is to evaluate if the linked solution is good enough to land it in Gutenberg as an existing experiment behind the feature flag.

@eric-michel
Copy link

I think @ridinghoodmedia and @unscripted have created an awesome outline for how this should work. I have just a couple other specifics for our use cases.

@talldan's prototype at #55807 is really impressive. Right now it shows text values of basic blocks like paragraph and heading being set to metafields, which will be a critical feature. But for us it would be really important that any content type be able to work with this system.

For instance, let's say I have a series of profile pages for college professors. I want to be able to create a partially-synced pattern that has:

  • An image block for the professor's photo
  • A group block for the professor's bio
  • A list block for the professor's credentials
  • A button with a mailto: link to the professor's email address

Ideally, I would be able to assign the source of the image block from the media library, the InnerBlocks of the group block, the list items for the list block, and the href field of the button as metafields to be customized on an instance-by-instance basis.

This would allow the user to create significant freeform content for the professor's bio, but only add list items for the credentials or modify the href field of the button.

Finally, it would be wonderful if these metafield values could also be assigned to blocks within a query block. Again using the professor bio pages example above, I could create the equivalent of an archive page of all professors with a query block that, for each professor, showed an image block with their photo (retrieved from the relevant metafield), page title (which is already possible), and a link to their email address (again retrieved from the relevant metafield).

I'm not sure if all of this is outside the scope of what's being worked on, but that would be the "MVP" solution for us, as it would allow for a wide range of flexibility or rigidity based on the content type that we're creating for our users.

As a crazy long shot request, eventually having the ability to assign any value or setting of a block within a partially-synced pattern as a metafield to be customized on an instance-by-instance basis, like even the color of a button, would be absolutely amazing. But I have to imagine that would be a ton of work.

@talldan
Copy link
Contributor

talldan commented Mar 5, 2024

@draganescu That particular 'patch' format was never released in the gutenberg plugin. It was briefly shipped to trunk, but reverted, and you must have created the pattern during that brief period.

No back compat is present for that format.

@getdave
Copy link
Contributor

getdave commented Mar 5, 2024

Yes I see no reason to include any migration for an implementation that was never shipped in a release.

Indeed using the new system with newly created patterns didn't cause the error.

As a result of this it's my understanding that we can assume the issue @draganescu reported is no longer a problem.

@getdave
Copy link
Contributor

getdave commented Mar 5, 2024

I don't think this is correct. As a user I can create a new synced pattern anywhere in the post editor / site editor via the block context menu (create pattern). The modal that shows up from there allows me to create a synced pattern. And anything that I renamed before / rename from there on when editing the syced pattern behaves this way. So I don't think this is a hidden power user only feature. (creating and editing of synced patterns)

This is an interesting observation. Perhaps we could consider avoiding creating bindings if/when a pattern is created using this workflow.

@fabiankaegy
Copy link
Member

fabiankaegy commented Mar 5, 2024

I don't think this is correct. As a user I can create a new synced pattern anywhere in the post editor / site editor via the block context menu (create pattern). The modal that shows up from there allows me to create a synced pattern. And anything that I renamed before / rename from there on when editing the syced pattern behaves this way. So I don't think this is a hidden power user only feature. (creating and editing of synced patterns)

This is an interesting observation. Perhaps we could consider avoiding creating bindings if/when a pattern is created using this workflow.

Honestly, I don't think that is making the experience any more clear. I really think we should go with what is outlined in #59583. Having a clear toggle is key for the experience to not be so confusing.

@gziolo
Copy link
Member

gziolo commented Mar 5, 2024

Perhaps we could consider avoiding creating bindings if/when a pattern is created using this workflow.

I’m sure it’s already working like that because the name gets set before the block is even within the scope of the pattern that initiates the binding. Anyway, I agree with @fabiankaegy that it’s going to be confusing from the user's perspective.

@getdave
Copy link
Contributor

getdave commented Mar 5, 2024

This is an interesting observation.

To avoid any confusion, I was acknowledging the observation rather than suggesting it as an overarching solution to the issue at hand.

I’m sure it’s already working like that because the name gets set before the block is even within the scope of the pattern that initiates the binding.

This is the current behaviour. If you create a pattern containing a block that is already renamed then it auto-creates a binding. This is because there is an effect which runs when in the pattern editor. The binding does not seem to be added during creation of the core/block but rather when the pattern is edited.

Screen.Capture.on.2024-03-05.at.16-32-33.mp4

@artemiomorales
Copy link
Contributor

artemiomorales commented Mar 6, 2024

For what it's worth, today when creating a Synced Pattern I was very confused when the checkbox to enable instance overrides was missing. Then I felt frustrated upon realizing I would need to give the block an explicit name in order to enable overrides for it, then moreso when I realized would need to do that for every block in the pattern.

Needing to devise names for blocks within a pattern that I was just experimenting with, and for which I had no good names yet, really broke my mental flow.

Granted, the context for this was doing some testing, but it also feels awkward to explain in testing instructions, "To enable overrides in the pattern, you need to give these blocks a name" — it seems counterintuitive.

Overall I see this as adding an extra unnecessary barrier between a user and their content, and I disagree that this would be only used by power users. Let's say I'm just a person with average technical skills who wants to build their site using WordPress — I'm in a creative flow building it, experimenting, and I want to use some patterns, but suddenly I need to start giving each overridable block an explicit name when I'm not ready to do that yet.

A checkbox seems like a reasonable amount of overhead to enable the instance overrides; for me at least, needing to name each block to enable that feels like a frustrating experience.

@unscripted
Copy link
Member

unscripted commented Mar 7, 2024

After reading the user's testing experience in #59651, I believe it reiterates the importance of a dedicated control for enabling an override.

I've gone back through this thread, re-reading how we got to this point and trying to understand the impact of the control being tied to the Block Renaming API as outlined in this comment.

In a later comment, @kevin940726 mentioned

FWIW, also note that it might be easier to just support both and use the unique id as a fallback.

and @glendaviesnz pointed out

The trouble with metadata.name is that it is exposed and editable in parts of the interface that are not compatible with the sort of naming conventions that would make shuffling, etc. reliable, eg. hero/title and where users can make changes with no understanding of the impact of the change, eg.

A key point in this exchange is the "where users can make changes with no understanding of the impact of the change" statement. I feel we've traded one approach for another that may still result in a user making changes without understanding the potential impact.

Given the desire to not paint ourselves in a corner for the future shuffling feature, the idea of a fallback gave me an idea of a dedicated key-value pair for the override. Would the approach outlined below be feasible?

  1. Bring back the toggle.
  2. Auto-generate an override id.
  3. When the toggle is active, an input appears below with the auto-generated override id visible.
  4. Add a description to the input letting the user know they can change the id.

My thought by making the override separate from the block id and block name is it would potentially lessen the impact of changes made to the Block Renaming API and could provide a unique id that could be used during a future implementation of the shuffling feature.

I'm sure there are technical challenges with this approach that I'm unaware of, and that it may not be possible. We would probably need UI guidance from @richtabor, as well.

I'd love your feedback and hope we can step back and think of a solution that is more intuitive for the end user and doesn't dual-purpose the Block Name field.

@kevin940726
Copy link
Member

kevin940726 commented Mar 7, 2024

Auto-generated keys allow uniqueness

I’ve seen use-cases where uniqueness is not desired. I’ve seen patterns where an image is shown multiple times in different places of the pattern, so duplicating the name, actually allows users to define it only once. I’ve seen patterns where logos/company names are in multiple places, using the same name also allows to solve this problem. So in other words, it’s actually a feature to allow using the same name multiple times.

Auto-generated keys allow uniqueness, but we can also allow them to be duplicated when the user decides to "opt-in". Using the Block Renaming API puts the burden of naming things on the developers/users instead, which is one of the most difficult things to do as a human 😅. Using auto-generated ids as the "default" releases that burden but also empowers users to achieve advanced features.

In addition, in the use cases you described, I'd imagine that "nested patterns" could achieve similar results. I don't think it's ever officially supported but I think it's worth looking into separately.

@glendaviesnz
Copy link
Contributor Author

and @glendaviesnz pointed out

The trouble with metadata.name is that it is exposed and editable in parts of the interface that are not compatible with the sort of naming conventions that would make shuffling, etc. reliable, eg. hero/title and where users can make changes with no understanding of the impact of the change, eg.

Following the recent changes and discussion I stand by the above view. I can understand the thinking behind the desire to link this to the name, but I believe that due to the above issues the disadvantages outweigh the advantages. In my view the best approach would be to stick with original explicit opt-in with random id generation as the default, but with the ability for advanced users to assign their own ids either in the UX or in the pattern serialized HTML. This would be very easy to achieve with the original architecture as prototyped here.

@fabiankaegy
Copy link
Member

I also just want to share that since the original checkbox UI had been present until the very end of Beta 3, there already is training material like the fantastic overview by Jamie Marsland here which train users on this UX: https://youtu.be/tf8w0xMNToY?si=a6VdLrzKkXevCyse

@youknowriad
Copy link
Contributor

Hey folks, thanks for raising your concerns. It’s clear that the feature doesn’t seem entirely ready to be shipped in WordPress, so we have made the decision to move it to WordPress 6.6 instead and keep it plugin only for now.

You can read more about this on make/core

The first big action time here is to work on protecting the feature behind the “IS_GUTENBERG_PLUGIN” flag. Cc @kevin940726 @talldan

For later, I’d like to note that the feature is not just about “making things overridable” by the user, while it’s the immediate use-case, we should think about this more holistically, it’s about separating content and presentation of patterns. It’s about providing a schema for the pattern.

So there’s a few things on my mind that I think we need to clarify

  • On the pattern creation/editing, clarify in terms of UI/UX when things are overridable…
  • Surfacing maybe at the top level (document/pattern) the schema of the pattern.
  • Provide an opt-out mechanism potentially (deleting an “overridable property”)
  • On the technical level, we also need to unify with block bindings and rely on the useSource API. This will help fix a bug that exists today where multiple bindings don’t work (same property used twice)

About using the name as the source, I think at the moment we should continue with it.

@talldan
Copy link
Contributor

talldan commented Mar 8, 2024

I've made a PR to make the feature plugin only - Implement pattern overrides behind IS_GUTENBERG_PLUGIN flag

I've been working on this while at WC Asia, so would appreciate some thorough testing, as I've just been doing bits here and there!

@talldan
Copy link
Contributor

talldan commented Mar 13, 2024

I've started working on a new epic issue focusing on what's needed for 6.6 - Pattern Overrides Epic (WordPress 6.6).

It might potentially be best to close this issue out, and move all future conversation there?

I've run out of time today, but will make sure this is communicated more widely tomorrow.

@talldan talldan changed the title Patterns: Synced Pattern Overrides Pattern Overrides epic (WordPress 6.5) Mar 14, 2024
@youknowriad
Copy link
Contributor

Thanks @talldan Let's close this one then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Feature] Patterns A collection of blocks that can be synced (previously reusable blocks) or unsynced [Feature] Synced Patterns Related to synced patterns (formerly reusable blocks) [Type] Enhancement A suggestion for improvement. [Type] Iteration Scoped iteration of an effort from a tracking issue or overview issue ideally for a major release.
Projects
None yet
Development

No branches or pull requests