Usando código DRY para renderizar blocos no servidor (PHP) e no cliente (JS)
Os blocos dinâmicos (Gutenberg) são blocos que constroem sua estrutura e conteúdo dinamicamente quando o bloco é renderizado no front-end.
A renderização de um bloco dinâmico no front-end (para exibi-lo no editor do WordPress) e no lado do servidor (para gerar o HTML do post do blog) normalmente busca seus dados de duas maneiras diferentes:
- Conectando-se à API no lado do cliente (JavaScript)
- Chamando funções do WordPress no lado do servidor (PHP)
Com o Gato GraphQL e suas extensões, é possível tornar essa lógica DRY, tendo uma única fonte de verdade para buscar dados tanto no lado do cliente quanto no lado do servidor. Vamos explorar como fazer isso.
Armazenando queries GraphQL em arquivos .gql
Para conectar-se ao servidor GraphQL a partir do cliente, normalmente executamos a query GraphQL incorporada no código JavaScript, desta forma:
const response = await fetch(endpoint, {
body: JSON.stringify({
query: `
query {
posts {
id
title
author {
id
name
}
}
}
`
)
} );Podemos alternativamente armazenar a query GraphQL em um arquivo .gql (ou .graphql) e importar seu conteúdo usando o raw-loader do 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;(Este código funciona para o Webpack v4; para a v5, devemos usar os Asset Modules em vez disso.)
Em seguida, colocamos a query GraphQL dentro de um arquivo .gql:
# File graphql-documents/fetch-posts-with-author.gql
query {
posts {
id
title
author {
id
name
}
}
}Por fim, dentro do código do bloco, importamos o arquivo e passamos seu conteúdo para o fetch:
import graphQLQuery from './graphql-documents/fetch-posts-with-author.gql';
// ...
const response = await fetch(endpoint, {
body: JSON.stringify({
query: graphQLQuery
)
} );Resolvendo arquivos .gql no lado do servidor
O arquivo GraphQL que criamos acima será nossa única fonte de verdade para buscar dados do bloco. Ele já atende a esse requisito para o lado do cliente; vamos agora ver como fazer isso para o lado do servidor.
A extensão Internal GraphQL Server instala um servidor que pode ser invocado dentro de nossa aplicação, usando código PHP.
o Internal GraphQL Server fornece os seguintes métodos estáticos, via classe GraphQLServer:
executeQuery: Executa uma query GraphQLexecuteQueryInFile: Executa uma query GraphQL contida em um arquivo (.gql)executePersistedQuery: Executa uma query GraphQL persistida (fornecendo seu ID como inteiro, ou slug como string) (a extensão Persisted Queries é necessária)
A assinatura de executeQueryInFile é a seguinte:
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 {
// ...
}
}Ao invocar executeQueryInFile passando o arquivo .gql criado anteriormente, recuperamos os dados ao renderizar o bloco dinâmico:
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);Desta forma, um único arquivo .gql busca os dados para alimentar blocos tanto no lado do cliente quanto no lado do servidor.