Учебник по схеме
Учебник по схемеУрок 16: Отправка уведомления при появлении новой записи

Урок 16: Отправка уведомления при появлении новой записи

Gato GraphQL может помочь нам автоматизировать задачи в приложении, например отправлять email-уведомление администратору при появлении новой записи.

В этом уроке мы рассмотрим два способа достичь этого.

GraphQL-запрос для отправки email-уведомления администратору

Этот GraphQL-запрос отправляет email администратору, уведомляя о создании новой записи на сайте:

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
  }
}

Чтобы отправить email в виде обычного текста:

  • Используйте параметр messageAs: { text: ... } в мутации _sendEmail
  • Удалите HTML-теги из содержимого записи с помощью глобального поля _htmlStripTags (предоставляемого расширением PHP Functions via Schema)

Рассмотрим далее, как запустить выполнение GraphQL-запроса.

Вариант 1: Всегда запускать, реагируя на хуки WordPress

Мы подключаемся к действию WordPress core new_to_publish, получаем данные только что созданной записи и выполняем определённый выше GraphQL-запрос против внутреннего GraphQL-сервера (предоставляемого расширением Internal GraphQL Server):

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-запросов.

Этот класс предоставляет 3 статических метода для выполнения запросов:

  • executeQuery: выполнить GraphQL-запрос
  • executeQueryInFile: выполнить GraphQL-запрос, содержащийся в файле (.gql)
  • executePersistedQuery: выполнить persisted GraphQL query (передав его ID как int или slug как string)

Этот GraphQL-запрос будет выполняться каждый раз при создании новой записи или, точнее, каждый раз при вызове функции WordPress wp_insert_post (поскольку эта функция запускает хук new_to_publish):

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

Это также происходит при выполнении другого GraphQL-запроса, который запускает мутацию createPost (поскольку её резолвер в PHP-коде вызывает функцию wp_insert_post):

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

GraphQL Server (который является «внешним», доступным как API через HTTP) и Internal GraphQL Server будут выполнять свои запросы, применяя собственную Schema Configuration, даже когда их выполнение переплетается.

Например, предположим, что мы выполняем GraphQL-запрос против единственного endpoint, и он создаёт запись, выполняя мутацию createPost. Тогда происходит следующая последовательность шагов:

(Внешний) GraphQL ServerInternal GraphQL Server
Выполняет GraphQL-запрос против единственного endpoint, используя собственную Schema Configuration(не активен)
Создаёт запись; это запускает new_to_publish(не активен)
(ожидание...)Реагирует на хук new_to_publish: запускает Internal GraphQL server, используя собственную Schema Configuration
(ожидание...)Выполняет запрос для отправки email
(ожидание...)Отправляет email, конец этого запроса
(ожидание...)Завершает работу сервера
Продолжает выполнение запроса, конец этого запроса(не активен)
Завершает работу сервера(не активен)

Вариант 2: Запускать путём цепочки GraphQL-запросов

Расширение Automation заставляет GraphQL Server запускать хук после завершения выполнения GraphQL-запроса. Это позволяет нам выстраивать цепочки GraphQL-запросов.

Этот PHP-код выполняет операцию SendEmail (GraphQL-запрос, определённый выше) после того, как GraphQL-сервер выполнил какой-либо другой запрос с операцией CreatePost (GraphQL-запрос, определённый выше):

// 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-запросов позволяет нам выполнить один запрос, даже если было изменено много ресурсов.

Например, этот GraphQL-запрос обновляет множество записей:

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-запросов:

Подключение к...Количество запускаемых GraphQL-запросов...
post_updated (WordPress core)По одному для каждой обновлённой записи
gatographql__executed_query:ReplaceDomains (расширение Automation)Один в целом (получит данные для всех обновлённых записей)