WordPress (Gutenberg) のブロック開発において、インナーブロックから親ブロックのパラメータ (attributes) を参照するには、一般的に親ブロックの block.json に providesContext
の値として対象のパラメータを列挙し、インナーブロックの block.json には usesContext
の値に対になるパラメータをまとめておくことで、親から子へのデータ提供が行われます。
逆に、親ブロックがインナーブロックの状態を監視して動的に UI を制御したり class を追加するなどの操作をしたい場合はどうすれば実現できるでしょうか?
今回は、useSelect
フックを活用して親ブロックからインナーブロックの attributes を監視し、その状態に基づいて親ブロックの表示や設定を動的に制御する方法について解説します。
インナーブロックの取得
useSelect
を利用し、まずは親ブロックの clientId
からインナーブロックを取得します。
const innerBlocksData = useSelect( ( select ) => {
const { getBlocks } = select( 'core/block-editor' );
const innerBlocks = getBlocks( clientId );
// ... 処理
}, [ clientId ] );
対象ブロックの絞り込み
次に、取得したインナーブロックからブロック名を指定して対象ブロックのみに絞り込みます。
const filteredBlocks = innerBlocks.filter(
block => block.name === 'my-plugin/inner-block-name'
);
my-plugin/inner-block-name
は対象とするインナーブロック名に置き換えます。
監視対象の属性の判定
取得した対象ブロックに判定したい属性値を条件として .some()
メソッドで判定を取得します。
return {
hasImage: filteredBlocks.some( item => item.attributes.showImage ),
hasDate: filteredBlocks.some( item => item.attributes.showDate ),
};
上記のようにして item.attributes
から判定したいインナーブロックの属性を必要なだけ指定します。
その他、.every()
メソッド で「すべてのブロックが条件を満たすか」を判定したり、.reduce()
メソッドでより複雑な集約処理をするなど、判定の扱いに応じて修正します。
一連をまとめたコード
ここまでのコードをまとめて、カスタムブロックの edit.js 内で利用します。
import { useSelect } from '@wordpress/data';
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
const Edit = ( props ) => {
...
// インナーブロックの attributes を取得
const innerBlocksData = useSelect( ( select ) => {
const { getBlocks } = select( 'core/block-editor' );
const innerBlocks = getBlocks( clientId );
if ( !innerBlocks ) {
return {
hasImage: false,
hasDate: false,
};
}
const filteredBlocks = innerBlocks.filter(
block => block.name === 'my-plugin/inner-block-name'
);
return {
hasImage: filteredBlocks.some( item => item.attributes.showImage ),
hasDate: filteredBlocks.some( item => item.attributes.showDate ),
};
}, [ clientId ] );
...
const blockProps = useBlockProps( {
className: innerBlocksData.hasImage && 'has-image',
} );
const innerBlocksProps = useInnerBlocksProps();
...
return (
<>
{ inspectorControls }
<div { ...blockProps }>
<div { ...innerBlocksProps }>
...
</div>
</div>
</>
)
}
export default Edit;
このような方法で、親ブロックがインナーブロックの状態を動的に監視し、それに基づいて親ブロック側で判定して UI やスタイルの制御することが可能になります。