Programmare con un'API
Programmare con un'APIUsare codice DRY per renderizzare i blocchi lato server (PHP) e lato client (JS)

Usare codice DRY per renderizzare i blocchi lato server (PHP) e lato client (JS)

I blocchi dinamici (Gutenberg) sono blocchi che costruiscono la loro struttura e il loro contenuto al volo quando il blocco viene renderizzato sul front-end.

Il rendering di un blocco dinamico sul front-end (per visualizzarlo nell'editor di WordPress) e lato server (per generare l'HTML dell'articolo del blog) di solito recupera i suoi dati in due modi diversi:

  • Connettendosi all'API lato client (JavaScript)
  • Chiamando le funzioni di WordPress lato server (PHP)

Con Gato GraphQL e le sue estensioni, è possibile rendere questa logica DRY, avendo un'unica fonte di verità per recuperare i dati sia lato client che lato server. Vediamo come fare.

Memorizzare le query GraphQL in file .gql

Per connettersi al server GraphQL dal client, di solito eseguiamo la query GraphQL incorporata nel codice JavaScript, in questo modo:

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

In alternativa possiamo memorizzare la query GraphQL in un file .gql (o .graphql) e importarne il contenuto utilizzando il raw-loader di 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;

(Questo codice funziona per Webpack v4; per la v5 dobbiamo utilizzare invece gli Asset Modules.)

Successivamente, inseriamo la query GraphQL all'interno di un file .gql:

# File graphql-documents/fetch-posts-with-author.gql
query {
  posts {
    id
    title
    author {
      id
      name
    }
  }
}

Infine, all'interno del codice del blocco, importiamo il file e passiamo il suo contenuto a fetch:

import graphQLQuery from './graphql-documents/fetch-posts-with-author.gql';
 
// ...
 
const response = await fetch(endpoint, {
  body: JSON.stringify({
    query: graphQLQuery
  )
} );

Risolvere i file .gql lato server

Il file GraphQL che abbiamo creato sopra sarà la nostra unica fonte di verità per recuperare i dati del blocco. Soddisfa già questo requisito per il lato client; vediamo ora come farlo per il lato server.

L'estensione Internal GraphQL Server installa un server che può essere invocato all'interno della nostra applicazione, utilizzando codice PHP.

l'Internal GraphQL Server fornisce i seguenti metodi statici, tramite la classe GraphQLServer:

  • executeQuery: esegue una query GraphQL
  • executeQueryInFile: esegue una query GraphQL contenuta in un file (.gql)
  • executePersistedQuery: esegue una query GraphQL persistita (fornendo il suo ID come intero, o il suo slug come stringa) (è richiesta l'estensione Persisted Queries)

La firma di executeQueryInFile è la seguente:

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 {
    // ...
  }
}

Invocando executeQueryInFile passando il file .gql creato in precedenza, recuperiamo i dati durante il rendering del blocco dinamico:

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

In questo modo, un unico file .gql recupera i dati per alimentare i blocchi sia lato client che lato server.