WordPressのブロック開発メモ その3 編集

前回(WordPressのブロック開発メモ その2 TypeScript編)の続きです。

属性

これまでsave及びeditは単に固定されたメッセージを表示するだけの最低限のコードでした。
今度はeditでの編集を保存し、saveで表示出来るように改良します。

編集するデータを保存するには属性を使います。
例えばメッセージを編集するためにmessageという属性を使うことにします。

インターフェースKurageExampleBlockPropsmessageを追加しますが、
その前にこのインターフェースをindex.tsから分離しましょう。
saveedit両方から参照されるのでそのままだと気持ち悪いです。

これまで以下の用になってたindex.tsからKurageExampleBlockPropsを分離します。

interface KurageExampleBlockProps
{

}

const blockConf: BlockConfiguration<KurageExampleBlockProps> =
{
    attributes: {},
    title: metadata.title,
    category: metadata.category,
    edit: Edit,
    save,
};

まずはインターフェース側。
適当にprops.tsとでも名付けてファイルを分けます。
string型のmessageプロパティを追加します。

interface KurageExampleBlockProps
{
    message: string;
}

元のindex.ts側です。

// propsを読み込む
import KurageExampleBlockProps from './props';

const blockConf: BlockConfiguration<KurageExampleBlockProps> =
{
    attributes: {
        message: {
            type: 'string'
        }
    },
    title: metadata.title,
    category: metadata.category,
    edit: Edit,
    save,
};

属性にmessageを追加します。
追加するにはattributesプロパティのオブジェクトにmessageを追加します。
さらにmessageが何の型なのかをtypeを設定します。
今回は文字列型のstringを指定。他にもarray, boolean, number, integer, object, nullなどのtypeがあります。

edit.tsxも変更。

面倒なのでロケール類は外します。

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

import './editor.scss';
import React from 'react';
import { BlockEditProps } from '@wordpress/blocks';
import KurageExampleBlockProps from './props';

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const { message } = props.attributes;
    const { setAttributes } = props;

    return (
        <p {...useBlockProps()}>

            <p>{ message }</p>

            <input
                type="text"
                value={message}
                onChange={ e => setAttributes({ message: e.target.value }) }
                />
        </p>
    );
}

コンポーネントのpropsに型を定義します。

export default (props: BlockEditProps)

attributesで設定したmessageは、props.attributes.messageで取得出来ます。
さらにprops.setAttributesを使い、属性の値を変更することも出来ます。
ようやくReact使ってるっぽくなってきました。

edit.saveの方も変更します。

import { useBlockProps } from '@wordpress/block-editor';
import { BlockSaveProps } from '@wordpress/blocks';
import React from 'react';
import KurageExampleBlockProps from './props';

export default (props: BlockSaveProps<KurageExampleBlockProps>) =>
{
    return (
        <p { ...useBlockProps.save() }>
            { props.attributes.message }
        </p>
    );
}

propsの型を定義します(editのpropsの時とは型が違うので注意)

export default (props: BlockSaveProps) 

実際に実行結果を見ていきます。

editのページ(入力出来ます)

saveのページ(プレビューしてみます)

そして保存した時のDBの結果

コメントに隠れて

wp:ブロック名 属性のリテラルオブジェクト

こんな形で保存されていることが分かります。

編集を保存した時にHTML化されてDBに入ってるようですね。
ページ表示毎にsaveコンポーネントがレンダリングされているわけではないようです。

属性の保存先

何も指定しない場合コメントに含まれてました。
sourceを指定すると保存先を変更出来ます。

ソースがattributeの時

const blockConf: BlockConfiguration<KurageExampleBlockProps> =
{
    attributes: {
        message: {
            type: 'string',
            source: 'attribute',
            selector: 'p',
            attribute: 'data-atr'
        }
    },
    title: metadata.title,
    category: metadata.category,
    edit: Edit,
    save,
};

sourceattributeを選びます。
selectorはそのままセレクタのことで今回はpとしています。
attributeはPタグの属性名を指定します。
Reactで実在しない属性は怒られるのでdata-を使うことにします。属性名にdata-atrを指定しました。

これで

することになります。

そしてsave.tsxのほうもそれに合わせます。

export default (props: BlockSaveProps<KurageExampleBlockProps>) =>
{
    return (
        <p { ...useBlockProps.save() } data-atr={ props.attributes.message }>
            { props.attributes.message }
        </p>
    );
}

data-atrを追加します。

これでPタグのdata-atr属性にデータを保存することになります。

DBを見ると

確認出来ます。

sourcetextの場合

const blockConf: BlockConfiguration<KurageExampleBlockProps> =
{
    attributes: {
        message: {
            type: 'string',
            source: 'text'
        }
    },
    title: metadata.title,
    category: metadata.category,
    edit: Edit,
    save,
};
export default (props: BlockSaveProps<KurageExampleBlockProps>) =>
{
    return (
        <p { ...useBlockProps.save() }>
            { props.attributes.message }
        </p>
    );
}

単にテキストに保存します。

ここに保存される

他にも属性にhtmlがありますがこれはまた後日紹介します。

サポートのalignのデータはどこに?

一旦話を戻して、前回のalignのサポートを思い出してください。

const blockConf: BlockConfiguration<KurageExampleBlockProps> =
{
    attributes: {
        message: {
            type: 'string'
        }
    },
    supports: {
        align: true,
        alignWide: true,
    },
    example: {},
    title: metadata.title,
    category: metadata.category,
    edit: Edit,
    save,
};

align属性が追加されていることが分かります。

useState()が使えるけど

useState()も使えます。
そのままだとインテリセンスが使えないのと、どうせなら次の型定義を追加します。

npm install --save-dev @types/wordpress__element

ただuseState()のデータは保存してないので更新する毎にリセットされます。

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

import './editor.scss';
import React from 'react';
import { BlockEditProps } from '@wordpress/blocks';

import { useState } from "@wordpress/element";

import KurageExampleBlockProps from './props';

export default (props: BlockEditProps<KurageExampleBlockProps>) =>
{
    const { message } = props.attributes;
    const { setAttributes } = props;

    const [ firstName, setFirstName ] = useState('');
    const [ lastName, setLastName ] = useState('');

    const updateMessage = () =>
    {
        setAttributes({
            message: `Hello ${firstName} ${lastName} !`
        });
    };

    return (
        <p {...useBlockProps()}>

            <p>{ message }</p>

            <input
                type="text"
                value={message}
                onChange={ e => setAttributes({ message: e.target.value }) }
                />

            <fieldset>
                <input
                    type="text"
                    value={firstName}
                    onChange={ e => setFirstName(e.target.value) }
                    />

                <input
                    type="text"
                    value={lastName}
                    onChange={ e => setLastName(e.target.value) }
                    />

                <button onClick={ e => updateMessage() }>補助入力</button>

            </fieldset>

        </p>
    );
}

補助としては使えるものの、

ページを更新すると、リセットされます。

保存してないので当然なのですが、例えばuseEffect(..., [lastName, firstName])setAttributes()を更新しようとすると、ブロックが更新されるたびにリセットされた状態で更新されてしまいます。

今のところ補助用として使ってます。

今回はReact標準のコンポーネントを使いました。
次回からはWordPress(Gutenberg)コアが提供しているコンポーネントを使っていきます。

WordPressのブロック開発メモ その4 コンポーネント

certificate Docker Gutenberg Hyper-V openssl PHP React ReduxToolkit REST ubuntu WordPress オレオレ認証局 フレームワーク