I have a block that basically functions as a background. So it creates a div that gets set with some options for background color and padding, and within it there is InnerBlocks.
Now, I'm trying to update this block with a new div to wrap the InnerBlocks that will have an optional container class.
Here's the error I'm getting in the editor when I load a page with the previous version of the block:
Block validation: Block validation failed for `kcdp/layout`
Expected:
<div class="wp-block-kcdp-layout alignfull kcdp-layout white-background medium-padding no-side-padding" data-side-padding="no-side-padding" data-background="white-background" data-padding="medium-padding" data-container="false"><div class=""></div></div>
Actual:
<div class="wp-block-kcdp-layout alignfull kcdp-layout white-background medium-padding no-side-padding" data-side-padding="no-side-padding" data-background="white-background" data-padding="medium-padding"></div>
As I understand it, the save function in the deprecated object is how Wordpress figures out that the block should be migrated. What's odd to me is that the "Actual" in this error is exactly what should be getting output by the deprecated save function. But it seems like it's not matching on that save function's output.
Here's the code I'm using:
const { __ } = wp.i18n;
const { InspectorControls, InnerBlocks, MediaUpload, PlainText } = wp.editor;
const { registerBlockType } = wp.blocks;
const { SelectControl, PanelBody, CheckboxControl } = wp.components;
// Import our CSS files
import './style.scss';
import './editor.scss';
const el = wp.element.createElement
registerBlockType('kcdp/layout', {
title: 'KCDP - Layout',
icon: 'nametag',
description: 'Creates a background and lets you set padding around your content.',
category: 'layout',
supports: {
align: ['full', 'center']
},
attributes: {
background: {
attribute: 'data-background',
selector: '.kcdp-layout',
default: ''
},
padding: {
attribute: 'data-padding',
selector: '.kcdp-layout',
default: ''
},
sidePadding: {
attribute: 'data-side-padding',
selector: '.kcdp-layout',
default: 'no-side-padding'
},
backgroundImage: {
attribute: 'data-background-image',
selector: '.kcdp-layout',
default: null
},
height: {
attribute: 'data-height',
selector: '.kcdp-layout',
default: null
},
container: {
attribute: 'data-container',
selector: '.kcdp-layout',
default: false
}
},
edit({ attributes, setAttributes, className }) {
if (!attributes.align) setAttributes({ align: 'full' });
var classes = `kcdp-layout ${attributes.background} ${attributes.padding}`;
if (attributes.container) {
classes += ' container';
}
var style = {};
if (attributes.backgroundImage) {
style.backgroundImage = 'url(' + attributes.backgroundImage + ')';
}
if (attributes.height) {
style.height = attributes.height;
}
return (
<div className={className}>
<div className={classes} style={style}>
<InspectorControls>
<PanelBody title={ __( 'Background' ) }>
<SelectControl
label="Background"
value={ attributes.background }
options={ [
{ label: 'White', value: 'white-background' },
{ label: 'Dark Blue', value: 'dark-blue-background' },
{ label: 'Blue', value: 'blue-background' },
{ label: 'Gray', value: 'gray-background' },
{ label: 'Transparent', value: '' }
] }
onChange={ ( val ) => { setAttributes( { background: val } ) } }
/>
</PanelBody>
<PanelBody title={ __( 'Background Image' ) }>
<MediaUpload
onSelect={(media) => setAttributes({backgroundImage: media.url})}
type="image"
value={ attributes.imageID }
render={({ open }) => {
var removeImage = () => {
setAttributes({backgroundImage: null})
};
if (attributes.backgroundImage) {
return (
<button onClick={removeImage}>
Remove Image
</button>
);
}
else {
return (
<button onClick={open}>
Select Image
</button>
);
}
}}
/>
</PanelBody>
<PanelBody title={ __( 'Container' ) }>
<label>
Wrap in container?
<CheckboxControl
onChange={ isChecked => setAttributes({ container: isChecked }) }
checked={ attributes.container }
/>
</label>
</PanelBody>
<PanelBody title={ __( 'Padding' ) }>
<SelectControl
label="Padding"
value={ attributes.padding }
options={ [
{ label: 'None', value: '' },
{ label: 'Tiny', value: 'tiny-padding' },
{ label: 'Small', value: 'small-padding' },
{ label: 'Medium', value: 'medium-padding' },
{ label: 'Large', value: 'large-padding' }
] }
onChange={ ( val ) => { setAttributes( { padding: val } ) } }
/>
</PanelBody>
<PanelBody title={ __( 'Side Padding' ) }>
<SelectControl
label="Side Padding"
value={ attributes.sidePadding }
options={ [
{ label: 'None', value: 'no-side-padding' },
{ label: 'Small', value: 'small-side-padding' },
{ label: 'Medium', value: 'medium-side-padding' },
{ label: 'Large', value: 'large-side-padding' }
] }
onChange={ ( val ) => { setAttributes( { sidePadding: val } ) } }
/>
</PanelBody>
<PanelBody>
<label>Height
<PlainText
onChange={ content => setAttributes({ height: content }) }
value={ attributes.height }
placeholder="Height"
className=""
/>
</label>
<div className="instructions">
Be sure to specify pixels or percentage (ie, '100px' or '100%')
</div>
</PanelBody>
</InspectorControls>
<div className="edit">
<InnerBlocks />
</div>
</div>
</div>
);
},
save({ attributes, className }) {
var classes = [ 'kcdp-layout', className, attributes.background, attributes.padding, attributes.sidePadding ];
var style = {};
var containerClass = '';
if (attributes.container) {
containerClass = 'container';
}
if (attributes.backgroundImage) {
style.backgroundImage = 'url(' + attributes.backgroundImage + ')';
}
if (attributes.height) {
style.height = attributes.height;
}
return (
<div className={classes}
data-side-padding={attributes.sidePadding}
data-background={attributes.background}
data-padding={attributes.padding}
data-background-image={attributes.backgroundImage}
data-height={attributes.height}
data-container={attributes.container}
style={style}>
<div class={containerClass}>
<InnerBlocks.Content />
</div>
</div>
);
},
deprecated: [
{
attributes: {
background: {
attribute: 'data-background',
selector: '.kcdp-layout',
default: ''
},
padding: {
attribute: 'data-padding',
selector: '.kcdp-layout',
default: ''
},
sidePadding: {
attribute: 'data-side-padding',
selector: '.kcdp-layout',
default: 'no-side-padding'
},
backgroundImage: {
attribute: 'data-background-image',
selector: '.kcdp-layout',
default: null
},
height: {
attribute: 'data-height',
selector: '.kcdp-layout',
default: null
},
},
supports: ['full', 'center'],
migrate(attributes, innerBlocks) {
attributes.container = false;
return [
attributes
];
},
save({attributes, className}) {
var classes = [ 'kcdp-layout', className, attributes.background, attributes.padding, attributes.sidePadding ];
var style = {};
if (attributes.backgroundImage) {
style.backgroundImage = 'url(' + attributes.backgroundImage + ')';
}
if (attributes.height) {
style.height = attributes.height;
}
return (
<div className={classes}
data-side-padding={attributes.sidePadding}
data-background={attributes.background}
data-padding={attributes.padding}
data-background-image={attributes.backgroundImage}
data-height={attributes.height}
style={style}>
<InnerBlocks.Content />
</div>
);
}
},
]
});
Thank you for any help you can provide!
I actually got this solved. I found this thread which explained the error I was receiving was the correct behavior for the when you have a new block version and load the page with the old block version on it, and it will fix itself after you update the page. I did experience a problem earlier where updating the page was breaking all of these blocks, but that seems to have been cleared up by tinkering with it.
If anyone knows of a good article or thread that explains or gives examples of deprecation, especially the migrate function, I'd love to see it. Thanks!
Most helpful comment
I actually got this solved. I found this thread which explained the error I was receiving was the correct behavior for the when you have a new block version and load the page with the old block version on it, and it will fix itself after you update the page. I did experience a problem earlier where updating the page was breaking all of these blocks, but that seems to have been cleared up by tinkering with it.
If anyone knows of a good article or thread that explains or gives examples of deprecation, especially the migrate function, I'd love to see it. Thanks!