【Gutenberg カスタムブロック】registerBlockTypeのattributes設定(WordPress)

【Gutenberg カスタムブロック】registerBlockTypeのattributes設定(WordPress)

カスタムブロックを作成するには”registerBlockType”を使ってブロックを登録するのですが、第二引数のオブジェクト内で設定するattributesオプション、少しややこしいですよね。
という訳でメモ書きです。

どのような場合にattributes設定が必要になるのか

まずはattributes設定はオプショナルなのですが、どのような場合に必要になるのでしょうか?

単に静的なデータを出力するだけの場合は不要なのですが、例えばリッチテキスト等の編集可能なブロックにする場合はブロック内のテキストデータを保持するためにattributesの定義が必要になります。

下記はリッチテキストを使用したシンプルなカスタムブロックの登録のコード例です。
(attributesの部分はひとまず、良くない例です。)

リッチテキストブロックの登録例 ※JavaScriptファイルです
const { RichText } = wp.editor;

registerBlockType('mytheme-blocks/richtexttest', {
    title: 'リッチテキストだよ',
    icon: 'heart', //Dashアイコンから好きなのを選んでね
    description: 'リッチテキストのサンプルだよー',
    category: 'common',
    attributes: { 
        content: {
            type: 'string',
        },
    },
    edit: ({attributes, setAttributes}) => {
        const { content } = attributes;
        const onChangeContent = content => {
            setAttributes({content});
        };
        return <RichText
            tagName = "p"
            onChange = {onChangeContent}            
            value = {content}
        />
    },
    save: ({attributes}) => {
        const {content} = attributes;
        return(
            <RichText.Content
                tagName="p"
                value={content}
            />
        )
    }
});

attributesの部分で”contentという名前の属性を扱います。属性値は文字列です”という宣言をしています。
ちなみに”content”の部分は好きな名前に変更OKです。

attributes{
  content: {
    type: 'string',
  },
},

attributesを宣言してあげると、editメソッド、saveメソッドからcontent属性にアクセスできるようになります。
(ソース上ではES6の分割代入を使ってAttributesを引数に取り、さらにAttributesからcontentを取り出しています。)
リッチテキスト内の文字が変更されたらonChangeContentメソッドでvalueに新しいテキストをセットするためにsetAttributesを実行しています。

このように編集可能なブロックの場合は、”attributes”を宣言して、属性値をeditメソッド内で変更や保存してあげるというのが流れになります。

attributesはどこに保存されているの?

編集画面で”ビジュアルエディタ”から”コードエディタ”に切り替えてみましょう。

何やらコメントアウトみたいなのがでてきますね。
最初と終わりのコメントがあって、その中に<p>タグが内包されています。
このコメントアウトの最初と終わりまでが1つのブロックになります。
公式サイトによるとコメント部分はコメントデリミタ(comment delimiter)と呼ぶらしいです。

最初のコメントの部分には、名前空間/ブロック名に続いてattributesがJSON形式で保存されています。

ちなみにデータベースにもこのまま、まるっと保存されています。

Gutenbergにおけるブロックデータの保存の流れ

ここからはattributesだけでは無く全体的な話になりますが…
下記はデータベースに保存されたコメントデリミタ付きのHTMLデータがどのように編集画面に反映されて、再度データベースに保存されるかまでの流れを表した図です。

まず、前述の通り、データベースにはコードエディタで表示されたコメントデリミタ付きのHTMLデータが保存されている訳ですが、まず、そこから Arrayオブジェクトに変換されます①。
この際に、HTMLタグ部分に加えて、コメントデリミタのJSONオブジェクトも配列の構成要素になります。

そこからeditメソッドを元にして編集画面のUIコンポネントやマークアップ部分がブロックとして構築されます。②

編集画面にて編集が終わるとPost Stateが書き換えられます(ReactのState、ReduxだとStoreみたいな感じ..)③
ちなみにこの部分はデータベース保存はされず特別なメモリ領域に保存されています。(どこかは詳しく聞かないで!)

それからSaveメソッドを元に再度HTMLの状態に変換され、「更新ボタン」を押すとデータベースに保存されます。④

こういった流れです。(間違っていたらすみません)

メモ

もし実際に図の①Parsingや②Serializeされたデータを見てみたい!という場合は編集画面でconsoleで下記メソッドを実行してみてください。

Parsing
wp.blocks.parse(wp.data.select(‘core/editor’).getEditedPostContent())

Serialize
wp.blocks.serialize(wp.data.select(‘core/editor’).getBlocks())

wpグローバル変数内には色々と便利なオブジェクトがたくさん詰まっていますよ。”core/editor”はReduxのStoreっぽいやつの1つと思われます…(知らんけど)。

コメントデリミタとHTMLタグ内の情報の重複を回避する

話をattributesに戻して…
もう1度コードエディタでブロック部分のソースを見てみましょう。

そう、コメント内の属性値と<p>要素内のテキストの内容が重複してしまっています。なんか無駄ですよね。

これを解決するためにattributesの宣言部分を見直します。

attributes: {
    content: {
        type: 'string',
        source: 'html', //追加
        selector: 'p' //追加
    },
},

すると、コメントデリミタのcontent属性部分が消えているのが確認できます。

※ブロックは新規に追加してください。なかなか修正が反映されない時はブラウザのキャッシュをクリアしてみてください。

何をしているのかと言うと、
content属性の値ををpタグのHTMLから取得する
という指示を加えています。

<p>リッチテキスト日和だな~</p>

↑ ↑ ↑
この部分から情報を参照するから、もうコメントのオブジェクト部分は不要です、とお知らせしているワケです。

別の例で、例えばimageという属性を作って、imgタグのsrc属性の値を文字列として属性値に設定したい場合には、下記のようにattributesの宣言をします。

attributes: {
    image: {
        type: 'string',
        source: 'attribute',
        selector: 'img',
        attributes: 'src'
    },
}

sourseが明示されていない場合は、属性値はコメントデリミタに保存される
sourseがあれば、その値部分から属性値を取得する

と言った感じです。

できるだけ情報の重複を避けるために、HTMLタグ内のテキストやタグのvalueから属性値が取得できそうな場合はsourseを設定してあげる&それが難しそうな場合(例えば画像ID等)はコメントデリミタに追加する、 というのがポイントかと思います。

あまり上手くまとまっていないかもしれませんが…以上になります。

この記事をシェア

Categories

Profile

兵庫県神戸市でWEB/DTPまわりのフリーランスをしています。
当ブログは主に業務で出会った諸々の備忘録です。

イラストスイッチ