DEV Community

Cover image for Criando Blocos Gutenberg Nativos com React (e como usar IA para acelerar o processo)
Carlos Rogerio Orioli
Carlos Rogerio Orioli

Posted on

Criando Blocos Gutenberg Nativos com React (e como usar IA para acelerar o processo)

Este tutorial mostra como criar um bloco Gutenberg nativo — sem depender do ACF — usando React puro, do zero até o build final. Na segunda parte, explico como usar um agente de IA com skills (arquivos de conhecimento reutilizáveis) e um harness (o "motor" que executa o agente em loop, com ferramentas) para acelerar esse tipo de desenvolvimento no dia a dia.


Parte 1 — Criando o bloco nativo

1. Pré-requisitos

  • Node.js instalado
  • Um tema ou plugin WordPress local para testar
  • @wordpress/scripts, o toolchain oficial que compila JSX sem você precisar configurar Webpack/Babel manualmente

2. Estrutura de pastas

Vamos criar um bloco de "Depoimento" (testimonial), 100% React, sem PHP de render.

my-plugin/
├── my-plugin.php
├── package.json
└── src/
    └── testimonial/
        ├── block.json
        ├── index.js
        ├── edit.js
        ├── save.js
        └── editor.scss
Enter fullscreen mode Exit fullscreen mode

3. Inicializando o projeto

mkdir my-plugin && cd my-plugin
npm init -y
npm install @wordpress/scripts --save-dev
Enter fullscreen mode Exit fullscreen mode

No package.json, adicione os scripts de build:

{
  "scripts": {
    "build": "wp-scripts build",
    "start": "wp-scripts start"
  }
}
Enter fullscreen mode Exit fullscreen mode

4. block.json

Aqui definimos os attributes são os dados que o próprio Gutenberg gerencia e salva dentro do post_content:

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "my-plugin/testimonial",
  "title": "Depoimento",
  "category": "widgets",
  "icon": "format-quote",
  "description": "Bloco de depoimento em React puro.",
  "textdomain": "my-plugin",
  "attributes": {
    "autor": { "type": "string", "default": "" },
    "cargo": { "type": "string", "default": "" },
    "depoimento": { "type": "string", "default": "" }
  },
  "supports": {
    "html": false
  },
  "editorScript": "file:./index.js",
  "editorStyle": "file:./editor.css",
  "style": "file:./style.css"
}
Enter fullscreen mode Exit fullscreen mode

5. edit.js — a interface no editor

import { useBlockProps, RichText } from '@wordpress/block-editor';

export default function Edit({ attributes, setAttributes }) {
  const { autor, cargo, depoimento } = attributes;
  const blockProps = useBlockProps({ className: 'testimonial-edit' });

  return (
    <div {...blockProps}>
      <RichText
        tagName="p"
        placeholder="Escreva o depoimento..."
        value={depoimento}
        onChange={(val) => setAttributes({ depoimento: val })}
      />
      <RichText
        tagName="strong"
        placeholder="Nome do autor"
        value={autor}
        onChange={(val) => setAttributes({ autor: val })}
      />
      <RichText
        tagName="span"
        placeholder="Cargo"
        value={cargo}
        onChange={(val) => setAttributes({ cargo: val })}
      />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

6. save.js — o que vira HTML final salvo no post

Isso substitui totalmente o render.php. O output desse componente é serializado e gravado em post_content no momento de salvar/publicar.

import { useBlockProps, RichText } from '@wordpress/block-editor';

export default function save({ attributes }) {
  const { autor, cargo, depoimento } = attributes;
  const blockProps = useBlockProps.save({ className: 'testimonial' });

  return (
    <div {...blockProps}>
      <blockquote>
        <RichText.Content tagName="p" value={depoimento} />
        <footer>
          <RichText.Content tagName="strong" value={autor} />
          {cargo && <RichText.Content tagName="span" value={` — ${cargo}`} />}
        </footer>
      </blockquote>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

7. index.js — registro

import { registerBlockType } from '@wordpress/blocks';
import Edit from './edit';
import save from './save';
import metadata from './block.json';
import './editor.scss';

registerBlockType(metadata.name, { edit: Edit, save });
Enter fullscreen mode Exit fullscreen mode

8. Registrando o bloco no PHP

<?php
/**
 * Plugin Name: My Plugin — Testimonial Block
 */

add_action('init', function () {
    register_block_type(__DIR__ . '/build/testimonial');
});
Enter fullscreen mode Exit fullscreen mode

Note que aponta para build/, não para src/ — é ali que o wp-scripts build gera os arquivos compilados.

9. Build

npm run build
Enter fullscreen mode Exit fullscreen mode

Ative o plugin no WordPress, abra o editor e o bloco "Depoimento" já aparece no inserter, pronto pra usar — sem nenhum PHP intermediando o render.

10. Indo além

A partir daqui, as extensões mais comuns são:

  • Imagem: attribute do tipo object guardando { url, id, alt }, usando MediaUpload
  • Repeater (lista de itens): attribute do tipo array, renderizado com .map() tanto no edit.js quanto no save.js
  • InnerBlocks: permitir que outros blocos sejam aninhados dentro do seu

Parte 2 — Usando IA (skills + harness) para acelerar esse trabalho

Quando você usa um agente como o Claude Code para esse tipo de tarefa, vale entender dois conceitos que mudam bastante a qualidade do resultado: harness e skills.

O que é o "harness"

O harness é o programa que roda o agente em loop: ele manda o prompt pro modelo, recebe de volta uma decisão (rodar um comando, editar um arquivo, ler algo), executa essa ação de verdade no seu sistema, devolve o resultado pro modelo, e repete — até a tarefa terminar. É a "carroceria" em volta do modelo: dá acesso a terminal, sistema de arquivos, git, etc. Sem harness, o modelo só conversa; com harness, ele efetivamente cria pastas, roda npm run build, edita block.json, testa e corrige.

Na prática, isso significa que pra um bloco Gutenberg você pode literalmente pedir "cria um bloco nativo de FAQ com repeater de perguntas e respostas, registra no plugin e roda o build" — e o agente executa passo a passo, igual você faria manualmente, mas sozinho.

O que são "skills"

Skills são arquivos de instrução (SKILL.md) que ficam disponíveis pro agente e são carregados automaticamente quando relevantes. Cada skill documenta um domínio específico — convenções do seu time, padrões de código, checklist de revisão, como aquele projeto em particular estrutura os blocos.

Para o seu caso de blocos Gutenberg + WordPress, uma skill útil poderia registrar:

  • A estrutura de pastas que seu time usa (src/blocks/<nome>/...)
  • Se vocês preferem SCSS ou CSS puro, apiVersion padrão, categoria default
  • Convenção de nomenclatura (meu-tema/nome-do-bloco)
  • Se o projeto usa ACF em paralelo (para blocos que precisam de campo global via post meta) e quando usar cada abordagem
  • Trechos de código de referência (exemplo de bloco com InnerBlocks, exemplo com upload de imagem) que o agente deve seguir como modelo

Isso transforma o agente de "sabe Gutenberg em geral" para "sabe exatamente como o seu projeto faz Gutenberg" — reduzindo o retrabalho de revisar código que não segue o padrão do time.

Fluxo prático sugerido

  1. Escreva uma skill descrevendo os padrões do seu projeto de blocos (pode ser gerada com apoio do próprio agente, revisando blocos já existentes no repositório)
  2. Peça a criação de um novo bloco em linguagem natural, descrevendo os campos e comportamento
  3. O agente, com a skill carregada e o harness executando comandos, cria a pasta, o block.json, edit.js, save.js, registra no PHP e roda o build
  4. Você revisa o diff (como revisaria um PR de qualquer dev) antes de commitar

Esse combo — harness pra executar e skill pra manter o padrão do projeto — é o que faz a diferença entre "gerar código genérico de Gutenberg" e "gerar código que já nasce do jeito que o seu time trabalha".


Resumo

Sem IA Com harness + skill
Criar estrutura do bloco Manual, arquivo por arquivo Agente cria tudo de uma vez, seguindo padrão do projeto
Consistência entre blocos Depende de disciplina do time Skill garante convenção fixa
Build e teste Você roda os comandos Agente roda e corrige erros de build sozinho
Revisão Você revisa o diff antes do commit, como um PR normal

Top comments (0)