การเขียนโค้ดด้วย API
การเขียนโค้ดด้วย APIการใช้โค้ดแบบ DRY เพื่อเรนเดอร์บล็อกสำหรับฝั่งเซิร์ฟเวอร์ (PHP) และฝั่งไคลเอนต์ (JS)

การใช้โค้ดแบบ DRY เพื่อเรนเดอร์บล็อกสำหรับฝั่งเซิร์ฟเวอร์ (PHP) และฝั่งไคลเอนต์ (JS)

Dynamic (Gutenberg) blocks คือบล็อกที่สร้างโครงสร้างและเนื้อหาแบบไดนามิกในขณะที่บล็อกถูกเรนเดอร์บนฝั่งหน้าบ้าน

การเรนเดอร์ dynamic block ในฝั่งหน้าบ้าน (เพื่อแสดงใน WordPress editor) และในฝั่งเซิร์ฟเวอร์ (เพื่อสร้าง HTML สำหรับบล็อกโพสต์) มักจะดึงข้อมูลด้วยวิธีที่แตกต่างกันสองวิธี:

  • เชื่อมต่อกับ API ฝั่งไคลเอนต์ (JavaScript)
  • เรียกใช้ฟังก์ชัน WordPress ฝั่งเซิร์ฟเวอร์ (PHP)

ด้วย Gato GraphQL และส่วนขยาย เราสามารถทำให้ลอจิกนี้เป็นแบบ DRY โดยมีแหล่งข้อมูลความจริงเดียวในการดึงข้อมูลทั้งฝั่งไคลเอนต์และเซิร์ฟเวอร์ มาดูวิธีการทำกัน

การจัดเก็บ GraphQL queries ในไฟล์ .gql

เพื่อเชื่อมต่อกับ GraphQL server จากฝั่งไคลเอนต์ เราโดยทั่วไปจะรัน GraphQL query ที่ฝังอยู่ในโค้ด JavaScript ดังนี้:

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

อีกทางเลือกหนึ่ง เราสามารถจัดเก็บ GraphQL query ในไฟล์ .gql (หรือ .graphql) และนำเข้าเนื้อหาของไฟล์โดยใช้ raw-loader ของ Webpack:

// 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
  )
} );

การ Resolve ไฟล์ .gql ในฝั่งเซิร์ฟเวอร์

ไฟล์ GraphQL ที่เราสร้างข้างต้นจะเป็นแหล่งข้อมูลความจริงเดียวในการดึงข้อมูลสำหรับบล็อก ไฟล์นี้ตอบสนองสำหรับฝั่งไคลเอนต์แล้ว มาดูกันว่าจะทำอย่างไรสำหรับฝั่งเซิร์ฟเวอร์

ส่วนขยาย Internal GraphQL Server ติดตั้งเซิร์ฟเวอร์ที่สามารถเรียกใช้งานภายในแอปพลิเคชันของเราโดยใช้โค้ด PHP

Internal GraphQL Server มีเมธอดแบบ static ดังต่อไปนี้ ผ่านคลาส GraphQLServer:

  • executeQuery: รัน GraphQL query
  • executeQueryInFile: รัน GraphQL query ที่อยู่ในไฟล์ (.gql)
  • executePersistedQuery: รัน persisted GraphQL query (ระบุ ID เป็น int หรือ slug เป็น string) (ต้องใช้ส่วนขยาย 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 {
    // ...
  }
}

ด้วยการเรียกใช้ executeQueryInFile โดยส่งไฟล์ .gql ที่สร้างไว้ก่อนหน้านี้ เราสามารถดึงข้อมูลได้เมื่อเรนเดอร์ dynamic block:

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 ไฟล์เดียวจะดึงข้อมูลเพื่อขับเคลื่อนบล็อกได้ทั้งฝั่งไคลเอนต์และเซิร์ฟเวอร์