-
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
Block Validation, Deprecation and Migration Experience #7604
Comments
Related: #5233. |
There seems to be two main parts here:
I think these can be done sequentially, depending how far we want to go. Improve the UI The suggested mockups seem a good way of improving the current setup, and breaks down into nice chunks which I’ll split off from this issue:
The ‘compare conversion’ ability seems a good thing to have in all situations - whatever my choice I’d like to know the result. Also, improving the text will be a big help here. As a new Gutenberg user the current message is an almost instant ‘panic’ situation that makes me want to switch back to the classic editor where it's not going to scare me! Improve the validation
Forgive my lack of design skills or knowledge of Gutenberg’s design language - maybe this already exists - but something like this? That is, some kind of small flag to indicate something happened, but it’s probably ok to ignore. Clicking it could show a reason with options to view the change and take other actions: It can be ignored without getting in the way of editing, and could disappear at some point as an implicit acknowledgement. |
@johngodley said:
I'd add a third:
Here's an example: Let's say I create a really great layout. I want to share it with others. But they don't have the media files I have and even if they did, they'd not be in a predictable place. So, I switch to code view in Gutenberg and copy the whole thing in the hopes that when they paste my whole layout into theirs it will pull the images from my site. But currently, if I'm using a full-width block, when Gutenberg notices that the block is modified both the "Convert to Blocks" and "Edit as HTML" options prevent me from using the full-width feature of the blocks. The best example of this problem is with the cover image block. |
To expand on this, you're suggesting that we have two levels of validation. One where there's a big or breaking change, that gets the modal notice. The other where we think the conversion is trivial and small, like changing whitespace adding a closing To polish your mockup a little bit, here's a different version: It's an exclamation mark in a circle, below the ellipsis. It's blue to ensure contrast, and because it's supposedly a small change it indicates. Let's also open the popout as an overlay of the block itself, i.e. down and left, so we don't have any responsive issues: |
@mathetos I'm not sure I fully understand. You are copy/pasting a post (or block?) HTML to another site and a block on the other site is showing the warning? |
I feel like what @mathetos could work, but perhaps even expanded to provide developers with the option to create "porting" functions for the block. Being forced to convert to html or remove the block entirely is not an option when the whole site is using the block that you changed. Either just giving a soft warning about block changes (meaning it doesn't force you to convert the block) or providing developers with an API to write "upgrade functions" that transform an older version of the block to a newer version is necessary for anyone who's gonna be creating and upgrading custom blocks. |
As a person new to editing and creating blocks; I'm still unsure of a proper workflow to ensure changes that I make to my blocks' source code (in a separate code editor, say sublimetext) are displayed as I intended in a post that contains the block. With this in mind, I'd tinker with the styling and content in the save button, add some new functionality, and then when I'd refresh the page containing that block; it would display. I think this feedback loop is very important and helpful to people new to creating gutenberg blocks. The author of #6826 also had the same concern and I'd love to hear your recommendations for handling this; workflow for rapidly viewing your changes you make to your block's source code. I see the tension in this; because if a plugin developer updates a block (changing a default class to be 20 px instead of 10px) and a less tech-experienced user (who never creates their own blocks) updates the plugin's block; the user's content could display remarkably differently and the user won't know why. |
I've noticed this happens even on the paragraph block. If you use the InspectorControls panel to set a custom font size of 30px the HTML looks like this:
If you change only |
Is there any update to this concern? I don’t really understand the need to save legacy code after the code base has been updated to newer structure. Then write deprecated logic to manually go to each post and update to reflect new structure. As well as maintain older styles to go along with legacy code. What’s the use case? If you want people to use less dynamic blocks as it’s encouraged in the Gutenberg handbook, it has to be easier to make html structure edits without jumping through hurdles and keeping legacy code from making it to the end user and audience. Is there something we are missing? Examples of does and don’t when coding our save outputs? I’ve just been reading through all these issues the last couple days and the defense’s just don’t work and an explanation of the logic behind the decision would really help everyone. If a contributor can explain. |
@TheAggressive The main concern here is about keeping the integrity of blocks across different versions, and being able to correctly parse the attributes from them. If you have a block wherein the class names and other structural things (or even attribute names) change over the course of the block/plugin being updated to have more fixes or features, the block editor would need a way to decipher what the block's actual attributes are based from a saved version of a block. For example, if you had created a post with a block a few months ago, and the plugin that supplied that block was updated a few times already, the legacy save code would provide a way to make sense of your old saved block. If the legacy code wasn't there, then there would be a chance that the attributes won't get parsed correctly. |
I'd like to bring up that reusable blocks with deprecated block versions won't run through the migration process. The problem here is that the reusable blocks don't go through the JS deprecation methods when they're being rendered for the frontend. The only way to migrate a reusable block with a deprecated block is to manually edit it in the block editor and update it. Related #9070 |
So, is there any easy way to just update the markup or add a css class in a custom block without fearing that it might break hundreds of pages? |
@vladoa From @jodamo5 's comment (quoted below), for now the solution is to use dynamic blocks to avoid validation/deprecation. For reference, here's the Tutorial: Creating Dynamic Blocks.
|
@eliot-akira if I use render_callback technique to render with PHP, will I be able to nest my custom block, in let's say, Columns Block? |
Thanks! I'll try that again. I had tried it, but only on blocks already in
use (I didn't remove and readd).
…On Fri, Dec 13, 2019 at 5:52 AM 3λiȯ+ ***@***.***> wrote:
@vladoa <https://github.com/vladoa> From @jodamo5
<https://github.com/jodamo5> 's comment, for now the solution is to use
dynamic blocks to avoid validation/deprecation. For reference, here's the Tutorial:
Creating Dynamic Blocks
<https://developer.wordpress.org/block-editor/tutorials/block-tutorial/creating-dynamic-blocks/>
.
Key points:
- Return null for the save function. This stops Gutenberg saving the
HTML into the database.
- Attributes of the blocks are automatically saved to the database
when the page is saved. (Stored as HTML comments that Gutenberg reads).
- We then use these attributes as the data to use when rendering the
block on the front end. So the HTML is always built on the fly from our PHP
code, which means that any update we make to the block will be immediately
replicated across the site.
In my mind this should be the default way blocks are built instead of the
current default of using the "save" function which stores the HTML in the
database.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#7604?email_source=notifications&email_token=AA25PJOQ4QQP2Q55I4642QLQYOHQRA5CNFSM4FHMZAWKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEG2A43Y#issuecomment-565448303>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA25PJJTGOLHR75YX4JI6UTQYOHQRANCNFSM4FHMZAWA>
.
|
My clients put their custom, dynamic blocks in various other blocks:
columns, embeds, paragraphs, code, etc.
…On Fri, Dec 13, 2019 at 10:34 AM Tina Granzo ***@***.***> wrote:
Thanks! I'll try that again. I had tried it, but only on blocks already in
use (I didn't remove and readd).
On Fri, Dec 13, 2019 at 5:52 AM 3λiȯ+ ***@***.***> wrote:
> @vladoa <https://github.com/vladoa> From @jodamo5
> <https://github.com/jodamo5> 's comment, for now the solution is to use
> dynamic blocks to avoid validation/deprecation. For reference, here's the Tutorial:
> Creating Dynamic Blocks
> <https://developer.wordpress.org/block-editor/tutorials/block-tutorial/creating-dynamic-blocks/>
> .
>
> Key points:
>
> - Return null for the save function. This stops Gutenberg saving the
> HTML into the database.
> - Attributes of the blocks are automatically saved to the database
> when the page is saved. (Stored as HTML comments that Gutenberg reads).
> - We then use these attributes as the data to use when rendering the
> block on the front end. So the HTML is always built on the fly from our PHP
> code, which means that any update we make to the block will be immediately
> replicated across the site.
>
> In my mind this should be the default way blocks are built instead of the
> current default of using the "save" function which stores the HTML in the
> database.
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <#7604?email_source=notifications&email_token=AA25PJOQ4QQP2Q55I4642QLQYOHQRA5CNFSM4FHMZAWKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEG2A43Y#issuecomment-565448303>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AA25PJJTGOLHR75YX4JI6UTQYOHQRANCNFSM4FHMZAWA>
> .
>
|
@MonsterKing you are right, I have just tried it out. Works fine. It just still feels weird doing it again in PHP even when React is introduced in the frontend. |
I like what @gziolo suggested above. I think that having 2 validation modes as a start could offer more flexibility:
The strict mode will be the default one, allowing users to switch to the moderate mode with a new Gutenberg setting in WP Admin and/or developers with a filter. For technical reference, the current strict mode is implemented in the |
I've added a try PR exploring what adding more block validation modes looks like. In this first pass I've added another option that basically defers to the block, provided that it doesn't throw errors in it's A more "moderate" mode here is in my opinion both expensive to build and does not clearly benefit end users. Let me know what folks think. |
anyone interested in seeing this resolved should checkout what's proposed in #21703 |
I’ve read this whole thread and feel there’s a lot of good discussion here. Simple changes in wording, and structure of the options in the dialog, can go a long way. I’ve created another issue with mock-ups and explanations that details my suggestions: |
Yes, this is a larger overview and endeavor that should not block other meaningful improvements to the user experience that can be done separately. |
While I understand the benefits of being able to just pull out the markup stored in the post content for display on the front end, trying to parse attributes from that content is just not a winning strategy for the long term. In practice, we end have 10+ versions of some of our blocks, and because it only updates on page edit, we have each and every one of those block deprecations living out in the wild somewhere, which means we have to keep old CSS around that's only used for pages that haven't been touched for 2+ years. The block editor is a react app, why are we not letting it act like one? The attributes array already provides data structure for all our blocks, why not just save attribute values explicitly in a json array in the db for each post as well as the html content? On update, we can nudge the blocks to update their html and they have a pool of explicit values on which to do so. |
Is there a way to trigger the “Attempt block recovery” action on all our broken blocks sitewide? Waiting since 18 months.. |
Not that I know of. I wrote a little script that looked for the problem content in the database and removed it. So, with my client, there is a button to click that cleans everything up (as long as it's the same problem). We haven't had to use it in a while. Not sure if it still works. But, if you look at (and copy and paste it in a text editor) the wp_content field in the (prefix)posts table for your post before you attempt a restore and then look again after restoration (copy and paste again) and compare the two, you'll see what shenanigans in the "bad" version were changed. That's what I did. It was just some weird "placeholder" thing that was being added. Once I stripped that stuff out, all was fine again. I wrote a function that did the work for me. |
Individual blocks have a strict shapes of markup and attributes that are expected to consider a block valid within the editor. The way this works, at a fundamental level, is that Gutenberg compares the source given for a ny block with what would be the output if that source is run through the block implementation for that block type (attribute sourcing and
save
). When there are differences here, we show the already infamous dialog.It's important to draw a distinction between the validation mechanism and what we choose to do with it (the user experience). For now, it's been incredibly useful to have a very strict validation experience where any detected change is considered an external modification.
The user experience goal, though, should be to avoid bothering users and avoid losing important content. From this, the potential tension is already obvious.
It's also crucial that the validation mechanism remains as simple as possible because it'd have performance costs — it is run for every block to determine validity upfront. So I'm not willing to add overhead there. That said, once we detect a block as initially invalid, that's where we have more room for establishing conditions:
These could also be combined for more sophisticated experiences, like attempting our best guess and offer a notice that a block has changed, letting people review the changes if something doesn't seem right. This could also be tied with post revisions. That is, if there's revisions support, and we can save one, we can be more aggressive in making a choice for the user. However, if revisions are not enabled or possible, we might want to be more conservative.
There's also multiple conversion choices we have already implemented:
save
and discards what doesn't match.All of these could be the right choice under certain circumstances, but it's harder to tell which should be the default one. It's important to offer all of these (maybe in an ellipsis menu on the dialog), and be very clear about the wording (the "Edit as HTML" is confusing, for example, since it converts the block).
Also, if these changes are being caused by switching to the HTML editor, we might want to act differently and word things differently — example, don't use "This has been edited externally" and maybe the HTML option becomes "Keep as HTML" in that case.
Previewing
We currently show a dimmed out preview of the block current state. It'd be nice to allow users to check a before / after for the different transformations so they can make the best decision visually. This could also be the basis for a better revisions experience by rendering the different states of the block.
Mockups
Here are some quick drafts as to how the process could look. The specific diffing interface might need refinement as we continue to explore, as well as the phrasings of the various options.
Invalid block message:
Contrary to now, the message now sits in a box that's the same height of a default paragraph (56px), and a gray scrim extends the height of the block.
Block conversion options:
Diffing interface:
Invalidation
Is the process with which a block source is compared with its output before the user interacts with a block. When this fails, for whatever reason, the block is considered invalid. This has been an extremely useful mechanism during the development process, highlighting issues with blocks, plugin compatibilities, and so on.
It's important to clarify that this is not a case of whether the markup is "valid" in terms of being HTML spec-compliant but about how the editor knows to create such markup and that its inability to create an identical result can be a strong indicator of potential data loss (the invalidation is then a protective measure).
It goes without saying that the general expectation for the user experience is that invalidation doesn't happen, and when it does, that it minimizes the amount of user intervention needed. However, considering an invalidation does occur, there are a few cases that need to be separated:
classes
orids
or evendata-attributes
). Even if they were to be discarded after a save cycle.figure
andimg
tags within an Image block) given the potential for losing content.The invalidation process can also be deconstructed in phases:
These are stacked in a way that favors performance and optimizes for the majority of cases. That is to say, the evaluation logic can become more sophisticated the further down it goes in the process. The first few checks have to be extremely efficient since they will be run for all valid blocks. However, once a block is detected as invalid — failing the three first steps — it is alright to spend more time determining validity before falling back to the user's decision.
Validate significance of differences
This is the area that could use improvements going forwards. Most of the currently reported issues come from differences that should not be significant yet produce an invalidation. There are generally two ways to approach this:
Related issues:
There are also intricacies that surface once blocks are extended.
Validation based on attributes
It has been proposed in several issues that the validation should be based on the attributes instead of the markup but since the blocks are persisted as markup, this is not something that can be actionable at the moment.
Transformations
Another case of data transformation is present in the mechanism for switching a block to another block type. Transforming a block into another block can be destructive, depending on the heuristics established by the two blocks, the source and the destination. Block transformations also come in two shapes:
The first case knows about the block's attributes and is the one used in the main block transformation menu. It allows the most knowledge-transfer in the mapping of attributes. Issues in this conversion should be assigned to the individual blocks responsible for it (example, mapping a quote's cite to a plain paragraph).
The second case is used for extracting blocks out of a Classic block, or converting an HTML block into validated core blocks.
This process is grounded on the same handlers for pasting, which is why in general it removes elements as part of its cleanup process — #6102 —. The intention behind pasting is to clean-up the source without losing meaningful information. However, it could be assumed that given an existing chunk of Classic content the editor could be more lenient in the conversion. One way of handling this is separating both operations, pasting and raw conversion: #6878. Another possibility is to alert the user when something is removed.
Related issues:
Potential Tasks
The aim of this issue is to provide enough context for all these related problems so that any improvements can be discussed holistically. Some examples:
The text was updated successfully, but these errors were encountered: