บทช่วยสอน 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
  }
}

หากต้องการส่งอีเมลในรูปแบบข้อความธรรมดา:

  • ใช้อินพุต messageAs: { text: ... } ใน mutation _sendEmail
  • ลบแท็ก HTML ออกจากเนื้อหาของโพสต์โดยใช้ฟิลด์ส่วนกลาง _htmlStripTags (จัดเตรียมโดยส่วนขยาย PHP Functions via Schema)

ต่อไปมาดูกันว่าจะทริกเกอร์การทำงานของ GraphQL query ได้อย่างไร

ตัวเลือกที่ 1: ทริกเกอร์เสมอโดยตอบสนองต่อ hook ของ WordPress

เราเชื่อมเข้ากับ action new_to_publish ของ WordPress core ดึงข้อมูลจากโพสต์ที่เพิ่งสร้างขึ้น และเรียกใช้ GraphQL query ที่กำหนดไว้ข้างต้นกับเซิร์ฟเวอร์ 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 query

คลาสนี้มี static method 3 ตัวสำหรับเรียกใช้ query:

  • executeQuery: เรียกใช้ GraphQL query
  • executeQueryInFile: เรียกใช้ GraphQL query ที่อยู่ในไฟล์ (.gql)
  • executePersistedQuery: เรียกใช้ persisted GraphQL query (โดยระบุ ID เป็น int หรือ slug เป็น string)

GraphQL query นี้จะถูกเรียกใช้ทุกครั้งที่มีการสร้างโพสต์ใหม่ หรือพูดให้แม่นยำกว่านั้นคือทุกครั้งที่ฟังก์ชัน wp_insert_post ของ WordPress ถูกเรียก (เนื่องจากฟังก์ชันนี้ทริกเกอร์ hook new_to_publish):

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

กรณีนี้ก็เกิดขึ้นเช่นกันเมื่อเรียกใช้ GraphQL query อื่นที่เรียกใช้ mutation createPost (เนื่องจาก resolver ของมันในโค้ด PHP เรียกฟังก์ชัน wp_insert_post):

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

GraphQL Server (ซึ่งเป็น "ภายนอก" เข้าถึงในฐานะ API ผ่าน HTTP) และ Internal GraphQL Server จะเรียกใช้ query ของแต่ละตัวโดยใช้ Schema Configuration ของตนเอง แม้ในขณะที่การทำงานของทั้งสองเกี่ยวพันกัน

ตัวอย่างเช่น สมมติว่าเรากำลังเรียกใช้ GraphQL query กับ single endpoint และมันสร้างโพสต์โดยเรียกใช้ mutation createPost จากนั้นลำดับขั้นตอนต่อไปนี้จะเกิดขึ้น:

(ภายนอก) GraphQL ServerInternal GraphQL Server
เรียกใช้ GraphQL query กับ single endpoint โดยใช้ Schema Configuration ของตนเอง(ไม่ทำงาน)
สร้างโพสต์ ซึ่งทริกเกอร์ new_to_publish(ไม่ทำงาน)
(กำลังรอ...)ตอบสนองต่อ hook new_to_publish: เริ่มเซิร์ฟเวอร์ Internal GraphQL โดยใช้ Schema Configuration ของตนเอง
(กำลังรอ...)เรียกใช้ query เพื่อส่งอีเมล
(กำลังรอ...)ส่งอีเมล จบ query นั้น
(กำลังรอ...)ปิดเซิร์ฟเวอร์
ดำเนินการเรียกใช้ query ต่อ จบ query นั้น(ไม่ทำงาน)
ปิดเซิร์ฟเวอร์(ไม่ทำงาน)

ตัวเลือกที่ 2: ทริกเกอร์โดยการเชื่อมโยง GraphQL query

ส่วนขยาย Automation ทำให้ GraphQL Server ทริกเกอร์ hook หลังจากเรียกใช้ GraphQL query เสร็จสิ้น ซึ่งทำให้เราสามารถเชื่อมโยง GraphQL query เข้าด้วยกันได้

โค้ด PHP นี้จะเรียกใช้ operation SendEmail (GraphQL query ที่กำหนดไว้ข้างต้น) หลังจากที่ GraphQL Server ได้เรียกใช้ query อื่นที่มี operation CreatePost (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 เข้าด้วยกันทำให้เราสามารถเรียกใช้ query เพียงครั้งเดียว แม้ว่าจะมีการ mutate ทรัพยากรจำนวนมากก็ตาม

ตัวอย่างเช่น 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 เพิ่มเติมหนึ่งหรือหลาย query ได้:

เชื่อมเข้ากับ...ทริกเกอร์จำนวน GraphQL query...
post_updated (โดย WordPress core)หนึ่ง query สำหรับทุกโพสต์ที่อัปเดต
gatographql__executed_query:ReplaceDomains (โดยส่วนขยาย Automation)หนึ่ง query โดยรวม (จะได้รับข้อมูลของโพสต์ที่อัปเดตทั้งหมด)