属性と編集可能フィールド

これまでに作ったサンプルブロックはメッセージを変更できないため、あまり面白くありませんでした。このセクションでは RichText フィールドを実装して、ユーザーが好きなメッセージを指定できるようにします。実装の前に、まず重要な、ブロックの状態である「属性」がどのように管理され、どのように変更されるかを理解しましょう。

属性

これまで、edit 関数と save 関数はシンプルな paragraph 要素を返しました。これらの関数はまた、ブロックの表示の構造の 記述 に責任をもつことも学んできました。ユーザーがブロックを変更すれば、その構造も変更する必要があります。この動作を実現するには、編集セッションの間中はずっと、ブロックの状態をプレーンな JavaScript オブジェクトとして管理しておき、更新があると、edit 関数を再び呼び出す必要があります。別の言い方をすれば、ブロックの出力は、ブロックの属性の関数になります。

ブロックの表示を JavaScript オブジェクトとして管理する場合の課題は、投稿の保存されたコンテンツから再びこのオブジェクトを取り出さなければならない点です。この問題の解決にはブロックタイプの attributes プロパティを使用します。

    attributes: {
        content: {
            type: 'array',
            source: 'children',
            selector: 'p',
        },
    },

新しいブロックタイプを登録する際、attributes プロパティで edit 関数や save 関数で受け取る属性オブジェクトの形を記述します。それぞれの値はブロックのマークアップから希望の値を見つける source 関数 になります。

上のコード例ではエディターのロード中に、保存された投稿のマークアップの中の paragraph 要素の HTML から content 値が取り出されます。

コンポーネントと RichText コンポーネント

これまでのサンプルでは createElement 関数を使用して DOM ノードを作成しましたが、この動きを「コンポーネント」にカプセル化することができます。この抽象化により共通の動作を共有しやすくなり、複雑さを自己完結したユニット内に隠す事ができます。

ブロックの実装に利用できるコンポーネントが多数あります。以下のサンプルではそのうちの1つ RichText コンポーネントを使用します。RickTest コンポーネントは wp-editor パッケージの一部です。

RichText コンポーネントはパワーアップした textarea 要素と見なせます。ここでは太字、車体、ハイパーリンクなどのリッチコンテンツを編集できます。

ES5 コードを使用して RichText コンポーネントを使用する場合は、wp_register_script 呼び出しの際の登録スクリプトハンドルの依存性配列に wp-editorを追加してください。

// automatically load dependencies and version
$asset_file = include( plugin_dir_path( __FILE__ ) . 'build/index.asset.php');

wp_register_script(
    'gutenberg-examples-03-esnext',
    plugins_url( 'build/index.js', __FILE__ ),
    $asset_file['dependencies'],
    $asset_file['version']
);

忘れずに register_block_type の editor_script ハンドルを gutenberg-examples-03-esnext に更新してください。

振る舞いをコンポーネントとして実装することで、ブロック開発者は編集可能フィールドに対するきめ細かい制御が可能になります。ブロックでは RichTextが不要かもしれませんし、それぞれが状態全体の一部を操作する多くの独立した RichText 要素が必要かもしれません。

RickText はネストしたノードが許されるため、多くの場合、保存されたコンテンツから取り出す際に html 属性ソースと組み合わせて使用されます。また RichText.Content は save 関数の中で RickText の出力に使用されます。

Example 03 の完全なブロック定義を以下に示します。

ESNext

import { registerBlockType } from '@wordpress/blocks';
import { RichText } from '@wordpress/block-editor';

registerBlockType( 'gutenberg-examples/example-03-editable-esnext', {
    title: 'Example: Editable (esnext)',
    icon: 'universal-access-alt',
    category: 'design',
    attributes: {
        content: {
            type: 'array',
            source: 'children',
            selector: 'p',
        },
    },
    example: {
        attributes: {
            content: 'Hello World',
        },
    },
    edit: ( props ) => {
        const { attributes: { content }, setAttributes, className } = props;
        const onChangeContent = ( newContent ) => {
            setAttributes( { content: newContent } );
        };
        return (
            <RichText
                tagName="p"
                className={ className }
                onChange={ onChangeContent }
                value={ content }
            />
        );
    },
    save: ( props ) => {
        return <RichText.Content tagName="p" value={ props.attributes.content } />;
    },
} );

ES5

( function( blocks, editor, element ) {
    var el = element.createElement;
    var RichText = editor.RichText;◊

    blocks.registerBlockType( 'gutenberg-examples/example-03-editable', {
        title: 'Example: Editable',
        icon: 'universal-access-alt',
        category: 'design',

        attributes: {
            content: {
                type: 'array',
                source: 'children',
                selector: 'p',
            },
        },
        example: {
            attributes: {
                content: 'Hello World',
            },
        },
        edit: function( props ) {
            var content = props.attributes.content;
            function onChangeContent( newContent ) {
                props.setAttributes( { content: newContent } );
            }

            return el(
                RichText,
                {
                    tagName: 'p',
                    className: props.className,
                    onChange: onChangeContent,
                    value: content,
                }
            );
        },

        save: function( props ) {
            return el( RichText.Content, {
                tagName: 'p', value: props.attributes.content,
            } );
        },
    } );
}(
    window.wp.blocks,
    window.wp.editor,
    window.wp.element
) );

最終更新日: