Why is my Gutenberg block returning an error after initial save?
-
22-04-2021 - |
質問
I created a Gutenberg block but after saving it and going back into the post I receive this error:
This block contains unexpected or invalid content
I couldn't find any inconsistencies and I had a friend also take a look over to see if there was anything amiss. What am I doing wrong?
registerBlockType('myblog/check-list', {
//Built-in Attributes
title: 'Check List',
description: 'Generate a bulleted list with green checkmarks',
icon: 'list-view',
category: 'design',
//Custom Attributes
attributes: {
title: {
type: 'string',
source: 'html',
selector: 'h2'
},
text: {
type: 'string',
source: 'html',
selector: 'p'
},
titleColor: {
type: 'string',
default: '#383838'
},
checkListItemOne: {
type: 'string',
source: 'html',
selector: 'span'
},
checkListItemTwo: {
type: 'string',
source: 'html',
selector: 'span'
}
},
//Built-in Functions
edit({attributes, setAttributes}) {
const{
title,
text,
titleColor,
checkListItemOne,
checkListItemTwo,
} = attributes;
//Custom Functions
function onChangeTitle(newTitle) {
setAttributes( { title: newTitle } );
}
function onChangeText(newText) {
setAttributes( { text: newText } );
}
function onTitleColorChange(newColor){
setAttributes( { titleColor: newColor } );
}
function onChangeCheckListItemOne(newListItemOne) {
setAttributes( { checkListItemOne: newListItemOne})
}
function onChangeCheckListItemTwo(newListItemTwo) {
setAttributes( { checkListItemTwo: newListItemTwo})
}
return ([
<InspectorControls style={ { marginBottom: '40px' } }>
<PanelBody title={ 'Headline Color' }>
<p><strong>Choose Title Color</strong></p>
<ColorPalette
value={titleColor}
onChange={onTitleColorChange}
/>
</PanelBody>
</InspectorControls>,
<div class="col-md-5 offset-md-1">
<div class="green-check-list-container">
<RichText
key="editable"
tagName="h2"
placeholder="Headline for check list"
value= { title }
onChange= { onChangeTitle }
style= { { color: titleColor } }
/>
<RichText
key="editable"
tagName="p"
placeholder="Additional context for the list"
value= { text }
onChange= { onChangeText }
/>
<ul class="green-check-list-items">
<li>
<RichText
key="editable"
tagName="span"
placeholder="List Item"
value= { checkListItemOne }
onChange= { onChangeCheckListItemOne }
/>
</li>
<li>
<RichText
key="editable"
tagName="span"
placeholder="List Item"
value= { checkListItemTwo }
onChange= { onChangeCheckListItemTwo }
/>
</li>
</ul>
</div>
</div>
]);
},
save({ attributes }) {
const {
title,
text,
titleColor,
checkListItemOne,
checkListItemTwo,
} = attributes;
return (
<div class="col-md-5 offset-md-1">
<div class="green-check-list-container">
<h2 style={ { color: titleColor } }>{title}</h2>
<p>{ text }</p>
<ul class="green-check-list-items">
<li>
<span>{ checkListItemOne }</span>
</li>
<li>
<span>{ checkListItemTwo }</span>
</li>
</ul>
</div>
</div>
);
}
});
解決
The main issue in your code is with these two attributes which use the exact same selector (the first span
element in your block content):
checkListItemOne: {
type: 'string',
source: 'html',
selector: 'span' // same as below
},
checkListItemTwo: {
type: 'string',
source: 'html',
selector: 'span' // same as above
}
Which means the block editor will always use the content of the first span
element in the saved block content, which then results in a "block validation failed" error like so:
Therefore, make sure that you set the proper selector
value for your block attributes. Here's an example using the CSS selectors element > element
and :nth-child(n)
:
checkListItemOne: {
type: 'string',
source: 'html',
selector: 'li:nth-child(1) > span'
},
checkListItemTwo: {
type: 'string',
source: 'html',
selector: 'li:nth-child(2) > span'
}
Additional Issues/Notes
The block editor handbook says:
HTML Formatting Tags Display in the Content
If the HTML tags from text formatting such as
<strong>
or<em>
are being escaped and displayed on the frontend of the site, this is likely due to an issue in your save function. Make sure your code looks something like<RichText.Content tagName="h2" value={ heading } />
(ESNext) within your save function instead of simply outputting the value with<h2>{ heading }</h2>
.So for example in your case, you'd use this instead of
<span>{ checkListItemOne }</span>
:<RichText.Content tagName="span" value={ checkListItemOne } />
If you look at the above screenshot, the block's outmost wrapper has two
class
attributes, which results in the "Expected attributeclass
of value `..." notice:<div class="col-md-5 offset-md-1" class="wp-block-myblog-check-list">
To fix that, use the
className
attribute and notclass
in your<div>
:And although
class
does work (despite being a reserved keyword in JavaScript), the (current) React documentation actually says, "To specify a CSS class, use theclassName
attribute.", so you should use that attribute in all your<div>
and other elements having a CSS class.return ( <div className="col-md-5 offset-md-1"> <div className="green-check-list-container"> ... your code. </div> </div> );
WordPress 5.6.0 uses block editor API version 2 which introduced a new hook named
useBlockProps
, so I suggest you to use it in your block'sedit
andsave
callbacks. :)Example in your
save
callback:const blockProps = useBlockProps.save( { className: 'col-md-5 offset-md-1' } ); return ( <div { ...blockProps }> <div className="green-check-list-container"> ... your code. </div> </div> );
他のヒント
You can check the WordPress Core file source and try to understand why this error appears, just search for the error message here:
https://raw.githubusercontent.com/WordPress/WordPress/master/wp-includes/js/dist/block-editor.js
From my point of view, there is might be a problem with using custom HTML elements. Try to replace all custom HTML with casual <div>
and see what will happen. If that error is gone, then the source is these elements.