0

I understand my question may be a bit broad, or even easy to answer. I have been building custom blocks using the --es5 flag of @wordpress/create-block (https://developer.wordpress.org/block-editor/packages/packages-create-block/), which has been fairly successful on projects.

The reason for using this method is that during development and post-launch there are often many changes required of the block and from my past experience (over a year ago) the ES Next method effectively 'killed' the block as soon as a change was made. So you would have to go through every instance of this block and change it.

Have WP's developers come up with a workable solution for this which enables developers to use the ES Next method in a project safely? I'd prefer to be using the methods as intended. The documentation since it's release has not been great so I thought it would be better to ask the wider community.

To try and explain better what I mean:

Building a custom block using the following method (https://github.com/WordPress/gutenberg-examples/blob/master/03-editable/block.js) of attributes with the --es5 flag appears to be more stable in terms of backwards compatibility. If I were to make changes to the render template (https://github.com/WordPress/gutenberg-examples/blob/master/03-editable/index.php) it wouldn't break the block.

Using the 'React' method (https://github.com/WordPress/gutenberg-examples/blob/master/03-editable-esnext/src/index.js), in my past experience, has caused issues. If I build a custom block using this method and a change has been made to the block's code, it 'kills' the block. There is no backwards compatibility from what I can tell.

I'm wondering if this is just something that has actually been resolved since the block editor was first introduced. Or is the way to continue building custom blocks is using the ES5 method

One important bit I have missed out What I was originally alluding to is that I am using server side rendered blocks (excuse my terminology here, its not exactly a clear subject to those unfamiliar with it) that gets around the 'change anything in the block code and you have to add that block again in the editor' problem. Not Ideal for client handover.

register_block_type( 'create-block/perk', array(
    'editor_script'     => 'create-block-perk-block-editor',
    'editor_style'      => 'create-block-perk-block-editor',
    'style'             => 'create-block-perk-block',
    'render_callback'   => 'perk_block_render',
) );

function perk_block_render($attr, $content) {
$str = '';

if(isset($attr['mediaID'])) {
    $mediaID = $attr['mediaID'];

    $src = wp_get_attachment_image_src($mediaID, 'perk');

    if($src && is_array($src) && isset($src[0])) {
        $srcset = wp_get_attachment_image_srcset($mediaID);
        $sizes = wp_get_attachment_image_sizes($mediaID, 'perk');
        $alt = get_post_meta($mediaID, '_wp_attachment_image_alt', true);

        if(!$alt) {
            $alt = 'Perk icon';
        }
    }
}

if(isset($attr['titleContent'])) {
    $title = $attr['titleContent'];
}

if(isset($attr['subContent'])) {
    $subtitle = $attr['subContent'];
}

$str = "<div class='perks__item animate'>";
    if($mediaID) {
        $str .= "<img loading='lazy' width='170' height='170' src='{$src[0]}' alt='{$alt}'/>";
    }

    if($title) {
        $str .= "<h2>{$title}</h2>";
    }

    if($subtitle) {
        $str .= "<p>{$subtitle}</p>";
    }

$str .= "</div>";

return $str;

}

I see now that it is not ES5/ESNext related, however, after looking through recent videos it seems like it is still an issue with developing custom blocks using WordPress's 'preferred' method. And also, judging by the answers using server-side-rendered blocks is the only way away this. Is my code going to experience issues if I continue to use server-side rendered blocks?

6
  • 3
    I don’t quite understand what you mean. Do you have an example? When it comes to editing blocks, it’s possible to change them such that old content created with them will no longer be compatible, but as far as I’m aware that doesn’t have anything to do with which method you use. – Jacob Peattie Mar 4 at 10:40
  • 2
    Can you explain what you mean by an ES Next block? I thought ES Next just meant newer language features transpiled by a tool such as Babel. If that's the case then I do not understand what the concern/problem is, and there are no examples in your code either. Also the --es5 flag of what? – Tom J Nowell Mar 4 at 10:45
  • Also, the ESNext moniker is there just to indicate it's React/JSX transpiled, not vanilla javascript. The problem you are reporting however is not normal, we would need to see the code to understand what's going on, but it implies you are trying to use something like jQuery to modify the DOM – Tom J Nowell Mar 4 at 11:48
  • Also, safe suggests this is a security question, but I do not believe it is, please adjust the question so this is clearer – Tom J Nowell Mar 4 at 11:49
  • 1
    Even if you use the ESNext method, the end result would still be in ES5, so why would using ESNext be unsafe? But it's just that if you build in ESNext, then you'd need to run the build setup which converts your code to ES5 for max compatibility with the different browsers. And if you modify the build scripts (the one already converted to ES5), then you'd need to ensure that you don't use ESNext code/syntax, or else your block would probably be "killed" when run on browsers not supporting the ESNext code you used. – Sally CJ Mar 4 at 12:12
2

Whatever issues you had that caused a block to be "killed" after editing was entirely unrelated to the two different methods of writing the block that you have outlined.

Building a custom block using the following method (https://github.com/WordPress/gutenberg-examples/blob/master/03-editable/block.js) of attributes with the --es5 flag appears to be more stable in terms of backwards compatibility. If I were to make changes to the render template (https://github.com/WordPress/gutenberg-examples/blob/master/03-editable/index.php) it wouldn't break the block.

Using the 'React' method (https://github.com/WordPress/gutenberg-examples/blob/master/03-editable-esnext/src/index.js), in my past experience, has caused issues. If I build a custom block using this method and a change has been made to the block's code, it 'kills' the block. There is no backwards compatibility from what I can tell.

The code in those two method is, for all intents and purposes, the same. They are just using different syntax.

The 'React' method (they're actually both React) is using some newer JavaScript features, but those are just nicer ways of writing the same code that work in newer browsers. That method also uses JSX for the render functions. This is just a different way of writing those functions which can be turned into functions exactly like the first example by a build process.

The issue you're describing is going to be a challenge of developing blocks regardless of which method you use. When a post built with the block editor is saved, the final output of your block is just saved into the post content as HTML. When the post is loaded back into the editor, your block needs to be able to parse that HTML and reconstruct the block data so that it can be edited again. If your block has changed since that HTML was published, it may not be able to do this and there will be an error. This is the expected behaviour.

The proper method for handling block updates without breaking existing posts is to 'deprecate' the block. The official documentation, with code examples, for that process is here.

If you encountered this issue when using ESNext, but not ES5, then that is more than likely a coincidence. It would have had more to do with what you were doing than which method you were doing it with, as this behaviour is a consequence of how block data is stored, and nothing to do with the JavaScript version used to write the block.

It's worth pointing out that this is not a unique problem for the block editor. If I write a bunch of code in any system that works with data in a certain format, and then I update that code in a way that changes the format, I can't expect the code to just automatically work with data in the old format. You need to think of the HTML your block outputs as a format, and approach developing your block accordingly.

1

I see now that it is not ES5/ESNext related

Yes, exactly.

And I agreed with all that Jacob said in his answer, but I specifically wanted to respond to the 3rd revision of your question, so I decided to write this answer than responding via the comments.

But before responding to that revision, let me first quote what I originally said in the comments:

Even if you use the ESNext method, the end result would still be in ES5, so why would using ESNext be unsafe? But it's just that if you build in ESNext, then you'd need to run the build setup which converts your code to ES5 for max compatibility with the different browsers. And if you modify the build scripts (the one already converted to ES5), then you'd need to ensure that you don't use ESNext code/syntax, or else your block would probably be "killed" when run on browsers not supporting the ESNext code you used.

And secondly, yes, you're right about the latter sentence below:

the ES Next method effectively 'killed' the block as soon as a change was made. So you would have to go through every instance of this block and change it.

However, it's actually because of the block validation and not whether you use ESNext or ES5 — excerpt from the block editor handbook:

During editor initialization, the saved markup for each block is regenerated using the attributes that were parsed from the post’s content. If the newly-generated markup does not match what was already stored in post content, the block is marked as invalid. This is because we assume that unless the user makes edits, the markup should remain identical to the saved content.

So in response to your 3rd question's revision:

after looking through recent videos it seems like it is still an issue with developing custom blocks using WordPress's 'preferred' method.

Maybe, but if you're frequently making changes to your block code, then a dynamic block with a server-side-generated output might be the preferred method for you instead of non-dynamic one with a client-side-generated output.

Is my code going to experience issues if I continue to use server-side rendered blocks?

From the above block validation perspective, no, because the block editor handbook says:

For many dynamic blocks, the save callback function should be returned as null

and

When you return null, the editor will skip the block markup validation process, avoiding issues with frequently-changing markup.

And if you're not actually frequently changing your block markup, then as the other answer said, you can avoid the 'change anything in the block code and you have to add that block again in the editor' (or block validation) issue using the deprecated property.

Excerpt from "How to preserve backward compatibility for a Block" in the block editor handbook:

Markup changes should be limited to the minimum possible, but if a block needs to change its saved markup, making previous versions invalid, a deprecated version of the block should be added.

ESNext+JSX examples:

  • Old version of the block:

    registerBlockType( 'my-blocks/foo-bar', {
        title: 'Foo Bar',
        icon: 'megaphone',
        category: 'widgets',
    
        attributes: {},
        save( props ) {
            return <p>foo bar</p>;
        },
    } );
    
  • New version — in this version, we updated the markup of the block to use a div instead of p and that we updated the block to use the new useBlockProps hook in the block API version 2 (WordPress 5.6+):

    registerBlockType( 'my-blocks/foo-bar', {
        apiVersion: 2,
        title: 'Foo Bar',
        icon: 'megaphone',
        category: 'widgets',
    
        attributes: {},
        edit( props ) { // define 'edit' so that the block is centered and clickable
            const blockProps = useBlockProps(); // here it's not useBlockProps.save()
            return <div { ...blockProps }>foo bar</div>;
        },
        save( props ) {
            const blockProps = useBlockProps.save();
            return <div { ...blockProps }>foo bar</div>;
        },
    
        deprecated: [ {
            attributes: {},
            save( props ) {
                return <p>foo bar</p>;
            },
        } ],
    } );
    

Additional Notes

When registering a dynamic block, you should define your block atrributes in both PHP (using register_block_type()) and JavaScript (using registerBlockType()).

Otherwise, you'd end up with an issue like this. 🙂

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.