DigiPress

Highly Flexible WordPress Theme

[WP]親ブロックからインナーブロックの attributes を参照する方法

カスタマイズ・技術情報

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 内で利用します。

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 やスタイルの制御することが可能になります。

Share / Subscribe
Facebook Likes
Posts
Hatena Bookmarks
Pinterest
Pocket
Feedly
Send to LINE