Używanie kodu DRY do renderowania bloków po stronie serwera (PHP) i klienta (JS)
Bloki dynamiczne (Gutenberg) to bloki, które budują swoją strukturę i zawartość dynamicznie w momencie renderowania bloku na front-endzie.
Renderowanie bloku dynamicznego na front-endzie (aby wyświetlić go w edytorze WordPress) i po stronie serwera (aby wygenerować HTML dla wpisu na blogu) zazwyczaj pobiera dane na dwa różne sposoby:
- Łącząc się z API po stronie klienta (JavaScript)
- Wywołując funkcje WordPress po stronie serwera (PHP)
Dzięki Gato GraphQL i jego rozszerzeniom możliwe jest uczynienie tej logiki DRY, posiadając jedno źródło prawdy do pobierania danych zarówno po stronie klienta, jak i serwera. Sprawdźmy, jak to zrobić.
Przechowywanie queries GraphQL w plikach .gql
Aby połączyć się z serwerem GraphQL po stronie klienta, zazwyczaj wykonujemy query GraphQL osadzone w kodzie JavaScript, w ten sposób:
const response = await fetch(endpoint, {
body: JSON.stringify({
query: `
query {
posts {
id
title
author {
id
name
}
}
}
`
)
} );Możemy alternatywnie przechowywać query GraphQL w pliku .gql (lub .graphql) i importować jego zawartość za pomocą 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;(Ten kod działa dla Webpack v4; dla v5 należy zamiast tego użyć Asset Modules.)
Następnie umieszczamy query GraphQL w pliku .gql:
# File graphql-documents/fetch-posts-with-author.gql
query {
posts {
id
title
author {
id
name
}
}
}Na koniec, w kodzie bloku, importujemy plik i przekazujemy jego zawartość do fetch:
import graphQLQuery from './graphql-documents/fetch-posts-with-author.gql';
// ...
const response = await fetch(endpoint, {
body: JSON.stringify({
query: graphQLQuery
)
} );Rozwiązywanie plików .gql po stronie serwera
Plik GraphQL, który stworzyliśmy powyżej, będzie naszym jednym źródłem prawdy do pobierania danych dla bloku. Spełnia już to wymaganie po stronie klienta; zobaczmy teraz, jak zrobić to samo po stronie serwera.
Rozszerzenie Internal GraphQL Server instaluje serwer, który można wywołać w ramach naszej aplikacji, używając kodu PHP.
Internal GraphQL Server udostępnia następujące metody statyczne, za pośrednictwem klasy GraphQLServer:
executeQuery: Wykonuje query GraphQLexecuteQueryInFile: Wykonuje query GraphQL zawarte w pliku (.gql)executePersistedQuery: Wykonuje utrwaloną query GraphQL (podając jej ID jako liczbę całkowitą lub slug jako ciąg znaków) (wymagane jest rozszerzenie Persisted Queries)
Sygnatura executeQueryInFile wygląda następująco:
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 {
// ...
}
}Wywołując executeQueryInFile i przekazując wcześniej utworzony plik .gql, pobieramy dane podczas renderowania bloku dynamicznego:
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);W ten sposób jeden plik .gql pobiera dane zasilające bloki zarówno po stronie klienta, jak i serwera.