通过 API 编写代码
通过 API 编写代码使用 DRY 代码为服务器端(PHP)和客户端(JS)渲染块

使用 DRY 代码为服务器端(PHP)和客户端(JS)渲染块

动态(Gutenberg)块是指在前端渲染块时动态构建其结构和内容的块。

在前端(显示于 WordPress 编辑器)和服务器端(为博客文章生成 HTML)渲染动态块时,通常以两种不同的方式获取数据:

  • 在客户端(JavaScript)连接 API
  • 在服务器端(PHP)调用 WordPress 函数

借助 Gato GraphQL 及其扩展,可以将此逻辑变为 DRY,为客户端和服务器端的数据获取提供单一可信来源。下面来看如何实现。

将 GraphQL queries 存储在 .gql 文件中

要从客户端连接到 GraphQL 服务器,通常将 GraphQL query 嵌入 JavaScript 代码中执行,例如:

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

也可以将 GraphQL query 存储在 .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 query 放入 .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 query
  • executeQueryInFile:执行包含在(.gql)文件中的 GraphQL query
  • executePersistedQuery:执行一个持久化的 GraphQL query(以 int 提供其 ID,或以 string 提供其 slug)(需要 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 文件便可同时为客户端和服务器端的块提供数据。