APIでのコーディング
APIでのコーディングサーバー(PHP)とクライアント(JS)両方のブロックレンダリングにDRYコードを使用する

サーバー(PHP)とクライアント(JS)両方のブロックレンダリングにDRYコードを使用する

動的(Gutenberg)ブロックとは、フロントエンドでブロックがレンダリングされるときに、その構造とコンテンツを動的に構築するブロックです。

動的ブロックをフロントエンド(WordPressエディターに表示するため)でレンダリングする場合と、サーバー側(ブログ投稿のHTMLを生成するため)でレンダリングする場合、通常は2つの異なる方法でデータを取得します。

  • クライアント側(JavaScript)でAPIに接続する
  • サーバー側(PHP)でWordPress関数を呼び出す

Gato GraphQLと拡張機能を使用すると、このロジックをDRYにして、クライアント側とサーバー側の両方でデータを取得するための単一の信頼できる情報源を持つことができます。その方法を見ていきましょう。

GraphQLクエリを.gqlファイルに保存する

クライアントからGraphQLサーバーに接続するには、通常、JavaScriptコード内にGraphQLクエリを埋め込んで実行します。例えば次のようになります。

const response = await fetch(endpoint, {
  body: JSON.stringify({
    query: `
      query {
        posts {
          id
          title
          author {
            id
            name
          }
        }
      }
    `
  )
} );

あるいは、GraphQLクエリを.gql(または.graphql)ファイルに保存し、Webpackのraw-loaderを使ってその内容をインポートすることもできます。

// File webpack.config.js
const config = require( '@wordpress/scripts/config/webpack.config' );
 
config.module.rules.push(
  {
    test: /\.(gql|graphql)$/i,
    use: 'raw-loader',
  },
);
 
module.exports = config;

(このコードはWebpack v4向けです。v5では、代わりにAsset Modulesを使用する必要があります。)

次に、GraphQLクエリを.gqlファイルに配置します。

# File graphql-documents/fetch-posts-with-author.gql
query {
  posts {
    id
    title
    author {
      id
      name
    }
  }
}

最後に、ブロックのコード内でファイルをインポートし、その内容をfetchに渡します。

import graphQLQuery from './graphql-documents/fetch-posts-with-author.gql';
 
// ...
 
const response = await fetch(endpoint, {
  body: JSON.stringify({
    query: graphQLQuery
  )
} );

サーバー側で.gqlファイルを解決する

上記で作成したGraphQLファイルが、ブロックのデータ取得における単一の信頼できる情報源となります。クライアント側についてはすでに対応できています。次にサーバー側でどのように行うかを見ていきましょう。

Internal GraphQL Server 拡張機能は、PHPコードを使ってアプリケーション内から呼び出せるサーバーをインストールします。

Internal GraphQL Serverは、GraphQLServerクラスを通じて以下の静的メソッドを提供します。

  • executeQuery: GraphQLクエリを実行する
  • executeQueryInFile: (.gql)ファイルに含まれるGraphQLクエリを実行する
  • executePersistedQuery: 永続化されたGraphQLクエリを実行する(IDをintで、またはスラッグをstringで指定)(Persisted Queries拡張機能が必要)

executeQueryInFileのシグネチャは次のようになっています。

namespace GatoGraphQL\InternalGraphQLServer;
 
class GraphQLServer {
  /**
   * Execute a GraphQL query contained in a (`.gql`) file
   */
  public static function executeQueryInFile(
      string $file,
      array $variables = [],
      ?string $operationName = null
  ): Response {
    // ...
  }
}

先ほど作成した.gqlファイルを渡してexecuteQueryInFileを呼び出すことで、動的ブロックのレンダリング時にデータを取得できます。

use GatoGraphQL\InternalGraphQLServer\GraphQLServer;
 
$block = [
  'render_callback' => function(array $attributes, string $content): string {
    // Provide the GraphQL query file
    $file = __DIR__ . '/blocks/my-block/graphql-documents/fetch-posts-with-author.gql';
 
    // Execute the query against the internal server
    $response = GraphQLServer::executeQueryInFile($file);
 
    // Get the content and decode it
    $responseContent = json_decode($response->getContent(), true);
 
    // Access the data and errors from the response
    $data = $responseContent["data"] ?? [];
    $errors = $responseContent["errors"] ?? [];
 
    // Do something with the data
    // $content = $this->useGraphQLData($content, $data, $errors);
    // ...
 
    return $content;
  },
];
register_block_type("namespace/my-block", $block);

このようにして、単一の.gqlファイルがクライアント側とサーバー側の両方でブロックにデータを提供できます。