Integrar um plugin existente
Por que isto importa
Um plugin que já roda em produção tem usuários reais, um build-zip.sh com convenções próprias e, às vezes, decisões antigas que colidem com o que o v3r-core espera — autoload incondicional, capability hardcoded, um filtro user_has_cap já registrado para outra coisa. Integrar aqui não é seguir a receita do zero (Plugin novo, do zero) do início ao fim; é aplicá-la em cima do que já existe, com atenção redobrada nos pontos em que o legado diverge.
1. Levante o terreno antes de mexer
Antes do primeiro commit, confira quatro coisas no plugin como ele está hoje:
- PHP mínimo declarado — se for menor que 8.2, decida se sobe agora (bloqueante para integrar) ou se a integração espera o bump acontecer numa entrega própria. Não misture os dois numa mesma PR sem dizer isso explicitamente na descrição.
- O plugin já usa Composer? Se não, este é o primeiro pacote a introduzi-lo — os itens 2–4 da trilha do zero valem sem atalho.
- Existe algum filtro
user_has_capjá registrado para outra finalidade (RBAC próprio, outra integração)? Se sim, ele não pode ser substituído pelo dov3r-core— os dois convivem; o dov3r-coreé registrado pela própria biblioteca (item 3) e só intercepta as duas capabilities de licença. - O plugin carrega
vendor/autoload.phpincondicionalmente? Se sim, isso precisa mudar — nenhum ponto do plugin pode depender de o Composer estar presente em runtime (ver item 3).
2. Declare a dependência e configure o Strauss
Mesmos passos 2 e 3 da trilha do zero: v3rtech/v3r-core em require-dev com o repositório vcs, bloco extra.strauss com namespace único do plugin, Strauss como .phar standalone.
Se o plugin já usa Strauss para outra dependência, o bloco
extra.straussjá existe — você só acrescenta"v3rtech/v3r-core"ao arraypackagese ooverride_autoloaddoplugin-update-checker(ver trilha do zero, item 3). Não crie um segundo blocoextra.strauss: o Strauss lê um só, e o namespace/prefixos continuam sendo os que o plugin já usa para as outras dependências prefixadas.
3. Adapte o arranque do plugin
Envolva a instanciação do Bootstrap em class_exists(), exatamente como na trilha do zero (item 4) — mesmo que hoje o plugin sempre tenha o vendor/autoload.php disponível, o comportamento de produção (vendor-prefixed/ gerado só depois de composer run prefix) é o mesmo para todo mundo.
Se o plugin já tinha um filtro
user_has_cappróprio do licenciamento anterior a este (por exemplo, uma integração feita antes da v0.4.0 dov3r-core, quando a biblioteca ainda exigia que o plugin registrasse o filtro), remova-o. Desde a v0.4.0, quem registrauser_has_cappara as capabilities de licença é a própria biblioteca (Bootstrap::withCapabilityDecider()), com a guarda de saída antecipada embutida. Manter os dois filtros registrados ao mesmo tempo não é redundância inofensiva — é o cenário exato que já derrubou um site: um filtro sem a guarda correta, chamado numa ordem que reintroduz o ciclouser_has_cap → user_can → user_has_cap.
4. A tela de licença
Se o plugin já tem uma tela de configurações com abas, a integração mais natural é uma aba nova, não a tela padrão da biblioteca — consuma os quatro endpoints REST internos, com a capability de cada operação vinda do RBAC que o plugin já tem.
Rótulo genérico é uma armadilha conhecida. A tela padrão da biblioteca, sem
withProductName(), se intitula só “Licença” — sem dizer de qual produto. Num site com mais de um plugin da casa instalado, essa entrada genérica é indistinguível das outras. Se optar pela tela padrão mesmo assim, sempre chamewithProductName().
5. Configuração de produção
Mesma regra da trilha do zero (item 6): as constantes compartilhadas V3R_LICENSE_API_URL/V3R_LICENSE_PUBLIC_KEY nunca são definidas pelo plugin, e os defaults de produção vão em constantes de nome próprio.
Se o plugin já tem alguma constante de configuração remota com nome parecido (de uma integração anterior, ou de outro serviço), confira que ela não colide por engano com os dois nomes compartilhados. E se este plugin for o segundo da casa a integrar num site que já tem outro plugin licenciado — o caso mais comum na prática —, é justamente aqui que o guard “as duas vieram, ou nenhuma” precisa estar certo: um
define()condicional mal escrito no primeiro plugin a carregar contamina o segundo (ver detalhe completo na trilha do zero, item 6).
6. Ajuste o build-zip.sh existente
O seu script de build já existe e tem uma ordem própria. Os pontos que precisam ser conferidos, não assumidos:
- O
cp -r vendor-prefixedacontece antes de qualquerdump-autoloadque o script rode dentro do diretório temporário do pacote — se o script achatar o layout (src/includes/virandoincludes/, por exemplo) e reescrevercomposer.jsonlá dentro, a ordem errada quebra com “Could not scan for classes inside "vendor-prefixed/"”, no meio do build. composer installroda de novo, logo antes de cadacomposer prefix— nunca reaproveite ovendor/de uma execução anterior (ver a armadilha dodelete_vendor_packagesna trilha do zero, item 7).- O guard de duas pontas (trilha do zero, item 8) entra como passo novo, se ainda não existir.
7. CI
Se o plugin já tem ci.yml, confira a matriz de PHP — ela precisa cobrir ['8.2', '8.3', '8.4'], e não uma versão mais antiga que o v3r-core não suporta. Se o plugin ainda não tem release.yml disparado por tag, este é o momento de criar um — a publicação manual, sem pipeline, é aceitável só como fallback comprovado (não como rotina).
8. Cadastro e primeira publicação
- Confira que o produto já existe no painel do V3RLicense com o slug exatamente igual à pasta raiz do zip que o plugin gera hoje. Se o plugin nunca foi distribuído como zip com pasta nomeada por slug, esse é o momento de acertar isso — não depois.
- Gere um token de publicação escopado a este produto (Gerenciar tokens de publicação) e configure o secret
V3RLICENSE_PUBLISH_TOKENno repositório. - Faça a primeira publicação de teste manualmente, pela pipeline, antes de considerar a integração concluída — não assuma que passou só porque a suíte automatizada ficou verde. A suíte não confere que o zip final tem a lib prefixada de verdade (ver o guard de duas pontas); só uma publicação real, seguida de conferência no painel, prova isso.
Dicas e armadilhas específicas de migração
- Trabalhar na lib e no plugin ao mesmo tempo, sem publicar tag a cada mudança: adicione temporariamente um repositório
pathnocomposer.jsondo plugin, antes dovcsna lista (o Composer respeita a ordem), apontando para o checkout local doV3RCore-Code, com"options": { "symlink": true }. Nunca comite esse bloco — remova antes do PR e rodecomposer update v3rtech/v3r-corepara voltar à versão travada. class_exists()que só existia por acaso. Um plugin com arranque já defensivo (por outro motivo — Composer sempre foi opcional em runtime, por exemplo) pode parecer já pronto para o item 3. Confira mesmo assim: “já era defensivo” e “está protegido no ponto certo, contra a ausência certa” não são a mesma garantia.LicenseManagerchamado fora do endpoint REST precisa detry/catch. O controller REST já captura a exceção e devolve o código do contrato; uma rotina de diagnóstico ou comando WP-CLI próprio que chame oLicenseManagerdireto recebe a exceção propagada — tela branca, se ninguém capturar.
Checklist antes de abrir o PR
- PHP mínimo do plugin já é 8.2, ou o bump está explicitamente escopado nesta mesma PR (não implícito).
- Nenhum filtro
user_has_capduplicado ou conflitante — o antigo (se existia) foi removido. - Todo ponto que toque o
v3r-coreestá atrás declass_exists()— inclusive onde o plugin já parecia defensivo. - Tela de licença existe e identifica o produto (
withProductName(), se for a tela padrão). V3R_LICENSE_API_URL/V3R_LICENSE_PUBLIC_KEYnão são definidas pelo plugin, mesmo que outro plugin da casa já esteja no mesmo site de teste.build-zip.shexistente ajustado na ordem certa (cópia antes do dump-autoload do pacote) e reinstalando antes de cada prefixação.- Guard de duas pontas presente no build ou na CI.
- Produto cadastrado com slug igual à pasta raiz do zip; token de publicação escopado gerado.
- Uma publicação de teste real foi feita e conferida no painel — não só a suíte verde.
- Testado com usuário autenticado, não só com requisição anônima.