ダイナミックブロックの作成

ダイナミックブロックはフロントエンドでレンダーされる際に動的に構造とコンテンツを構築するブロックです。

ダイナミックブロックの代表的な使用例が2つあります。

  1. 投稿が更新されていなくてもコンテンツを変更するブロック。WordPress から例を挙げると「最近の更新」ブロックがあります。このブロックは新しい投稿が発行されるとすべての使用箇所を更新します。
  2. HTML、CSS、JS などのコードを更新するとすぐにWeb サイトのフロントエンド側で反映されるブロック。たとえば新しいクラスを追加したり、HTML 要素を追加したり、その他の方法でレイアウトを変更してブロックの構造を更新した場合、ダイナミックブロックを使えばサイト内のすべてのブロックの使用箇所に即座に変更を適用できます。ダイナミックブロックを使わない場合、ブロックコードが更新されると Gutenberg の妥当性検証プロセスが適用され、ユーザーに検証メッセージ「ブロックの外観は外部で更新されました」が表示されます。

多くのダイナミックブロックでは save コールバック関数は null として返されるべきです。これを受けてエディターはデータベースにブロックの属性のみを保存します。その後、これらの属性はサーバー側レンダリングコールバックに渡されるため、サイトのフロントエンドでどのようにブロックを表示するか決定できます。null を返すとエディターはブロックのマークアップの妥当性検査プロセスをスキップするため、頻繁にマークアップを変更する際の問題を回避できます。

ダイナミックブロック内で InnerBlocks を使用している場合には、<InnerBlocks.Content/> を使用して save コールバック関数内で InnerBlocks を保存する必要があります。

ブロックの HTML 表現も保存できます。サーバー側レンダリングコールバックを提供すると、この HTML はコールバックの出力で置換されますが、ブロックが無効化されたり、レンダリングコールバックが削除される場合には、レンダーされます。

ブロックの属性は、ブロックのために保存したい任意のコンテツや設定に対して使用できます。最初の最新の投稿ブロックの例では、フロントエンドに表示したい最新の投稿数を属性として保存できます。2番目の例では、フロントエンドで表示したい各コンテンツの部品、たとえば見出しテキスト、段落テキスト、画像、URLとして属性を使用できます。

次のコード例では最後の投稿だけをリンクとして表示するダイナミックブロックを作成します。

ESNext

import { registerBlockType } from '@wordpress/blocks';
import { withSelect } from '@wordpress/data';
import { useBlockProps } from '@wordpress/block-editor';

registerBlockType( 'gutenberg-examples/example-dynamic', {
    apiVersion: 2,
    title: 'Example: last post',
    icon: 'megaphone',
    category: 'widgets',

    edit: withSelect( ( select ) => {
        return {
            posts: select( 'core' ).getEntityRecords( 'postType', 'post' ),
        };
    } )( ( { posts } ) => {
        const blockProps = useBlockProps();

        return (
            <div { ...blockProps }>
                { ! posts && 'Loading' }
                { posts && posts.length === 0 && 'No Posts' }
                { posts && posts.length > 0 && (
                    <a href={ posts[ 0 ].link }>
                        { posts[ 0 ].title.rendered }
                    </a>
                ) } 
            </div>
        )
        
    } ),
} );

ES5

( function( blocks, element, data, blockEditor ) {
    var el = element.createElement,
        registerBlockType = blocks.registerBlockType,
        withSelect = data.withSelect,
        useBlockProps = blockEditor.useBlockProps;

    registerBlockType( 'gutenberg-examples/example-dynamic', {
        apiVersion: 2,
        title: 'Example: last post',
        icon: 'megaphone',
        category: 'widgets',
        edit: withSelect( function( select ) {
            return {
                posts: select( 'core' ).getEntityRecords( 'postType', 'post' ),
            };
        } )( function( props ) {
            var blockProps = useBlockProps();
            var content;
            if ( ! props.posts ) {
                content = 'Loading...';
            } else if ( props.posts.length === 0 ) {
                content = 'No posts';
            } else {
                var post = props.posts[ 0 ];
                content = el(
                    'a',
                    { href: post.link },
                    post.title.rendered
                );
            }

            return el( 
                'div',
                blockProps,
                content
            );
        } ),
    } );
}(
    window.wp.blocks,
    window.wp.element,
    window.wp.data,
    window.wp.blockEditor,
) );

これはダイナミックブロックですのでクライアントのデフォルトの save 実装をオーバーライドする必要はありません。代わりにサーバーコンポーネントが必要です。サイトのフロントエンドのコンテツは register_block_type の render_callback プロパティに呼び出される関数に依存します。

<?php

/**
 * Plugin Name: Gutenberg examples dynamic
 */

function gutenberg_examples_dynamic_render_callback( $block_attributes, $content ) {
    $recent_posts = wp_get_recent_posts( array(
        'numberposts' => 1,
        'post_status' => 'publish',
    ) );
    if ( count( $recent_posts ) === 0 ) {
        return 'No posts';
    }
    $post = $recent_posts[ 0 ];
    $post_id = $post['ID'];
    return sprintf(
        '<a class="wp-block-my-plugin-latest-post" href="%1$s">%2$s</a>',
        esc_url( get_permalink( $post_id ) ),
        esc_html( get_the_title( $post_id ) )
    );
}

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

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

    register_block_type( 'gutenberg-examples/example-dynamic', array(
        'apiVersion' => 2,
        'editor_script' => 'gutenberg-examples-dynamic',
        'render_callback' => 'gutenberg_examples_dynamic_render_callback'
    ) );

}
add_action( 'init', 'gutenberg_examples_dynamic' );

いくつか注意点があります。

  • 依然として edit 関数はエディターのコンテキストにおけるブロックの外観を表示します (レンダーバージョンとまったく異なる場合もあります。これはブロック作者の好みによります)
  • 組み込みの save 関数は null を返すだけです。これはレンダリングがサーバー側で実行されるためです。
  • サーバー側レンダリングは、ブロックとブロックの内部コンテンツを引数に取る関数で、ショートコードに似たマークアップを返します。

ブロックエディター内でのライブレンダリング

Gutenberg 2.8 は <ServerSideRender> ブロックを追加しました。JavaScript の代わりに PHP を使用してサーバー上でレンダリングを実行します。

サーバー側レンダーはフォールバックです。常に JavaScript によるクライアントサイドレンダリングが好まれます。クライアントレンダリングは速く、エディターの操作性が高くなります).

ESNext

import { registerBlockType } from '@wordpress/blocks';
import ServerSideRender from '@wordpress/server-side-render';
import { useBlockProps } from '@wordpress/block-editor';

registerBlockType( 'gutenberg-examples/example-dynamic', {
    apiVersion: 2,
    title: 'Example: last post',
    icon: 'megaphone',
    category: 'widgets',

    edit: function( props ) {
        const blockProps = useBlockProps();
        return (
            <div {...blockProps}>
                <ServerSideRender
                    block="gutenberg-examples/example-dynamic"
                    attributes={ props.attributes }
                />
            </div>
        );
    },
} );

ES5

( function( blocks, element, serverSideRender, blockEditor ) {
    var el = element.createElement,
        registerBlockType = blocks.registerBlockType,
        ServerSideRender = serverSideRender,
        useBlockProps = blockEditor.useBlockProps;

    registerBlockType( 'gutenberg-examples/example-dynamic', {
        apiVersion: 2,
        title: 'Example: last post',
        icon: 'megaphone',
        category: 'widgets',

        edit: function( props ) {
            var blockProps = useBlockProps();
            return (
                el(
                    'div',
                    blockProps,
                    el( ServerSideRender, {
                        block: 'gutenberg-examples/example-dynamic',
                        attributes: props.attributes,
                    } )
                )
            );
        },
    } );
}(
    window.wp.blocks,
    window.wp.element,
    window.wp.serverSideRender,
    window.wp.blockEditor,
) );

注意: このコードは wp-server-side-render パッケージを使用し、wp-data を使用しません。PHP コード内の依存性を更新してください。自動で依存性を設定するには wp-scripts と ESNext 設定を使用してください (PHP コード設定については gutenberg-examples リポジトリーを参照してください)。

原文

最終更新日: