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