Gutenberg block "This block appears to have been modified externally" on save

Just starting to play with Gutenberg block development, and I am building a very simple button (yes I know buttons are already included, but this block will have lots of settings and classes not included in the core block).

Seem's pretty strait forward, but when I save the block and reload, I get a validation error and the "This block appears to have been modified externally" message.

registerBlockType('franklin/button', {
    title: 'Button',
    keywords: ['button' ],
    icon: 'admin-links',
    category: 'layout',
    attributes: {
        text: {
            source: 'text',
            selector: '.button-text'
        },
    },

    edit({attributes, setAttributes }) {

        return (
            div class="guttenberg-usa-button"
                button class="usa-button"
                    PlainText
                      onChange={ content = setAttributes({ text: content }) }
                      value={ attributes.text }
                      placeholder="Your button text"
                      className="button-text"
                    / 
                /button
            /div
        );
    },

    save({attributes}) {
        return (
            button class="usa-button"
                { attributes.text }
            /button
        );
    } 

});

So in the editor, I'll add my block, modify the (button) text, save, and reload where I get the This block appears to have been modified externally" message.

Console shows the following error

Expected:

button class="usa-button" class="wp-block-franklin-button"/button

Actual:

button class="usa-button" class="wp-block-franklin-button"testest/button

I must be missing some fundamental concept or something, but I thought the save() function determines what gets displayed on the frontend which btw, looks as expected.

Topic block-editor Wordpress javascript

Category Web


This is because your attribute is using the HTML to get its value, and the selector is .button-text, but there is nothing that matches that selector in the saved output.

    save({attributes}) {
        return (
            <button class="usa-button">
                { attributes.text }
            </button>
        );
    } 

Notice that button-text is nowhere to be found, therefore its value is empty. This contradicts the edit component which does contain such a class.

Either change the attribute to not use HTML/text as the source, or ensure that the selector matches something that contains the text in the saved output.


You are getting this error because your edit and save function output doesn't match.

 save({attributes}) {
    return (
        <button class="usa-button">
            { attributes.text }
        </button>
    );
} 

precisely, { attributes.text } is the save function is not being called or used in edit function. Either add attributes.text in edit function or remove that from save function. Something like this should work -

 <button class="usa-button">
                    <PlainText
                      onChange={ content => setAttributes({ text: content }) }
                      value={ attributes.text }
                      placeholder="Your button text"
                      className="button-text"
                    /> { attributes.text }
                </button>

Notice attributes.text is also outputting same text in the edit function just like save function.

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.