Gutenberg Custom Block Not Validating – Ideas?

I added a Custom Block in Gutenberg (which basically customizes the Gutenberg Section block type that is made available by Ultimate Addons for Gutenberg), in WordPress 5.7. It is a block I call let’s call exercise. In admin I can add the block fine, and on front end it seems to display fine, but in admin I get this block validation error:

blocks.min.js?ver=7ed7fe32dad771c4e0af4f56539ff156:2 Block validation: Block validation failed for `uagb/section` ({name: 'uagb/section', icon: {…}, keywords: Array(3), providesContext: {…}, usesContext: Array(0), …}).

Content generated by `save` function:

<div id="an-exercise" class="contenttype-wrapper sometopictype-exercise" content-id="" data-id="5830199b"><div class="heading d-flex flex-row"><i class="contenticon fas fa-guitar fa-7x"></i><div class="col"><div class="row"><span class="content-name">Exercise</span></div><div class="row"><h3 class="topictype-title">an exercise</h3></div></div></div><section class="wp-block-uagb-section uagb-section__wrap uagb-section__background-undefined" id="uagb-section-5830199b"><div class="uagb-section__overlay"></div><div class="uagb-section__inner-wrap"></div></section></div>

Content retrieved from post body:

<div id="an-exercise" class="contenttype-wrapper sometopictype-exercise" content-id="" data-id="5830199b"><div class="heading d-flex flex-row"><i class="contenticon fas fa-guitar fa-7x"></i><div class="col"><div class="row"><span class="content-name">Exercise</span></div><div class="row"><h3 class="topictype-title">an exercise</h3></div></div></div><section class="wp-block-uagb-section uagb-section__wrap uagb-section__background-undefined uagb-block-5830199b"><div class="uagb-section__overlay"></div><div class="uagb-section__inner-wrap"></div></section></div>

Now, I can see the essence of the error, since the code generated by save function contains id="uagb-section-5830199b whereas retrieved from body there is uagb-block-5830199b.

I just can’t figure out why there would be this discrepancy.

So I thought I would share my code here and see if anyone sees anything obviously wrong.

First, here is the block code in javascript which is included in my plugin that I use to create the block:

const { assign } = lodash;
const { addFilter } = wp.hooks;
const { __ } = wp.i18n;

// Enable spacing control on the following blocks
const enableBlockContentTypeAttribute = [
    'uagb/section',
];

// Available spacing control options
const contenttypeControlOptions = [
    {
        label: __( 'None' ),
        value: '',
    },
    {
        label: __( 'Exercise' ),
        value: 'exercise',
    },
    {
        label: __( 'Concept' ),
        value: 'concept',
    },
    {
        label: __( 'Something' ),
        value: 'something',
    },
];

/**
 * Add spacing control attribute to block.
 *
 * @param {object} settings Current block settings.
 * @param {string} name Name of block.
 *
 * @returns {object} Modified block settings.
 */
const addBlockContentTypeAttribute = ( settings, name ) => {
    // Do nothing if it's another block than our defined ones.

    if ( ! enableBlockContentTypeAttribute.includes( name ) ) {
        return settings;
    }
    //console.log('Add content type option');
    // Use Lodash's assign to gracefully handle if attributes are undefined
    settings.attributes = assign( settings.attributes, {
        contenttype: {
            type: 'string',
            default: contenttypeControlOptions[ 0 ].value,
        },
        contenttitle: {
            type: 'string',
            default: '',
        },
        contentname: {
            type: 'string',
            default: contenttypeControlOptions[ 0 ].label,
        },
        contentid: {
            type: 'string',
            default: '',
        },

    } );

    return settings;
};

addFilter( 'blocks.registerBlockType', 'my-mods/attribute/contenttype', addBlockContentTypeAttribute );

const { createHigherOrderComponent } = wp.compose;
const { Fragment } = wp.element;
const { InspectorControls, InnerBlocks } = wp.blockEditor;
const { PanelBody, PanelRow, SelectControl, TextControl } = wp.components;

/**
 * Create HOC to add content type control to inspector controls of block.
 */
const withContentTypeControl = createHigherOrderComponent( ( BlockEdit ) => {
    return ( props ) => {
    // Do nothing if it's another block than our defined ones.
    if ( ! enableBlockContentTypeAttribute.includes( props.name ) ) {
        return (
            <BlockEdit { ...props } />
    );
    }
    //console.log(props.attributes);
    const { contenttype } = props.attributes;
    const { contenttitle } = props.attributes;
    const { contentname } = props.attributes;

    function getContentTitle ( content ) {
        props.setAttributes({contenttitle: content});
    }

    return (
        <Fragment>
        <BlockEdit { ...props } />
<InspectorControls>
    <PanelBody
    title={ __( 'Choose Content Type' ) }
    initialOpen={ true }
        >
        <SelectControl
    label={ __( 'Content Type' ) }
    value={ contenttype }
    options={ contenttypeControlOptions }
    onChange={ ( selectedContentTypeOption ) => {
        var name = contenttypeControlOptions.filter(obj => {
                return obj.value === selectedContentTypeOption
            });
        //console.log(name);
        name = name[0].label;
        //console.log(name);
        props.setAttributes( {
            contenttype: selectedContentTypeOption,
            contentname: name,
        } );
    } }
/>

<TextControl
    label={ __( 'Content Title' ) }
    value={ contenttitle }
    onChange={ ( getContentTitle ) => {
        props.setAttributes( {
            contenttitle: getContentTitle,
        });
    }}
/>

</PanelBody>
    </InspectorControls>
    </Fragment>
);
};
}, 'withSpacingControl' );

addFilter( 'editor.BlockEdit', 'my-mods/with-contenttype-control', withContentTypeControl );



// do something with these attributes - add header to section if exercise type block
const addContentTypeMarkup = ( element, blockType, attributes ) => {
    // Do nothing if it's another block than our defined ones.
    if ( ! enableBlockContentTypeAttribute.includes( blockType.name ) ) {
        return element;
    }
    if ( attributes.contenttitle) {

        // add header with anchor link and class name
        var title_slug = attributes.contenttitle.trim().split(/s+/).join('-');

        var iconclassbase='contenticon ';
        var iconclass='';
        switch(attributes.contenttype) {
            case 'exercise':
                iconclass =  'fas fa-guitar';
                break;
            case 'concept':
                iconclass = 'fas fa-atom';
                break;
            default:
                iconclass = 'fas fa-atom';
        }
        iconclass = iconclassbase + iconclass;

        return (
            <React.Fragment>
            <div id = {`${title_slug}`} className = {`contenttype-wrapper sometopictype-${attributes.contenttype}`} content-id="" data-id = {`${attributes.block_id}`}>
                <div className = "heading d-flex flex-row">
                    <i className={`${iconclass} fa-7x`}></i>
                    <div className = "col">
                       <div className = "row"><span className="content-name">{attributes.contentname}</span></div>
                       <div className = "row"><h3 className="topictype-title" dangerouslySetInnerHTML={ { __html: attributes.contenttitle } }></h3></div>
                    </div>
                </div>
                {element}
            </div>
        </React.Fragment>
    )
    } else {
        return element;
    }
    //return saveElementProps;
};

addFilter( 'blocks.getSaveElement', 'my-mods/add-content-type-markup', addContentTypeMarkup);

And here is the php code for the plugin that I made to create my custom block:

/ this is to alter uagb-section block
function my_block_mods_backend_enqueue() {
    wp_enqueue_script(
        'my-block-mods', // Unique handle.
        plugins_url( 'blocks/js/dest/block.bundle.js', __FILE__ ), // block.js: We register the block here.
        array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-hooks', 'lodash', 'wp-editor' ) // Dependencies, defined above.
    );
}
add_action( 'enqueue_block_editor_assets', 'my_block_mods_backend_enqueue' );

Maybe it has to do with the fact that I originally worked on this a couple years ago with WordPress 5.1, and now using 5.7, and perhaps there are some nuanced changes?

Also, for what it is worth, I found the code in the Ultimate Gutenberg Addons plugin that is responsible for creating the section markup. namely,

function (e, t, n) {
    "use strict";
    var a = n(0), l = n.n(a), r = n(1), i = n(364), o = (n.n(i), n(365)), c = (n.n(o), n(366)), s = n(367), u = (n(118), wp.i18n.__), p = wp.blocks.registerBlockType, m = wp.editor.InnerBlocks;
    p("uagb/section", {
        title: uagb_blocks_info.blocks["uagb/section"].title,
        description: uagb_blocks_info.blocks["uagb/section"].description,
        icon: r.a.section,
        category: uagb_blocks_info.category,
        keywords: [u("section"), u("wrapper"), u("uag")],
        attributes: c.a,
        edit: s.a,
        getEditWrapperProps: function (e) {
            var t = e.align, n = e.contentWidth;
            if (("left" === t || "right" === t || "wide" === t || "full" === t) && "full_width" == n)return {"data-align": t}
        },
        save: function (e) {
            var t = (e.attributes, e.className), n = e.attributes, a = n.block_id, r = n.tag, i = n.backgroundType, o = n.backgroundVideo, c = n.contentWidth, s = n.align, u = "";
            "full_width" == c && ("wide" != s && "full" != s || (u = "align" + s));
            var p = "" + r;
            return wp.element.createElement(p, {
                className: l()(t, "uagb-section__wrap", "uagb-section__background-" + i, u),
                id: "uagb-section-" + a
            }, wp.element.createElement("div", {className: "uagb-section__overlay"}), "video" == i && wp.element.createElement("div", {className: "uagb-section__video-wrap"}, o && wp.element.createElement("video", {
                        autoplay: !0,
                        loop: !0,
                        muted: !0,
                        playsinline: !0
                    }, wp.element.createElement("source", {
                        src: o.url,
                        type: "video/mp4"
                    }))), wp.element.createElement("div", {className: "uagb-section__inner-wrap"}, wp.element.createElement(m.Content, null)))
        },
        deprecated: [{
            attributes: c.a, save: function (e) {
                var t = (e.attributes, e.className), n = e.attributes, a = n.block_id, r = n.tag, i = n.backgroundType, o = n.backgroundVideo, c = n.contentWidth, s = n.align, u = "";
                "full_width" == c && ("wide" != s && "full" != s || (u = "align" + s));
                var p = "" + r;
                return wp.element.createElement(p, {
                    className: l()(t, "uagb-section__wrap", "uagb-section__background-" + i, u),
                    id: "uagb-section-" + a
                }, wp.element.createElement("div", {className: "uagb-section__overlay"}), "video" == i && wp.element.createElement("div", {className: "uagb-section__video-wrap"}, o && wp.element.createElement("video", {
                            src: o.url,
                            autoPlay: !0,
                            loop: !0,
                            muted: !0
                        })), wp.element.createElement("div", {className: "uagb-section__inner-wrap"}, wp.element.createElement(m.Content, null)))
            }
        }]
    })

So it is a matter of figuring out why that markup is being altered and where/why?

Thanks!

$299 Affordable Web Design WordPress

This article was republished from its original source.
Call Us: 1(800)730-2416

Pixeldust is a 20-year-old web development agency specializing in Drupal and WordPress and working with clients all over the country. With our best in class capabilities, we work with small businesses and fortune 500 companies alike. Give us a call at 1(800)730-2416 and let’s talk about your project.

FREE Drupal SEO Audit

Test your site below to see which issues need to be fixed. We will fix them and optimize your Drupal site 100% for Google and Bing. (Allow 30-60 seconds to gather data.)

Powered by

Gutenberg Custom Block Not Validating – Ideas?

On-Site Drupal SEO Master Setup

We make sure your site is 100% optimized (and stays that way) for the best SEO results.

With Pixeldust On-site (or On-page) SEO we make changes to your site’s structure and performance to make it easier for search engines to see and understand your site’s content. Search engines use algorithms to rank sites by degrees of relevance. Our on-site optimization ensures your site is configured to provide information in a way that meets Google and Bing standards for optimal indexing.

This service includes:

  • Pathauto install and configuration for SEO-friendly URLs.
  • Meta Tags install and configuration with dynamic tokens for meta titles and descriptions for all content types.
  • Install and fix all issues on the SEO checklist module.
  • Install and configure XML sitemap module and submit sitemaps.
  • Install and configure Google Analytics Module.
  • Install and configure Yoast.
  • Install and configure the Advanced Aggregation module to improve performance by minifying and merging CSS and JS.
  • Install and configure Schema.org Metatag.
  • Configure robots.txt.
  • Google Search Console setup snd configuration.
  • Find & Fix H1 tags.
  • Find and fix duplicate/missing meta descriptions.
  • Find and fix duplicate title tags.
  • Improve title, meta tags, and site descriptions.
  • Optimize images for better search engine optimization. Automate where possible.
  • Find and fix the missing alt and title tag for all images. Automate where possible.
  • The project takes 1 week to complete.