O Gutenberg é o editor padrão do WordPress. O editor permite que você crie e estilize o conteúdo usando blocos discretos para texto, imagens, vídeo e outros elementos do site por meio de uma interface de arrastar e soltar. Essa abordagem aprimora a flexibilidade e os recursos de design do WordPress.

Este guia explica como analisar o conteúdo do Gutenberg como HTML usando a API REST do WordPress em um site estático Next.js.

Pré-requisitos

Para acompanhar, você precisa de:

Obter conteúdo do Gutenberg usando uma API REST

Para interagir com seu site WordPress de forma programática e recuperar conteúdo estruturado em blocos do Gutenberg, você pode usar a API REST do WordPress ou o plugin WPGraphQL. Essas ferramentas permitem que você busque seu conteúdo do WordPress no formato JSON.

Para habilitar o acesso aos dados JSON por meio da API REST, ajuste as configurações de permalink do seu WordPress para algo diferente de “Simples”. Isso permite o acesso à API por meio de uma URL estruturada, conforme segue:

https://yoursite.com/wp-json/wp/v2

Ao fazer solicitações de API para esse URL, você pode recuperar programaticamente várias informações e executar operações no seu site WordPress. Por exemplo, você pode obter uma lista de artigos enviando uma solicitação GET para:

https://yoursite.com/wp-json/wp/v2/posts

Isso retornará um objeto JSON contendo informações sobre os artigos em seu site WordPress, incluindo títulos, conteúdo, detalhes do autor e muito mais.

Analisar blocos do Gutenberg como HTML

Ao recuperar artigos de um site WordPress que usa o editor Gutenberg, o conteúdo armazenado no banco de dados pode apresentar uma combinação de metadados HTML e JSON para descrever vários tipos de blocos, como citações e galerias. Por exemplo:

<!-- wp:quote {"className":"inspirational-quote","style":{"typography":{"fontSize":"large"}}} -->
<blockquote class="wp-block-quote inspirational-quote has-large-font-size"><p>“The journey of a thousand miles begins with one step.”</p><cite>Lao Tzu</cite></blockquote>
<!-- /wp:quote -->

<!-- wp:gallery {"ids":[34,35],"columns":2,"linkTo":"none","sizeSlug":"medium","className":"custom-gallery"} -->
<ul class="wp-block-gallery columns-2 is-cropped custom-gallery"><li class="blocks-gallery-item"><figure><img src="http://example.com/wp-content/uploads/2021/09/image1-300x200.jpg" alt="A breathtaking view of the mountains" class="wp-image-34"/></figure></li><li class="blocks-gallery-item"><figure><img src="http://example.com/wp-content/uploads/2021/09/image2-300x200.jpg" alt="Serene lakeside at dawn" class="wp-image-35"/></figure></li></ul>
<!-- /wp:gallery -->

Este snippet ilustra dois blocos do Gutenberg: Uma Citação e uma Galeria. Cada um deles é aumentado com metadados JSON encapsulados em comentários HTML. Os metadados definem atributos como nomes de classes, estilos e outras configurações relevantes para a apresentação do bloco.

Quando você obtém esses blocos por meio da API REST do WordPress ou do WPGraphQL, o WordPress os processa, transformando a combinação de metadados HTML e JSON em elementos HTML totalmente renderizados que você pode incorporar diretamente nas páginas web. O HTML transformado para os blocos acima apareceria da seguinte forma:

<blockquote class="wp-block-quote inspirational-quote has-large-font-size"><p>“The journey of a thousand miles begins with one step.”</p><cite>Lao Tzu</cite></blockquote>

<ul class="wp-block-gallery columns-2 is-cropped custom-gallery">
  <li class="blocks-gallery-item"><figure><img loading="lazy" src="http://example.com/wp-content/uploads/2021/09/image1-300x200.jpg" alt="A breathtaking view of the mountains" class="wp-image-34" sizes="(max-width: 300px) 100vw, 300px" /></figure></li>
  <li class="blocks-gallery-item"><figure><img loading="lazy" src="http://example.com/wp-content/uploads/2021/09/image2-300x200.jpg" alt="Serene lakeside at dawn" class="wp-image-35" sizes="(max-width: 300px) 100vw, 300px" /></figure></li>
</ul>

Para os desenvolvedores que criam aplicativos desacoplados ou headless usando frameworks JavaScript como Next.js, isso apresenta um método simples de exibir conteúdo injetando diretamente o HTML na página usando a propriedade dangerouslySetInnerHTML para renderizar a marcação.

<div dangerouslySetInnerHTML={{ __html: <raw_html_string> }} />

Além disso, talvez você precise realizar uma formatação adicional para elementos como links e lidar com o excesso de caracteres de nova linha (\n), o que este guia explica posteriormente.

Analisar o conteúdo dos blocos do Gutenberg no site estático Next.js

Nesta seção, vamos buscar o conteúdo do WordPress em um projeto Next.js e, em seguida, analisar os blocos do Gutenberg como HTML.

  1. Comece configurando uma função para buscar artigos do seu site WordPress. Abra o arquivo src/page.js em seu projeto e substitua seu conteúdo pelo seguinte trecho de código:
    const getWpPosts = async () => {
    	const res = await fetch('https://yoursite.com/wp-json/wp/v2/posts');
      	const posts = await res.json();
    	return posts;
    };

    Essa função assíncrona executa uma solicitação de API para a API REST do WordPress. Isso busca todos os artigos disponíveis em seu site e as retorna como uma array.

  2. Em seguida, vamos utilizar os artigos obtidos em um componente de página Next.js simples, registrando os artigos no console e renderizando uma saudação básica:
    const page = async () => {
      const posts = await getWpPosts();
      console.log(posts);
      
      return (
        <div>
          <h1>Hello World</h1>
        </div>
      );
    };
    
    export default page;

    Quando você executa o projeto usando npm run dev, ele exibe a mensagem “Hello World” e registra em registro os artigos obtidos no Terminal.

    [
      {
        "_links" : {
          "about" : [...],
          "author" : [...],
          "collection" : [...],
          "curies" : [...],
          "predecessor-version" : [...],
          "replies" : [...],
          "self" : [...],
          "version-history" : [...],
          "wp:attachment" : [...],
          "wp:term" : [...]
        },
        "author" : 1,
        "categories" : [...],
        "comment_status" : "open",
        "content" : {
          "protected" : false,
          "rendered" : "\n<p>Fire, a primal force, captivates with its <strong>flickering flames</strong>, evoking both awe and caution. Its <quote>dance</quote> symbolizes destruction and renewal, consuming the old to make way for the new. While it warms our homes and hearts, fire demands respect for its power to devastate.</p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"250\" height=\"148\" src=\"https://img.example.com/wp-content/uploads/2024/02/burningbuilding.jpg\" alt=\"\" class=\"wp-image-14\"/></figure>\n\n\n\n<p>In ancient times, fire was a beacon of light and warmth, essential for survival. Today, it remains a symbol of human ingenuity and danger. From the comforting glow of a hearth to the destructive fury of wildfires, fire’s dual nature reminds us of our fragile relationship with the elements.</p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https://img.example.com/premium-photo/painting-burning-building-illuminated-by-bright-flames-night_168058-249.jpg?w=1380\" alt=\"\"/></figure>\n\n\n\n<p>You can check out other articles on our blog:</p>\n\n\n\n<ul>\n<li><a href=\"https://yoursite.com/?p=6\">Lorem Ipsum: Beginnings</a></li>\n\n\n\n<li><a href=\"https://yoursite.com/?p=9\">Lorem Ipsum: Act 2</a></li>\n\n\n\n<li><a href=\"https://yoursite.com/?p=11\">Lorem Ipsum: Act 3</a></li>\n</ul>\n"
        },
        "date" : "2024-02-27T12:08:30",
        "date_gmt" : "2024-02-27T12:08:30",
        "excerpt" : {
          "protected" : false,
          "rendered" : "<p>Fire, a primal force, captivates with its flickering flames, evoking both awe and caution. Its dance symbolizes destruction and renewal, consuming the old to make way for the new. While it warms our homes and hearts, fire demands respect for its power to devastate. In ancient times, fire was a beacon of light and warmth, […]</p>\n"
        },
        "featured_media" : 0,
        "format" : "standard",
        "guid" : {
          "rendered" : "https://yoursite.com/?p=13"
        },
        "id" : 13,
        "link" : "https://yoursite.com/?p=13",
        "meta" : {
          "footnotes" : ""
        },
        "modified" : "2024-02-29T16:45:36",
        "modified_gmt" : "2024-02-29T16:45:36",
        "ping_status" : "open",
        "slug" : "fire-fire",
        "status" : "publish",
        "sticky" : false,
        "tags" : [],
        "template" : "",
        "title" : {
          "rendered" : "Fire"
        },
        "type" : "post"
       },
      },
      ...
    ]

    Os objetos JSON que representam os dados de artigos individuais do Gutenberg incluem vários campos, entre os quais os campos de conteúdo e de trecho são retornados como blocos do Gutenberg analisados como strings de caracteres HTML.

  3. Para renderizar esse conteúdo HTML corretamente no Next.js, empregamos a propriedade dangerouslySetInnerHTML:
    const page = async () => {
      const posts = await getWpPosts();
    
      return (
        <>
          <h1> Headless Blog </h1>
    
          <div>
            {posts.map((post) => (
              <Link href={'/blog/' + post.id} key={post.id}>
                <h2>
                  {post.title.rendered} <span>-></span>
                </h2>
                <div dangerouslySetInnerHTML={{ __html: post.excerpt.rendered }} />
              </Link>
            ))}
          </div>
        </>
      );
    };
    
    export default page;

    Nesse componente atualizado, mapeamos a array de artigos obtidos para gerar uma lista de trechos de artigos. Cada trecho é agrupado em um componente Link para navegação, exibindo o título do artigo e um trecho de seu conteúdo.

    A propriedade dangerouslySetInnerHTML é usada para analisar e renderizar o conteúdo HTML contido no campo excerpt.rendered.

  4. Em seguida, crie um arquivo blog/[id]/page.js no diretório do aplicativo. Você usa pastas para definir rotas. Portanto, ao criar uma pasta blog, você define a rota blog. Você combina isso com o roteamento dinâmico para gerar rotas para cada artigo.
  5. Cada artigo tem um ID. Você usa esse ID para gerar sua rota exclusiva, /blog/{post_id} em seu aplicativo. Você adiciona o seguinte código:
    import Link from 'next/link';
    
    export async function generateStaticParams() {
        const res = await fetch('https://yoursite.com/wp-json/wp/v2/posts');
        const posts = await res.json();
        return posts.map((post) => {
            return {
                params: {
                    id: post.id.toString(),
                },
            };
        });
    }
    
    export async function getPost(id) {
        const response = await fetch('https://yoursite.com/wp-json/wp/v2/posts/' + id);
        const post = await response.json();
        return post;
    }

    A função generateStaticParams() gera rotas estaticamente no momento da compilação com base no ID correspondente retornado em cada artigo. A função getPost() obtém dados do Gutenberg a partir da API REST para o artigo com um ID passado.

    Uma seção anterior mostrou um exemplo de dados do Gutenberg analisados retornados da API REST para um artigo. Por enquanto, estamos preocupados apenas com o campo content.rendered:

    [
      {
        ...
        "content": {
          "rendered" : "\n<p>Fire, a primal force, captivates with its <strong>flickering flames</strong>, evoking both awe and caution. Its <quote>dance</quote> symbolizes destruction and renewal, consuming the old to make way for the new. While it warms our homes and hearts, fire demands respect for its power to devastate.</p>\n\n\n\n<figure> class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"250\" height=\"148\" src=\"https://img.example.com/wp-content/uploads/2024/02/burningbuilding.jpg\" alt=\"\" class=\"wp-image-14\"/></figure>\n\n\n\n<p>In ancient times, fire was a beacon of light and warmth, essential for survival. Today, it remains a symbol of human ingenuity and danger. From the comforting glow of a hearth to the destructive fury of wildfires, fire’s dual nature reminds us of our fragile relationship with the elements.</p>\n\n\n\n<figure> class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https://img.example.com/premium-photo/painting-burning-building-illuminated-by-bright-flames-night_168058-249.jpg?w=1380\" alt=\"\"/></figure>\n\n\n\n<p>You can check out other articles on our blog:</p>\n\n\n\n<ul>\n<li><a> href=\"https://yoursite.com/?p=6\">Lorem Ipsum: Beginnings</a></li>\n\n\n\n<li><a> href=\"https://yoursite.com/?p=9\">Lorem Ipsum: Act 2</a></li>\n\n\n\n<li><a> href=\"https://yoursite.com/?p=11\">Lorem Ipsum: Act 3</a></li>\n</ul>\n"
        },
        ...
      }
    ]

    Esse campo contém o HTML bruto do artigo. Você pode renderizá-lo diretamente usando a propriedade dangerouslySetInnerHTML desta forma, <div dangerouslySetInnerHTML={{ __html: <raw_html_string> }} />.

  6. Em seguida, você pode processar os dados analisando os links internos e redimensionando as imagens. Instale o pacote html-react-parser para simplificar o processo de análise de tags:
    npm install html-react-parser --save
  7. Adicione o seguinte código ao arquivo blog/[id]/page.js:
    import parse, { domToReact } from "html-react-parser";
    
    /*
     * We use a regular expression (pattern) to match the specific URL you want to replace.
     * The (\d+) part captures the numeric ID after ?p=.
     * Then, we use the replacement string 'data-internal-link="true" href="/blog/$1"',
     * where $1 is a placeholder for the captured ID.
     */
    export function fixInternalLinks(html_string) {
      const pattern = /href="https:\/\/yoursite.com\/\?p=(\d+)"/g;
      const replacement = 'data-internal-link="true" href="/blog/$1"';
    
      return html_string.replace(pattern, replacement);
    }
    
    export function parseHtml(html) {
      // Replace 2+ sequences of '\n' with a single '<br />' tag
      const _content = html.replace(/\n{2,}/g, '<br />');
      const content = fixInternalLinks(_content);
    
      const options = {
        replace: ({ name, attribs, children }) => {
          // Convert internal links to Next.js Link components.
          const isInternalLink =
            name === "a" && attribs["data-internal-link"] === "true";
    
          if (isInternalLink) {
            return (
              <Link href={attribs.href} {...attribs}>
                {domToReact(children, options)}
              </Link>
        	  );
          } else if (name === "img") {
            attribs["width"] = "250";
            attribs["height"] = "150";
            return (
              <img {...attribs}/>
            );
          }
        },
      };
    
      return parse(content, options);
    }

    A função fixInternalLinks() usa uma expressão regular para encontrar links para artigos em seu site WordPress a partir da string de caracteres HTML. No HTML bruto, você pode ver que o artigo contém uma tag List com links para outros artigos em seu site, substituindo esses links por links internos para rotas em seu site estático.

    A função parseHTML() localiza várias sequências de novas linhas em excesso, ne as substitui por tags <br />. Ela também localiza links internos e converte as tags de âncora em tags de link. Em seguida, essa função redimensiona as imagens usando atributos de tag.

  8. Para gerar a interface do usuário principal para cada rota dinâmica, adicione o seguinte código:
    export default async function Post({ params }) {
      const post = await getPost(params.id);
    
      const content = parseHtml(post.content.rendered);
    
      return (
        <>
          <h1>
            {post.title.rendered}
          </h1>
     	 
          <div>{content}</div>
        </>
      );
    }

    Depois de analisar o HTML bruto dos dados do Gutenberg, o código retorna JSX representando a interface do usuário (UI) formatada da página.

Por fim, quando você executar seu projeto, a página inicial exibirá uma lista de artigos no seu WordPress. Além disso, ao clicar em artigos individuais, você verá o conteúdo analisado do Gutenberg renderizado corretamente.

Implante seu site estático Next.js na Kinsta

Ao combinar o WordPress headless com frameworks de ponta como o Next.js, encontrar uma solução de implantação econômica se torna essencial, especialmente quando você usa uma hospedagem de sites WordPress poderosa como a da Kinsta para o seu site WordPress. O serviço de Hospedagem de Site Estático da Kinsta oferece uma maneira simples e econômica de colocar seu site on-line.

A Kinsta permite que você hospede até 100 sites estáticos gratuitamente. Primeiro, envie seu código para um provedor Git preferido (Bitbucket, GitHub ou GitLab). Quando seu repositório estiver pronto, siga estas etapas para implantar seu site estático na Kinsta:

  1. Faça login ou crie uma conta para visualizar seu painel MyKinsta.
  2. Autorize a Kinsta com seu provedor Git.
  3. Clique em Sites estáticos na barra lateral esquerda e, em seguida, clique em Adicionar site.
  4. Selecione o repositório e a branch a partir dos quais você deseja implantar.
  5. Atribua um nome exclusivo ao seu site.
  6. Adicione as configurações de build no seguinte formato:
    • Comando build: npm run build
    • Versão do node: 18.16.0
    • Diretório de publicação: out
  7. Por fim, clique em Criar site.

E é isso! Agora você tem um site implantado em poucos segundos. Você receberá um link para acessar a versão implantada do seu site. Posteriormente, você poderá adicionar seu domínio personalizado e o certificado SSL, se desejar.

Como alternativa à hospedagem de site estático, você pode optar por implantar seu site estático com o serviço de Hospedagem de Aplicativos da Kinsta, que oferece maior flexibilidade de hospedagem, uma gama mais ampla de benefícios e acesso a recursos mais robustos – como escalabilidade, implantação personalizada usando um Dockerfile e análises abrangentes que englobam dados históricos e em tempo real. Você também não precisa configurar seu projeto Next.js para renderização estática.

Resumo

Este guia explicou como integrar e analisar o conteúdo do bloco do Gutenberg de forma eficaz como HTML por meio da API do WordPress. Isso torna possível a renderização de qualquer tipo de conteúdo em seu frontend quando você usa o WordPress headless.

Você pode hospedar seu WordPress headless em nosso serviço de hospedagem gerenciada de sites WordPress e implantar seu site estático em nosso serviço de hospedagem de site estático. Isso significa que tudo sobre seu site está em um único painel: MyKinsta.

Ao optar pela Kinsta, você ganha um provedor de hospedagem comprometido com o desempenho e a escalabilidade ideais do seu site, ao mesmo tempo que reforça a segurança com medidas avançadas. Experimente a Kinsta hoje mesmo! Conheça a Kinsta hoje mesmo!

O que você acha do WordPress headless e sua renderização? Você tem uma maneira melhor de integrar os blocos do Gutenberg? Compartilhe suas ideias na seção de comentários!

Jeremy Holcombe Kinsta

Editor de Conteúdo & Marketing na Kinsta, Desenvolvedor Web WordPress e Escritor de Conteúdo. Fora do universo WordPress, eu curto praia, golfe e filmes. Também enfrento problemas de gente alta ;).