Gutenberg: Block Validation, Deprecation and Migration Experience

Created on 28 Jun 2018  Ā·  57Comments  Ā·  Source: WordPress/gutenberg

image

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:

  • We could set up a threshold of characters and be ok with overwriting if it's below it (say 30 characters).
  • We could have a list of elements we allow to be different (attributes like classes).
  • We could overwrite and offer a way back instead of showing a dialog.

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:

  • Overwrite: runs the block through save and discards what doesn't match.
  • Convert to HTML: transforms the original block into an HTML block.
  • Convert to Blocks: takes the HTML source and runs it through the raw handling mechanism to infer blocks again.

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:

invalid

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:

invalid options

Diffing interface:

diff

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:

  • Things that should not invalidate a block in the first place (HTML attributes like classes or ids or even data-attributes). Even if they were to be discarded after a save cycle.
  • Things that cannot be reconciled and need a decision (like adding an entirely new paragraph between a figure and img tags within an Image block) given the potential for losing content.
  • The user experience of handling conflicts.

The invalidation process can also be deconstructed in phases:

  1. Validate the block exists.
  2. Validate source matches output.
  3. Validate source matches deprecated outputs.
  4. Validate significance of differences.

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:

  • Revise block saving to allow for these differences (like HTML attributes).
  • Overwrite differences that fall under a threshold as insignificant.

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:

  • Registering a transformation for a block into another.
  • Using raw-handling / pasting for conversion.

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 ā€” https://github.com/WordPress/gutenberg/issues/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: https://github.com/WordPress/gutenberg/issues/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:

  • Capture unexpected top-level attributes and re-apply them without causing an invalidation.
  • Distinguish between pasting and raw conversion so that different elements can be preserved.
  • Use a visual diff check after a source invalidation.
  • Improve the user experience of handling conflicts: https://github.com/WordPress/gutenberg/issues/7604
  • Avoid showing the errors in the console when the block is upgraded.
Framework [Feature] Blocks [Feature] Raw Handling [Feature] Writing Flow [Type] Discussion [Type] Overview

Most helpful comment

Block validation as it currently stands is really a burden on developers and users alike. It leads to confusion, uncertainty and bad code.

Updating blocks is really hard because of that. Providing deprecations and deprecated styles will eventually lead to a lot of bloat in themes with the thought process being: Leaving that deprecation in is cheaper than the eventual support request by that one, old user.

Quickly developing and iterating upon blocks is nearly impossible. Every change in markup in save will eventually lead to the need to re-add the block. I see developers using dynamic blocks just for this reason.

Semi-Dynamic content in static blocks will lead to a lot of sadness. One of our biggest gripes at the moment are i18n issues. When we use i18n for labels or date-formats in some of our blocks, validation obviously fails after the change of language.

If I could turn off the validator, I would do it.

All 57 comments

Related: #5233.

There seems to be two main parts here:

  • Improve the UI with better choices
  • Improve the validation so we can make decisions for the user and reduce interruption

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:

  • Change block warning to match mocked style
  • Improve text
  • Add an ellipsis menu to the block warning where actions can be added
  • Include additional actions (convert to classic blocks, apply copy/paste cleanup, compare conversion etc)

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

offer a notice that a block has changed, letting people review the changes if something doesn't seem right

Forgive my lack of design skills or knowledge of Gutenbergā€™s design language - maybe this already exists - but something like this?

a4f8126f-0a94-4679-af27-ad3ff2e002da

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:

5f43b23f-eb92-4baa-a6e6-cfcf8986910e

It can be ignored without getting in the way of editing, and could disappear at some point as an implicit acknowledgement.

@johngodley said:

There seems to be two main parts here:

  • Improve the UI with better choices
  • Improve the validation so we can make decisions for the user and reduce interruption

I'd add a third:

  • Ensure that externally modified blocks can still remain "portable"

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.

Forgive my lack of design skills or knowledge of Gutenbergā€™s design language - maybe this already exists - but something like this?

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 </p> tag or other small changes, and then go ahead and perform the conversion without asking, but notify the user so they can undo it if they like ā€” is that correct? If yes, then I love it.

To polish your mockup a little bit, here's a different version:

screen shot 2018-07-06 at 10 43 51

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:

screen shot 2018-07-06 at 10 44 14

@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.
Many developers do running upgrades to their theme (at least I do, improve template files, new layouts, etc.), so changing how the markup of the block will look like is something that is highly likely a developer would have to do, even on a production site.

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 https://github.com/WordPress/gutenberg/issues/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:

<p style="font-size:30px">This is text</p>

If you change only 30 to 20 in the 'Edit as HTML' view then you get the modified externally error. As the structure has stayed exactly the same with only one value changing it seems like Gutenberg should be able to handle the change.

Closed #8532 as a duplicate and am copying the suggestions here for reference:

Suggestions

  • Exclude data- attributes from validation (they represent an elements state, not its structure)
  • Add support for custom block validation methods (within registerBlockType) to allow users to override the default behaviour
  • Maybe use the attribute schema to validate the structure, including an optional flag

So what is propper way to update custom blocks ? What if i change structure of my block, but that block was used on hundred of places?

Noting #8798, which provides an example of the kinds of confusion and frustration that validation issues can cause.

Any news on this, its killing me as a new developer to Gutenberg, its the one thing holding me back from totally embracing it.

Is this closed by #7741? what's the remaining items?

7741 was a main one yes, and these are what I consider the remaining items:

  • [ ] #9088 - Allow re-editing of HTML
  • [x] #7995 - Show difference between invalid block conversion options
  • [ ] #8166 - Add block warning overwrite
  • [ ] (no PR yet) - Allow data attributes without triggering validation errors

This should give us a good set of mechanisms for fixing an invalid block, as well as relaxing the validation process

I've also been working on the warning mechanism mentioned here that also solves #9198. It's a bigger change that affects other things, so something that can come after this is closed.

Just mentioning a couple of things I noted on #9473:
screen shot 2018-09-05 at 3 12 23 pm

  • 'Convert to Blocks' appears twice for this warning, once in the main warning body and also in the more menu
  • The 'Convert to Blocks' button copy doesn't make much sense, since this is already a block, just one with a warning.
  • "This block has been modified externally" - reading this from a user's perspective, this doesn't tell me why there's an issue, and only goes halfway to explaining how it happened. It also reads like quite a technical sentence. I think something like "This block has unexpected HTML, so it can no longer by edited as a paragraph block" might be an improvement.

@youknowriad Can you update this issue's description with a summary of the other issues you've closed, so that information isn't lost in this process of consolidating?

It's very hard to merge issues with comments, I tried adding the most important notes to the description but feel free to add anything I missed. Also the context is not entirely lost as there are links.

Once we come up with clear actionable items that are technically valid and improve the experience, I'd love to create a smaller issue to tackle these.

So what is the way forward here, after all these issues were closed?

The last message does not state what the criteria are for passing the "technically valid" and "improve the experience" hurdles. It also does not state who will have to come up with these (who is the "we"?) and when this will or can happen.

Sure, here are some thoughts:

  • The user should know when extra html is being deleted from its content. the user might not agree about random content being removed without consent if he tweaked the HTML manually.
  • Any improvement to the invalidation UI that brings more clarity is welcome.
  • Auto-Migration triggered by block authors on plugin upgrades is a possibility. Technically speaking, I'm not certain how this would work though.

Auto-Migration triggered by block authors on plugin upgrades is a possibility. Technically speaking, I'm not certain how this would work though.

Migrating a large number of posts is a solved problem. This can and has been done uncountable times through either WP CLI or upgrade routines run through the admin.

What Gutenberg is missing is the framework to migrate block content. To my knowledge there is currently no way in PHP to extract instances of a specific type of block type from post content to update them.

@youknowriad can you please elaborate why "replace with new version", which could include a warning saying that custom modifications will be lost, is not an option?

We are all wasting a lot of time during development with this issue when this simple solution could be implemented. It's what everyone here seems to be requesting and in my opinion this does not hinder finding other viable solutions for cases where plug-ins are updated.

can you please elaborate why "replace with new version", which could include a warning saying that custom modifications will be lost, is not an option?

This is already possible, when the "invalid" warning is displayed, you can click the "..." menu and click "Attempt block recovery".

The UI here could be improved like I suggested above.

Hmm

can you please elaborate why "replace with new version", which could include a warning saying that custom modifications will be lost, is not an option?

This is already possible, when the "invalid" warning is displayed, you can click the "..." menu and click "Attempt block recovery".

The UI here could be improved like I suggested above.

Thanks!

Hm, guess I should try going on the new branch then, this isn't available in WP 5.1, right?

Right, it's not on 5.1. It should come on 5.2.

Block validation as it currently stands is really a burden on developers and users alike. It leads to confusion, uncertainty and bad code.

Updating blocks is really hard because of that. Providing deprecations and deprecated styles will eventually lead to a lot of bloat in themes with the thought process being: Leaving that deprecation in is cheaper than the eventual support request by that one, old user.

Quickly developing and iterating upon blocks is nearly impossible. Every change in markup in save will eventually lead to the need to re-add the block. I see developers using dynamic blocks just for this reason.

Semi-Dynamic content in static blocks will lead to a lot of sadness. One of our biggest gripes at the moment are i18n issues. When we use i18n for labels or date-formats in some of our blocks, validation obviously fails after the change of language.

If I could turn off the validator, I would do it.

Agree with @Luehrsen wholeheartedly. What a mess! Deprecation is all very proper and organised etc, but far out, this is WordPress, not NASA. Developers use WordPress because it's easy and hackable. Gutenberg right now is the neither of those things.

In my experience developing sites with completely dynamic blocks, I don't care if the output doesn't match. I should be able to tell WordPress this.

As of now the current approach kills any attempt to develop extensions to built-in blocks.
It kills any attempt to develop static blocks.
It makes any client request to change anything or add feature to blocks a complete nightmare.
Gutenberg is shooting its own foot here when it comes in getting support from developersā€™ community.

You should at least give a global variable or hook that will allow disabling this validation function so we can circumvent this mess till a proper solution is in place. There was a mention that it would be not fair to allow plugins to change user content output without their consent. WEā€™VE BEEN DOING IT for over decade since introduction of first action hook and Internet still exists.
In case you forgot the most infamous interference was when WordPress core was doing it by replacing Wordpress with WordPress :P TinyMCE been doing it _(changing user content, and it was doing it on the fly without any confirmation)_ since forever and we dealt with it.
I donā€™t think it is a problem especially when itā€™s done for userā€™s own good.

Long term alternative would be to give us validation hooks where we could decide whether block structure is valid or not.

Edit because I don't want spread emotional ranting across multiple posts:
I've asked all my clients and so far got response from 16 of them. Not a single one understands what it means that the block is expired or was changed externally. Their brain is blown when they see any mention of HTML or code. Going into Diff and seeing all those highlights in the code scares the crap out of everyone and they think they broke something and they revert back to me 'to have a look at that ASAP'.
I don't believe anyone who chooses WordPress for the sake of easy of use will know how to deal with those pop-ups and messages.

This is a huge architectural flaw. I can't believe your UX / architectural chief allowed for this. The current Gutenberg block validation approach successfully and unscrupulously converts WP development into complete contradiction to what was once the most amazing and extensible CMS on the planet.

currently we are having to use https://github.com/nk-o/lazy-blocks/ which seems to have found a work around and update blocks using that, would be good to see not depreciating blocks as a per theme option or something. It makes lots of sense from a user point of view once you have a final relese you don't want your theme messing with your content but during development it's such a problem :-/

I'm personally coming to the conclusion that we should rethink when validation error triggers. We should split that into two parts:

  • very strict error: is the content of the block the same as when it was saved, does it contain all HTML attributes and DOM nodes that are referenced in attributes definition
  • a tiny warning or no action required: your saved content contains some additional HTML attributes or nodes added by filters - clean it up or continue as is
  • a tiny warning or no action required: your saved content contains some additional HTML attributes or nodes added by filters - clean it up or continue as is

This flexibility is likely reasonable, though worth noting there may be specific circumstances in which transparently migrating could result in unintended breakage (e.g. CSS or JavaScript selectors on :not( [attribute] ) or :not( .class ) where behavior becomes changed without user consent). A minimal warning as you mention may be a compromise, though would need some design / UX consideration.

In my humble opinion the main question here is where lies the concern, in other words is it really WPā€™s core that should be responsible, blamable and charged with duty to guard end user from potential content and behavior breaking caused by plugin or theme?

From end user experience perspective block validation with preventing and obstructing features like they are now should be an opt-in (or opt-out) feature decided individually by administrator / editor.
What Iā€™m trying to say as well is that admins - whom mostly donā€™t know what HTML is - donā€™t want be bothered with technicalities. They leave trust in WP and plugin developers and if something goes wrong they are most likely able to notice themselves that something has changed (and they can quickly narrow down the problem to the action they did themselves ā€“ like installing a plugin, updating WP etc.).

Ideally, we can have different level of warnings / UX obstructions (i.e. kill my editing experience, show big exclamation sign, show small exclamation sign, show kitten, donā€™t bother anymore about this block type, donā€™t bother ever about anything) and admins should be able to pick up one thatā€™s favorable by them.
This way we leave the responsibility in their hands.

You can let admins opt-in / opt-out to/from this feature and let them select appropriate level of validation importance in different places i.e. during installation, on first login, in writing settings, in a pop-up with validation warning windows etc.

Iā€™m pretty sure this will make way more people happy, because giving people choice, makes them happy.

is it really WPā€™s core that should be responsible, blamable and charged with duty to guard end user from potential content and behavior breaking caused by plugin or theme?

It is, at least according to the WordPress Philosophy "Decisions, not Options".

https://wordpress.org/about/philosophy/#decisions

Every time you give a user an option, you are asking them to make a decision. When a user doesnā€™t care or understand the option this ultimately leads to frustration. As developers we sometimes feel that providing options for everything is a good thing, you can never have too many choices, right? Ultimately these choices end up being technical ones, choices that the average end user has no interest in. Itā€™s our duty as developers to make smart design decisions and avoid putting the weight of technical choices on our end users.

I definitely think the validation process needs to be completely reconsidered. I develop custom Gutenberg blocks for my clients' websites. If I update the layout of one of the blocks, I don't want my clients to be greeted with these warnings. I just want the block update to roll out automatically. So having the ability to globally opt-out of validation, or at the very least, tell the block to opt-out of needing to be validated would make sense to me.

Secondly, the other major flaw associated with this is that when blocks are updated the changes are not rolled out automatically across the whole site. This is a major problem with the fundamental construction of Gutenberg. If my clients ask for a change to be applied to a certain block type, the expectation is that one change in the backend should automatically update all occurrences of that block throughout the site.

We have a site we're about to begin building that will have over 4000 posts when it is launched. If we update the code for a block on that site, we definitely don't want to have to re-save 4000 posts one at a time in order for them to get the updated block layout! An update to the code of a block should automatically be reflected across the whole site.

I realise this is a fundamental shift for Gutenberg. Perhaps this could be enabled as an option when creating a block - developers can choose whether to have validation, or whether they want to dynamically pull in the block layout both when editing and rendering.

Leaving validation as an option could keep whoever came up with the original logic happy, for whatever use-case they thought up. But I expect the majority of developers will wholeheartedly adapt the option of rendering blocks on the fly so that any updates get automatically applied throughout the site.

@jodamo5 Check out dynamic blocks: https://developer.wordpress.org/block-editor/tutorials/block-tutorial/creating-dynamic-blocks/

They allow you to build the UI for the editor just like any block but then the actual output is handled with PHP. No validation errors, updates are pushed automatically to all blocks, etc.

Thanks @davidyeiser but I think dynamic blocks won't work in this scenario. I might be wrong, but from reading about dynamic blocks, it is for when the content isn't saved on the page as such - like the example where the block pulls in the latest posts, which is a dynamically changing list. There is no specific content saved into the block for that page.

What I'm addressing is a different issue. I'll expand the example to try to make what I'm meaning clearer:

We might create a specific type of block which has the following custom fields: Title, paragraph content, link text, URL to link to, and up to 4 images, which will be shown in a gallery carousel. We build these into a block as the client was consistency of this component across their site, and ease of editing.

We build out a large site for this client, and this block gets used on 100 different pages on the site.

I don't believe a dynamic block will work in this situation, because we want the content that we inserted into the block to be saved on those pages. Is my understanding correct? Or am I missing something?

To continue the example, later we discover a slight bug in the block when there are only 3 images instead of 4 images selected. Or perhaps we decide to apply the link to the title of the block as well as the link text. Or maybe an update is released for the third-party carousel code that we use and we need to apply the update.

Whatever the reason, when we make a change to the block code my expectation is that I want to see this immediately rolled out across all pages on the site. But with the current validation process all of those blocks would instead be marked as "modified externally" and the changes would not be reflected on the front end until each of those pages is re-saved.

So the ideal scenario in my mind is to enable users to insert blocks into the Gutenberg editor, type in the content they way, select images, etc, and when they save it saves the content they've inserted, but not the full HTML structure of the block. The HTML, CSS and javascript should be rendered on the fly when the page loads on the front end. (Or, as mentioned earlier, at least give developers an option for blocks to be handled like that). That way, any code changes that are made will immediately be visible across the whole site.

If I've mis-understood dynamic blocks, and this is actually already possible, please do let me know. But at this point, I still think this is a fundamental flaw in Gutenberg.

Hey @jodamo5, dynamic blocks can work just as you're describing if I understand you correctly. They aren't just for pulling the latest posts, etc.

For example, I just built out a client site recently and used dynamic blocks for all their specialized content management. We had blocks for inserting big headlines, feature images, testimonials, etc. And scenarios like you're describing happened ā€”Ā in one case there was a bug in a block that had already been used on multiple pages, I just updated the dynamic block code and the bugfix was pushed instantly to all those pages. (And the text and image content for each page's block was different.)

I wrote a tutorial on dynamic blocks, it might help you more than me describing my various scenarios: https://davidyeiser.com/tutorial/creating-custom-dynamic-gutenberg-block-wordpress-part1

@davidyeiser OK an update ... I've dug more into dynamic blocks and you're right, it looks like this is what is needed. To avoid this whole validation mess and to have any block updates be reflected across the site immediately we need to use dynamic blocks. Thanks for your guidance.

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.

This dynamic blocks tutorial needs some significant enhancement to make it much more obvious:
https://developer.wordpress.org/block-editor/tutorials/block-tutorial/creating-dynamic-blocks/

@jodamo5 Ive run into the same problem as you. I started implementing dynamic blocks. They don't seem to support which are used on some of my blocks. @davidyeiser have you run into / found a way to get into the php version of the block?

@afridley Try the setup below and let me know if it doesn't work for you.

In the main _registerBlockType_ function, for the save method where you would normally have return null for dynamic blocks, change it to this:

save: (props) => {
  // For dynamic blocks, return InnerBlocks.content for rendering
  return <InnerBlocks.Content />
}

And then in your function that renders the dynamic block, add a second argument $content where you normally would just have $attributes:

function render_dynamic_block($attributes, $content) {
  // $content will contain InnerBlocks.Content
}

Notes:

  • Youā€™ll still have access to $attributes like usual.
  • I don't think you need to have the (props) in the save method, I was going off some old code I wrote and I think that was just left in there by mistake, but I'm not in a place where I can test to be sure. This probably works just the same: save: () => { ā€¦

I also had problems with the validation process of Gutenberg, but I created a workaround.

The problem: I have created a block for the editor, where users can add or delete training hours and locations within a table.
Table_Block_Gutenberg
Everything worked fine until someone wanted to edit the table. Everytime a validation error occurred when the page containing the block was opened in the edit mode.

The solution: I managed to fix this problem by only having a string in the 'attributes'-property which holds the data. Within every 'onChange'-methode the string is parsed into a JSON-object, the values are changed, the object is repared into a string and finally the string is set to the property.
Everything works as excepted now.

'Attribues' property:

attributes: {
    schedules: {
        type: 'string',
        default: '[]'
    }
},

'TextControl' example:

const getLocation = (schedule) => {
    return (
        <td>
            <TextControl
                type="text"
                value={schedule.location}
                onChange={value => {
                    let schedules = JSON.parse(props.attributes.schedules);
                    schedules.forEach(tempSchedule => {
                        if (schedule.id == tempSchedule.id) {
                            tempSchedule.location = value;
                        }
                    });
                    props.setAttributes({ schedules: JSON.stringify(schedules) });
                }}
                placeholder="Enter location"
            />
        </td>
    );
}

Adding this in case it's useful... I have built almost 3 dozen dynamic blocks for a client. "Save" output (for lack of a better term) always looks exactly like this:

    return (
        <ServerSideRender
            block="cgb/block-dynamic-block"
        />
    );

or this:
block="cgb/block-dynamic-block"
attributes={{ indent: divBreadIndent }}
/>

Occasionally, after an update, I get the oh-so-fun "this block has encountered an error and can't be previewed" message.

In these cases, the console shows that ā€œsaveā€ returns nothing (not null, just nothing) and that the post content is this (with the block name differing block-to-block, of course):

When I remove and re-add the block, the post content changes to this:

And all is fine.

The thing is, I canā€™t figure out why it changes in the first place.

I have written a script that fixes it after-the-fact (replaces the bad content in the database), but it would be great to not have to use it.

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?
Writing a deprecation for every little thing is just painful.

@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.

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.

@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ČÆ+ notifications@github.com 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
https://github.com/WordPress/gutenberg/issues/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 galdrar@gmail.com 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ČÆ+ notifications@github.com 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
https://github.com/WordPress/gutenberg/issues/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:

  • Strict: the current one that marks a block as invalid if it is not an exact match.
  • Moderate: allows extra attributes, as long as the ones provided by the save function are not altered (i.e. additional classes, data-* attributes, etc). It could still warns the differences in the browser console, and shows a tiny icon as a UI indicator that displays those differences when hovering it.

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 isEquivalentHTML function.

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 save function. (mimics behavior of "attempt block recovery" without prompting the user)

A more "moderate" mode here is in my opinion both expensive to build and does not clearly benefit end users.

https://github.com/WordPress/gutenberg/pull/19188

Let me know what folks think.

anyone interested in seeing this resolved should checkout what's proposed in https://github.com/WordPress/gutenberg/issues/21703

Iā€™ve read this whole thread and feel thereā€™s a lot of good discussion here.
The thoughts about future evolution of how migration and deprecation should work are good to read, however, I think there is a lot of UX improvements that can make the process much smoother as well.

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:
https://github.com/WordPress/gutenberg/issues/25436

Yes, this is a larger overview and endeavor that should not block other meaningful improvements to the user experience that can be done separately.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

maddisondesigns picture maddisondesigns  Ā·  3Comments

mhenrylucero picture mhenrylucero  Ā·  3Comments

cr101 picture cr101  Ā·  3Comments

jasmussen picture jasmussen  Ā·  3Comments

spocke picture spocke  Ā·  3Comments