Skip to content

Latest commit

History

15 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

CVSync

Sincronização bidirecional entre o conteúdo Gutenberg no banco de dados e arquivos versionados no repositório git (content/). O banco é a autoridade em tempo de edição; o repositório é a autoridade de transporte entre ambientes (spec: cvsync v1 + Apêndice A).

O que faz

  • Export (banco → arquivo): edições no admin marcam a entidade como dirty e o export acontece no shutdown do request, lendo o estado final do banco (debounce natural). Arquivos canônicos: frontmatter YAML + corpo de blocos, com placeholders no lugar de IDs internos ({{ref:slug}}, {{attachment:slug}}, {{attachment_url:slug}}, {{term:taxonomy:slug}}, {{home_url}}).
  • Apply (arquivo → banco):wp sync apply aplica o conteúdo do repositório no banco, com detecção de conflitos (3-way por hash), preservação do lado perdedor, snapshot pré-apply e audit log.
  • Entidades versionadas: páginas, padrões (wp_block), templates e template parts, navegações (wp_navigation), menus, global styles, branding (logo/ícone do site), anexos de mídia (sidecar + blob) e — opcional, desligado por default — termos de taxonomia (Apêndice B).
  • Ambientes: matriz normativa por ambiente (local/staging/homolog/prod) — em produção, apply e export automáticos ficam OFF (apply manual exige --force + TTY + CVSYNC_ALLOW_PROD_APPLY).

Instalação

  1. Copie plugins/cvsync/ para wp-content/plugins/ (ou monte como submódulo git).
  2. Opcional:composer install dentro do diretório do plugin (instala symfony/yaml e o autoloader otimizado). Sem vendor/, o plugin funciona com o autoloader próprio de fallback e o parser YAML interno.
  3. Ative o plugin. A ativação:
    • verifica a pré-condição dura: todo post type versionado precisa de suporte a revisions (exceção: attachment);
    • instala as tabelas wp_cvsync_state, wp_cvsync_conflicts, wp_cvsync_log;
    • executa a sonda PHP-off de uploads (.htaccess/sonda HTTP em CLI) — falha gera admin notice crítico, sem bloquear a ativação.
  4. Instale os git hooks: wp sync install-hooks.
  5. Defina o ambiente via WP_ENVIRONMENT_TYPE (core) e, quando necessário, CVSYNC_ENVIRONMENT (única porta para homolog).

Constantes CVSYNC_*

Precedência: constante em wp-config.php > variável de ambiente > default. Nenhuma flag vive no banco (options viajam com dumps). Valor inválido em qualquer constante → default fail-safe + admin notice (nunca silencioso).

ConstanteValoresDefaultNotas
CVSYNC_ENVIRONMENTlocal | staging | homolog | prodderivado de wp_get_environment_type(); desconhecido → prod (fail-closed)homolog só via constante explícita
CVSYNC_CONFLICT_WINNERdb | filepor ambiente (matriz §7.3)CI staging define file no job
CVSYNC_DEPLOY_GATEwarn | haltwarnhalt = apply falha em conflito (exit 2)
CVSYNC_ALLOW_PROD_APPLYtrueausente = negadopré-condição de --force em prod
CVSYNC_IMPORT_USERlogin ou IDprimeiro administradorusuário técnico do import
CVSYNC_CONTENT_DIRpath<repo-root>/contentdetecção: primeiro ancestral do plugin com .git; fallback dirname(ABSPATH). Nunca em tema/plugin/uploads
CVSYNC_FILE_MODE / CVSYNC_DIR_MODEoctal0664 / 0775nunca depender de umask de request
CVSYNC_ATTACHMENT_MAX_BYTESbytes10485760 (10 MB)teto único de anexo
CVSYNC_ATTACHMENT_MIME_TYPESlista CSVimage/jpeg,image/png,image/webp,image/gif,application/pdfallowlist estática (interseção com get_allowed_mime_types())
CVSYNC_ATTACHMENT_ALLOW_SVGtrue | falsefalse (default-deny)opt-in de SVG; exige sanitizador (§A.9.3)
CVSYNC_ATTACHMENT_SCOPEreferenced | allreferencedall exporta todo upload; typo NUNCA vira all silencioso
CVSYNC_SNAPSHOT_KEEPint10retenção de snapshots pré-apply
CVSYNC_SNAPSHOT_MAX_BYTESbytes536870912 (512 MB)teto de disco com purge LRU
CVSYNC_TOMBSTONE_TTL_DAYSint90retenção de tombstones

cvsync.json × constantes CVSYNC_*

São duas superfícies de configuração com papéis distintos (§A.13.10):

  • Constantes configuram o runtime (apply/export dentro do WordPress).
  • cvsync.json (na raiz do repo) configura o lint de CI (bin/cvsync-lint.php) — o CI não lê wp-config.php.

O apply loga warning quando a config do lint e as constantes divergirem. Mantenha as duas em sincronia (mesmos limites de tamanho/MIME).

Post types versionados

A estrutura de site versionada por default (posts de conteúdo comum não são versionados):

Post typeDiretório em content/Extensão
pagepages/.page.html
wp_block (padrões)patterns/.pattern.html
wp_templatetemplates/.template.html
wp_template_parttemplates/parts/.template-part.html
wp_navigationnavigation/.navigation.html

Adicionando CPTs — filtro cvsync/post_types

add_filter('cvsync/post_types', fn () => [
'projeto', // forma simples: defaults derivados'institucional' => [ // forma associativa: sobrescreve campos'dir' => 'site/institucional',
'ext' => '.inst.html',
'stage' => 3,
'meta' => ['_thumbnail_id', '_wp_page_template', 'destaque'],
],
]);

Campos da forma associativa:

CampoControlaDefault derivado
dirDiretório em content/{type}s
extExtensão do arquivo.{type}.html
stageEstágio de aplicação (deps: 1 blocos/navegação, 2 templates, 3 páginas/CPTs)3
statusesStatuses versionados['publish', 'draft', 'private']
metaAllowlist de meta no payload/hash['_thumbnail_id']
identity_taxonomiesTaxonomias cujos termos entram no payload do post[]

Pré-condição dura: revisions (§3.2)

Todo post type versionado precisa de suporte a revisions — o plugin recusa operar sem isso (erro claro na ativação e no verify): registre o CPT com supports => ['title', 'editor', 'revisions', ...] ou, para CPT alheio já registrado, add_post_type_support('projeto', 'revisions').

Conteúdo existente

Post type adicionado em projeto com conteúdo já criado: os posts aparecem como untracked no verify até rodar wp sync export (a "adoção" gera o uuid e exporta os arquivos canônicos).

Meta versionado (allowlist) por post type

Só o meta na allowlist do post type entra no payload canônico e no hash (§3.3). Defaults:

Post typeMeta versionado
page_wp_page_template, _thumbnail_id
CPTs adicionados via config/filtro_thumbnail_id
wp_block / wp_template / wp_template_part / wp_navigation / wp_global_stylesnenhum — a estrutura vive em taxonomias identitárias, não em meta

Como ampliar — filtro cvsync/meta_allowlist (forma canônica):

add_filter('cvsync/meta_allowlist', function (array$meta, string$postType) {
if ($postType === 'page') {
$meta[] = '_meu_plugin_config'; // meta custom do seu plugin
}
return$meta;
}, 10, 2);

Ampliar a allowlist muda o hash das entidades afetadas → elas aparecem como dirty_db no próximo ciclo e são re-exportadas normalmente. Nada quebra; é o mesmo fluxo de qualquer edição de conteúdo.

  • Storage próprio (Pods table-based, ACF fora da Meta API): fora por padrão — meta que não passa pela Meta API do WP não é visto. Use o filtro cvsync/meta_providers (§3.3) com callables fn (int $postId, string $type): array (o retorno é mesclado ao payload/hash); o wp sync verify emite warning quando detecta campos table-based conhecidos fora da allowlist.
  • Terminologia: o projeto usa allowlist/denylist (nunca whitelist/blacklist) — a deny-list de taxonomias do Apêndice B (B.1.2) segue o mesmo vocabulário.
  • Nomes antigos dos filtros:cvsync/meta_whitelist e cvsync/term_meta_whitelist ainda funcionam como fallback deprecated (usados somente quando o nome novo não tem callback registrado) — serão removidos; migre para os nomes com allowlist.

identity_taxonomies × taxonomias versionadas

São coisas diferentes: identity_taxonomies define termos que entram no payload/hash do post (associação — ex.: wp_pattern_category nos padrões); taxonomia versionada como entidade (definição do termo em content/terms/) é opt-in via cvsync/taxonomies — ver seção Termos de taxonomia (Apêndice B).

Attachments

Anexos de mídia não se configuram por este filtro: são entidade própria (Apêndice A, escopo referenced — ver CVSYNC_ATTACHMENT_* na tabela de constantes).

Painel de configuração (Ferramentas → CVSync → Configuração)

Tela admin (manage_options) para configurar escopo e comportamento de import — o que continua fora dela é decisão de deploy/CLI. Tudo persiste na option única cvsync_settings (taxonomies, post_types, lock_imports, auto_import).

  • Ambiente (read-only): box no topo mostra o ambiente efetivo (local/staging/homolog/prod) e a política resultante (apply/import e export: ON/OFF). Não é editável na tela por norma (§7.1/§10.1): ambiente é fail-closed via wp-config.php/env (WP_ENVIRONMENT_TYPE ou CVSYNC_ENVIRONMENT) — uma option viajaria num dump de banco; em prod o box é um aviso fail-closed explícito (apply manual só com triplo fator).
  • Bloquear importações neste ambiente (lock_imports): recusa comandos e handlers de import no ambiente. Só sabe restringir — se a option viajar num dump, o destino fica bloqueado, nunca liberado (fail-closed por direção). Em prod o toggle fica desabilitado (a matriz §7.3 já bloqueia).
  • Importação automática ao detectar mudanças no repositório (auto_import): habilita o check passivo de HEAD-hash + reconcile agendado. Em prod: desabilitado (matriz manda OFF; a option é inócua num dump).
  • Taxonomias sincronizadas: checkboxes das taxonomias públicas; a deny-list do Apêndice B (nav_menu, wp_theme, wp_pattern_category, wp_template_part_area, link_category, post_format) aparece desabilitada com o motivo. O filtro cvsync/taxonomies do código continua valendo (união com o marcado na tela).
  • Post types sincronizados: os defaults (estrutura de site) aparecem marcados e travados; os demais públicos são opcionais — sem suporte a revisions o checkbox fica desabilitado com o motivo (§3.2). União com o filtro cvsync/post_types. Attachments não se configuram aqui (Apêndice A).

Exportar / importar conteúdo (.zip)

Botões na mesma tela (handlers em admin-post.php, nonce cvsync_io):

  • Export: empacota o content/ atual para download. Liberado em qualquer ambiente (read-only). Use para capturar conteúdo de um ambiente sem git ou para transferência manual.
  • Import: upload de um zip com o content/ de outro ambiente — o zip é input de terceiro e atravessa a mesma fronteira de um PR, então a validação roda antes de qualquer byte tocar o content dir ativo: teto de 200 MB (físico e descompactado — zip bomb), varredura de path traversal/symlinks/executáveis, allowlist de subdirs/extensões, validação de conteúdo (frontmatter, anti-regressão §6.2, magic bytes dos blobs), teto de ~50 entidades, extração em tmp, backup do content/ atual e swap atômico (rename); falha pós-backup restaura o backup automaticamente. O resultado do apply (aplicados/ignorados/conflitos/erros) volta como notice na tela.
  • Quando usar CLI: ambientes com o content dir em FS imutável, lotes grandes que precisem de --batch, e qualquer operação fora da fronteira admin — a CLI é o caminho canônico (§8.3).

Ressalva operacional (import via web): o swap atômico usa rename no diretório pai do content dir — em ambientes docker com bind mount, o www-data precisa de permissão de escrita nesse pai (no projeto-base o compose alinha o uid via WWW_DATA_UID). Sem isso, o import falha com a mensagem acionável (via wp-cli/root funciona).

Termos de taxonomia (Apêndice B)

Versionamento opcional da definição editorial de termos (name, slug, description, parent por slug e meta da allowlist). Desligado por default: nada é versionado até o projeto optar via filtro cvsync/taxonomies (B.1.1):

add_filter('cvsync/taxonomies', fn () => [
'category' => ['dir' => 'categories'],
'projeto_tag' => [], // item com valor simples: defaults derivados
]);
  • Item com valor simples → defaults: diretório {taxonomy}s e allowlist de meta ['thumbnail_id']; item associativo sobrescreve (dir, meta).
  • Deny-list (erro claro na ativação): nav_menu, wp_theme, wp_pattern_category, wp_template_part_area, link_category, post_format e taxonomias não-públicas.
  • Um arquivo por termo, layout plano (hierarquia é campo, não path): content/terms/{dir}/{slug}.term.yml:
# content/terms/categories/noticias.term.ymluuid: 018f4b2e-7c3a-7d4e-9a1f-5e7c9b2d1e44 # identidade (termmeta _cvsync_uuid) — NUNCA no hashtaxonomy: category # hash: entraslug: noticias # hash: entraname: "Notícias"# hash: entradescription: "Conteúdo jornalístico"# hash: entraparent: null # hash: entra — SLUG do pai, nunca term_idmeta:
thumbnail_id: "{{attachment:logo}}"# placeholderizado (§A.6)hash: sha256:9f2c71ab… # derivado — última linha
  • A associação post↔termo continua no frontmatter do post (ortogonal à definição do termo — B.6.1); terms são aplicados no estágio 0, antes dos posts.
  • Export bulk: wp sync export --taxonomy=<tax> (sem flag = todas as taxonomias versionadas).
  • Erratas à spec v1: E2-bis (updates de count e edited_term_taxonomies ficam fora do dirty-marking — import não suja a fila) e E5-bis (delete de termo não tem trash — a rede de segurança é git + conflicts + tombstone + dirty-mark reverso).

Regras de ouro

  • content/** é artefato gerado que é versionado: nunca editar à mão. Mudanças manuais serão perdidas no próximo export (§12.2).
  • O plugin nunca roda git no runtime web, nunca commita, nunca escreve em .git.
  • Commit de conteúdo é decisão humana: edite no admin → export automático → git add content/... && git commit → PR com review humano do diff.
  • Um worktree ↔ um banco/ambiente WP.
  • Nunca force-push em branch compartilhada de conteúdo.

CLI (contrato §8.3)

Todos os comandos vivem no namespace wp sync. Neste projeto, rode dentro do container:

docker compose exec -T wordpress wp sync <comando>

Convenções gerais (de CommandBase, aplicam-se a quase todos):

  • --format=json emite saída estruturada (uma linha JSON por item + resumo);
  • constantes CVSYNC_* com valor inválido geram warning no início de qualquer comando (nunca passam silenciosas);
  • comandos de mutação (apply, bootstrap, resolve, restore) respeitam a matriz de ambientes: em local/staging/homolog são livres via CLI; em prod exigem o triplo fator (--force + TTY interativo + CVSYNC_ALLOW_PROD_APPLY=true) — stdin não-TTY é recusado;
  • export, plan, verify, status, log, blame, conflicts são read-only no banco e livres em qualquer ambiente (inclusive prod).

Tabela-resumo

ComandoO que fazMutação?Exit codes
applyReconcilia arquivos → bancosim0 ok · 1 falha/recusa · 2 deploy_gate=halt com conflito · 3 migration pendente
planDry-run do plano completonão0 ok · 1 erro de plano · 3 migration pendente
exportExporta banco → arquivos (bulk/filtros)não (banco)0 ok · 1 erro ou diff no --check · 3 migration pendente
bootstrapSeed inicial da state tablesim0 ok · 1 falhas · 3 migration pendente
verifyRecalcula hashes dos dois lados × statenão0 convergente · ≠0 divergência
statusVisão geral do sync no ambientenão0 sempre
logAudit trail recentenão0 sempre
blame"Por que esta entidade mudou?"não0 sempre
conflictsLista conflitos pendentes / prunenão / prune0 ok · 1 erro
conflict showDespeja o payload do lado perdedornão0 ok · 1 id inexistente
resolveResolução manual de conflitosim0 ok · 1 erro/sem pendente
rebaseRe-alinha state sem aplicar mudançasstate apenas0 ok · 1 erros
restoreRe-aplica snapshot pré-applysim0 ok · 1 snapshot inexistente
install-hooksAponta git para .githooks/git config0 ok · 1 sem git/.githooks
purge-revisionsRemove revisions antigas (com retenção)sim (seguro)0 sempre
attachments gcGC de blobs do repo / arquivos de uploadsdry-run default0 sempre

Reconciliação

wp sync apply

Aplica o conteúdo do repositório no banco (arquivo → banco). Detecta conflitos 3-way por hash, preserva o lado perdedor na tabela de conflitos, tira snapshot pré-apply e registra tudo no audit log. Entidades com editor lock ativo são puladas (skipped-locked — conta como falha para o exit code; o retry é natural no próximo checkpoint).

FlagDescriçãoDefault
--dry-runSimula sem escrever (equivale ao plan, com gates de ambiente desligados)off
--force1º fator do apply em prodoff
--force-locksSobrescreve entidades com editor lock — só com TTY interativooff
--delete / --force-deleteAutoriza deleções pendentes (respeitam a política do ambiente: trash em local/staging; homolog é trash-only e recusa --force-delete; prod nunca deleta)off
--format=jsonSaída estruturadaoff

Exit codes: 0 sucesso (conflitos auto-resolvidos não sobem exit code) · 1 houve falhas ou recusa de ambiente/lock · 2CVSYNC_DEPLOY_GATE=halt e houve conflito auto-resolvido no lote · 3 migration de schema pendente (fail-closed §5.9 — recusa imediata com ação prescritiva, sem resumo; reative o plugin ou rode a migration no pipeline).

docker compose exec -T wordpress wp sync apply --dry-run # ensaio
docker compose exec -T wordpress wp sync apply # aplica de verdade (local)

wp sync plan

Mostra o plano completo sem aplicar nada: o que seria importado, exportado, os conflitos, deleções pendentes e purges de tombstone. Ideal para review de PR e pipeline. Exit 0/1 (1 = erro de plano) · 3 migration pendente (recusa imediata com ação prescritiva).

docker compose exec -T wordpress wp sync plan

wp sync export

Exporta o banco para os arquivos (bulk, recuperação ou captura inicial). Livre em prod (read-only no banco) — é a porta para trazer conteúdo do cliente de volta ao repo.

FlagDescriçãoDefault
--post-type=<type>Restringe a um post type (inclui attachment, nav_menu, wp_global_styles, branding)todos
--taxonomy=<tax>Restringe a uma taxonomia versionada (Apêndice B)todas as versionadas
--scope=referenced|allEscopo de attachments: só referenciados ou biblioteca inteirareferenced
--batch=<n>Tamanho do lote (chunking retomável por idempotência)50
--out=<dir>Destino alternativo (ex.: captura de prod em dir temporário — não toca o FS do deploy)content dir real
--checkModo CI: falha (exit 1) se o export geraria diff — gate de idempotênciaoff
--format=jsonSaída estruturadaoff
docker compose exec -T wordpress wp sync export --check # CI: repo está em sincronia?
docker compose exec -T wordpress wp sync export --post-type=attachment --scope=all

wp sync bootstrap

Seed inicial da state table — a ausência de state nunca é inferida, este comando é a porta explícita. Comando de mutação (prod: triplo fator).

FlagDescriçãoDefault
--from=filesRepo é a autoridade: importa o que falta no banco, recria linhas convergentes silenciosamente, marca divergências como conflict (nunca adivinha)default
--from=dbBanco é a autoridade: exporta cada entidade do escopo
--force1º fator em prodoff
docker compose exec -T wordpress wp sync bootstrap # ambiente novo, repo cheio
docker compose exec -T wordpress wp sync bootstrap --from=db # banco legado, repo vazio

Inspeção e diagnóstico

wp sync status

Visão geral: ambiente efetivo, política da matriz, versão do schema, contagens por status na state table, HEAD do repo × último HEAD aplicado. Exit 0 sempre (observação pura).

docker compose exec -T wordpress wp sync status

wp sync verify

Recalcula os hashes dos dois lados e compara com a state table. Relatório por entidade (ok, drift-db, drift-file, orphan, pending_ref, conflict, missing_binary, oversized-untracked) + seções agregadas (tree-hash por tipo, drift externo de otimizadores, sonda PHP-off de uploads). É o comando de monitoramento em prod e o gate de CI/pós-deploy.

FlagDescriçãoDefault
--deepRe-hash dos blobs binários (única varredura de disco em massa — uso sob demanda explícita)off
--format=jsonSaída estruturadaoff

Exit: ≠ 0 em qualquer divergência (apto para CI). Sonda PHP-off: FAIL → exit ≠ 0; INDETERMINATE → warning, exit 0 (nunca trava operação por não-verificabilidade).

docker compose exec -T wordpress wp sync verify

wp sync log [--last=50]

Audit trail recente: entidade, direção, gatilho, actor, resultado, arquivo, hash antes/depois. Exit 0 sempre.

docker compose exec -T wordpress wp sync log --last=20

wp sync blame <entidade> [--last=20]

Responde "por que esta página mudou?": últimas aplicações da entidade, com gatilho, arquivo e hashes. <entidade> = post_type:slug | kind:post_type:key | uuid. Exit 0 sempre.

docker compose exec -T wordpress wp sync blame page:home

Conflitos

wp sync conflicts

Lista os conflitos pendentes (entidade, lado perdedor, vencedor, gatilho, actor, HEAD do git). Exit 0.

wp sync conflict show <id> [--out=<path>]

Despeja o payload preservado do lado perdedor de um conflito — na tela ou em arquivo (--out). Exit 1 se o id não existir.

wp sync resolve <entidade> --keep=db|file [--force]

Resolução manual: aplica o vencedor escolhido e fecha administrativamente os conflitos pendentes da entidade. --keep=db re-exporta a partir do banco (lossless; o working tree diverge do HEAD — commit depois); --keep=file importa o arquivo (sempre cria revisions). Mutação: prod exige triplo fator.

docker compose exec -T wordpress wp sync conflicts
docker compose exec -T wordpress wp sync conflict show 3
docker compose exec -T wordpress wp sync resolve page:home --keep=db

wp sync conflicts prune [--older-than=90d] [--all-resolved]

Housekeeping da tabela de conflitos: remove registros já resolvidos mais antigos que o cutoff (90d default; --all-resolved remove todos os resolvidos). Exit 0.

Manutenção

wp sync rebase --from=db|files

Recalcula a state table sem aplicar mudanças (não importa nem exporta) — re-alinha os hashes observados do lado escolhido à realidade. Caso de uso: após rename de tema (o global styles namespaced pelo stylesheet antigo vira órfão). Divergências resultantes aparecem no plan/verify seguintes. Exit 0/1.

wp sync restore <timestamp> [--force]

Re-aplica um snapshot pré-apply (rede de segurança): reimporta o estado preservado em uploads/cvsync-backups/<ts>/ e re-materializa binários ausentes (aditivo — nunca sobrescreve byte alheio). Sem argumento, lista os snapshots disponíveis. Mutação: prod exige triplo fator. Exit 1 se o snapshot não existir.

docker compose exec -T wordpress wp sync restore 20260804-133000

wp sync purge-revisions [--older-than=90d]

Contenção de volume de revisions (o import sempre cria revisions; a contenção é purge documentado, nunca supressão). Nunca remove a revision mais recente de cada post nem toca posts que não são revisions. Exit 0 sempre (falhas individuais são warnings).

wp sync attachments gc (--blobs|--files) [--execute] [--older-than=90d]

Os dois coletores de lixo de mídia, dry-run por default (--execute aplica):

  • --blobs — GC do repo: blob sem sidecar referenciando e sem linha não-tombstone na state. A remoção efetiva é commit humano em PR próprio (chore(media): gc) — o plugin lista, nunca commita;
  • --files — GC físico de uploads: arquivo sem _wp_attached_file correspondente (o guard cruzado inclui thumbnails e originais -scaled via _wp_attachment_metadata; nunca varre uploads/cvsync-backups/**).

Em prod, recomenda-se --older-than=180d. Exit 0.

docker compose exec -T wordpress wp sync attachments gc --files # dry-run
docker compose exec -T wordpress wp sync attachments gc --files --execute --older-than=180d

Setup

wp sync install-hooks

Aponta o git para os hooks versionados (git config core.hooksPath .githooks). É o único comando que invoca o binário git (permitido em SAPI CLI; o runtime web nunca roda git). Exit 1 se não houver .git (artefato deployado) ou .githooks/.

docker compose exec -T wordpress wp sync install-hooks

Fluxos comuns

1. Primeiro uso (repo já tem conteúdo versionado):

docker compose exec -T wordpress wp sync install-hooks
docker compose exec -T wordpress wp sync bootstrap # importa o repo, cria a state
docker compose exec -T wordpress wp sync status # confere o resultado

2. Puxei código do colega (git pull trouxe content/** novo):

# O hook post-merge já tenta o apply automaticamente. Para conferir/reenviar:
docker compose exec -T wordpress wp sync plan
docker compose exec -T wordpress wp sync apply

3. Apareceu conflito, e agora?

docker compose exec -T wordpress wp sync conflicts # o que está pendente
docker compose exec -T wordpress wp sync conflict show <id># vê o lado perdedor
docker compose exec -T wordpress wp sync resolve page:home --keep=db # escolhe o vencedor# --keep=db: re-exporta do banco → git add content/... && git commit (o tree diverge do HEAD)

4. Capturar mídia de produção para o repo (FS de prod é imutável):

# No servidor de prod (export é livre, read-only no banco):
wp sync export --post-type=attachment --scope=all --out=/tmp/cvsync-capture
# Copia /tmp/cvsync-capture para a estação, merge no content/ do repo, PR com review.

5. Verify em CI / pós-deploy:

# CI: o repo deve estar em sincronia com o banco de homolog
wp sync verify --format=json # exit ≠ 0 falha o pipeline# Gate de idempotência: export não pode gerar diff
wp sync export --check # exit 1 se geraria diff

Observabilidade

  • Audit log (wp_cvsync_log), conflitos (wp_cvsync_conflicts) e estado (wp_cvsync_state).
  • Admin: metabox de origem na tela de edição, notices (drift em prod, conflitos em homolog, sonda PHP-off, constantes inválidas) e Ferramentas > CVSync (log + conflitos).
  • Hooks para notificação: cvsync_applied, cvsync_failed, cvsync_conflict_registered, cvsync_files_materialized.

About

Sincronização bidirecional entre o conteúdo Gutenberg no banco de dados e arquivos versionáveis

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages