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
3. Inicializando o projeto
mkdir my-plugin && cd my-plugin
npm init -y
npm install @wordpress/scripts --save-dev
No package.json, adicione os scripts de build:
{
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start"
}
}
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"
}
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>
);
}
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>
);
}
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 });
8. Registrando o bloco no PHP
<?php
/**
* Plugin Name: My Plugin — Testimonial Block
*/
add_action('init', function () {
register_block_type(__DIR__ . '/build/testimonial');
});
Note que aponta para build/, não para src/ — é ali que o wp-scripts build gera os arquivos compilados.
9. Build
npm run build
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
objectguardando{ url, id, alt }, usandoMediaUpload -
Repeater (lista de itens): attribute do tipo
array, renderizado com.map()tanto noedit.jsquanto nosave.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,
apiVersionpadrã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
- 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)
- Peça a criação de um novo bloco em linguagem natural, descrevendo os campos e comportamento
- 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 - 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)