Урок 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 Server | Internal 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) | Один в целом (получит данные для всех обновлённых записей) |