WordPress (Gutenberg)のカスタムブロックを作成していると、エディターを更新した際に「このブロックには、想定されていないか無効なコンテンツが含まれています。」というメッセージが表示されて、毎回ブロックのリカバリーを試行しなければブロックが表示されなくなる場合がありました。
同時に、ブラウザのコンソールには以下の警告とエラーが出力されています。
Block validation: Expected attributes …
Block validation: Block validation failed for `ブロック名` …
原因
このエラーが発生する原因は、Gutenberg にて編集時 (edit.js) と保存時 (save.js) の間でブロックの属性が一貫しているかを検証する処理において失敗すると発生します。
つまり、edit.js で変更された属性が save.js でも正確に反映されている必要があります。
しかし、 例えば save.js が空の状態でもこのエラーは発生しません。
従って、edit.js と save.js で return
されるコンポーネントが一致している必要はありません。
エラーが発生するパターン
このエラーが発生するケースはいくつかありますが、例えば save.js を以下のようにしている場合に発生します。
const save = props => {
const blockProps = useBlockProps.save();
const serializedData = JSON.stringify({
props.dataA,
props.dataB,
});
return (
<div { ...blockProps } data-custom-data={ serializedData }>
// Other codes
</div>
);
}
この save.js では、JSON.stringify
を使用して props
から取り出したデータをシリアライズして親要素の dataset
にセットしています。
save.js で動的にシリアライズを行うと、保存時と検証時で生成されるシリアライズ結果に微妙な違いが生じる可能性があり、この違いによってブロックの検証エラーが発生します。
特に、シリアライズの順序やフォーマットの違いが原因でブロックの検証が失敗することがあります。
例えば、JSON.stringify
はプロパティの順序やスペースを保持しないため、微妙な違いが生じることがあるようです。
つまり、edit.js で setAttributes
で保存したデータをそのまま save.js で利用するのではなく、save.js 側で何か処理を施したデータを return
に含めてしまうと、その処理の仕様(一貫性の有無)によっては、ブロック保存時とエディターを更新した際のブロック検証時(動的処理の再実行)での生成コンテンツに違いが発生するため、このエラーが発生します。
解決策
このエラーを解決するには、save.js で return
に含めるデータを動的に処理するのではなく、edit.js 側で動的処理を行った結果を静的データとして setAttributes
で保存し、保存済みのデータを save.js で直接利用することで解決できます。
先述のエラーが発生するケースであれば、edit.js で JSON.stringify
によってシリアライズされたデータを setAttributes で保存し、save.js ではシリアライズ済みの静的データをそのまま利用することでデータの一貫性が保たれるため、検証エラーが発生しなくなります。