Habilidade de Submissão de Plugin WordPress.org
Faça qualquer plugin passar pela varredura automatizada e revisão manual do wp.org sem
precisar reenviar cinco vezes. Extraído de ciclos de revisão reais (do tipo em que um simples
.gitkeep solitário faz toda a varredura falhar).
Mantenedor: moksa · moksaweb.com · Licença: MIT
Quando usar
Acione esta habilidade quando o usuário pedir para:
- Empacotar / construir um zip de instalação limpo para o wordpress.org
- Submeter ou ressubmeter um plugin ao diretório wp.org
- Corrigir feedback da equipe de revisão do wp.org (as 4 categorias clássicas)
- Diagnosticar uma rejeição da varredura automatizada (arquivos ocultos, prefixos, chamadas a banco…)
- Atualizar a versão de um plugin de forma consistente (cabeçalho + readme + constantes)
- Pré-verificar um plugin antes do envio
NÃO use para:
- Projetos que não são WordPress
- Plugins privados/internos que nunca irão para o wp.org (as regras de revisão não se aplicam, embora as práticas de segurança ainda ajudem)
Os dois portões
- Varredura automatizada (Plugin Check, executada no upload) — bloqueios rígidos. Deve ser aprovada para
sequer chegar a um humano. Veja
references/automated-scan.md. - Revisão manual (um humano, após a varredura passar) — envia problemas por e-mail, você corrige + responde.
Quase sempre uma de 4 categorias de código (
references/review-categories.md) mais diretrizes de política que nenhum linter captura — licenciamento, código remoto, rastreamento, incômodos administrativos, marcas registradas, divulgação de serviço externo (references/guidelines.md).
Mapa de referências
| Tópico | Arquivo |
|---|---|
| Plugin Check (PCP) — manual UI/CLI, todas as 31 verificações → mapa de correção, erros vs avisos | references/plugin-check.md |
| Bloqueios rígidos da varredura automatizada (arquivos ocultos, BD, chamadas proibidas) | references/automated-scan.md |
| As 4 categorias de revisão manual + frases para resposta | references/review-categories.md |
| Lições de revisões reais (exemplo→varredura total, nonce de 3 casos, phpcs:ignore≠escape, cast≠sanitize, caminhos, prefixos de fork) | references/real-review-lessons.md |
| Prefixação de todo global (funções/opções/hooks/handles/CPT/meta…) | references/prefixing.md |
Sanitizar · validar · escapar + $wpdb->prepare + assinaturas de webhook | references/sanitization-escaping.md |
| Enfileirar JS/CSS (deps/versão, inline, controle, blocos, sem tags cruas) | references/enqueue.md |
| i18n (textdomain==slug, strings literais, comentários para tradutores, JS) | references/i18n.md |
| Capacidades & callbacks de permissão (autorização, REST, priv/nopriv) | references/capabilities.md |
| Diretrizes de política (licença, código remoto, rastreamento, incômodos, marcas registradas, divulgação) | references/guidelines.md |
| Formato readme.txt (cabeçalhos, tags≤5, desc curta≤150, screenshots, Serviços externos) | references/readme-txt.md |
| API de Habilidades · Cliente de IA · MCP (autorização por habilidade, fronteira de dados, confirmação destrutiva, divulgação de provedor) | references/abilities-ai-mcp.md |
| Extras de segurança (arquivos/WP_Filesystem, uploads, SSRF, chamadas proibidas/ofuscadas) | references/security-extras.md |
| Desinstalação & ciclo de vida (limpeza de dados, não excluir conteúdo do usuário, multissite) | references/uninstall.md |
| Empacotamento do zip + consistência de versão/cabeçalho/readme + .mo | references/packaging.md |
| Consulta de código → correção (Scan/PHPCS) | data/plugin-check-errors.csv |
Lista de verificação rápida pré-upload (copie e cole para verificar)
VARREDURA AUTOMATIZADA (bloqueios rígidos)
[ ] Nenhum arquivo oculto no zip: `find . -name '.*' -not -name '.' -not -name '..'` está VAZIO
(.gitkeep / .gitignore / .DS_Store / .editorconfig todos falham em "hidden_files")
[ ] Sem node_modules/, .git/, tests/, scripts/, phpcs.xml, webpack.config.js no zip
[ ] Todos os globais do plugin usam um prefixo único >=4 caracteres (sem wp_ / __ / _ único)
[ ] Nenhuma consulta $wpdb direta sem prepare(); nenhuma execução remota de código; nenhum phone-home
REVISÃO MANUAL (as 4 categorias)
[ ] Enfileiramento: sem echo cru '<script>'/'<style>'; wp_enqueue_* + wp_add_inline_*
[ ] Nonce + current_user_can em toda AJAX/admin_post que altera estado; webhooks verificam
assinatura do provedor com hash_equals antes de usar (nonce WP não é possível)
[ ] Cada $_POST/$_GET sanitizado (wp_unslash + sanitize_*); json_decode -> map_deep;
saída escapada tardiamente (esc_html/esc_attr/esc_url/wp_kses)
[ ] textdomain == slug; __() argumentos são strings literais; /* translators: */ antes de %s
POLÍTICA (revisão manual, nenhum linter captura — references/guidelines.md)
[ ] Licença compatível com GPL declarada + arquivo LICENSE; cada biblioteca/recurso agrupado compatível com GPL
[ ] Sem execução remota de código / sem carregar JS executável de um CDN; agrupar assets localmente
[ ] Qualquer chamada de API de terceiros divulgada no readme "== Serviços externos ==" (quais dados, quando, URLs)
[ ] Sem coleta/rastreamento de dados sem aceite explícito (padrão DESLIGADO); sem link de crédito
no front-end a menos que aceite; notificações administrativas dispensáveis + restritas à tela (sem spam de notificações)
[ ] Slug/nome não começa com uma marca registrada que você não possui (woocommerce-… / google-…)
README.TXT (references/readme-txt.md — valide no validador de readme do wp.org)
[ ] Cabeçalho interpreta: Contribuidores=nomes de usuário wp.org, Tags<=5, Stable tag = versão real enviada
[ ] Descrição curta <=150 caracteres, texto simples; Changelog tem uma entrada para a Stable tag
[ ] Screenshots/banner/ícone vão no SVN /assets/, NÃO no zip
IA / HABILIDADES / MCP (se o plugin registra habilidades, chama um LLM ou expõe MCP)
[ ] Cada wp_register_ability tem um permission_callback real (cap em nível de objeto), não __return_true
[ ] Fronteira de dados: uma ferramenta de habilidade/MCP retorna apenas o que as capacidades do usuário atual permitem
[ ] Entrada de modelo/agente tratada como não confiável; habilidades destrutivas protegidas por confirmação
[ ] SDK de LLM/IA agrupado (GPL); provedor divulgado em == Serviços externos ==; chaves nunca registradas
[ ] Endpoint MCP autentica (Senha de aplicativo/OAuth) E executa o permission_callback de cada habilidade
SEGURANÇA EXTRA + CICLO DE VIDA
[ ] Sem eval/shell/ofuscação/extract; sem var_dump/print_r/error_log deixados
[ ] Arquivos via WP_Filesystem apenas para uploads; uploads via wp_handle_upload + lista branca MIME
[ ] Chamadas remotas via wp_safe_remote_* (SSRF: bloquear intervalos internos) + timeout + verificação de resposta
[ ] uninstall.php protegido por WP_UNINSTALL_PLUGIN; remove apenas seus dados prefixados; nunca conteúdo do usuário
PACOTE + METADADOS
[ ] Versão sincronizada: cabeçalho Version do arquivo principal, constante de versão, readme Stable tag, Changelog
[ ] Cabeçalhos Requires correspondem TANTO no arquivo principal QUANTO no readme.txt (WP / PHP / WC) — e qualquer
constante MIN_* em tempo de execução que controle a ativação
[ ] vendor/ é `composer install --no-dev` (sem squizlabs/phpunit/phpcompatibility)
[ ] Nome da pasta raiz do zip == slug do plugin
Fluxo de trabalho
- Leia as regras para a tarefa (veja o Mapa de referências acima) — comece com
references/automated-scan.md+references/review-categories.md, depois o mergulho profundo que corresponde ao achado (prefixing.md/sanitization-escaping.md/enqueue.md/i18n.md) ereferences/packaging.mdpara a construção. - Construa o zip limpo — execute
scripts/build-zip.sh(lida com git archive, remove arquivos de desenvolvimento + TODOS os arquivos pontilhados, instalavendor/--no-dev, zipa com o slug como raiz). Nunca zipe manualmente a árvore de trabalho; é assim que lixo de desenvolvimento e arquivos pontilhados vazam. - Pré-verifique — execute
scripts/preflight.sh <caminho-para-zip-ou-dir>: varre arquivos ocultos, verifica consistência de versão + cabeçalho/readme, executa PHPCS se configurado. Corrija até ficar limpo. - Execute Plugin Check (PCP) — a ferramenta oficial que executa as próprias verificações automatizadas
do diretório localmente.
wp plugin check <slug> --require=./wp-content/plugins/plugin-check/cli.php(ou Ferramentas → Plugin Check). Corrija cada ERRO, revise cada AVISO. Vejareferences/plugin-check.mdpara todas as 31 verificações, flags e qual capítulo da habilidade corrige cada. - Envie. Se a varredura automatizada rejeitar → leia o código exato, mapeie via
data/plugin-check-errors.csv, corrija, reconstrua, reenvie. - Resposta à revisão manual — quando o revisor enviar problemas por e-mail, corrija cada um em todo lugar (os
exemplos são uma amostra — faça grep em toda a árvore, execute Plugin Check + PHPCS sobre todo o
plugin; a mesma categoria recorrente = rejeição imediata). Depois responda ponto a ponto
referenciando o que mudou. Veja
references/review-categories.mdpara correções canônicas + frases de resposta ereferences/real-review-lessons.mdpara os comandos de varredura por categoria e as armadilhas que sobrevivem a uma primeira correção.
Pegadinhas duramente conquistadas (as caras)
.gitkeepfalha na varredura automatizada. É um arquivo oculto. Remova todo arquivo pontilhado do pacote; remova.gitkeepdo git para quegit archivenunca o readicione.- Derivação de versão Requerida. wp.org lê o cabeçalho do arquivo principal E o readme.txt; uma constante
MIN_WC/MIN_PHPem tempo de execução pode controlar a ativação separadamente. Todos os três devem concordar, ou um usuário com uma versão muito baixa instala com sucesso e depois encontra recursos quebrados. - Webhooks não podem usar nonces do WP. Revisores marcam "sem nonce" em manipuladores IPN — isso é um
falso positivo; a resposta correta é verificação de assinatura do provedor com
hash_equals(). Documente com umphpcs:ignorepor linha + motivo. json_decodenão é sanitização. Sempre apliquemap_deep(sanitize_text_field)no resultado.composer install(sem--no-dev) vaza phpcs/phpunit para vendor/ → pacote inchado e sinalizado. Sempre use--no-devpara o zip enviado.