無駄と文化

実用的ブログ

インナーブロックの情報を親ブロックから取得する (WordPress, カスタムブロック)

Gutenberg のカスタムブロックでインナーブロックを配置できるようにしたとき、親ブロックからインナーブロックの情報を取得する方法をまとめます。

 

以下、 @wordpress/create-block を使ってひな形を作成したときのファイル構成を前提に解説します。

インナーブロックを配置できるようにしたときの最小構成

まず、普通に最小構成でブロックを構築するとこんな感じになります。

src/edit.js

import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';

export function Edit() {
    const blockProps = useBlockProps();
    const innerBlocksProps = useInnerBlocksProps( blockProps, {} );

    return (
        <div { ...innerBlocksProps  } />
    );
}

やりたいこと

useInnerBlocksProps を利用すると、簡単お手軽にインナーブロックを配置できるブロックが作れます。
save() 関数側でも <InnerBlocks.Content /> と書くだけでインナーブロックの管理はお任せできます。

しかし、 "お任せできる" というのは言い換えると "ブラックボックスになっていて外から中の状態を知り得ない" ということです。それでは困る場面もあるでしょう。
というわけで親ブロックからインナーブロックの情報を取得してみましょう。

useSelect を使ってインナーブロックの情報を取得する

インナーブロックの情報を取得するために useSelect を使います。

src/edit.js

import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';

export function Edit({ clientId }) {
    const innerBlocks = useSelect( select => select( 'core/block-editor' ).getBlocks( clientId ) );
    console.log( { innerBlocks  } );

    const blockProps = useBlockProps();
    const innerBlocksProps = useInnerBlocksProps(blockProps, {});

    return (
        <div { ...innerBlocksProps  } />
    );
}

useSelect を使って useSelect( select => select( 'core/block-editor' ).getBlocks( clientId ) ) のように書くとインナーブロックの情報を取得できます。
getBlocks() メソッドには引数として clientId を渡す必要があります。 Edit() のオブジェクト引数から取得できる clientId をそのまま渡せば大丈夫です。

取得した innerBlocks を実際に見てみると、以下のようなデータになっています。

[
    {
        "clientId": "0c8bc6d7-4b66-46e7-a1aa-5f7284498655",
        "name": "core/heading",
        "isValid": true,
        "attributes": {
            "content": "Foo Bar",
            "level": 1
        },
        "innerBlocks": []
    },
    {
        "clientId": "7e1d6dd0-4152-41a6-98ca-205db0b29a9e",
        "name": "core/paragraph",
        "isValid": true,
        "attributes": {
            "content": "Hoge Fuga",
            "dropCap": false
        },
        "innerBlocks": []
    }
]

attributes プロパティを参照することでインナーブロックのコンテンツに設定されているテキストなどが直接手に入ります。
その他 innerBlocks プロパティを参照すると、「インナーブロックの中のインナーブロック」まで辿っていくこともできます。

withSelect を使ってインナーブロックの情報を取得する

useSelect の代わりに withSelect を使ってもインナーブロックの情報を取得できます。
useSelect を使ったときと理屈は同じです。

src/edit.js

import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
import { withSelect } from '@wordpress/data';

export const Edit = withSelect( ( select, { clientId } ) => ({
    innerBlocks: select( 'core/block-editor' ).getBlocks( clientId ),
}))(edit);

function edit({ innerBlocks }) {
  console.log( { innerBlocks  } );

  const blockProps = useBlockProps();
  const innerBlocksProps = useInnerBlocksProps(blockProps, {});

  return (
      <div { ...innerBlocksProps  } />
  );
}

withSelect() の返り値で edit() 関数をデコレートしてあげることで、 edit() 関数のオブジェクト引数に { innerBlocks: [ ... ] } という形でインナーブロックの情報が引き渡されます。

まとめ

@wordpress/data の API 、挙動がマジカルすぎて理解が難しい。

 

私からは以上です。

参考

github.com