Schema 教程
Schema 教程第16课:有新文章时发送通知

第16课:有新文章时发送通知

Gato GraphQL 可以帮助我们自动化应用程序中的任务,例如在有新文章时向管理员发送通知邮件。

在本教程课程中,我们将探讨实现这一目标的两种方式。

向管理员发送通知邮件的 GraphQL Query

以下 GraphQL query 向管理员用户发送一封邮件,通知其站点上有新文章被创建:

query GetEmailData(
  $postTitle: String!,
  $postContent: String!
  $postURL: URL!
) {
  adminEmail: optionValue(name: "admin_email")
    @export(as: "adminEmail")
 
  emailMessageTemplate: _strConvertMarkdownToHTML(
    text: """
 
There is a [new post on the site]({$postURL}):
 
**{$postTitle}**:
 
{$postContent}
 
    """
  )
  emailMessage: _strReplaceMultiple(
    search: ["{$postTitle}", "{$postContent}", "{$postURL}"],
    replaceWith: [$postTitle, $postContent, $postURL],
    in: $__emailMessageTemplate
  )
    @export(as: "emailMessage")
 
  emailSubject: _sprintf(
    string: "New post: \"%s\"",
    values: [$postTitle]
  )
    @export(as: "emailSubject")
}
 
mutation SendEmail @depends(on: "GetEmailData") {
  _sendEmail(
    input: {
      to: $adminEmail
      subject: $emailSubject
      messageAs: {
        html: $emailMessage
      }
    }
  ) {
    status
  }
}

以纯文本格式发送邮件:

  • _sendEmail mutation 中使用输入 messageAs: { text: ... }
  • 使用 PHP Functions via Schema 扩展提供的全局字段 _htmlStripTags 从文章内容中去除 HTML 标签

接下来,我们来看如何触发 GraphQL query 的执行。

选项 1:通过响应 WordPress 钩子始终触发

我们挂载到 WordPress 核心操作 new_to_publish,从新创建的文章中获取数据,并针对内部 GraphQL 服务器(由 Internal GraphQL Server 扩展提供)执行上面定义的 GraphQL query:

use GatoGraphQL\InternalGraphQLServer\GraphQLServer;
use WP_Post;
 
// The GraphQL query, under var `$query`, is the one defined above
// $query = '...';
add_action(
  'new_to_publish',
  function (WP_Post $post) use ($query) {
    $variables = [
      'postTitle' => $post->post_title,
      'postContent' => $post->post_content,
      'postURL' => get_permalink($post->ID),
    ]
    GraphQLServer::executeQuery($query, $variables, 'SendEmail');
  }
);

GatoGraphQL\InternalGraphQLServer\GraphQLServer 不可作为外部 API 访问。它应由应用程序通过 PHP 代码调用,用于通过 GraphQL query 执行和自动化管理任务。

该类提供 3 个静态方法来执行 query:

  • executeQuery:执行一个 GraphQL query
  • executeQueryInFile:执行包含在(.gql)文件中的 GraphQL query
  • executePersistedQuery:执行一个持久化 GraphQL query(以 int 形式提供其 ID,或以 string 形式提供其 slug)

每当有新文章被创建时,此 GraphQL query 就会被执行。更准确地说,每当 WordPress 函数 wp_insert_post 被调用时就会执行(因为该函数会触发钩子 new_to_publish):

$postID = wp_insert_post([
  'post_title' => 'Hello world!'
]);

当执行另一个包含 createPost mutation 的 GraphQL query 时也是如此(因为其解析器在 PHP 代码中会调用函数 wp_insert_post):

mutation CreatePost {
  createPost(input: {
    title: "Hello world!"
  }) {
    status
    postID
  }
}

GraphQL 服务器("外部"服务器,通过 HTTP 作为 API 访问)和 Internal GraphQL 服务器在执行 query 时各自应用自己的 Schema Configuration,即使两者的执行交织在一起也是如此。

例如,假设我们正在针对单一端点执行一个 GraphQL query,它通过执行 mutation createPost 来创建一篇文章。此时会发生以下一系列步骤:

(外部) GraphQL ServerInternal GraphQL Server
针对单一端点执行 GraphQL query,使用自己的 Schema Configuration(未激活)
创建文章,触发 new_to_publish(未激活)
(等待中...)响应 new_to_publish 钩子:启动 Internal GraphQL 服务器,使用自己的 Schema Configuration
(等待中...)执行发送邮件的 query
(等待中...)发送邮件,该 query 结束
(等待中...)关闭服务器
继续执行 query,该 query 结束(未激活)
关闭服务器(未激活)

选项 2:通过链式 GraphQL Query 触发

Automation 扩展使 GraphQL 服务器在完成一个 GraphQL query 的执行后触发一个钩子。这使我们能够链式执行 GraphQL query。

以下 PHP 代码在 GraphQL 服务器执行完带有 CreatePost 操作的某个 query(上面定义的 GraphQL query)之后,执行 SendEmail 操作(上面定义的 GraphQL query):

// The GraphQL query, under var `$query`, is the one defined above
// $query = '...';
add_action(
  "gatographql__executed_query:CreatePost",
  function (Response $response) use ($query) {
    // @var string
    $responseContent = $response->getContent();
    // @var array<string,mixed>
    $responseJSON = json_decode($responseContent, true);
    $postID = $responseJSON['data']['createPost']['postID'] ?? null;
    if ($postID === null) {
      // Do nothing
      return;
    }
 
    $post = get_post($postID);
    $variables = [
      'postTitle' => $post->post_title,
      'postContent' => $post->post_content,
      'postURL' => get_permalink($post->ID),
    ]
    GraphQLServer::executeQuery($query, $variables, 'SendEmail');
  }
);

通过链式执行 GraphQL query,即使有许多资源被 mutation,我们也只需执行一个 query。

例如,以下 GraphQL query 更新了许多文章:

mutation ReplaceDomains {
  posts {
    id
    rawContent
    adaptedRawContent: _strReplace(
      search: "https://my-old-domain.com"
      replaceWith: "https://my-new-domain.com"
      in: $__rawContent
    )
    update(input: {
      contentAs: { html: $__adaptedRawContent }
    }) {
      status
      postID
    }
  }
}

根据我们的策略,我们可以触发一个或多个额外 GraphQL query 的执行:

挂载到...触发的 GraphQL Query 数量...
post_updated(由 WordPress 核心触发)每个被更新的文章触发一次
gatographql__executed_query:ReplaceDomains(由 Automation 扩展触发)总计一次(将接收所有被更新文章的数据)