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

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

属性

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

JavaScript オブジェクトとしてブロックの外観を管理する場合の1つの挑戦は、投稿の保存されたコンテンツから再びこのオブジェクトを取り出す必要がある点です。

    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: 'layout',
    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: 'layout',

        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
) );

最終更新日: