バリエーションを持つブロックの拡張

独自のブロックバリエーションを特定のクエリループブロック設定で登録することにより、クエリループブロックが提供する完全な機能を利用しながら、どのように表示されるかをより細かく制御できます。ブロックバリエーションに不慣れな場合は、こちらで詳細を学んでください。

ブロックバリエーションAPIを使用すると、ユースケースに最も適したデフォルト設定を提供できます。

クエリループバリエーションを正しく機能させるためには、次のことを行う必要があります:

– デフォルト値を持つcore/queryブロックのブロックバリエーションを登録する

– ブロックバリエーションのレイアウトを定義する

namespace属性をisActiveブロックバリエーションプロパティで使用する

例えば、book カスタム投稿タイプを登録するプラグインのバリエーションを設定する旅に出ましょう。

1. 理にかなったデフォルトを提供する

最初のステップは、デフォルトでブログ投稿の代わりに本のリストを表示するように設定されたバリエーションを作成することです。完全なバリエーションコードは次のようになります:

  1. const MY_VARIATION_NAME = 'my-plugin/books-list';
  2. registerBlockVariation( 'core/query', {
  3. name: MY_VARIATION_NAME,
  4. title: 'Books List',
  5. description: 'Displays a list of books',
  6. isActive: ( { namespace, query } ) => {
  7. return (
  8. namespace === MY_VARIATION_NAME
  9. && query.postType === 'book'
  10. );
  11. },
  12. icon: /** An SVG icon can go here*/,
  13. attributes: {
  14. namespace: MY_VARIATION_NAME,
  15. query: {
  16. perPage: 6,
  17. pages: 0,
  18. offset: 0,
  19. postType: 'book',
  20. order: 'desc',
  21. orderBy: 'date',
  22. author: '',
  23. search: '',
  24. exclude: [],
  25. sticky: '',
  26. inherit: false,
  27. },
  28. },
  29. scope: [ 'inserter' ],
  30. }
  31. );

これが多く聞こえる場合でも、心配しないでください。ここにある各プロパティを見て、それらがなぜ存在するのか、何をしているのかを確認しましょう。

基本的に、次のようなものから始めます:

  1. registerBlockVariation( 'core/query', {
  2. name: 'my-plugin/books-list',
  3. attributes: {
  4. query: {
  5. /** ...more query settings if needed */
  6. postType: 'book',
  7. },
  8. },
  9. } );

このようにすることで、ユーザーはドロップダウンからカスタムpostTypeを選択する必要がなく、正しい設定がすでに表示されます。しかし、ユーザーはこのバリエーションをどのように見つけて挿入するのでしょうか?良い質問です!これを有効にするには、次のことを追加する必要があります:

  1. {
  2. /** ...variation properties */
  3. scope: [ 'inserter' ],
  4. }

このようにして、ユーザーがエディターで検索している間、あなたのブロックは他のブロックと同様に表示されます。この時点で、カスタムアイコン、タイトル、説明をバリエーションに追加したいかもしれません。次のように:

  1. {
  2. /** ...variation properties */
  3. title: 'Books List',
  4. description: 'Displays a list of books',
  5. icon: /* Your svg icon here */,
  6. }

この時点で、あなたのカスタムバリエーションは実質的にスタンドアロンブロックと区別がつかなくなります。完全にプラグインにブランド化され、発見しやすく、ユーザーに直接利用可能な形で提供されます。

しかし、クエリループバリエーションはまだ機能しません — 正しくレンダリングできるようにレイアウトを定義する必要があります。

2. バリエーションレイアウトをカスタマイズする

クエリループブロックは、'block'scopeプロパティの文字列としてサポートしていることに注意してください。理論的には、これはブロック自体を挿入した後にバリエーションを取得できるようにするためです。ブロックバリエーションピッカーについての詳細はこちらでお読みください。

しかし、現在これを使用することは推奨されません。これは、パターンとscope: [ 'block' ]バリエーションを持つクエリループの設定によるもので、選択されたパターンの属性はpostTypeinheritクエリプロパティを除いてすべて使用されるため、競合や機能しないバリエーションを引き起こす可能性があります。

これを回避するために、2つのルートがあります。最初のルートは、デフォルトのinnerBlocksを追加することです。次のように:

  1. innerBlocks: [
  2. [
  3. 'core/post-template',
  4. {},
  5. [ [ 'core/post-title' ], [ 'core/post-excerpt' ] ],
  6. ],
  7. [ 'core/query-pagination' ],
  8. [ 'core/query-no-results' ],
  9. ],
  1. もう一つの方法は、バリエーションに特有のパターンを登録し、それらがセットアップで提案され、ブロックのフローを置き換えることです。
  2. クエリループブロックは、自身のアクティブなバリエーションがあるかどうか、またこのバリエーションに特定のパターンが利用可能かどうかを判断します。もしあれば、これらのパターンはユーザーに提案される唯一のものであり、元のクエリループブロックのデフォルトのものは含まれません。そうでなければ、そのようなパターンがない場合、デフォルトのものが提案されます。
  3. パターンがクエリループバリエーションと「接続」されるためには、パターンの`````blockTypes`````プロパティにクエリループ名で接頭辞を付けたバリエーションの名前(例:`````core/query/$variation_name`````)を追加する必要があります。パターンの登録に関する詳細は[こちらを参照](/read/wordpress/799313da32f74279.md)してください。
  4. バリエーションに`````innerBlocks`````を提供していない場合、ユーザーがセットアップフェーズで`````Start blank`````を選択したときに「接続された」バリエーションを提案する方法もあります。これは、「接続された」パターンと同様の方法で処理され、クエリループのアクティブなバリエーションがあるかどうか、提案する接続されたバリエーションがあるかどうかを確認します。
  5. バリエーションが別のクエリループバリエーションに接続されるためには、`````scope`````属性を`````['block']`````の値で定義し、`````namespace`````属性を配列として定義する必要があります。この配列には、接続したいバリエーションの名前(`````name`````プロパティ)を含める必要があります。
  6. 例えば、`````scope: ['inserter']`````に公開されたクエリループバリエーションが`````products`````という名前を持っている場合、`````block`````バリエーションを接続するには、`````namespace`````属性を`````['products']`````に設定します。ユーザーが`````Start blank`````をクリックした後にこのバリエーションを選択すると、名前空間属性はメインの挿入バリエーションによって上書きされます。
  7. <a name="3-making-gutenberg-recognize-your-variation"></a>
  8. ### 3. Gutenbergにバリエーションを認識させる
  9. このバリエーションを実装した後に気づくかもしれない小さな問題があります:ユーザーが挿入しているときには透明ですが、Gutenbergは依然としてこのバリエーションをクエリループブロックとして認識します。そのため、挿入後にはエディターのツリービューにクエリループブロックとして表示されます。
  10. このブロックが実際にあなたの特定のバリエーションであることをエディターに伝える方法が必要です。これが`````isActive`````プロパティの目的です:これは、ブロックの属性に基づいて特定のバリエーションがアクティブかどうかを判断する方法です。次のように使用できます:
  11. ``````bash
  12. {
  13. /** ...variation properties */
  14. isActive: ( { namespace, query } ) => {
  15. return (
  16. namespace === MY_VARIATION_NAME
  17. && query.postType === 'book'
  18. );
  19. },
  20. }
  21. `
  1. そのため、クエリループブロックは`````namespace`````という特別な属性を公開しています。これは、ブロック実装内では何も行わず、拡張者が自分のバリエーションを認識し、スコープを設定するための簡単で一貫した方法として使用されます。さらに、`````isActive`````は比較する属性の文字列の配列も受け入れます。多くの場合、`````namespace`````で十分ですので、次のように使用します:
  2. ``````bash
  3. {
  4. /** ...variation properties */
  5. attributes: {
  6. /** ...variation attributes */
  7. namespace: 'my-plugin/books-list',
  8. },
  9. isActive: [ 'namespace' ],
  10. }
  11. `

このようにして、Gutenbergはあなたのカスタム名前空間と一致する場合にのみ、あなたの特定のバリエーションであることを知ります!とても便利です!

クエリの拡張

これらすべてを考慮しても、あなたのカスタム投稿タイプには独自の要件があるかもしれません:特定のカスタム属性をサポートしている場合、それをフィルタリングしてクエリする必要があるかもしれませんし、他のクエリパラメータは無関係であったり、完全にサポートされていない場合もあります!私たちはこのようなユースケースを考慮してクエリループブロックを構築しましたので、この問題をどのように解決できるか見てみましょう。

無関係またはサポートされていないクエリコントロールの無効化

例えば、あなたの本ではsticky属性を全く使用しないとしましょう。これはブロックのカスタマイズには全く無関係です。設定が何をするのかについてユーザーを混乱させないために、明確なUXを提供するために、このコントロールを利用できないようにしたいと考えています。さらに、authorフィールドを全く使用しないとしましょう。これは一般的にその投稿をデータベースに追加した人を示しますが、代わりにカスタムbookAuthorフィールドを使用します。そのため、authorフィルターを保持することは混乱を招くだけでなく、あなたのクエリを「壊す」ことになります。

この理由から、クエリループブロックバリエーションは、表示したいコントロールのキーの配列を受け入れるallowedControlsというプロパティをサポートしています。デフォルトでは、すべてのコントロールを受け入れますが、このプロパティに配列を提供すると、私たちにとって関連性のあるコントロールのみを指定したいと考えています!

Gutenbergバージョン14.2以降、次のコントロールが利用可能です:

  • inherit – クエリがテンプレートから直接継承されることを許可するトグルスイッチを表示します。
  • postType – 利用可能な投稿タイプのドロップダウンを表示します。
  • order – クエリの順序を選択するためのドロップダウンを表示します。
  • sticky – スティッキーポストの扱いを選択するためのドロップダウンを表示します。
  • taxQuery – 現在選択されている投稿タイプの利用可能なタクソノミーフィルターを表示します。
  • author – 著者によってクエリをフィルタリングするための入力フィールドを表示します。
  • search – キーワードによってクエリをフィルタリングするための入力フィールドを表示します。

私たちの場合、このプロパティは次のようになります:

  1. {
  2. /** ...variation properties */
  3. allowedControls: [ 'inherit', 'order', 'taxQuery', 'search' ],
  4. }

上記のすべてのコントロールを非表示にしたい場合は、allowedControlsの値として空の配列を設定できます。

私たちはpostTypeコントロールも無効にしたことに注意してください。ユーザーが私たちのバリエーションを選択したとき、なぜ投稿タイプを変更するための混乱を招くドロップダウンを表示するのでしょうか?さらに、カスタムコントロールを実装できるため、ブロックが壊れる可能性があります。

追加コントロールの追加

私たちのプラグインは、クエリする必要があるカスタム属性を使用しているため、ユーザーがコアインスペクターコントロールから無効にしたものの代わりにそれらを選択できるようにするために、独自のコントロールを追加したいと考えています。これをReact HOCを介してブロックフィルターにフックすることで行うことができます。次のように:

  1. import { InspectorControls } from '@wordpress/block-editor';
  2. export const withBookQueryControls = ( BlockEdit ) => ( props ) => {
  3. // We only want to add these controls if it is our variation,
  4. // so here we can implement a custom logic to check for that, similar
  5. // to the `isActive` function described above.
  6. // The following assumes that you wrote a custom `isMyBooksVariation`
  7. // function to handle that.
  8. return isMyBooksVariation( props ) ? (
  9. <>
  10. <BlockEdit key="edit" { ...props } />
  11. <InspectorControls>
  12. <BookAuthorSelector /> { /** Our custom component */ }
  13. </InspectorControls>
  14. </>
  15. ) : (
  16. <BlockEdit key="edit" { ...props } />
  17. );
  18. };
  19. addFilter( 'editor.BlockEdit', 'core/query', withBookQueryControls );

もちろん、あなたはコントロールのロジックを実装する責任があります(@wordpress/componentsを見て、あなたのコントロールがGutenberg UIにシームレスにフィットするようにすることをお勧めします)。queryオブジェクト内に割り当てた追加のパラメータは、少しの追加の努力で、あなたのニーズに応じたカスタムクエリを作成するために使用できます。

現在、フロントエンド側(つまり、エンドユーザー側)でクエリが正しく動作するようにするために、エディター側で正しいプレビューを表示するために、わずかに異なるパスを実装する必要があるでしょう。

  1. {
  2. /** ...variation properties */
  3. attributes: {
  4. /** ...variation attributes */
  5. query: {
  6. /** ...more query settings if needed */
  7. postType: 'book',
  8. /** Our custom query parameter */
  9. bookAuthor: 'J. R. R. Tolkien'
  10. }
  11. }
  12. }

フロントエンド側でカスタムクエリを機能させる

クエリループブロックは、主に属性を受け取り、そこからクエリを構築する投稿テンプレートブロックを介して機能します。クエリループブロックの他のファーストクラスの子(ページネーションブロックなど)も同様に動作します。彼らはクエリを構築し、その後、フィルターquery_loop_block_query_varsを介して結果を公開します。

そのフィルターにフックして、クエリを適宜修正できます。ただし、少なくともフィルターを自分のバリエーションにのみ適用することを確認して、他のクエリループブロックに副作用を引き起こさないようにしてください!

  1. if( 'my-plugin/books-list' === $block[ 'attrs' ][ 'namespace' ] ) {
  2. add_filter(
  3. 'query_loop_block_query_vars',
  4. function( $query ) {
  5. /** You can read your block custom query parameters here and build your query */
  6. },
  7. );
  8. }

(上記のコードでは、ブロックにアクセスする方法があると仮定しています。例えば、pre_render_blockフィルター内ですが、特定の解決策はユースケースによって異なる可能性があるため、これは厳密な推奨ではありません)。

エディター側でカスタムクエリを機能させる

カスタムバリエーションを完成させるために、エディターがカスタムクエリの変更に反応し、それに応じて適切なプレビューを表示することを望むかもしれません。これは機能するブロックには必須ではありませんが、ブロックの消費者にとって完全に統合されたユーザーエクスペリエンスを提供します。

クエリループブロックは、WordPress REST APIを使用してプレビューを表示するために投稿を取得します。queryオブジェクトに追加された追加のパラメータは、APIへのクエリ引数として渡されます。これは、これらの追加パラメータがREST APIによってサポートされているか、またはカスタムフィルター(例えば、rest_{$this->post_type}_queryフィルター)によって処理される必要があることを意味します。このフィルターを使用して、カスタム投稿タイプのAPIリクエストにフックできます。次のように:

  1. add_filter(
  2. 'rest_book_query',
  3. function( $args, $request ) {
  4. /** We can access our custom parameters from here */
  5. $book_author = $request->get_param( 'bookAuthor' );
  6. /** ...your custom query logic */
  7. }
  8. );

これで、クエリループブロックの完全に機能するバリエーションを作成しました!