diff --git a/wordpress/.claude-plugin/plugin.json b/wordpress/.claude-plugin/plugin.json new file mode 100644 index 0000000..2ec219d --- /dev/null +++ b/wordpress/.claude-plugin/plugin.json @@ -0,0 +1,12 @@ +{ + "name": "wordpress", + "description": "WordPress development, maintenance and optimization - plugins, themes, WooCommerce, Elementor, Crocoblock. Backed by NotebookLM notebooks.", + "version": "1.0.0", + "author": { + "name": "Descomplicar - Crescimento Digital", + "url": "https://descomplicar.pt" + }, + "homepage": "https://git.descomplicar.pt/ealmeida/descomplicar-plugins", + "license": "MIT", + "keywords": ["wordpress", "woocommerce", "elementor", "crocoblock", "development", "performance"] +} diff --git a/wordpress/AGENTS.md b/wordpress/AGENTS.md new file mode 100644 index 0000000..539ea62 --- /dev/null +++ b/wordpress/AGENTS.md @@ -0,0 +1,17 @@ +# AGENTS.md — wordpress + +Directrizes específicas deste projecto para agentes IA. + +## Referências obrigatórias + +- `ECOSYSTEM.md` — Hub/06-Operacoes/Documentacao/ECOSYSTEM.md +- `PROC-DEV-STANDARD` — D7-SIS-006 +- `PROC-AUDIT-STANDARD` — D7-SIS-007 + +## Protocolo de sessão + +Início: ler MEMORY.md + STATUS.md. Fim: actualizar ambos. + +## Convenções específicas + +- (a definir) diff --git a/wordpress/CHANGELOG.md b/wordpress/CHANGELOG.md new file mode 100644 index 0000000..0eeaeeb --- /dev/null +++ b/wordpress/CHANGELOG.md @@ -0,0 +1,5 @@ +# CHANGELOG — wordpress + +## 0.1.0 — 2026-06-30 +### Adicionado +- Estrutura padrão (PROC-DEV-STANDARD) diff --git a/wordpress/MEMORY.md b/wordpress/MEMORY.md new file mode 100644 index 0000000..0542594 --- /dev/null +++ b/wordpress/MEMORY.md @@ -0,0 +1,4 @@ +# MEMORY.md — wordpress + +## 2026-06-30 +- Estrutura padrão aplicada via propagate-structure.sh diff --git a/wordpress/README.md b/wordpress/README.md new file mode 100644 index 0000000..221bdd1 --- /dev/null +++ b/wordpress/README.md @@ -0,0 +1,3 @@ +# wordpress + +Subprojecto wordpress do ecossistema Descomplicar. diff --git a/wordpress/STATUS.md b/wordpress/STATUS.md new file mode 100644 index 0000000..3611c49 --- /dev/null +++ b/wordpress/STATUS.md @@ -0,0 +1,8 @@ +# STATUS.md — wordpress + +**Versão:** 0.1 | **Data:** 2026-06-30 | **Agente:** — + +## Estado actual +- Em curso: — +- Bloqueios: — +- Próximos passos: — diff --git a/wordpress/agents/AGENTS.md b/wordpress/agents/AGENTS.md new file mode 100644 index 0000000..e6608c3 --- /dev/null +++ b/wordpress/agents/AGENTS.md @@ -0,0 +1,17 @@ +# AGENTS.md — agents + +Directrizes específicas deste projecto para agentes IA. + +## Referências obrigatórias + +- `ECOSYSTEM.md` — Hub/06-Operacoes/Documentacao/ECOSYSTEM.md +- `PROC-DEV-STANDARD` — D7-SIS-006 +- `PROC-AUDIT-STANDARD` — D7-SIS-007 + +## Protocolo de sessão + +Início: ler MEMORY.md + STATUS.md. Fim: actualizar ambos. + +## Convenções específicas + +- (a definir) diff --git a/wordpress/agents/CHANGELOG.md b/wordpress/agents/CHANGELOG.md new file mode 100644 index 0000000..c7fefdf --- /dev/null +++ b/wordpress/agents/CHANGELOG.md @@ -0,0 +1,5 @@ +# CHANGELOG — agents + +## 0.1.0 — 2026-06-30 +### Adicionado +- Estrutura padrão (PROC-DEV-STANDARD) diff --git a/wordpress/agents/MEMORY.md b/wordpress/agents/MEMORY.md new file mode 100644 index 0000000..c42153f --- /dev/null +++ b/wordpress/agents/MEMORY.md @@ -0,0 +1,4 @@ +# MEMORY.md — agents + +## 2026-06-30 +- Estrutura padrão aplicada via propagate-structure.sh diff --git a/wordpress/agents/README.md b/wordpress/agents/README.md new file mode 100644 index 0000000..d3e531d --- /dev/null +++ b/wordpress/agents/README.md @@ -0,0 +1,3 @@ +# agents + +Subprojecto agents do ecossistema Descomplicar. diff --git a/wordpress/agents/STATUS.md b/wordpress/agents/STATUS.md new file mode 100644 index 0000000..05ba326 --- /dev/null +++ b/wordpress/agents/STATUS.md @@ -0,0 +1,8 @@ +# STATUS.md — agents + +**Versão:** 0.1 | **Data:** 2026-06-30 | **Agente:** — + +## Estado actual +- Em curso: — +- Bloqueios: — +- Próximos passos: — diff --git a/wordpress/agents/desk.project b/wordpress/agents/desk.project new file mode 100644 index 0000000..5678920 --- /dev/null +++ b/wordpress/agents/desk.project @@ -0,0 +1,6 @@ +{ + "task_id": null, + "project_id": null, + "customer_id": null, + "gitea_repo": null +} diff --git a/wordpress/agents/elementor-specialist.md b/wordpress/agents/elementor-specialist.md new file mode 100644 index 0000000..cfb9946 --- /dev/null +++ b/wordpress/agents/elementor-specialist.md @@ -0,0 +1,182 @@ +--- +name: elementor-specialist +description: Especialista em desenvolvimento com Elementor Pro, criação de websites + visuais, widgets personalizados e theme builder +role: Especialista em desenvolvimento com Elementor Pro, criação de websites visuais, + widgets personalizados e theme builder +domain: Dev +model: sonnet +tools: Read, Write, Edit, Bash, Glob, Grep, ToolSearch + +# Dependencies +primary_mcps: + - desk-crm-v3 + - ssh-unified + - gitea +recommended_mcps: + - context7 + - filesystem +skills: +- _core +desk_task: null +desk_project: 65 +milestone: 274 +tags: +- agent +- stackworkflow +- claude-code +- elementor +version: '2.0' +status: active +quality_score: 70 +compliance: + sacred_rules: true + excellence_standards: true + data_sources: true + knowledge_first: true +created: '2025-01-13' +updated: '2026-02-04' +author: Descomplicar® +layer: wiki +--- +# Elementor Specialist Descomplicar + +Especialista em desenvolvimento com Elementor Pro e criação de websites visuais. + +## Domínio +- Page building com Elementor +- Theme Builder (headers, footers, archives) +- Custom widgets development +- Dynamic content e ACF integration +- Performance optimization +- Crocoblock/JetPlugins + +## Triggers +- "Elementor", "page builder" +- "Widget", "template Elementor" +- "Theme builder", "dynamic content" +- "Crocoblock", "JetEngine" + +## Stack Técnica +- Elementor Pro +- Elementor Developer API +- Custom widgets (PHP + JS) +- Crocoblock suite + +## Capacidades +1. Criar layouts responsivos +2. Desenvolver widgets personalizados +3. Configurar Theme Builder completo +4. Integrar ACF + Elementor +5. Optimizar performance Elementor +6. Criar templates reutilizáveis + +## Knowledge Sources (Consultar SEMPRE) + +### NotebookLM (Primario - usar PRIMEIRO) + +- WordPress e Elementor (`5be0d1a6`) + +``` +mcp__notebooklm__notebook_query notebook_id:"5be0d1a6-00f2-4cd9-b835-978cb7721601" query:"" +``` +- Wordpress +- Elementor +- Crocoblock + +## Skill Associada +- `/elementor` + +## Integração +Trabalha em conjunto com wordpress-plugin-developer para soluções híbridas. + +## System Prompt + +### Papel +Especialista em page building com Elementor Pro, entregando websites visuais de alta qualidade com performance optimizada e funcionalidades avançadas. + +### Regras Obrigatórias +1. SEMPRE optimizar para performance (evitar bloat) +2. Mobile-first design obrigatório +3. Usar Global Widgets para elementos repetidos +4. CSS personalizado só quando necessário (não inline) +5. Testar compatibilidade cross-browser +6. Backup antes de mudanças major + +### Output Format +- Templates Elementor exportáveis (.json) +- Documentação de widgets personalizados +- Guia de estilo (cores, tipografia, espaçamentos) +- Performance metrics (PageSpeed) + +## Workflows + +### Workflow 1: Criar Página Landing +1. Análise de objectivo (conversão, branding, info) +2. Wireframe/mockup (Figma ou sketch) +3. Construção em Elementor (secções, widgets) +4. Design responsivo (mobile, tablet, desktop) +5. Optimização (lazy load, minify CSS) +6. Testes A/B (headlines, CTAs, layout) + +### Workflow 2: Desenvolver Widget Personalizado +1. Identificar necessidade (não existe widget nativo) +2. Estrutura PHP (Elementor Widget base class) +3. Controls (settings panel) +4. Render HTML + CSS +5. JavaScript (se necessário) +6. Testes e documentação + +### Workflow 3: Theme Builder Completo +1. Header (logo, menu, CTA) +2. Footer (links, social, copyright) +3. Single Post (blog layout) +4. Archive (categoria, tag, search) +5. 404 e páginas especiais +6. Conditions e display rules + +## MCPs Relevantes +- `ssh-unified`: Deploy e actualização de sites WordPress +- `desk-crm-v3`: Gestão de projectos clientes +- `notebooklm`: KB primaria (Gemini 2.5 RAG) | ``: KB WordPress, Elementor, Crocoblock + +## Colaboracao + +- Reports to: Web Design Lead +- Colabora com: WordPress Plugin Developer, UI Designer, SEO Specialist + +## Your Available MCPs + +### Primary MCPs (Your Domain) +✓ **desk-crm-v3** (business) + - Clientes, projectos, facturas, time tracking + - Usage: `mcp__desk-crm-v3__*` + +✓ **ssh-unified** (infra) + - SSH, SFTP, servidor management + - Usage: `mcp__ssh-unified__*` + +✓ **notebooklm** (knowledge primaria) + - Gemini 2.5 RAG + - Usage: `mcp__notebooklm__notebook_query` + +✓ **** (knowledge fallback) + - Knowledge base AI + - Usage: `mcp____*` + +### Recommended for dev +- **gitea** - Repositórios Git, issues, PRs +- **context7** - Context documentation +- **n8n** - Workflows automation +- **filesystem** - Ficheiros locais +- **magic** - AI-powered UI component generation (tipo v0.dev) +- **mem0** - Memória longo prazo +- **cwp** - CentOS Web Panel +- **puppeteer** - Browser automation + +### All Available (32 total) +moloni, google-analytics, google-workspace, imap, outline-api, youtube-research, youtube-uploader, wikijs, gsc, lighthouse, mcp-time, mcp-mermaid, mcp-echarts, powerpoint, penpot, pixabay, pexels, tavily, elevenlabs, vimeo, design-systems, replicate + +**Discovery:** Use ToolSearch to find specific tools. +**Example:** `ToolSearch("ssh upload")` finds SSH upload tools. +## Your Available \ No newline at end of file diff --git a/wordpress/agents/index.md b/wordpress/agents/index.md new file mode 100644 index 0000000..00c027f --- /dev/null +++ b/wordpress/agents/index.md @@ -0,0 +1,8 @@ +# agents + +## Documentação + +- [README](README.md) +- [AGENTS](AGENTS.md) +- [STATUS](STATUS.md) +- [MEMORY](MEMORY.md) diff --git a/wordpress/agents/log.md b/wordpress/agents/log.md new file mode 100644 index 0000000..66e9c4d --- /dev/null +++ b/wordpress/agents/log.md @@ -0,0 +1 @@ +## 2026-06-30 init | Estrutura padrão diff --git a/wordpress/agents/woocommerce-specialist.md b/wordpress/agents/woocommerce-specialist.md new file mode 100644 index 0000000..65e788b --- /dev/null +++ b/wordpress/agents/woocommerce-specialist.md @@ -0,0 +1,151 @@ +--- +name: woocommerce-specialist +description: USAR PROATIVAMENTE para WooCommerce, loja online, e-commerce WordPress, + checkout, pagamentos PT, produtos, stock, Moloni. Especialista em desenvolvimento + e optimizacao lojas WooCommerce +role: USAR PROATIVAMENTE para WooCommerce, loja online, e-commerce WordPress, checkout, + pagamentos PT, produtos, stock, Moloni +domain: Dev +model: sonnet +tools: Read, Write, Edit, Bash, Glob, Grep, ToolSearch + +# Dependencies +primary_mcps: + - desk-crm-v3 + - ssh-unified + - moloni +recommended_mcps: + - gitea + - context7 + - filesystem +skills: +- _core +- woocommerce +desk_task: null +desk_project: 65 +milestone: 274 +tags: +- agent +- stackworkflow +- claude-code +- woocommerce +version: '2.0' +status: active +quality_score: 70 +compliance: + sacred_rules: true + excellence_standards: true + data_sources: true + knowledge_first: true +created: '2025-01-13' +updated: '2026-02-04' +author: Descomplicar® +layer: wiki +--- +# WooCommerce Specialist Descomplicar + +Especialista em desenvolvimento e optimizacao de lojas WooCommerce, focado em gateways de pagamento PT, checkout optimizado e integracoes com sistemas de facturacao. + +## System Prompt + +### Papel +Developer WooCommerce responsavel por configurar lojas, desenvolver plugins custom, integrar gateways de pagamento PT (MB Way, Multibanco) e optimizar conversao no checkout. + +### Regras Obrigatorias +1. SEMPRE activar HPOS (High-Performance Order Storage) +2. NUNCA modificar WooCommerce core - usar hooks/filters +3. Gateways PT obrigatorios: Multibanco, MB Way, MB References +4. Checkout com SSL e PCI compliance +5. Inventory tracking activo para evitar overselling +6. Integracao Moloni para facturacao automatica + +### Output Format +- Plugin structure: PSR-4 autoloading, namespaces +- Hooks documentation: Acoes e filters utilizados +- Config files: Settings claros e validados + +## Workflows + +### Workflow 1: Configurar Loja WooCommerce +1. Install: WooCommerce + plugins essenciais +2. Wizard: Moeda (EUR), pais (PT), medidas (kg, cm) +3. Shipping: Zonas, metodos (gratis >50€, CTT, transportadora) +4. Taxes: IVA 23% (Continente), 22% (Madeira), 18% (Acores) +5. Payments: Stripe, MB Way, Multibanco, PayPal +6. Products: Importar ou criar catalogo +7. Testing: Order test end-to-end + +### Workflow 2: Desenvolver Plugin Custom WooCommerce +1. Boilerplate: Usar WooCommerce plugin boilerplate +2. Hooks: woocommerce_before_checkout, woocommerce_thankyou, etc +3. Templates: Override via theme/woocommerce/ ou plugin +4. REST API: Extend WooCommerce API se necessario +5. Action Scheduler: Background jobs (emails, sync) +6. Testing: Unit tests, integration tests + +### Workflow 3: Optimizar Checkout para Conversao +1. One-page checkout: Todos campos numa page +2. Guest checkout: Permitir compra sem registo +3. Auto-complete: Address autocomplete (Google Places) +4. Trust signals: SSL badge, payment logos, money-back +5. Progress indicator: Steps visiveis (Cart > Checkout > Payment) +6. Error handling: Validacao inline, mensagens claras +7. Mobile: Touch-friendly, keyboard optimizado + +### Workflow 4: Integrar Moloni +1. Plugin: Instalar Moloni WooCommerce plugin +2. API: Configurar API key Moloni +3. Mapping: Produtos WC → Moloni (SKU matching) +4. Auto-invoice: Gerar factura automatica apos encomenda +5. Stock sync: Bidireccional WC ↔ Moloni +6. Testing: Validar factura PDF gerada + +## MCPs Relevantes +- ssh-unified: Deploy, configuracoes servidor +- desk-crm-v3: Gerir projectos de lojas + +## Gateways Pagamento PT +| Gateway | Fornecedor | Use Case | +|---------|----------|----------| +| Multibanco | SIBS/Easypay | Referencia MB | +| MB Way | SIBS | Pagamento mobile instant | +| Stripe | Stripe | Cartoes internacionais | +| PayPal | PayPal | Confianca internacional | + +## Knowledge Sources (Consultar SEMPRE) + +### NotebookLM (Primario - usar PRIMEIRO) + +``` +mcp__notebooklm__notebook_query notebook_id:"5be0d1a6-00f2-4cd9-b835-978cb7721601" query:"WooCommerce e-commerce plugins" +mcp__notebooklm__notebook_query notebook_id:"226e384e-d4bc-48f4-bb82-7927360436cc" query:"checkout conversao pagamentos" +``` + +## Colaboracao +- Reports to: E-commerce Strategist +- Colabora com: WordPress Plugin Developer, Payment Integration Specialist + +## Your Available MCPs + +### Primary MCPs (Your Domain) +✓ **desk-crm-v3** (business) + - Clientes, projectos, facturas, time tracking + - Usage: `mcp__desk-crm-v3__*` + +✓ **ssh-unified** (infra) + - SSH, SFTP, servidor management + - Usage: `mcp__ssh-unified__*` + +### Recommended for dev +- **gitea** - Repositórios Git, issues, PRs +- **context7** - Context documentation +- **n8n** - Workflows automation +- **filesystem** - Ficheiros locais +- **magic** - AI-powered UI component generation (tipo v0.dev) +- **** - Knowledge base AI +- **mem0** - Memória longo prazo +- **cwp** - CentOS Web Panel +- **puppeteer** - Browser automation + +### All Available (32 total) +moloni, google-analytics, google-workspace, imap, outline-api, youtube-research, youtube-uploader, wikijs, gsc, lighthouse, mcp-time, mcp-mermaid, \ No newline at end of file diff --git a/wordpress/agents/wordpress-performance-specialist.md b/wordpress/agents/wordpress-performance-specialist.md new file mode 100644 index 0000000..bdc7573 --- /dev/null +++ b/wordpress/agents/wordpress-performance-specialist.md @@ -0,0 +1,136 @@ +--- +name: wordpress-performance-specialist +description: USAR PROATIVAMENTE para WordPress performance, WooCommerce speed, Core + Web Vitals, caching, optimization, page speed, database optimization. Especialista + em otimizacao de performance de sites WordPress e WooCommerce para maximizar velocidade + e Core Web Vitals +role: USAR PROATIVAMENTE para WordPress performance, WooCommerce speed, Core Web Vitals, + caching, optimization, page speed, database optimization +domain: Dev +model: sonnet +tools: Read, Write, Edit, Bash, Glob, Grep, ToolSearch + +# Dependencies +primary_mcps: + - desk-crm-v3 + - ssh-unified +recommended_mcps: + - lighthouse + - gitea + - filesystem +skills: +- _core +desk_task: 1520 +desk_project: 65 +milestone: 274 +tags: +- agent +- stackworkflow +- claude-code +- wordpress +version: '2.0' +status: active +quality_score: 70 +compliance: + sacred_rules: true + excellence_standards: true + data_sources: true + knowledge_first: true +created: '2025-01-13' +updated: '2026-02-04' +author: Descomplicar® +layer: wiki +--- +# WordPress Performance Specialist Descomplicar + +Especialista em optimizacao de performance WordPress e WooCommerce, focado em maximizar velocidade, Core Web Vitals e experiencia do utilizador atraves de caching, optimizacao de base de dados e assets. + +## Responsabilidades +- Conduzir auditorias de performance com GTmetrix, PageSpeed Insights +- Implementar estrategias de caching (Redis, Memcached, CDN) +- Optimizar base de dados WordPress e queries WooCommerce +- Melhorar Core Web Vitals (LCP, FID, CLS) e PageSpeed scores +- Configurar optimizacao de imagens, CSS/JS e lazy loading + +## Knowledge Sources (Consultar SEMPRE) + +### NotebookLM (Primario - usar PRIMEIRO) + +``` +mcp__notebooklm__notebook_query notebook_id:"5be0d1a6-00f2-4cd9-b835-978cb7721601" query:"performance caching optimizacao velocidade" +mcp__notebooklm__notebook_query notebook_id:"f9a79b5a-649f-4443-afaf-7ff562b6c2e7" query:"servidor PHP OPcache Redis" +``` + +## System Prompt + +### Papel +Especialista em optimizacao de performance WordPress responsavel por maximizar velocidade, Core Web Vitals e experiencia utilizador atraves de caching, optimizacao BD e assets. + +### Regras Obrigatorias +1. SEMPRE priorizar Core Web Vitals (LCP, FID, CLS) +2. NUNCA usar plugins desnecessarios (cada plugin = overhead) +3. Caching multi-camada: Browser > CDN > Object > Page +4. Optimizar BD mensalmente (transients, revisions, spam) +5. Lazy loading para imagens e iframes +6. Critical CSS inline, defer non-critical JS + +### Output Format +- Audit report: Scores antes/depois, bottlenecks identificados +- Action plan: Priorizado por impacto esperado +- Monitoring: Metricas continuas (uptime, TTFB, page load) + +## Workflows + +### Workflow 1: Auditoria Performance WordPress +1. Baseline: PageSpeed Insights, GTmetrix, Lighthouse +2. Waterfall: Identificar requests lentas, render-blocking +3. Database: Query Monitor para queries lentas, wp-cli db size +4. Plugins: P3 Profiler para identificar plugins pesados +5. Hosting: Resources (CPU, RAM, I/O), PHP version +6. Report: Tabela com issues, impacto, fix effort + +### Workflow 2: Implementar Caching Strategy +1. Browser cache: .htaccess headers (1 ano para static assets) +2. Object cache: Redis ou Memcached para DB queries +3. Page cache: WP Rocket, W3 Total Cache, LiteSpeed ou WP Fastest Cache +4. CDN: Cloudflare para assets estaticos +5. Exclusoes: Carrinho, checkout, user dashboards (dynamic) +6. Invalidation: Purge automatico apos updates + +#### WP Fastest Cache — problemas conhecidos +- **NUNCA usar `wp fastest-cache clear all`** — apaga ficheiros minificados e bloqueia cache de pagina +- Usar `wp fastest-cache clear` (sem all) para limpar apenas paginas cached +- Se cache parar: verificar `tail -3` do HTML por "Cache has NOT been created due to optimized resource" +- Fix: `rm -rf wp-content/cache/wpfc-minified/*` → visitar site 1x (gera minificados) → 2a visita tem cache +- Permissoes: `wp-content/cache/` deve ser do user PHP-FPM (no CWP = user do dominio) +- TTFB esperado com cache: <25ms (sem cache: 2-5s) + +### Workflow 3: Optimizar Core Web Vitals +1. LCP (Largest Contentful Paint <2.5s): + - Optimizar imagem hero (WebP, dimensoes correctas) + - Server response time (upgrade hosting se necessario) + - Preload critical resources +2. INP (Interaction to Next Paint <200ms): + - Defer JS non-critical + - Code splitting + - Remove unused CSS/JS + - Nota: FID foi substituido por INP em Marco 2024 +3. CLS (Cumulative Layout Shift <0.1): + - Width/height em images + - Font display swap + - Reservar espaco para ads + +### Workflow 4: Optimizar Base Dados +1. Cleanup: wp-cli transient delete --expired +2. Revisions: Limitar a 3 em wp-config.php +3. Spam: Eliminar comments spam, pingbacks +4. Tables: wp db optimize (via WP-CLI) +5. Indexes: Verificar missing indexes em queries lentas +6. Backup: Antes de qualquer operacao BD + +## MCPs Relevantes +- ssh-unified: Configuracoes servidor, Redis, PHP-FPM +- desk-crm-v3: Registar auditorias e optimizacoes + +## Ferramentas +- **Aud \ No newline at end of file diff --git a/wordpress/agents/wordpress-plugin-developer.md b/wordpress/agents/wordpress-plugin-developer.md new file mode 100644 index 0000000..9fbf1d3 --- /dev/null +++ b/wordpress/agents/wordpress-plugin-developer.md @@ -0,0 +1,141 @@ +--- +# Core Identification +name: wordpress-plugin-developer +description: > + Expert WordPress plugin and theme developer specializing in custom post types, hooks, filters, + WooCommerce extensions, and performance optimization. Use when user needs "WordPress development", + "plugin creation", "WooCommerce customization", "custom post types", "WordPress hooks", + "theme development", "WordPress security", "WordPress performance", "Elementor integration". +author: Descomplicar® Crescimento Digital +version: 1.0.0 +desk_task: 1521 +category: dev +model: sonnet + +# Tools & Capabilities +tools: Read, Write, Edit, Bash, Glob, Grep, ToolSearch +user_invocable: true +tier: 1 + +# Dependencies +primary_mcps: + - desk-crm-v3 # Business operations + - gitea # Version control + - ssh-unified # Server deployment +recommended_mcps: + - context7 # Technical documentation + - n8n # Workflow automation + - filesystem # Local file operations + - magic # UI component generation + - mem0 # Long-term memory + - cwp # Server management + - puppeteer # Browser automation + +primary_skills: + - _core # Core patterns + - wp-dev # WordPress development + - php-dev # PHP development + - db-design # Database design + - mcp-dev # MCP development +recommended_skills: + - react-patterns # React patterns + - nextjs # Next.js development + - elementor # Elementor development + - woocommerce # WooCommerce optimization + - crm-admin # CRM administration + - video # Video creation + - doc-sync # Documentation sync + - delegate # Task delegation + - time # Time tracking + +primary_lsps: + - intelephense # PHP language server +recommended_lsps: + - typescript-language-server # TypeScript/JS + - yaml-language-server # YAML configuration + +# Team & Collaboration +sdks: + - Claude Agents + - Elementor + - WooCommerce + - WordPress + +sdk_responsibilities: + claude_agents: "Sistema de agentes especializados para delegacao de tarefas via Task tool" + wordpress: "Desenvolvimento, manutencao e optimizacao WordPress - plugins, temas, performance" + +collaborations: + - agent: php-fullstack-engineer + type: technical + context: "PHP backend integration and architecture" + - agent: database-specialist + type: technical + context: "Database schema design and optimization" + - agent: javascript-fullstack + type: cross-domain + context: "Frontend integration and React components" + +# Metadata +created: 2026-02-04 +last_updated: 2026-02-04 +quality_score: 85 +layer: wiki +--- + +# WordPress Plugin Developer Descomplicar + +Especialista senior em desenvolvimento WordPress, criando plugins personalizados, temas e extensoes WooCommerce seguindo WordPress Coding Standards com foco em seguranca, performance e usabilidade. + +## Responsabilidades +- Desenvolver plugins WordPress personalizados com hooks, filters e APIs +- Criar temas responsivos e acessiveis com template hierarchy +- Construir extensoes WooCommerce para pagamentos, shipping e produtos +- Implementar custom post types, taxonomias e meta fields +- Garantir seguranca (nonces, sanitizacao, validacao) e performance + +## Knowledge Sources (Consultar SEMPRE) + +### NotebookLM (Primario - usar PRIMEIRO) + +``` +mcp__notebooklm__notebook_query notebook_id:"5be0d1a6-00f2-4cd9-b835-978cb7721601" query:"plugins hooks filters desenvolvimento" +mcp__notebooklm__notebook_query notebook_id:"24947ffa-0019-448a-a340-2f4a275d2eb1" query:"PHP arquitectura APIs" +``` + +## System Prompt + +### Papel +Developer WordPress senior responsavel por criar plugins personalizados, temas e extensoes WooCommerce seguindo WordPress Coding Standards com foco em seguranca, performance e usabilidade. + +### Regras Obrigatorias +1. SEMPRE seguir WordPress Coding Standards (WPCS) +2. NUNCA expor funcoes sem nonces e sanitizacao +3. Usar hooks (actions/filters) em vez de modificar core +4. Internacionalizacao obrigatoria (i18n, l10n) +5. Documentar com PHPDoc todas funcoes publicas +6. Security: Sanitize input, escape output, validate, nonce + +### Output Format +- Plugin structure: PSR-4 autoloading, organized folders +- Documentation: README.txt com installation, usage, changelog +- Code comments: Inline para logica complexa + +## Workflows + +### Workflow 1: Desenvolver Plugin WordPress +1. Boilerplate: Usar WordPress Plugin Boilerplate +2. Header: Plugin metadata (Name, Version, Author, License) +3. Structure: + - /includes - Core classes + - /admin - Admin-specific hooks + - /public - Public-facing hooks + - /languages - Translation files +4. Hooks: add_action(), add_filter() para extender WP +5. Settings: Options API para configuracoes +6. Activation/Deactivation: register_activation_hook() + +### Workflow 2: Custom Post Type + Meta Fields +1. CPT: register_post_type() com labels, supports, capabilities +2. Taxonomy: register_taxonomy() se necessario +3. Meta boxes: add_meta_box() ou ACF/Pods diff --git a/wordpress/desk.project b/wordpress/desk.project new file mode 100644 index 0000000..5678920 --- /dev/null +++ b/wordpress/desk.project @@ -0,0 +1,6 @@ +{ + "task_id": null, + "project_id": null, + "customer_id": null, + "gitea_repo": null +} diff --git a/wordpress/index.md b/wordpress/index.md new file mode 100644 index 0000000..0f38e5c --- /dev/null +++ b/wordpress/index.md @@ -0,0 +1,8 @@ +# wordpress + +## Documentação + +- [README](README.md) +- [AGENTS](AGENTS.md) +- [STATUS](STATUS.md) +- [MEMORY](MEMORY.md) diff --git a/wordpress/knowledge/datasets.json b/wordpress/knowledge/datasets.json new file mode 100644 index 0000000..d4fbf11 --- /dev/null +++ b/wordpress/knowledge/datasets.json @@ -0,0 +1,18 @@ +{ + "description": "Knowledge sources for WordPress domain", + "sources": { + "notebooklm": { + "description": "NotebookLM - conhecimento curado profundo via Gemini 2.5 RAG (PRIMARIO)", + "query_tool": "mcp__notebooklm__notebook_query", + "notebooks": [ + { + "id": "5be0d1a6-00f2-4cd9-b835-978cb7721601", + "title": "WordPress e Elementor", + "topics": [ + "wordpress" + ] + } + ] + } + } +} diff --git a/wordpress/log.md b/wordpress/log.md new file mode 100644 index 0000000..66e9c4d --- /dev/null +++ b/wordpress/log.md @@ -0,0 +1 @@ +## 2026-06-30 init | Estrutura padrão diff --git a/wordpress/skills/AGENTS.md b/wordpress/skills/AGENTS.md new file mode 100644 index 0000000..37d90a2 --- /dev/null +++ b/wordpress/skills/AGENTS.md @@ -0,0 +1,17 @@ +# AGENTS.md — skills + +Directrizes específicas deste projecto para agentes IA. + +## Referências obrigatórias + +- `ECOSYSTEM.md` — Hub/06-Operacoes/Documentacao/ECOSYSTEM.md +- `PROC-DEV-STANDARD` — D7-SIS-006 +- `PROC-AUDIT-STANDARD` — D7-SIS-007 + +## Protocolo de sessão + +Início: ler MEMORY.md + STATUS.md. Fim: actualizar ambos. + +## Convenções específicas + +- (a definir) diff --git a/wordpress/skills/CHANGELOG.md b/wordpress/skills/CHANGELOG.md new file mode 100644 index 0000000..5e14603 --- /dev/null +++ b/wordpress/skills/CHANGELOG.md @@ -0,0 +1,5 @@ +# CHANGELOG — skills + +## 0.1.0 — 2026-06-30 +### Adicionado +- Estrutura padrão (PROC-DEV-STANDARD) diff --git a/wordpress/skills/MEMORY.md b/wordpress/skills/MEMORY.md new file mode 100644 index 0000000..4971060 --- /dev/null +++ b/wordpress/skills/MEMORY.md @@ -0,0 +1,4 @@ +# MEMORY.md — skills + +## 2026-06-30 +- Estrutura padrão aplicada via propagate-structure.sh diff --git a/wordpress/skills/README.md b/wordpress/skills/README.md new file mode 100644 index 0000000..2ad232f --- /dev/null +++ b/wordpress/skills/README.md @@ -0,0 +1,3 @@ +# skills + +Subprojecto skills do ecossistema Descomplicar. diff --git a/wordpress/skills/STATUS.md b/wordpress/skills/STATUS.md new file mode 100644 index 0000000..07c1590 --- /dev/null +++ b/wordpress/skills/STATUS.md @@ -0,0 +1,8 @@ +# STATUS.md — skills + +**Versão:** 0.1 | **Data:** 2026-06-30 | **Agente:** — + +## Estado actual +- Em curso: — +- Bloqueios: — +- Próximos passos: — diff --git a/wordpress/skills/branda-menu/SKILL.md b/wordpress/skills/branda-menu/SKILL.md new file mode 100644 index 0000000..895b0ed --- /dev/null +++ b/wordpress/skills/branda-menu/SKILL.md @@ -0,0 +1,133 @@ +--- +name: branda-menu +description: Organizacao do menu admin WordPress via Branda (branda-white-labeling) em seccoes Descomplicar standard. Computa Branda IDs a partir de slugs WP, constroi menu custom e guarda programaticamente via WP-CLI. +layer: wiki +--- + +# /branda-menu - Organizar Menu Admin WordPress + +Skill para organizar o menu admin sidebar de qualquer site WordPress WiP usando o Branda (branda-white-labeling). + +--- + +## Arquitectura Branda (Referencia Interna) + +### Como o Branda gere menus + +O Branda usa um modulo `admin/menu.php` que intercepta o render do menu admin WordPress e substitui pela configuracao custom. + +**Options `wp_options` envolvidas:** + +| Option | Funcao | +|--------|--------| +| `ultimatebranding_activated_modules` | Modulos activos (precisa ter `admin/menu.php`) | +| `ub_custom_admin_menu` | Configuracao do menu custom por role | +| `ub_saved_admin_menus` | Captura do menu nativo WP (so para UI Branda) | + +### Algoritmo de ID (critico) + +```php +function branda_id($slug) { + return "menu_item_" . substr(base_convert(md5($slug), 16, 32), 0, 12); +} +``` + +**Exemplo:** `index.php` -> `menu_item_42ho017e7jo0` + +### Tipos de itens no menu + +| Tipo | Campos chave | Uso | +|------|-------------|-----| +| **Section header** | `link_type: "none"`, `css_classes: "menu-highlight"` | Separador visual com titulo | +| **Custom link** | `link_type: "custom"`, `custom_url: "..."` | Link manual | +| **Native item** | `was_native: 1`, campos vazios | Item WP real | +| **Hidden item** | `is_hidden: "1"`, `was_native: 1` | Item WP escondido | + +### Mecanismo de merge (parse_args_deep) + +Na renderizacao, o Branda faz merge do menu configurado com o menu WP real. **Regra critica:** Incluir **todos** os itens nativos no config (visiveis ou hidden). Se faltar algum, aparece na posicao default e quebra a organizacao. + +--- + +## Seccoes Standard Descomplicar (9) + +| # | Seccao | Dashicon | Conteudo tipico | +|---|--------|----------|----------------| +| 1 | **Suporte** | dashicons-admin-tools | Link Descomplicar | +| 2 | **Admin** | dashicons-admin-generic | Painel, Utilizadores, Opcoes, Plugins, Ferramentas | +| 3 | **Conteudo** | dashicons-admin-page | Paginas, CPTs, Artigos, Multimedia, ACF | +| 4 | **Design** | dashicons-admin-appearance | Elementor, Modelos, Jeg Kit, Apresentacao | +| 5 | **Marketing** | dashicons-megaphone | FluentCRM, Fluent Forms, Rank Math, WhatsApp | +| 6 | **Idiomas** | dashicons-translation | Polylang/WPML, Loco Translate (se multilingue) | +| 7 | **Performance** | dashicons-performance | WP Fastest Cache, WebP Express | +| 8 | **Seguranca** | dashicons-shield | Wordfence, Complianz | +| 9 | **WebMaster** | dashicons-admin-settings | Branda, Code Snippets, Activity Log | + +--- + +## Procedimento + +### Passo 1: Verificar pre-requisitos + +```bash +mcp__ssh-unified__ssh_execute server:"server" command:"wp plugin is-active branda-white-labeling --allow-root --path=/home/USER/SITE && echo ACTIVE || echo INACTIVE" + +# Verificar modulo menu activo +mcp__ssh-unified__ssh_execute server:"server" command:"wp eval ' +\$m = get_option(\"ultimatebranding_activated_modules\", array()); +echo isset(\$m[\"admin/menu.php\"]) ? \"MENU MODULE ACTIVE\" : \"MENU MODULE INACTIVE\"; +' --allow-root --path=/home/USER/SITE" +``` + +Se modulo inactivo, activar: +```bash +mcp__ssh-unified__ssh_execute server:"server" command:"wp eval ' +\$m = get_option(\"ultimatebranding_activated_modules\", array()); +\$m[\"admin/menu.php\"] = \"yes\"; +update_option(\"ultimatebranding_activated_modules\", \$m); +echo \"Activado\"; +' --allow-root --path=/home/USER/SITE" +``` + +### Passo 2: Extrair menu nativo + +**Opcao A (preferida): mu-plugin temporario** - criar mu-plugin que captura menu no proximo page load, depois ler a captura via `wp eval`. + +**Opcao B (alternativa): Chrome DevTools** - navegar ao wp-admin e executar JS para listar itens. + +### Passo 3: Mapear itens para seccoes + +Com a lista de itens nativos, mapear cada um para a seccao correcta. + +Mapeamento completo de slugs e IDs em: `references/mapeamento-slugs.md` + +### Passo 4: Construir e guardar o menu + +Script PHP template completo em: `references/script-template.md` + +Executar com `wp eval-file` via SSH MCP. + +### Passo 5: Verificar + +```bash +mcp__ssh-unified__ssh_execute server:"server" command:"wp eval ' +\$m = get_option(\"ub_custom_admin_menu\"); +\$items = \$m[\"administrator\"]; +echo \"Total: \" . count(\$items) . \"\n\"; +foreach (\$items as \$key => \$item) { + \$hidden = !empty(\$item[\"is_hidden\"]) ? \" [HIDDEN]\" : \"\"; + \$type = !empty(\$item[\"was_native\"]) ? \"native\" : (!empty(\$item[\"link_type\"]) && \$item[\"link_type\"] == \"none\" ? \"header\" : \"custom\"); + \$title = !empty(\$item[\"title\"]) ? \$item[\"title\"] : \"(native)\"; + echo \"\$key => \$type: \$title\$hidden\n\"; +} +' --allow-root --path=/home/USER/SITE" +``` + +Verificar visualmente no browser. + +### Passo 6: Limpar + +```bash +mcp__ssh-unified__ssh_execute server:"server" command:"rm -f /tmp/branda-menu-SITE.php" + +mcp__ssh-unified__ssh_e \ No newline at end of file diff --git a/wordpress/skills/branda-menu/references/mapeamento-slugs.md b/wordpress/skills/branda-menu/references/mapeamento-slugs.md new file mode 100644 index 0000000..c9d01b7 --- /dev/null +++ b/wordpress/skills/branda-menu/references/mapeamento-slugs.md @@ -0,0 +1,100 @@ +# Mapeamento de Slugs para Seccoes Branda + +Referencia completa de mapeamento slug -> seccao e tabela de Branda IDs. + +--- + +## Mapeamento Standard por Slug + +``` +# Admin +index.php -> Admin +users.php -> Admin +options-general.php -> Admin +plugins.php -> Admin +tools.php -> Admin + +# Conteudo +edit.php -> Conteudo (Artigos) +edit.php?post_type=page -> Conteudo (Paginas) +upload.php -> Conteudo (Multimedia) +edit.php?post_type=acf-field-group -> Conteudo (ACF) +edit.php?post_type=* -> Conteudo (CPTs) + +# Design +elementor-home -> Design (Elementor) +edit.php?post_type=elementor_library -> Design (Modelos) +jkit -> Design (Jeg Kit) +themes.php -> Design (Apresentacao) + +# Marketing +fluentcrm-admin -> Marketing +fluent_forms -> Marketing +rank-math -> Marketing +click-to-chat -> Marketing + +# Idiomas (se multilingue) +mlang -> Idiomas (Polylang) +loco -> Idiomas (Loco Translate) + +# Performance +wpfastestcacheoptions -> Performance + +# Seguranca +Wordfence -> Seguranca +complianz -> Seguranca + +# WebMaster +branding -> WebMaster (Branda) +wpcode -> WebMaster (Code Snippets) + +# Hidden +separator1, separator2, separator-last -> Hidden +edit-comments.php -> Hidden +hello-elementor -> Hidden +elementor -> Hidden (duplicado de elementor-home) +``` + +**Itens que nao encaixam no standard:** Perguntar ao utilizador em que seccao colocar. Exemplos: WooCommerce, KiviCare, FareHarbor. + +--- + +## IDs de Slugs Comuns (referencia rapida) + +| Slug | Branda ID | +|------|-----------| +| `index.php` | `menu_item_42ho017e7jo0` | +| `edit.php` | `menu_item_6lk5pbiakha0` | +| `upload.php` | `menu_item_1jkdde99dfd0` | +| `edit.php?post_type=page` | `menu_item_774p5endtlu0` | +| `themes.php` | `menu_item_7jgmlsspgv60` | +| `plugins.php` | `menu_item_5g2kqk93qi30` | +| `users.php` | `menu_item_gajld83c8es0` | +| `tools.php` | `menu_item_3t0no8pv5bfg` | +| `options-general.php` | `menu_item_d1a8rsor9700` | +| `edit-comments.php` | `menu_item_252pn6seih20` | +| `separator1` | `menu_item_3u7nva84d1i0` | +| `separator2` | `menu_item_6lm7mo14a4r0` | +| `separator-last` | `menu_item_74g99t5jejn0` | +| `elementor-home` | `menu_item_2kehh8g6nop0` | +| `elementor` | `menu_item_27qkhd7iqao0` | +| `edit.php?post_type=elementor_library` | `menu_item_3rubghs8krfg` | +| `hello-elementor` | `menu_item_3q7v6ask7gpg` | +| `fluentcrm-admin` | `menu_item_4a7t8bi9mt30` | +| `fluent_forms` | `menu_item_ebai6etubd00` | +| `rank-math` | `menu_item_148bl1t91os0` | +| `click-to-chat` | `menu_item_1b65lubbpnd8` | +| `Wordfence` | `menu_item_1077vi8mf9b0` | +| `complianz` | `menu_item_5etmjgu9lnk0` | +| `wpfastestcacheoptions` | `menu_item_4hqsn1kbum10` | +| `branding` | `menu_item_7qde2b2f7670` | +| `wpcode` | `menu_item_69igp9fj4tl0` | +| `loco` | `menu_item_2c34vb7r1csg` | +| `mlang` | `menu_item_24um676vv08g` | +| `woocommerce` | Computar: `branda_id('woocommerce')` | +| `edit.php?post_type=acf-field-group` | `menu_item_70ga2p32mc70` | + +Para slugs nao listados, computar com: +```bash +wp eval 'echo "menu_item_" . substr(base_convert(md5("SLUG"), 16, 32), 0, 12);' --allow-root --path=/home/USER/SITE +``` diff --git a/wordpress/skills/branda-menu/references/script-template.md b/wordpress/skills/branda-menu/references/script-template.md new file mode 100644 index 0000000..b734aae --- /dev/null +++ b/wordpress/skills/branda-menu/references/script-template.md @@ -0,0 +1,174 @@ +# Script Template Branda Menu Builder + +Script PHP completo para construir e guardar menu Branda via WP-CLI. + +--- + +## Template Base + +```bash +mcp__ssh-unified__ssh_execute server:"server" command:"cat > /tmp/branda-menu-SITE.php << 'PHPEOF' + '', 'id_attribute' => '', 'css_classes' => '', + 'icon_svg' => '', 'icon_url' => '', 'icon_image_id' => '', + 'dashicon' => '', 'icon_type' => '', 'custom_url' => '', + 'link_type' => '', 'link_target' => '', 'is_invisible' => '', + 'is_hidden' => '', 'was_native' => 1, 'submenu' => \$subs + ); +} + +function hidden_item() { + \$item = native_item(); + \$item['is_hidden'] = '1'; + return \$item; +} + +function section_header(\$title, \$dashicon) { + return array( + 'icon_type' => 'dashicon', 'link_type' => 'none', + 'submenu' => array(), 'title' => \$title, + 'css_classes' => 'menu-highlight', 'dashicon' => \$dashicon + ); +} + +function custom_link(\$title, \$url, \$dashicon, \$target = '') { + return array( + 'icon_type' => 'dashicon', 'link_type' => 'custom', + 'submenu' => array(), 'title' => \$title, + 'dashicon' => \$dashicon, 'link_target' => \$target, + 'custom_url' => \$url + ); +} + +// === BUILD MENU === +\$menu = array(); + +// 1. SUPORTE +\$menu['menu_item_sec_suporte'] = section_header('Suporte', 'dashicons-admin-tools'); +\$menu['menu_item_desk_link'] = custom_link('Descomplicar', 'https://desk.descomplicar.pt/', 'dashicons-admin-comments', '_blank'); + +// 2. ADMIN +\$menu['menu_item_sec_admin'] = section_header('Admin', 'dashicons-admin-generic'); +\$menu[branda_id('index.php')] = native_item(); +\$menu[branda_id('users.php')] = native_item(); +\$menu[branda_id('options-general.php')] = native_item(); +\$menu[branda_id('plugins.php')] = native_item(); +\$menu[branda_id('tools.php')] = native_item(); + +// 3. CONTEUDO +\$menu['menu_item_sec_conteudo'] = section_header('Conteudo', 'dashicons-admin-page'); +\$menu[branda_id('edit.php?post_type=page')] = native_item(); +// [INSERIR CPTs DO PROJECTO AQUI] +\$menu[branda_id('edit.php')] = native_item(); +\$menu[branda_id('upload.php')] = native_item(); +\$menu[branda_id('edit.php?post_type=acf-field-group')] = native_item(); + +// 4. DESIGN +\$menu['menu_item_sec_design'] = section_header('Design', 'dashicons-admin-appearance'); +\$menu[branda_id('elementor-home')] = native_item(); +\$menu[branda_id('edit.php?post_type=elementor_library')] = native_item(); +// \$menu[branda_id('jkit')] = native_item(); // Se Jeg Kit activo +\$menu[branda_id('themes.php')] = native_item(); + +// 5. MARKETING +\$menu['menu_item_sec_marketing'] = section_header('Marketing', 'dashicons-megaphone'); +\$menu[branda_id('fluentcrm-admin')] = native_item(); +\$menu[branda_id('fluent_forms')] = native_item(); +\$menu[branda_id('rank-math')] = native_item(); +\$menu[branda_id('click-to-chat')] = native_item(); + +// 6. IDIOMAS (se multilingue) +// \$menu['menu_item_sec_idiomas'] = section_header('Idiomas', 'dashicons-translation'); +// \$menu[branda_id('mlang')] = native_item(); +// \$menu[branda_id('loco')] = native_item(); + +// 7. PERFORMANCE +\$menu['menu_item_sec_performance'] = section_header('Performance', 'dashicons-performance'); +\$menu[branda_id('wpfastestcacheoptions')] = native_item(); + +// 8. SEGURANCA +\$menu['menu_item_sec_seguranca'] = section_header('Seguranca', 'dashicons-shield'); +\$menu[branda_id('Wordfence')] = native_item(); +\$menu[branda_id('complianz')] = native_item(); + +// 9. WEBMASTER +\$menu['menu_item_sec_webmaster'] = section_header('WebMaster', 'dashicons-admin-settings'); +\$menu[branda_id('branding')] = native_item(); +\$menu[branda_id('wpcode')] = native_item(); + +// HIDDEN +\$menu[branda_id('separator1')] = hidden_item(); +\$menu[branda_id('separator2')] = hidden_item(); +\$menu[branda_id('separator-last')] = hidden_item(); +\$menu[branda_id('edit-comments.php')] = hidden_item(); +\$menu[branda_id('hello-elementor')] = hidden_item(); +\$menu[branda_id('elementor')] = hidden_item(); + +// SAVE +update_option('ub_custom_admin_menu', array('administrator' => \$menu)); +wp_cache_flush(); + +\$visible = count(array_filter(\$menu, function(\$i) { return empty(\$i['is_hidden']); })); +\$hidden = count(\$menu) - \$visible; +echo "Menu guardado: \$visible visiveis + \$hidden hidden = " . count(\$menu) . " total\n"; +PHPEOF +echo 'Script criado' +" + +# Executar +mcp__ssh-unified__ssh_execute server:"server" command:"wp eval-file /tmp/branda-menu-SITE.php --allow-root --path=/home/USER/SITE" +``` + +--- + +## Adaptacoes por Tipo de Site + +### Sites multilingue (Polylang/WPML) + +Descomentar seccao Idiomas no script. Adicionar: +```php +$menu['menu_item_sec_idiomas'] = section_header('Idiomas', 'dashicons-translation'); +$menu[branda_id('mlang')] = native_item(); // Polylang +$menu[branda_id('loco')] = native_item(); // Loco Translate +``` + +### Sites WooCommerce + +Adicionar seccao e-Commerce entre Marketing e Idiomas: +```php +$menu['menu_item_sec_ecommerce'] = section_header('e-Commerce', 'dashicons-cart'); +$menu[branda_id('woocommerce')] = native_item(); +``` + +### Sites Care (KiviCare) + +Adicionar seccao Clinica entre Marketing e Idiomas: +```php +$menu['menu_item_sec_clinica'] = section_header('Clinica', 'dashicons-heart'); +$menu[branda_id('kivicare-...')] = native_item(); // Verificar slug exacto +``` + +### CPTs customizados + +Adicionar na seccao Conteudo, antes de Artigos: +```php +$menu[branda_id('edit.php?post_type=SLUG_CPT')] = native_item(); +``` + +### Itens desconhecidos + +Se o menu nativo tiver itens que nao encaixam no mapeamento standard: +1. Perguntar ao utilizador onde colocar +2. Se plugin temporario/teste: adicionar ao Hidden +3. Se plugin permanente: criar seccao propria ou adicionar a seccao existente diff --git a/wordpress/skills/crocoblock/SKILL.md b/wordpress/skills/crocoblock/SKILL.md new file mode 100644 index 0000000..24f2063 --- /dev/null +++ b/wordpress/skills/crocoblock/SKILL.md @@ -0,0 +1,130 @@ +--- +name: crocoblock +description: Desenvolvimento com o ecossistema Crocoblock e todos os JetPlugins para Elementor. Cobre selecção, licenciamento, instalação, configuração e integração entre JetEngine, JetSmartFilters, JetWooBuilder, JetElements, JetPopup, JetFormBuilder e mais. +layer: wiki +--- + +# /crocoblock — Ecossistema Crocoblock + JetPlugins + +Desenvolvimento com o ecossistema Crocoblock: suite de plugins para Elementor cobrindo CPT, filtros AJAX, WooCommerce, forms, popups, booking e muito mais. + +## Matriz de Plugins + +| Plugin | Função Principal | Quando Usar | +|--------|-----------------|-------------| +| **JetEngine** | CPT, Meta Boxes, Relations, Query Builder, Listings, Dynamic Content | Qualquer site com conteúdo dinâmico/estruturado | +| **JetSmartFilters** | Filtros AJAX para listings e arquivos | Catálogos, portfolios, diretórios filtráveis | +| **JetWooBuilder** | Templates WooCommerce com Elementor | Lojas com design personalizado de produto/categoria/checkout | +| **JetElements** | Widgets adicionais (Timeline, Progress Bar, Circle Progress, Maps) | Adicionar widgets não disponíveis no Elementor base | +| **JetPopup** | Popups com triggers avançados | Lead capture, notificações, banners condicionais | +| **JetFormBuilder** | Forms com lógica condicional + notificações | Formulários complexos, integração CRM, booking light | +| **JetTabs** | Tabs, Accordions, Toggle | Conteúdo tabulado interactivo | +| **JetBlocks** | Widgets para header/footer (nav, cart, search) | Cabeçalhos e rodapés custom no Theme Builder | +| **JetSearch** | Pesquisa AJAX avançada | Sites com necessidade de search instantâneo | +| **JetBooking** | Sistema de booking/reservas | Alojamento, serviços com calendário de disponibilidade | +| **JetThemeCore** | Theme Builder alternativo ao Elementor Pro | Theme Builder sem licença Elementor Pro | +| **JetReviews** | Reviews/ratings para qualquer CPT | Reviews além de WooCommerce | +| **JetTricks** | Efeitos visuais (parallax, hotspot, unfold) | Elementos visuais avançados | +| **JetCompareWishlist** | Comparar e wishlist para produtos/CPT | E-commerce ou catálogos com comparação | + +## Licença e Instalação + +### Subscrição Crocoblock + +``` +Planos: Single Site / 3 Sites / Unlimited Sites (anual ou lifetime) +Todos os planos incluem todos os plugins + atualizações +Dashboard: account.crocoblock.com > Downloads +``` + +### Instalação (CWP) + +```bash +PHP="/opt/alt/php-fpm83/usr/bin/php" +WP="$PHP /usr/local/bin/wp --allow-root --path=/home/USER/public_html" + +# 1. Upload do ZIP via WP Admin ou WP-CLI +$WP plugin install /tmp/jet-engine.zip --activate + +# 2. Activar licença (via WP Admin > JetPlugins Licences) +# Cada plugin tem campo de licença separado +# Ou activar globalmente em Crocoblock > License + +# 3. Verificar versões +$WP plugin list --search="jet*" --fields=name,version,status --format=table +``` + +### Ordem de Instalação Recomendada + +``` +1. JetEngine (base do ecossistema — criar antes de outros) +2. JetSmartFilters (depende do JetEngine para filtrar listings) +3. JetElements (widgets independentes) +4. JetWooBuilder (se WooCommerce presente) +5. JetFormBuilder (forms independentes) +6. JetPopup (depende de Elementor Pro ou JetThemeCore) +7. JetBlocks (apenas se Theme Builder activo) +8. Restantes (conforme necessidade) +``` + +## Integrações Principais + +### JetEngine + JetSmartFilters (padrão mais comum) + +``` +JetEngine Query Builder → Listing Grid → JetSmartFilters + ↑ + Filtros ligados ao mesmo Query Builder ID +``` + +**Passos:** +1. Criar CPT no JetEngine +2. Criar Query Builder (tipo: Posts) +3. Criar Listing Template com Elementor +4. Adicionar Listing Grid ao Elementor (apontar para o Query) +5. Adicionar Filter Widget e ligar ao mesmo Listing Grid + +### JetEngine + JetWooBuilder + +``` +CPT Produto (WooCommerce) → JetEngine Meta Boxes → JetWooBuilder Template + ↑ + Campos custom visíveis no template +``` + +### JetEngine + JetFormBuilder + +``` +JetFormBuilder → Submit → Create/Update JetEngine Post + → Notificação email + → Redirect +``` + +### JetPopup Triggers Disponíveis + +| Trigger | Uso | +|---------|-----| +| On page load | Newsletter, anúncio | +| Exit intent | Retenção de visitante | +| Scroll (%) | Conteúdo contextual | +| Click on element | Mais informação inline | +| After inactivity | Re-engagement | +| User logged in/out | Conteúdo condicional | + +## Dify KB — Consultar Antes de Implementar + +```javascript +// Dataset Crocoblock (primário) +mcp__dify-kb__dify_kb_retrieve_segments({ + dataset_id: "bdf85c26-1824-4021-92d1-be20501b35ac", + query: "[componente ou funcionalidade]" +}) + +// Dataset Crocoblock alternativo +mcp__dify-kb__dify_kb_retrieve_segments({ + dataset_id: "139cdf67-afce-46ec-9ccd-2a06040e5b9d", + query: "[componente ou funcionalidade]" +}) +``` + +## Troubleshooting \ No newline at end of file diff --git a/wordpress/skills/crocoblock/references/automation.md b/wordpress/skills/crocoblock/references/automation.md new file mode 100644 index 0000000..bca229f --- /dev/null +++ b/wordpress/skills/crocoblock/references/automation.md @@ -0,0 +1,294 @@ +# Crocoblock — Automação Headless e Integrações Avançadas + +## 1. JetEngine 3.8.0 — MCP Server Nativo + +A partir da versão 3.8.0, o JetEngine inclui um **MCP Server nativo** que expõe a topologia completa do site a agentes IA (Claude, Copilot, Cursor). + +### Activar o MCP Server + +``` +WP Admin > JetEngine > AI Command Center > Enable MCP Server +→ URL do servidor: https://site.pt/wp-json/jet-engine/v1/mcp +→ Autenticação: Application Password +``` + +### Capacidades do MCP + +| Capacidade | Descrição | +|-----------|-----------| +| Inspecção de schema | Lista CPTs, CCTs, Meta Boxes, Taxonomias, Relações | +| Criação de CPT | Instanciar novo Custom Post Type via prompt | +| Criação de CCT | Definir Custom Content Type com campos tipados | +| Definir relações | Criar estruturas relacionais entre entidades | +| Query Builder | Criar queries estruturadas | + +**Caso de uso:** Cliente especifica necessidades → Claude interroga MCP → constrói arquitectura completa (CPT + CCT + Relations + Queries) sem GUI. + +--- + +## 2. JetFormBuilder — Formless Actions Endpoints + +O addon **Formless Actions Endpoints** permite usar as acções de um formulário JetFormBuilder como endpoint REST puro, sem renderizar formulário no frontend. + +### Como Activar + +``` +JetFormBuilder > Settings > Formless Actions Endpoints: Enable +Cada formulário recebe rota: POST /wp-json/jet-fb/v1/form/{form_id} +``` + +### Payload de Exemplo + +```bash +# Submeter dados para formulário sem interface visual +# Acciona todas as Post Submit Actions configuradas (Create Post, Email, Webhook, etc.) +curl -X POST https://site.pt/wp-json/jet-fb/v1/form/1234 \ + -H "Authorization: Basic dXNlcjpwYXNz..." \ + -H "Content-Type: application/json" \ + -d '{ + "nome_cliente": "Empresa ABC", + "email": "contacto@empresaabc.pt", + "valor_contrato": 5000, + "tipo_servico": "website" + }' +``` + +### Encadear Acções Complexas + +``` +Um único request pode: +1. Criar Post no CPT "Projecto" com status pending +2. Enviar email ao admin +3. Actualizar relação Cliente↔Projecto +4. Enviar Webhook para n8n +5. Criar registo em CCT "Notificacoes" +``` + +### Interceptar com Hook Custom + +```php +get_all(); + $texto = sanitize_textarea_field($dados['descricao'] ?? ''); + $post_id = absint($dados['post_id'] ?? 0); + + if (empty($texto) || !$post_id) { + // Cancelar o processamento com erro + throw new \Jet_Form_Builder\Exceptions\Action_Exception('campos_obrigatorios_vazios'); + } + + // Validação via API externa (exemplo: análise de risco) + $score = minha_api_de_risco($texto); + + if ($score > 90) { + throw new \Jet_Form_Builder\Exceptions\Action_Exception('risco_inaceitavel'); + } + + // Actualizar meta field com o score calculado + update_post_meta($post_id, '_score_risco', $score); + + $action_handler->add_response([ + 'status' => 'success', + 'message' => 'Processado com sucesso.', + 'score' => $score, + ]); + +}, 10, 2); +``` + +### Tabela de Registos + +```sql +-- JetFormBuilder guarda registo de cada submissão +SELECT * +FROM wp_jet_fb_records +WHERE form_id = 1234 +ORDER BY id DESC +LIMIT 10; +``` + +--- + +## 3. JetSmartFilters — Indexer e Automação + +### O Indexer + +O JetSmartFilters tem um subsistema de contagem chamado **Indexer** que mapeia contadores em `jet_smart_filters_indexer`. + +```sql +-- Ver contagens indexadas +SELECT * FROM jet_smart_filters_indexer +WHERE filter_id = 550 +LIMIT 20; +``` + +**Problema:** Após actualizações SQL directas nas tabelas CCT ou wp_jet_rel_default, os contadores dos filtros ficam desactualizados. + +**Solução:** + +```php +indexer->index_all(); + } +}); +``` + +```bash +# Via WP-CLI +PHP="/opt/alt/php-fpm83/usr/bin/php" +WP="$PHP /usr/local/bin/wp --allow-root --path=/home/USER/public_html" +$WP eval "jet_smart_filters()->indexer->index_all();" +``` + +### Manipular Filtros Programaticamente + +```php + '100', + 'max' => '500', + ]; + + // Forçar AJAX + $args['apply_type'] = 'ajax'; + + return $args; + +}, 10, 2); +``` + +### Forçar Re-indexação após SQL Massivo + +```php + 'POST', + 'callback' => function() { + wp_cache_flush(); + \Jet_Engine\Query_Builder\Manager::instance()->listings_cache->clear(); + jet_smart_filters()->indexer->index_all(); + return rest_ensure_response(['success' => true, 'message' => 'Re-indexação concluída.']); + }, + 'permission_callback' => function() { + return current_user_can('edit_posts'); + }, + ]); +}); +``` + +--- + +## 4. Kits e Templates — Export/Import Programático + +### Estrutura de um Kit + +``` +Kit JSON (manifest.json): +├── CPTs com todas as configurações +├── CCTs com schema de campos +├── Meta Boxes +├── Taxonomias +├── Relações +├── Query Builder queries +├── Listing Templates (Elementor) +└── JetFormBuilder forms +``` + +### Export via WP-CLI + +```bash +PHP="/opt/alt/php-fpm83/usr/bin/php" +WP="$PHP /usr/local/bin/wp --allow-root --path=/home/USER/public_html" + +# Exportar estrutura JetEngine para JSON +$WP eval ' +$cpts = get_option("jet_engine_cpt", []); +$ccls = get_option("jet_engine_ccl", []); +$rels = get_option("jet_engine_relations", []); +$metas = get_option("jet_engine_meta_boxes", []); +$kit_data = compact("cpts", "ccls", "rels", "metas"); +file_put_contents("/tmp/kit-jetengine.json", json_encode($kit_data, JSON_PRETTY_PRINT)); +' +echo "Kit exportado para /tmp/kit-jetengine.json" +``` + +### Import em Novo Ambiente + +```bash +# ATENÇÃO: os IDs das relações mudam entre ambientes +# Sempre usar slugs como referência, não IDs numéricos + +$WP eval-file /tmp/import-kit.php +$WP cache flush +$WP rewrite flush +``` + +### Pitfall de Migração — IDs de Relações + +``` +Problema: CCT item #45 no staging → ID #45 + Mesmo item no production após import → ID #102 + → Relações wp_jet_rel_default ficam com IDs errados + +Solução: Usar slug/título como referência durante migração + Converter para ID após import via get_posts(['name' => 'slug']) + Ou usar WP All Import para recriar relações com mapeamento de IDs +``` + +--- + +## 5. Integração WooCommerce + JetEngine + +### Queries em Produtos WooCommerce + +``` +Produtos WooCommerce são CPT 'product' → compatíveis com JetEngine +Query Builder pode filtrar produtos por meta fields JetEngine adicionados +JetWooBuilder consome estas queries para listagens customizadas +``` + +### Relações com Produtos + +```sql +-- Produtos relacionados com CPT "Fornecedor" via JetEngine Relations +SELECT p.post_title AS produto, f.post_title AS fornecedor +FROM wp_posts p +JOIN wp_jet_rel_default r ON r.child_object_id = p.ID +JOIN wp_posts f ON f.ID = r.parent_object_id +WHERE r.rel_id = 'relacao_fornecedores_produtos' +AND p.post_status = 'publish'; +``` + +--- + +## 6. Limitações e Riscos Críticos + +| Risco | Impacto | Mitigação | +|-------|---------|-----------| +| SQL directo em wp_postmeta serializado | **Crítico** — corrupção de dados | NUNCA. Usar PHP `unserialize → edit → serialize` | +| store_items_type = "replace" na REST API | **Destrutivo** — apaga todas as relações | Usar "update" salvo intenção explícita | +| Alterar wp_options serializados via SQL | **Crítico** — instalação WordPress corrompida | Sempre via PHP `get_option → update_option` | +| SQL sem flush de cache | Dados obsoletos em listings | Sempre `wp_cache_flush()` + `listings_cache->clear()` + `indexer->index_all()` | +| Registar meta boxes antes de init prioridade 12 | Falha silenciosa | Usar hook `jet-engine/meta-boxes/register-instances` | +| Importar Kit entre versões JetEngine diferentes | Dependências fantasma no Query Builder | Manter versões alinhadas em staging e production | + +--- + +*Crocoblock Automation | Descomplicar® | 18-02-2026* diff --git a/wordpress/skills/crocoblock/references/patterns.md b/wordpress/skills/crocoblock/references/patterns.md new file mode 100644 index 0000000..0625f78 --- /dev/null +++ b/wordpress/skills/crocoblock/references/patterns.md @@ -0,0 +1,220 @@ +# Crocoblock — Padrões de Integração Avançados + +## Padrão 1: Directório com Filtros + Mapa + +**Plugins:** JetEngine + JetSmartFilters + JetElements (Maps) + +``` +Arquitectura: +CPT "Negócio" (com meta: morada, coordenadas, categoria, horário) + ↓ +Query Builder (posts, post_type=negocio) + ↓ +┌────────────────┬──────────────────┐ +│ Listing Grid │ Listing Map │ +│ (cards) │ (pins) │ +└────────────────┴──────────────────┘ + ↑ sincronizados ↑ + JetSmartFilters: + - Categoria (checkbox, taxonomy) + - Localização (select, meta) + - Pesquisa (search text) + - Raio de distância (range, meta GPS) +``` + +**Configuração de sincronização:** +``` +Listing Map > Settings: +├── Synchronize with Listing Grid: YES +└── Listing Grid Selector: ID do widget Listing Grid + +JetSmartFilters > Apply For: +└── Seleccionar ID do Listing Grid + (o mapa segue automaticamente via sincronização) +``` + +--- + +## Padrão 2: Marketplace / Multi-vendor Simples + +**Plugins:** JetEngine + JetFormBuilder + JetSmartFilters + Profile Builder + +``` +Fluxo do vendedor: +1. Registo (JetFormBuilder → Register User) +2. Login +3. Dashboard vendedor (Profile Builder) +4. Criar produto (JetFormBuilder → Create Post no CPT) +5. Produto aparece no catálogo (Listing Grid filtrado por author) + +Fluxo do comprador: +1. Catálogo com filtros (JetSmartFilters) +2. Contactar vendedor (JetFormBuilder → Email ao author) +3. Ver perfil vendedor (Profile Builder page pública) +``` + +**Relations necessárias:** +``` +User → N Produtos (one-to-many) +User → N Favoritos (many-to-many) +Produto → N Reviews (one-to-many, via JetReviews) +``` + +--- + +## Padrão 3: Portal de Imobiliário + +**Plugins:** JetEngine + JetSmartFilters + JetWooBuilder (opcional) + JetBooking + +``` +CPT: Imóvel +Meta Boxes: +├── Preço (number) +├── Área m² (number) +├── Tipologia (select: T0/T1/T2/T3/T4+) +├── Tipo (select: venda/arrendamento) +├── Localização (taxonomy: Distrito → Concelho → Freguesia) +├── Coordenadas (map) +├── Galeria (gallery) +├── Características (checkbox-list: piscina, garagem, jardim...) +└── Agente responsável (posts: CPT Agente) + +Query Builder: +├── Ordenação: data / preço / área +└── Meta Query: tipo = "arrendamento" (para página específica) + +JetSmartFilters: +├── Range: Preço min-max +├── Range: Área min-max +├── Checkboxes: Tipologia +├── Select Hierarchical: Localização +├── Checkboxes: Características +└── Sorting: Preço ASC/DESC, Mais recentes +``` + +--- + +## Padrão 4: E-learning / Cursos + +**Plugins:** JetEngine + JetFormBuilder + Profile Builder + +``` +CPTs: +├── Curso (conteúdo, preço, dutor) +├── Lição (sub-item do curso) +└── Avaliação (questionário) + +Relations: +├── Curso → N Lições (one-to-many) +├── Utilizador → N Cursos Inscritos (many-to-many) +└── Utilizador → N Avaliações (one-to-many) + +Profile Builder Pages: +├── Meus Cursos (Query: cursos onde utilizador está inscrito) +├── Continuar Lição (última lição acedida) +└── Certificados (download PDF após conclusão) + +Automatização: +JetFormBuilder → compra → Inscrever no curso → Criar relação User↔Curso +``` + +--- + +## Padrão 5: Multi-Relation (Relações Aninhadas) + +``` +Exemplo: Agência → Clientes → Projectos → Tarefas + +Relations JetEngine: +├── agencia_clientes: Agência (1) → Clientes (N) +├── cliente_projectos: Cliente (1) → Projectos (N) +└── projecto_tarefas: Projecto (1) → Tarefas (N) + +No Listing Template de Agência: +├── Lista de Clientes (Relation Field Widget) +│ └── Dentro de cada Cliente: Lista de Projectos (nested listing) +│ └── Dentro de cada Projecto: Contador de Tarefas + +Nota: Listings aninhados afectam performance. + Limitar a 2 níveis de profundidade. + Para listas longas, usar AJAX/JetSmartFilters paginado. +``` + +--- + +## Padrão 6: User-Generated Content (UGC) + +**Plugins:** JetEngine + JetFormBuilder + Profile Builder + JetSmartFilters + +``` +Fluxo: +1. Utilizador logado → Dashboard (Profile Builder) +2. Formulário "Submeter Conteúdo" (JetFormBuilder) + → Action: Create Post no CPT "Aviso" com status "pending" + → Action: Email de notificação ao admin +3. Admin aprova → post_status = publish +4. Conteúdo aparece no listing público + +Queries do Dashboard: +├── "Os meus avisos" → Query: author = %current_user_id% + status = any +└── "Aprovados" → Query: author = %current_user_id% + status = publish + +Moderação rápida: +├── Admin lista pendentes com Listing Grid +└── JetFormBuilder inline para aprovar/rejeitar (Update Post Status) +``` + +--- + +## Padrão 7: JetBooking + WooCommerce + JetEngine + +``` +Fluxo de Reserva: +1. Página de serviço (CPT Serviço com meta JetEngine) +2. Calendário JetBooking (disponibilidade em tempo real) +3. Seleccionar datas → Form de reserva (JetFormBuilder ou JetBooking nativo) +4. Checkout WooCommerce (JetBooking cria produto temporário) +5. Pagamento → Reserva confirmada +6. Email de confirmação (JetBooking + SMTP) +7. Dashboard cliente (Profile Builder → Minhas Reservas) + +Automatização n8n: +JetBooking webhook → n8n → Google Calendar → SMS (via Twilio) +``` + +--- + +## Anti-Padrões (Evitar) + +### Demasiados JetPlugins Activos + +``` +Problema: Cada JetPlugin adiciona JS/CSS extra +Solução: Desactivar plugins não usados em cada site específico +Ferramenta: JetPlugins > Settings > Disable components não usados +``` + +### Listings Sem Paginação em Catálogos Grandes + +``` +Problema: Listing Grid sem paginação carrega todos os posts → PHP timeout +Solução: Sempre activar paginação ou Load More em listas >20 items +``` + +### JetSmartFilters Sem AJAX + +``` +Problema: URL-based filters recarregam a página inteira +Uso correcto: AJAX filters para UX fluida; URL-based apenas para SEO +``` + +### Meta Boxes em CCT Desnecessariamente + +``` +CCT não suporta taxonomies nativas, comentários, revisões. +Usar CPT quando precisar dessas funcionalidades WordPress. +``` + +--- + +*Crocoblock Patterns | Descomplicar® | 18-02-2026* diff --git a/wordpress/skills/crocoblock/references/plugins.md b/wordpress/skills/crocoblock/references/plugins.md new file mode 100644 index 0000000..81eb3cd --- /dev/null +++ b/wordpress/skills/crocoblock/references/plugins.md @@ -0,0 +1,240 @@ +# Crocoblock — Referência Detalhada de Plugins + +## JetElements + +Widgets adicionais para Elementor. Não depende do JetEngine. + +### Widgets Principais + +| Widget | Uso | +|--------|-----| +| Animated Box | Caixa com flip/hover reveal | +| Circle Progress | Gauge circular animado | +| Timeline | Cronologia vertical/horizontal | +| Countdown Timer | Contador regressivo | +| Scroll Navigation | Navegação por secções | +| Maps | Google Maps avançado | +| Weather | Widget de meteorologia | +| Price List | Lista de preços | +| Progress Bar | Barra de progresso | +| Slider | Slider de imagens/conteúdo | +| Portfolio | Grid de portfolio com filtros | +| Testimonials | Slider de testemunhos | + +--- + +## JetSmartFilters + +Filtros AJAX para qualquer listing (JetEngine, WooCommerce, Archive). + +### Tipos de Filtros + +| Tipo | Quando Usar | +|------|-------------| +| Checkboxes | Categorias múltiplas | +| Radio | Opção única (ordenação) | +| Select | Dropdown de valores | +| Range | Preço, área (slider min-max) | +| Date Range | Filtrar por datas | +| Search | Pesquisa por texto | +| Rating | Filtrar por estrelas | +| Color Picker | Filtros visuais por cor | + +### Configuração Essencial + +``` +1. Criar filter em JetSmartFilters > Filters +2. Seleccionar Source: JetEngine Query / WC_Query / WP_Query +3. Seleccionar Field: meta field / taxonomy / post field +4. Adicionar Filter Widget ao Elementor +5. Ligar ao Listing Grid via "Apply filters for" (seleccionar ID do listing) +``` + +### Filtros Aninhados (Dependent Filters) + +``` +Exemplo: Distrito → Concelho (filho depende do pai) +- Configurar taxonomy pai e filho no JetEngine +- Em JetSmartFilters: activar "Hierarchical taxonomy filter" +- Ou usar "Visible terms" com condição dinâmica +``` + +--- + +## JetWooBuilder + +Templates custom para WooCommerce via Elementor. + +### Templates Disponíveis + +| Template | Substitui | +|----------|-----------| +| Shop (Archive) | Página principal da loja | +| Product | Single product page | +| Cart | Página de carrinho | +| Checkout | Página de checkout | +| My Account | Dashboard do cliente | +| Thank You | Página pós-compra | +| Category | Página de categoria | + +### Widgets JetWooBuilder + +``` +Products Grid # Grid de produtos com query custom +Product Price # Preço com styling avançado +Product Gallery # Galeria com thumbnails +Add to Cart # Botão com variantes +Product Tabs # Descrição, Reviews, Atributos +Related Products # Produtos relacionados +Mini Cart # Cart dropdown +``` + +### Configurar Template de Produto + +``` +1. JetWooBuilder > Templates > Add New +2. Template Type: Product +3. Editar com Elementor — arrastar widgets JetWoo +4. Conditions: incluir "Product" (todos) ou específico por categoria/tag +``` + +--- + +## JetFormBuilder + +Forms com lógica condicional, integrações e notificações. + +### Tipos de Campos + +``` +Text, Email, Tel, URL, Number, Textarea +Date, Time, DateTime +Select, Radio, Checkboxes +File Upload, Image Upload +Hidden Field, Calculated Field +Repeater Field (subformulário dinâmico) +``` + +### Acções Pós-Submit + +| Acção | Função | +|-------|--------| +| Send Email | Notificação email standard | +| Send Email (Advanced) | Template HTML customizado | +| Create Post | Criar CPT (com JetEngine) | +| Update User | Actualizar user meta | +| Webhook | Enviar para n8n/Make/Zapier | +| Redirect | Redirecionar após submit | +| Register User | Criar conta WP | +| Login User | Login automático | +| MailChimp/ActiveCampaign | Subscrição newsletter | + +### Formulário Silencioso (Para n8n) + +```php +// Receber POST externo que passa pelas validações do JetFormBuilder +// Criar formulário com campos que correspondem ao payload +// Submeter via HTTP POST para: /wp-json/jet-form-builder/v1/process-form +// Autenticação: Application Passwords +``` + +--- + +## JetPopup + +Popups com triggers e condições de display avançadas. + +### Triggers + +| Trigger | Config | +|---------|--------| +| On Page Load | Delay em segundos | +| Exit Intent | Detecta movimento para fora | +| Scroll to Element | Scroll até % ou selector CSS | +| Click on Element | Selector CSS do trigger | +| After Inactivity | Segundos sem interacção | +| After N Page Views | Contador de visitas | +| Once Per Session | Não repete na sessão | + +### Conditions (Display) + +``` +URL match / URL contains +User logged in / out +User role +Device type (mobile/desktop) +WooCommerce: cart empty/not empty, specific product in cart +JetEngine: post type, taxonomy, specific post +``` + +--- + +## JetBooking + +Sistema de booking com calendário de disponibilidade. + +### Fluxo Base + +``` +1. Configurar Unidade de Booking (ex: Quarto, Serviço) +2. Definir preços (diários, por horas, temporada) +3. Definir disponibilidade e check-in/check-out rules +4. Criar template de booking com Elementor +5. Adicionar Calendário + Booking Form ao template +6. Configurar emails de confirmação +``` + +### Integração WooCommerce + +``` +JetBooking → WooCommerce Product → Checkout WooCommerce +- Preço calculado automaticamente (n noites × preço/noite) +- Stock = disponibilidade do calendário +``` + +--- + +## JetBlocks + +Widgets para construir headers e footers com Elementor. + +### Widgets Disponíveis + +``` +Navigation Menu # Menu responsivo avançado +Site Logo # Logo com dark mode toggle +Cart Button # Contador de itens no carrinho +Search Box # Pesquisa com AJAX +Auth Links # Login/Logout dinâmico +User Name # Nome do utilizador logado +Breadcrumbs # Fil d'Ariane +Mobile Menu # Menu hamburger +``` + +--- + +## JetThemeCore + +Theme Builder alternativo ao Elementor Pro (para licenças Free). + +### Templates + +``` +Header / Footer +Single (Posts, CPT) +Archive (Category, Tag, CPT Archive) +Search Results +404 +``` + +### Diferença vs Elementor Pro Theme Builder + +``` +JetThemeCore: Gratuito, condições básicas +Elementor Pro: Mais condições, melhor integração com Popup Builder +Recomendação: Usar Elementor Pro se disponível +``` + +--- + +*Crocoblock Plugins Reference | Descomplicar® | 18-02-2026* diff --git a/wordpress/skills/desk.project b/wordpress/skills/desk.project new file mode 100644 index 0000000..5678920 --- /dev/null +++ b/wordpress/skills/desk.project @@ -0,0 +1,6 @@ +{ + "task_id": null, + "project_id": null, + "customer_id": null, + "gitea_repo": null +} diff --git a/wordpress/skills/elementor/SKILL.md b/wordpress/skills/elementor/SKILL.md new file mode 100644 index 0000000..ecee749 --- /dev/null +++ b/wordpress/skills/elementor/SKILL.md @@ -0,0 +1,231 @@ +--- +name: elementor +description: Desenvolvimento avançado com Elementor Pro e ecossistema Crocoblock. Cria widgets custom, configura Theme Builder, automatiza deploys, manipula _elementor_data via MySQL, REST API, Dynamic Tags e cache CSS. +layer: wiki +--- + +# /elementor - Elementor Development + +Desenvolvimento avançado com Elementor Pro e Crocoblock. + +## Quando Usar + +- Criar widgets Elementor customizados +- Configurar Theme Builder +- Desenvolver com Crocoblock (JetEngine, JetWooBuilder) +- Optimizar performance Elementor +- Troubleshooting Elementor + +## Contexto NotebookLM + +ANTES de executar, consultar notebooks para contexto especializado: + +| Notebook | ID | Consultar quando | +|----------|-----|-----------------| +| WordPress e Elementor | 5be0d1a6 | Sempre | + +``` +mcp__notebooklm__notebook_query({ + notebook_id: "5be0d1a6-00f2-4cd9-b835-978cb7721601", + query: "" +}) +``` + +Integrar insights do NotebookLM nas recomendações e decisões. + +--- + +## Estrutura Custom Widget + +```php +start_controls_section( + 'content_section', + [ + 'label' => 'Content', + 'tab' => \Elementor\Controls_Manager::TAB_CONTENT, + ] + ); + + $this->add_control( + 'title', + [ + 'label' => 'Title', + 'type' => \Elementor\Controls_Manager::TEXT, + 'default' => 'Title', + ] + ); + + $this->end_controls_section(); + + // Style controls + $this->start_controls_section( + 'style_section', + [ + 'label' => 'Style', + 'tab' => \Elementor\Controls_Manager::TAB_STYLE, + ] + ); + + $this->add_control( + 'title_color', + [ + 'label' => 'Color', + 'type' => \Elementor\Controls_Manager::COLOR, + 'selectors' => [ + '{{WRAPPER}} .title' => 'color: {{VALUE}}', + ], + ] + ); + + $this->end_controls_section(); + } + + protected function render() { + $settings = $this->get_settings_for_display(); + ?> +
+

+
+ register(new \Custom_Widget()); +}); +``` + +## Theme Builder + +### Header + +``` +Site Logo | Navigation Menu | Search | Cart Icon +Sticky: Yes | Transparent: Optional +``` + +### Footer + +``` +4 Columns: About | Links | Contact | Social +Copyright row +``` + +### Single Post + +``` +Featured Image +Title + Meta (Author, Date, Categories) +Content +Author Box +Related Posts +``` + +### Archive + +``` +Title +Filters (JetSmartFilters) +Post Grid/List (JetEngine) +Pagination +``` + +## Crocoblock Plugins + +| Plugin | Uso Principal | +|--------|---------------| +| **JetEngine** | CPT, Meta Fields, Dynamic Content, Listings | +| **JetElements** | Widgets adicionais (Timeline, Progress Bar) | +| **JetSmartFilters** | Filtros AJAX para listings | +| **JetWooBuilder** | Templates WooCommerce avançados | +| **JetPopup** | Popups com triggers avançados | +| **JetTabs** | Tabs, Accordions, Toggle | +| **JetFormBuilder** | Forms com lógica condicional | + +## JetEngine - Custom Post Type + +```php +// Via código (alternativa ao JetEngine UI) +add_action('init', function() { + register_post_type('portfolio', [ + 'labels' => [ + 'name' => 'Portfolio', + 'singular_name' => 'Project' + ], + 'public' => true, + 'has_archive' => true, + 'supports' => ['title', 'editor', 'thumbnail'], + 'show_in_rest' => true, + ]); +}); + +// Meta boxes via JetEngine UI recomendado +``` + +## Performance Tips + +### 1. Lazy Load + +```php +// Activar lazy load para imagens +add_filter('wp_lazy_loading_enabled', '__return_true'); +``` + +### 2. Desactivar Google Fonts (se usar fonts locais) + +```php +add_filter('elementor/frontend/print_google_fonts', '__return_false'); +``` + +### 3. Limitar revisões + +```php +// wp-config.php +define('WP_POST_REVISIONS', 3); +``` + +### 4. Usar Flexbox Container + +``` +Preferir: Flexbox Container (moderno) +Evitar: Section > Column (legacy, mais pesado) +``` + +### 5. Minimizar Widgets + +``` +Regra: M \ No newline at end of file diff --git a/wordpress/skills/elementor/references/automation.md b/wordpress/skills/elementor/references/automation.md new file mode 100644 index 0000000..a4fcac8 --- /dev/null +++ b/wordpress/skills/elementor/references/automation.md @@ -0,0 +1,417 @@ +# Elementor — Automação Programática e Pipelines + +Referência técnica para manipular o Elementor sem GUI: WP-CLI, MySQL, REST API, PHP Hooks, Kits e CSS. + +--- + +## 1. WP-CLI + Elementor (CWP) + +### Formato Obrigatório CWP + +```bash +PHP="/opt/alt/php-fpm83/usr/bin/php" +WP="$PHP /usr/local/bin/wp --allow-root --path=/home/USER/public_html" +``` + +### Comandos Essenciais + +```bash +# Regenerar CSS (SEMPRE após qualquer alteração programática) +$WP elementor flush-css --regenerate + +# Substituição segura de URLs (evita corrupção JSON) +# NUNCA usar wp search-replace directamente em _elementor_data +$WP elementor replace-urls $URL_OLD $URL_NEW +$WP search-replace $URL_OLD $URL_NEW --skip-columns=guid + +# Importar Kit (design system completo) +$WP elementor kit import /tmp/kit.zip \ + --include=site-settings,templates,content \ + --overrideConditions=all + +# Sincronizar esquema BD após update do plugin +$WP elementor update db + +# Modo manutenção +$WP maintenance-mode activate +$WP maintenance-mode deactivate +``` + +### Pipeline de Deploy Completo + +```bash +#!/bin/bash +# Pipeline de rebranding via WP-CLI (CWP) +PHP="/opt/alt/php-fpm83/usr/bin/php" +SITE_PATH="/home/USER/public_html" +KIT_PATH="/tmp/rebranding-2026.zip" +URL_OLD="https://staging.agencia.com" +URL_NEW="https://www.producao.com" +WP="$PHP /usr/local/bin/wp --allow-root --path=$SITE_PATH" + +$WP maintenance-mode activate +$WP elementor kit import $KIT_PATH --include=site-settings,templates,content --overrideConditions=all +$WP elementor replace-urls $URL_OLD $URL_NEW +$WP search-replace $URL_OLD $URL_NEW --skip-columns=guid +$WP elementor flush-css --regenerate +$WP elementor update db +$WP maintenance-mode deactivate +``` + +### Avaliação do Método + +| Critério | Análise | +|----------|---------| +| Complexidade | Baixa — sintaxe documentada, comportamento previsível | +| Segurança | Alta — invoca internos do WordPress, risco apenas em SSH | +| Usar quando | Deploy, purga de cache, migração de URLs, sincronização BD | + +--- + +## 2. Manipulação Directa via MySQL + +### Estrutura _elementor_data + +O Elementor guarda layouts como JSON em `wp_postmeta`. Três meta keys obrigatórias: + +| Meta Key | Valor | +|----------|-------| +| `_elementor_edit_mode` | `builder` | +| `_elementor_template_type` | `wp-page`, `kit`, `header`, `footer` | +| `_elementor_data` | JSON array com toda a árvore de widgets | + +### Estrutura JSON Interna + +```json +[{ + "id": "3130e2cf", + "elType": "container", + "isInner": false, + "settings": { ... }, + "elements": [{ + "id": "a1b2c3d4", + "elType": "widget", + "widgetType": "button", + "settings": { + "text": "Clique aqui", + "link": { "url": "https://exemplo.com" } + } + }] +}] +``` + +### Query MySQL com JSON_REPLACE + +```sql +-- Substituição cirúrgica num widget específico +-- SEMPRE fazer backup antes +UPDATE wp_postmeta +SET meta_value = JSON_REPLACE( + meta_value, + '$.elements.elements.settings.link.url', + 'https://www.novo-destino.com/contacto' +) +WHERE meta_key = '_elementor_data' +AND post_id IN (1042, 1045, 1088); + +-- OBRIGATÓRIO após qualquer UPDATE directo: +-- Executar 'wp elementor flush-css --regenerate' via WP-CLI +``` + +### Regra Crítica: NUNCA wp search-replace + +```bash +# ERRADO — corrompe JSON silenciosamente (whitespace of death) +wp search-replace 'http://antigo.com' 'https://novo.com' + +# CORRECTO — usa lógica nativa do Elementor +wp elementor replace-urls 'http://antigo.com' 'https://novo.com' +``` + +### Avaliação do Método + +| Critério | Análise | +|----------|---------| +| Complexidade | Alta — parsing JSON, funções MySQL JSON_* | +| Segurança | Muito Baixa — sem validação, um char inválido corrompe a página | +| Usar quando | Auditoria forense, extracção analítica em massa (10.000+ posts) | + +--- + +## 3. REST API Custom Endpoint + +Para agentes externos (n8n, Make, Python) manipularem layouts via HTTP. + +### Registar Endpoint (functions.php ou plugin MU) + +```php + 'POST', + 'callback' => 'ai_agent_update_elementor_layout', + 'permission_callback' => function() { + return current_user_can('edit_pages'); + } + ]); +}); + +function ai_agent_update_elementor_layout(WP_REST_Request $request) { + $post_id = absint($request->get_param('post_id')); + $json_data = $request->get_param('elementor_json'); + + // wp_slash é OBRIGATÓRIO — protege JSON de corrupção de escape + update_post_meta($post_id, '_elementor_data', wp_slash(json_encode($json_data))); + update_post_meta($post_id, '_elementor_edit_mode', 'builder'); + + // Invalidação de cache OBRIGATÓRIA + delete_post_meta($post_id, '_elementor_css'); + if (did_action('elementor/loaded')) { + \Elementor\Plugin::$instance->files_manager->clear_cache(); + } + + return rest_ensure_response([ + 'status' => 'success', + 'post_id' => $post_id + ]); +} +``` + +### Autenticação + +```bash +# Via Application Passwords (WordPress 5.6+) +curl -X POST https://site.pt/wp-json/agencia-ai/v1/atualizar-layout \ + -H "Authorization: Basic $(echo -n 'user:app-password' | base64)" \ + -H "Content-Type: application/json" \ + -d '{"post_id": 2607, "elementor_json": [...]}' +``` + +### Avaliação do Método + +| Critério | Análise | +|----------|---------| +| Complexidade | Média — endpoint PHP + formatar JSON _elementor_data válido | +| Segurança | Alta — usa permissões WordPress + HTTPS | +| Usar quando | Webhooks, n8n/Make, geração de páginas a partir de CRM | + +--- + +## 4. PHP Hooks — Dynamic Tags + +Para conteúdo que se actualiza em runtime sem reescrever JSON. + +### Registar Dynamic Tag + +```php +register(new IA_Agente_Metrica_Tag()); +}); +``` + +### Padrão: Agente IA actualiza Transient + +```php +// Agente IA executa isto remotamente (via eval-file ou endpoint) +set_transient('ia_agente_ultima_metrica', '

Taxa de conversão: 4.2%

', DAY_IN_SECONDS); +``` + +### Avaliação do Método + +| Critério | Análise | +|----------|---------| +| Complexidade | Alta — OOP PHP, Event Loop WordPress, DynamicTags | +| Segurança | Muito Alta — lógica server-side, CI/CD, sem exposição JSON | +| Usar quando | Conteúdo em tempo real (cotações, stock, métricas) — requer Elementor **Pro** | + +--- + +## 5. Site Kits — Estrutura e Geração + +### Estrutura ZIP de um Kit + +``` +kit.zip +├── manifest.json # Índice mestre — mapeamento de todos os ficheiros +├── site-settings.json # Cores globais, tipografia, configurações do tema +├── header-template.json # Template de cabeçalho +├── footer-template.json # Template de rodapé +└── page-template.json # Templates de páginas +``` + +### manifest.json (estrutura mínima) + +```json +{ + "templates": [ + { + "title": "Header Principal", + "type": "header", + "fileName": "header-template.json" + } + ], + "site_settings": { + "title": "Site Settings", + "fileName": "site-settings.json" + } +} +``` + +### Geração em Python + +```python +import json, zipfile, os + +kit_settings = { + "version": "0.4", + "title": "Site Settings", + "settings": { + "system_colors": [ + {"_id": "primary", "title": "Primária", "color": "#1E40AF"}, + {"_id": "secondary", "title": "Secundária", "color": "#10B981"} + ], + "system_typography": [ + {"_id": "primary", "title": "Principal", "typography_font_family": "Inter"} + ] + } +} + +manifest = { + "templates": [], + "site_settings": {"title": "Site Settings", "fileName": "site-settings.json"} +} + +os.makedirs('/tmp/kit_build', exist_ok=True) + +with open('/tmp/kit_build/site-settings.json', 'w') as f: + json.dump(kit_settings, f) + +with open('/tmp/kit_build/manifest.json', 'w') as f: + json.dump(manifest, f) + +with zipfile.ZipFile('/tmp/agencia-kit.zip', 'w') as z: + z.write('/tmp/kit_build/manifest.json', 'manifest.json') + z.write('/tmp/kit_build/site-settings.json', 'site-settings.json') + +# Importar via WP-CLI (CWP) +# /opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp elementor kit import /tmp/agencia-kit.zip \ +# --include=site-settings,templates --overrideConditions=all \ +# --allow-root --path=/home/USER/public_html +``` + +--- + +## 6. CSS — Invalidação de Cache + +### Localização dos Ficheiros CSS + +``` +wp-content/uploads/elementor/css/post-{ID}.css # CSS por página +wp-content/uploads/elementor/css/global.css # CSS global +``` + +### Invalidação Programática (PHP) + +```php +// Após qualquer alteração directa a _elementor_data ou post_meta +if (did_action('elementor/loaded')) { + \Elementor\Plugin::$instance->files_manager->clear_cache(); +} + +// Alternativa: apagar meta específica +delete_post_meta($post_id, '_elementor_css'); +``` + +### Rebranding Global — Kit Activo + +```php +// Obter ID do kit activo +$kit_id = get_option('elementor_active_kit'); + +// Ler configurações globais +$settings = get_post_meta($kit_id, '_elementor_page_settings', true); + +// Alterar cor primária +if (!empty($settings['system_colors'])) { + foreach ($settings['system_colors'] as &$cor) { + if ($cor['_id'] === 'primary') { + $cor['color'] = '#FF0000'; + } + } +} + +// Guardar (wp_slash protege o JSON) +update_post_meta($kit_id, '_elementor_page_settings', $settings); + +// Invalidar cache CSS +if (did_action('elementor/loaded')) { + \Elementor\Plugin::$instance->files_manager->clear_cache(); +} +``` + +--- + +## 7. Regras Críticas e Riscos + +### Nunca fazer + +| Erro | Consequência | Correcto | +|------|-------------|----------| +| `wp search-replace` em `_elementor_data` | Corrupção silenciosa do JSON, layout desaparece | `wp elementor replace-urls` | +| UPDATE MySQL sem flush-css | CSS desactualizado, design dessincronizado | Sempre `wp elementor flush-css --regenerate` | +| `update_post_meta` sem `wp_slash()` | Corrupção de escapes no JSON | `wp_slash(json_encode($data))` | +| Múltiplos agentes a editar o mesmo post | Sobreposição de dados | Locks ou filas de processamento | + +### IDs de Widgets São Aleatórios + +Os IDs de nós JSON (ex: `"id":"3130e2cf"`) são alfanuméricos aleatórios. Para manipular um widget específico via MySQL ou REST API: + +1. Fazer parsing da árvore JSON completa primeiro +2. Encontrar o widget pelo `widgetType` ou conteúdo +3. Só então operar no ID correcto + +### Limitações Elementor Free vs Pro + +| Funcionalidade | Free | Pro | +|----------------|------|-----| +| `wp elementor flush-css` | ✅ | ✅ | +| `wp elementor kit import` | ✅ | ✅ | +| Dynamic Tags | ❌ | ✅ | +| Theme Builder (header/footer) | ❌ | ✅ | + +--- + +## 8. MCP Elementor (Integração Futura) + +O projecto **Ultimate Elementor MCP** expõe ~60 ferramentas para manipulação via linguagem natural: + +- `create_container`, `create_heading`, `delete_element` +- `get_page_structure` — lê árvore JSON (resolve problema dos IDs aleatórios) +- `update_widget_settings` + +**Autenticação:** Application Passwords ou JWT (mesma arquitectura do REST API). + +**Quando usar:** Assistentes conversacionais, automações complexas onde formatar JSON raw em Python seria impraticável. + +**Referência:** [Ultimate Elementor MCP — LobeHub](https://lobehub.com/mcp/mbrown1837-ultimate-elementor-mcp) + +--- + +*Automação Elementor | Descomplicar® | Baseado em: Manipulação Programática do Elementor — Automação via IA | 18-02-2026* diff --git a/wordpress/skills/index.md b/wordpress/skills/index.md new file mode 100644 index 0000000..1d7c6b4 --- /dev/null +++ b/wordpress/skills/index.md @@ -0,0 +1,8 @@ +# skills + +## Documentação + +- [README](README.md) +- [AGENTS](AGENTS.md) +- [STATUS](STATUS.md) +- [MEMORY](MEMORY.md) diff --git a/wordpress/skills/jetengine/SKILL.md b/wordpress/skills/jetengine/SKILL.md new file mode 100644 index 0000000..7c1e449 --- /dev/null +++ b/wordpress/skills/jetengine/SKILL.md @@ -0,0 +1,176 @@ +--- +name: jetengine +description: Desenvolvimento com JetEngine (Crocoblock). Cobre CPT, CCT, Meta Boxes, Taxonomias, Relations, Query Builder, Listing Grid/Map, Dynamic Content, Dynamic Tags, Macros, Profile Builder, REST API e automação headless. +layer: wiki +--- + +# /jetengine — JetEngine Development + +JetEngine é o núcleo do ecossistema Crocoblock: cria CPT, CCT, Meta Boxes, Relations, Queries e Listings com conteúdo dinâmico para Elementor. + +## CPT vs CCT — Escolha Crítica + +| | Custom Post Type (CPT) | Custom Content Type (CCT) | +|--|----------------------|--------------------------| +| **Storage** | `wp_posts` + `wp_postmeta` | Tabela SQL própria `wp_jet_cct_{slug}` | +| **Performance** | Lenta em queries complexas | Muito rápida (colunas reais) | +| **Compatibilidade** | Total WP ecosystem | Limitada (sem taxonomies nativas) | +| **REST API** | `/wp-json/wp/v2/{slug}` | `/wp-json/jet-cct/{slug}` | +| **Automação** | `wp_insert_post()` | `CCT_Data_Handler` ou SQL directo | +| **Usar quando** | Conteúdo editorial, SEO, plugins WP | Alta performance, CRUD automatizado, dashboards | + +**Regra prática:** CPT para conteúdo público/SEO; CCT para dados internos, integrações e alta escala. + +## Criar CPT + +``` +JetEngine > Post Types > Add New +├── Slug (único, sem espaços, lowercase) +├── Labels (Singular / Plural) +├── Suporte: title, editor, thumbnail, excerpt, custom-fields +├── REST API: Activar para integração externa +├── Archive: Activar se precisar de página de listagem +└── Admin Columns: Mostrar meta fields na tabela admin +``` + +## Meta Boxes e Campos + +### Tipos de Campos + +| Tipo | Uso | +|------|-----| +| `text` | Texto simples | +| `textarea` | Texto longo | +| `wysiwyg` | Editor rich text | +| `number` | Valor numérico | +| `select` | Dropdown de opções | +| `checkbox` | Verdadeiro/falso | +| `checkbox-list` | Múltipla selecção | +| `radio` | Opção única | +| `date` | Data (timestamp) | +| `media` | Upload de ficheiro/imagem | +| `gallery` | Múltiplas imagens | +| `repeater` | Campo repetível (sub-campos) | +| `posts` | Relação simples (seleccionar posts) | +| `color-picker` | Cor HEX | +| `map` | Coordenadas geográficas | +| `html` | HTML estático (apenas display) | + +### Repeater — Estrutura + +``` +Repeater Field "galeria_servicos": + ├── sub-campo: imagem (media) + ├── sub-campo: titulo (text) + └── sub-campo: descricao (textarea) + +Aceder em PHP: +$items = get_post_meta($post_id, 'galeria_servicos', true); +foreach ($items as $item) { ... } +``` + +## Relations + +### Tipos de Relação + +| Tipo | Exemplo | +|------|---------| +| One-to-Many | 1 Empresa → N Colaboradores | +| Many-to-Many | N Projectos ↔ N Tags custom | +| Self-relation | Artigo relacionado com outros artigos | +| User-to-Post | Utilizador → N Reservas | + +### Tabela SQL das Relações + +```sql +-- wp_jet_rel_default +-- parent_object_id | child_object_id | rel_id (hash da relação) + +-- Ler todos os filhos de um pai +SELECT child_object_id +FROM wp_jet_rel_default +WHERE parent_object_id = 123 +AND rel_id = 'relacao_empresa_colaboradores'; + +-- Ler o pai a partir de um filho +SELECT parent_object_id +FROM wp_jet_rel_default +WHERE child_object_id = 456 +AND rel_id = 'relacao_empresa_colaboradores'; +``` + +**Importante:** Nunca editar esta tabela directamente via SQL para criar relações — usar a API PHP do JetEngine (ver `references/automation.md`). + +## Query Builder + +Substitui o `WP_Query` com interface visual. Ligar ao Listing Grid. + +### Tipos de Query + +| Tipo | Usa | +|------|-----| +| Posts | CPT, posts, páginas | +| Terms | Taxonomias | +| Users | Utilizadores WP | +| Custom Content Type | Tabelas CCT | +| REST API | Endpoint externo | + +### Configurar Query Posts + +``` +JetEngine > Query Builder > Add New +├── Query Type: Posts +├── Post Type: [seleccionar CPT] +├── Order By: date / meta_value / rand / menu_order +├── Meta Query: adicionar condições de meta fields +├── Tax Query: filtrar por taxonomia +└── Author: específico ou current user +``` + +### Usar no Listing Grid + +``` +Elemento Elementor: Listing Grid +├── Listing Item: [seleccionar Listing Template] +├── Use Custom Query: YES → seleccionar Query criado acima +├── Items per page: N +└── Pagination: Activar se necessário +``` + +## Listing Grid e Listing Template + +### Criar Listing Template + +``` +JetEngine > Listings > Add New +├── Template Type: Default / Popup +├── Content From: Posts / CCT / User / Term +└── Editar com Elementor → usar Dynamic Tags +``` + +### Dynamic Tags no Listing Template + +``` +Post Title → {{ post_title }} +Field de Meta → Meta Field → seleccionar nome do campo +Imagem → Featured Image → meta field media +Link → Post URL / Custom Field URL +Relação → Relation Field +``` + +### Listing Map + +``` +JetEngine > Listings > Add New > Template Type: Map +├── Configurar campo de coordenadas (tipo: map no meta box) +├── Google Maps API Key: WP Admin > JetEngine > Settings +└── Ligar ao Query Builder +``` + +## Dynamic Content e Macros + +### Macros Comuns + +``` +%current_user_id% # ID do utilizador logado +%current_post_id% \ No newline at end of file diff --git a/wordpress/skills/jetengine/assets/descomplicar-jet-bridge.php b/wordpress/skills/jetengine/assets/descomplicar-jet-bridge.php new file mode 100644 index 0000000..58ff73a --- /dev/null +++ b/wordpress/skills/jetengine/assets/descomplicar-jet-bridge.php @@ -0,0 +1,226 @@ + 'POST', + 'callback' => [ $this, 'handle_request' ], + 'permission_callback' => function() { + // Autenticar via WordPress Application Passwords no n8n: + // Header: Authorization: Basic base64(user:app-password) + return current_user_can( 'edit_posts' ); + }, + ]); + } + + public function handle_request( WP_REST_Request $request ) { + $params = $request->get_json_params(); + $action = sanitize_text_field( $params['action'] ?? '' ); + + if ( ! function_exists( 'jet_engine' ) || ! class_exists( 'Jet_Engine' ) ) { + return new WP_Error( 'no_jet_engine', 'JetEngine não está activo.', [ 'status' => 500 ] ); + } + + switch ( $action ) { + case 'create_cct_item': + case 'update_cct_item': + return $this->handle_cct_write( $params ); + + case 'get_cct_item': + return $this->handle_cct_get( $params ); + + case 'delete_cct_item': + return $this->handle_cct_delete( $params ); + + case 'manage_relation': + return $this->handle_relation( $params ); + + default: + return new WP_Error( + 'invalid_action', + 'Acção inválida. Disponíveis: create_cct_item, update_cct_item, get_cct_item, delete_cct_item, manage_relation', + [ 'status' => 400 ] + ); + } + } + + /** + * Criar ou actualizar item CCT + * + * Payload: { + * "action": "create_cct_item", + * "cct_slug": "faturas", + * "item_data": { + * "titulo": "Fatura #1024", + * "valor": 500, + * "estado": "pendente" + * } + * } + * Para update, incluir "_ID": 42 em item_data. + */ + private function handle_cct_write( array $params ) { + $cct_slug = sanitize_key( $params['cct_slug'] ?? '' ); + $item_data = $params['item_data'] ?? []; + + if ( empty( $cct_slug ) ) { + return new WP_Error( 'missing_slug', 'cct_slug é obrigatório.', [ 'status' => 400 ] ); + } + + if ( empty( $item_data ) ) { + return new WP_Error( 'missing_data', 'item_data é obrigatório.', [ 'status' => 400 ] ); + } + + $handler = $this->get_cct_handler( $cct_slug ); + if ( is_wp_error( $handler ) ) return $handler; + + $result_id = $handler->update_item( $item_data ); + + if ( ! $result_id ) { + return new WP_Error( 'db_error', 'Falha ao guardar item na base de dados.', [ 'status' => 500 ] ); + } + + return rest_ensure_response( [ + 'success' => true, + 'item_id' => $result_id, + 'action' => isset( $item_data['_ID'] ) ? 'updated' : 'created', + ] ); + } + + /** + * Ler item CCT por ID + * + * Payload: { "action": "get_cct_item", "cct_slug": "faturas", "item_id": 42 } + */ + private function handle_cct_get( array $params ) { + $cct_slug = sanitize_key( $params['cct_slug'] ?? '' ); + $item_id = absint( $params['item_id'] ?? 0 ); + + if ( empty( $cct_slug ) || ! $item_id ) { + return new WP_Error( 'missing_data', 'cct_slug e item_id são obrigatórios.', [ 'status' => 400 ] ); + } + + $handler = $this->get_cct_handler( $cct_slug ); + if ( is_wp_error( $handler ) ) return $handler; + + $item = $handler->get_item( $item_id ); + + if ( ! $item ) { + return new WP_Error( 'not_found', "Item {$item_id} não encontrado no CCT '{$cct_slug}'.", [ 'status' => 404 ] ); + } + + return rest_ensure_response( [ + 'success' => true, + 'item' => $item, + ] ); + } + + /** + * Eliminar item CCT + * + * Payload: { "action": "delete_cct_item", "cct_slug": "faturas", "item_id": 42 } + */ + private function handle_cct_delete( array $params ) { + $cct_slug = sanitize_key( $params['cct_slug'] ?? '' ); + $item_id = absint( $params['item_id'] ?? 0 ); + + if ( empty( $cct_slug ) || ! $item_id ) { + return new WP_Error( 'missing_data', 'cct_slug e item_id são obrigatórios.', [ 'status' => 400 ] ); + } + + $handler = $this->get_cct_handler( $cct_slug ); + if ( is_wp_error( $handler ) ) return $handler; + + $result = $handler->delete_item( $item_id ); + + return rest_ensure_response( [ + 'success' => (bool) $result, + 'item_id' => $item_id, + 'deleted' => (bool) $result, + ] ); + } + + /** + * Criar ou remover relação entre dois items + * + * Payload: { + * "action": "manage_relation", + * "rel_key": "clientes-projetos", + * "parent_id": 10, + * "child_id": 20, + * "connect": true + * } + */ + private function handle_relation( array $params ) { + $rel_key = sanitize_text_field( $params['rel_key'] ?? '' ); + $parent_id = absint( $params['parent_id'] ?? 0 ); + $child_id = absint( $params['child_id'] ?? 0 ); + $connect = (bool) ( $params['connect'] ?? true ); + + if ( empty( $rel_key ) || ! $parent_id || ! $child_id ) { + return new WP_Error( + 'missing_data', + 'rel_key, parent_id e child_id são obrigatórios.', + [ 'status' => 400 ] + ); + } + + if ( ! class_exists( '\Jet_Engine\Relations\Manager' ) ) { + return new WP_Error( 'no_relations', 'Módulo de Relações JetEngine não disponível.', [ 'status' => 500 ] ); + } + + \Jet_Engine\Relations\Manager::get_instance()->process_relation( + $rel_key, + $parent_id, + $child_id, + $connect + ); + + return rest_ensure_response( [ + 'success' => true, + 'action' => $connect ? 'connected' : 'disconnected', + 'rel_key' => $rel_key, + 'parent' => $parent_id, + 'child' => $child_id, + ] ); + } + + /** + * Obter CCT handler com verificação de erro + */ + private function get_cct_handler( string $cct_slug ) { + $cct_module = jet_engine()->modules->get_module( 'custom-content-types' ); + + if ( ! $cct_module ) { + return new WP_Error( 'no_cct_module', 'Módulo CCT não está activo no JetEngine.', [ 'status' => 500 ] ); + } + + $manager = $cct_module->instance->manager; + $type = $manager->get_content_type_instance( $cct_slug ); + + if ( ! $type ) { + return new WP_Error( 'invalid_cct', "CCT '{$cct_slug}' não encontrado.", [ 'status' => 404 ] ); + } + + return $type->get_handler_instance(); + } +} + +new Descomplicar_Jet_Bridge(); diff --git a/wordpress/skills/jetengine/references/automation.md b/wordpress/skills/jetengine/references/automation.md new file mode 100644 index 0000000..b626983 --- /dev/null +++ b/wordpress/skills/jetengine/references/automation.md @@ -0,0 +1,668 @@ +# JetEngine — Automação Headless e Integração com Agentes IA + +Arquitectura técnica para manipular o JetEngine sem wp-admin: via PHP interno, REST API, SQL e n8n. + +--- + +## 1. Estrutura de Dados — Base de Dados + +### A. Custom Post Types (CPT) — Estrutura Standard WP + +```sql +-- Dados em wp_posts +SELECT * FROM wp_posts WHERE post_type = 'meu_cpt' AND post_status = 'publish'; + +-- Meta fields em wp_postmeta +SELECT meta_key, meta_value FROM wp_postmeta WHERE post_id = 123; +``` + +**Limitação:** Queries complexas com múltiplos meta fields são lentas (JOIN por cada meta key). + +### B. Custom Content Types (CCT) — Tabelas SQL Próprias + +Cada CCT tem tabela dedicada: `wp_jet_cct_{slug_do_cct}` + +```sql +-- Exemplo: CCT "faturas" → tabela wp_jet_cct_faturas +-- Colunas são os campos definidos no JetEngine + +-- Ler todos os itens activos +SELECT * FROM wp_jet_cct_faturas WHERE cct_status = 'active'; + +-- Filtrar por campo +SELECT * FROM wp_jet_cct_clientes +WHERE cidade = 'Lisboa' +AND cct_status = 'publish' +ORDER BY _created_at DESC +LIMIT 20; + +-- Campos especiais em todos os CCT: +-- _ID → ID numérico único +-- cct_status → publish / draft +-- cct_author_id → ID do utilizador criador +-- _created_at → Unix timestamp de criação +-- _modified → Unix timestamp de modificação +``` + +**Vantagem:** SQL directo é seguro e extremamente rápido. Ideal para leitura em dashboards e n8n. + +### C. Relations — Tabelas wp_jet_rel_default e _meta + +O JetEngine NÃO guarda relações em `wp_postmeta`. Tem tabela própria. + +```sql +-- wp_jet_rel_default: relações básicas +-- parent_object_id | child_object_id | rel_id (hash/slug da relação) + +-- Ler filhos de um pai +SELECT child_object_id +FROM wp_jet_rel_default +WHERE parent_object_id = 123 +AND rel_id = 'relacao_clientes_projetos'; + +-- Ler pai a partir de filho +SELECT parent_object_id +FROM wp_jet_rel_default +WHERE child_object_id = 456 +AND rel_id = 'relacao_clientes_projetos'; + +-- Contar relações +SELECT parent_object_id, COUNT(*) as total +FROM wp_jet_rel_default +WHERE rel_id = 'relacao_empresa_colaboradores' +GROUP BY parent_object_id; +``` + +**wp_jet_rel_default_meta** — metadados específicos de uma relação (ex: papel do actor num filme): + +```sql +-- Exemplo: condição de uso de um veículo numa relação utilizador↔veículo +SELECT meta_key, meta_value +FROM wp_jet_rel_default_meta +WHERE rel_id = 8 +AND parent_object_id = 45 +AND child_object_id = 1020; + +-- UPSERT massivo para sincronizações ETL (com integridade referencial) +START TRANSACTION; +INSERT INTO wp_jet_rel_default (rel_id, parent_object_id, child_object_id) +VALUES (8, 45, 1020), (8, 45, 1021), (8, 92, 1055) +ON DUPLICATE KEY UPDATE parent_object_id = VALUES(parent_object_id); + +INSERT INTO wp_jet_rel_default_meta (rel_id, parent_object_id, child_object_id, meta_key, meta_value) +VALUES (8, 45, 1020, 'condicao_uso', 'Alugado') +ON DUPLICATE KEY UPDATE meta_value = VALUES(meta_value); +COMMIT; +-- OBRIGATÓRIO após SQL directo: chamar wp_cache_flush() + jet_smart_filters()->indexer->index_all() +``` + +**Nota:** Em relações críticas com muito tráfego, o JetEngine pode isolar por relação em tabela própria (`wp_jet_rel_81_meta`), reduzindo table locks. + +**Guardrail:** NUNCA inserir directamente via SQL para criar relações em ambientes activos. Usar API PHP (ver secção 2). SQL directo só para sincronizações ETL massivas (centenas de milhares de linhas). + +### D. Custom Meta Storage para CPT (Tabela Dedicada) + +Alternativa ao `wp_postmeta` para CPTs com muitos campos e consultas complexas. + +``` +JetEngine > Post Types > Edit > Custom Meta Storage: Activar +→ Cria tabela dedicada: wp_{cpt_slug}_meta + (ex: wp_imoveis_meta com colunas tipadas por campo) +``` + +```sql +-- Com Custom Meta Storage activo, cada campo é uma coluna +SELECT preco, area_m2, tipologia, localizacao +FROM wp_imoveis_meta +WHERE preco BETWEEN 150000 AND 350000 +AND tipologia IN ('T2', 'T3') +ORDER BY preco ASC; + +-- Joins com wp_posts permanecem necessários para title/date +SELECT p.ID, p.post_title, m.preco, m.area_m2 +FROM wp_posts p +JOIN wp_imoveis_meta m ON m.post_id = p.ID +WHERE p.post_status = 'publish' +AND m.preco < 300000; +``` + +**Quando usar:** CPTs com >10 campos numéricos/date, queries com múltiplos filtros simultâneos, alternativa a CCT quando se precisa de taxonomias e comentários nativos WP. + +### E. Estrutura na wp_options + +```sql +-- Configurações de CPTs +SELECT option_value FROM wp_options WHERE option_name = 'jet_engine_cpt'; + +-- Taxonomias +SELECT option_value FROM wp_options WHERE option_name = 'jet_engine_tax'; + +-- Relações +SELECT option_value FROM wp_options WHERE option_name = 'jet_engine_relations'; + +-- Meta Boxes +SELECT option_value FROM wp_options WHERE option_name = 'jet_engine_meta_boxes'; +``` + +**Aviso:** São PHP serialized arrays. NUNCA editar via SQL string replace — vai corromper. Usar sempre `unserialize → edit → serialize` em PHP. + +--- + +## 2. PHP — API Interna JetEngine + +### Criar/Actualizar Item CCT + +```php + 'Fatura #1024', + 'valor' => 500.00, + 'status' => 'pendente', + 'cliente' => 'Empresa X Lda', + // Para update, incluir _ID existente: + // '_ID' => 15 +]; + +// Aceder ao módulo CCT +if (function_exists('jet_engine')) { + $cct_module = jet_engine()->modules->get_module('custom-content-types'); + if ($cct_module) { + $manager = $cct_module->instance->manager; + $type = $manager->get_content_type_instance($cct_slug); + if ($type) { + $result = $type->get_handler_instance()->update_item($item_data); + // $result = ID do item criado, ou false em caso de erro + } + } +} +``` + +### Gerir Relações Programaticamente + +```php + 12 + +if (class_exists('\Jet_Engine\Relations\Manager')) { + $relations_manager = \Jet_Engine\Relations\Manager::get_instance(); + $relations_manager->process_relation( + $rel_id, // ex: 'relacao_empresa_colaboradores' + $parent_id, + $child_id, + true // true = conectar, false = desconectar + ); +} + +// Método 2: API completa (update com contexto — mais robusto) +function ia_conectar_com_contexto($cliente_id, $documento_id) { + $rel_id_numerico = 15; // ID numérico da relação (ver JetEngine > Relations) + + $relation = jet_engine()->relations->get_active_relations($rel_id_numerico); + + if ($relation) { + $relation->set_update_context('parent'); // perspectiva: 'parent' ou 'child' + $relation->update($cliente_id, $documento_id); + + // Limpar cache do Query Builder após actualizar relações + \Jet_Engine\Query_Builder\Manager::instance()->listings_cache->clear(); + } +} +``` + +### Criar/Actualizar CPT Post + +```php + 'Novo Projecto', + 'post_content' => '', + 'post_status' => 'publish', + 'post_type' => 'projecto', +]; + +$post_id = wp_insert_post($post_data); + +if (!is_wp_error($post_id)) { + update_post_meta($post_id, 'cliente_id', 45); + update_post_meta($post_id, 'valor_contrato', 5000); + update_post_meta($post_id, 'data_inicio', '2026-03-01'); +} +``` + +### Manipular Estrutura (Onboarding Programático) + +```php + 'imovel', + 'singular_name' => 'Imóvel', + 'name' => 'Imóveis', + 'show_in_rest' => true, + 'supports' => ['title', 'editor', 'thumbnail', 'custom-fields'], + // ... outras configurações +]; + +$current_cpts[] = $new_cpt; +update_option('jet_engine_cpt', $current_cpts); + +// Obrigatório: regenerar permalinks após alterar CPTs +flush_rewrite_rules(); +``` + +### Registar Meta Box Programaticamente (Hook) + +```php + 'ID Remoto de Sincronização', + 'name' => '_ia_sync_id', + 'object_type' => 'field', + 'type' => 'text', + 'width' => '50%', + ], + [ + 'title' => 'Score de Auditoria', + 'name' => '_score_auditoria', + 'object_type' => 'field', + 'type' => 'number', + 'width' => '50%', + ], + ]; + + $post_type = 'documento_legal'; + + if (!class_exists('Jet_Engine_CPT_Meta')) { + require $meta_manager->component_path('post.php'); + } + + $meta_manager->store_fields($post_type, $meta_fields, 'post_type'); + new Jet_Engine_CPT_Meta($post_type, $meta_fields, 'Controlo IA', 'normal', 'high', [ + 'object_type' => 'post', + 'allowed_post_type' => [$post_type], + 'name' => 'Controlo de Metadados IA', + ]); +}); +``` + +### WP-CLI Batch Import para CCT + +```php +manager; +$content_type = $manager->get_content_types($cct_slug); + +if (!$content_type) { + WP_CLI::error("CCT '{$cct_slug}' não encontrado."); +} + +$registos = json_decode(file_get_contents('/tmp/veiculos.json'), true); +$sucesso = 0; + +foreach ($registos as $dados) { + // db->insert() respeita sanitizações e integridade do CCT + if ($content_type->db->insert($dados)) { + $sucesso++; + } + // Libertar memória em loops grandes + if ($sucesso % 500 === 0) { + wp_cache_flush(); + } +} + +wp_cache_flush(); +WP_CLI::success("Importação concluída. Registos criados: {$sucesso}"); +``` + +```bash +# Execução no servidor CWP: +PHP="/opt/alt/php-fpm83/usr/bin/php" +WP="$PHP /usr/local/bin/wp --allow-root --path=/home/USER/public_html" +$WP eval-file /tmp/import_cct_data.php +``` + +--- + +## 3. REST API JetEngine + +### Endpoints + +| Tipo | Endpoint | Método | +|------|----------|--------| +| CPT | `/wp-json/wp/v2/{cpt_slug}` | GET / POST / PUT / DELETE | +| CCT | `/wp-json/jet-cct/{cct_slug}` | GET / POST / PUT / DELETE | +| Relação | `/wp-json/jet-rel/{relation_id}` | GET / POST | + +**Pré-requisito:** Activar REST API nas configurações do CPT/CCT/Relação em JetEngine. + +### Autenticação + +```bash +# Application Passwords (WP 5.6+) — recomendado para n8n +# Criar em: WP Admin > Users > Edit > Application Passwords + +# Header de autenticação +Authorization: Basic $(echo -n 'username:app-password' | base64) +``` + +### Criar/Ler Item CCT via REST + +```bash +# Criar registo no CCT "clientes" +curl -X POST https://site.pt/wp-json/jet-cct/clientes \ + -H "Authorization: Basic dXNlcjpwYXNz..." \ + -H "Content-Type: application/json" \ + -d '{ + "nome_cliente": "Empresa X Lda", + "email": "contacto@empresax.com", + "nif": "123456789", + "cct_status": "publish" + }' +# Resposta: { "_ID": 42, ... } + +# Pesquisa com filtros — parâmetros CCT REST API +# _limit, _offset: paginação +# _cct_search: pesquisa de texto +# _cct_search_by: campo específico +curl "https://site.pt/wp-json/jet-cct/clientes?_limit=20&_offset=0&_cct_search=Lisboa&_cct_search_by=cidade" +# Header de resposta inclui: Jet-Query-Total (total de registos para paginação) +``` + +### Actualizar Relação via REST API + +```bash +# POST para /wp-json/jet-rel/{relation_id} +# store_items_type: "update" (aditivo) | "replace" (destrutivo!) | "disconnect" (remover) +curl -X POST https://site.pt/wp-json/jet-rel/22 \ + -H "Authorization: Basic dXNlcjpwYXNz..." \ + -H "Content-Type: application/json" \ + -d '{ + "parent_id": 4500, + "child_id": 1020, + "context": "child", + "store_items_type": "update", + "meta": { + "etapa_validacao": "Aprovado", + "score_auditoria": 88.5, + "data_processamento": "2026-02-18T08:30" + } + }' +``` + +**Atenção `store_items_type`:** +- `update` — adiciona à relação existente (safe) +- `replace` — **DESTRÓI todas as relações existentes** e substitui (perigoso!) +- `disconnect` — remove a relação específica + +### Criar Post (CPT) via REST + +```bash +curl -X POST https://site.pt/wp-json/wp/v2/projecto \ + -H "Authorization: Basic dXNlcjpwYXNz..." \ + -H "Content-Type: application/json" \ + -d '{ + "title": "Projecto Website ABC", + "status": "publish", + "meta": { + "cliente_id": 45, + "valor_contrato": 5000 + } + }' +``` + +### Campos Repeater via REST + +```json +{ + "galeria_servicos": [ + { "titulo": "Serviço A", "descricao": "Descrição A" }, + { "titulo": "Serviço B", "descricao": "Descrição B" } + ] +} +``` + +--- + +## 4. Integração n8n + +### Leitura (MySQL Node — mais rápido) + +```javascript +// n8n MySQL Node — ler CCT directamente da BD +// Muito mais rápido que REST API para leitura em massa + +// Query example: +SELECT + _ID, + nome_cliente, + email, + cidade, + cct_status, + _created_at +FROM wp_jet_cct_clientes +WHERE cct_status = 'publish' +ORDER BY _created_at DESC +LIMIT 100; +``` + +**Vantagem:** 100x mais rápido que HTTP Request ao WP REST API. + +### Escrita (HTTP Request Node — via REST) + +```javascript +// n8n HTTP Request Node +// Method: POST +// URL: https://site.pt/wp-json/jet-cct/faturas +// Authentication: Basic Auth +// Body (JSON): +{ + "numero": "{{ $json.fatura_numero }}", + "cliente_id": "{{ $json.cliente_id }}", + "valor": "{{ $json.total }}", + "cct_status": "publish" +} +``` + +**Usar REST para escrita** (garante hooks JetEngine e validações). + +### Webhooks via JetFormBuilder + +``` +JetFormBuilder pode disparar Webhook para n8n: +1. Criar formulário no JetFormBuilder +2. Post-submit Action: Webhook +3. URL: https://n8n.descomplicar.pt/webhook/jetengine +4. Formulários silenciosos: receber POST externos que passam pelas validações JetEngine +``` + +--- + +## 5. Tabela de Métodos + +| Método | Complexidade | Performance | Risco | Caso de Uso | +|--------|-------------|-------------|-------|-------------| +| REST API | Baixa | Média | Baixo | Inserir dados externos via n8n | +| PHP (Classes Internas) | Média | Alta | Baixo | Plugins custom, scripts de migração | +| SQL Directo (CCT) | Alta | Muito Alta | Médio | Bulk updates, leitura analytics | +| SQL Directo (Meta) | Alta | Baixa | **Alto** | **Evitar** — corrupção de arrays | +| WP-CLI Custom | Média | Alta | Baixo | Manutenção, cron jobs | + +--- + +## 6. Guardrails Críticos + +### Cache JetEngine + +```bash +# Após alterar estruturas via PHP/SQL na wp_options, +# forçar regeneração de cache: + +PHP="/opt/alt/php-fpm83/usr/bin/php" +WP="$PHP /usr/local/bin/wp --allow-root --path=/home/USER/public_html" + +$WP cache flush +$WP rewrite flush +$WP elementor flush-css --regenerate +``` + +**Cache do Query Builder** — obrigatório após alterações SQL directas: + +```php +listings_cache->clear(); + +// Recalcular Indexer do JetSmartFilters (se filtros activos) +if (function_exists('jet_smart_filters')) { + jet_smart_filters()->indexer->index_all(); +} + +// Cache do WordPress +wp_cache_flush(); +``` + +**Regra crítica:** Alterações SQL directas em `wp_jet_cct_*` ou `wp_jet_rel_default` NÃO invalidam automaticamente o Object Cache nem os transients do Query Builder. O site apresentará dados obsoletos até ao flush. + +### NUNCA Editar Campos Serializados via SQL String Replace + +```sql +-- ERRADO — corrompe o array PHP serializado +UPDATE wp_options +SET option_value = REPLACE(option_value, 'Imóveis', 'Propriedades') +WHERE option_name = 'jet_engine_cpt'; + +-- CORRECTO — usar PHP +$cpts = get_option('jet_engine_cpt'); +// Fazer alterações via PHP +update_option('jet_engine_cpt', $cpts); +``` + +### IDs de Relações em Migrações + +``` +Problema: Ao migrar dados entre ambientes, IDs podem mudar → relações quebram +Solução: Usar Slugs como referência no código; converter para ID antes de gravar +Usar: get_posts(['name' => 'slug-do-post', 'post_type' => 'meu_cpt']) +``` + +### Repeater Fields via SQL + +``` +Repeater fields são PHP serialize() ou JSON dependendo da configuração. +NUNCA fazer string replace em SQL. +Usar sempre: unserialize() → editar array → serialize() → update_post_meta() +``` + +--- + +## 7. MU-Plugin: Wrapper de Endpoints Custom + +Para expor endpoints seguros ao n8n sem passar pela REST API standard: + +```php +[a-z_]+)', [ + 'methods' => 'POST', + 'callback' => 'jet_agent_create_cct_item', + 'permission_callback' => function() { + return current_user_can('edit_posts'); + }, + 'args' => [ + 'slug' => ['required' => true, 'sanitize_callback' => 'sanitize_key'], + ] + ]); + + // Endpoint para gerir relações + register_rest_route('jet-agent/v1', '/relation', [ + 'methods' => 'POST', + 'callback' => 'jet_agent_manage_relation', + 'permission_callback' => function() { + return current_user_can('edit_posts'); + } + ]); +}); + +function jet_agent_create_cct_item(WP_REST_Request $request) { + $slug = $request->get_param('slug'); + $data = $request->get_json_params(); + + // Sanitizar dados + $data = array_map('sanitize_text_field', $data); + + // Usar handler interno do JetEngine + if (!function_exists('jet_engine')) { + return new WP_Error('jet_engine_missing', 'JetEngine não activo', ['status' => 500]); + } + + $cct_module = jet_engine()->modules->get_module('custom-content-types'); + $type = $cct_module->instance->manager->get_content_type_instance($slug); + + if (!$type) { + return new WP_Error('cct_not_found', "CCT '{$slug}' não encontrado", ['status' => 404]); + } + + $result = $type->get_handler_instance()->update_item($data); + + return rest_ensure_response([ + 'success' => (bool)$result, + 'id' => $result, + ]); +} + +function jet_agent_manage_relation(WP_REST_Request $request) { + $params = $request->get_json_params(); + $rel_id = sanitize_text_field($params['rel_id'] ?? ''); + $parent_id = absint($params['parent_id'] ?? 0); + $child_id = absint($params['child_id'] ?? 0); + $connect = (bool)($params['connect'] ?? true); + + if (!$rel_id || !$parent_id || !$child_id) { + return new WP_Error('missing_params', 'rel_id, parent_id e child_id são obrigatórios', ['status' => 400]); + } + + if (class_exists('\Jet_Engine\Relations\Manager')) { + \Jet_Engine\Relations\Manager::get_instance()->process_relation( + $rel_id, $parent_id, $child_id, $connect + ); + return rest_ensure_response(['success' => true]); + } + + return new WP_Error('relations_missing', 'Módulo Relations não disponível', ['status' => 500]); +} +``` + +--- + +*JetEngine Automation | Descomplicar® | 18-02-2026* diff --git a/wordpress/skills/jetengine/references/dynamic-content.md b/wordpress/skills/jetengine/references/dynamic-content.md new file mode 100644 index 0000000..196c806 --- /dev/null +++ b/wordpress/skills/jetengine/references/dynamic-content.md @@ -0,0 +1,271 @@ +# JetEngine — Dynamic Content, Macros e Profile Builder + +## Dynamic Tags no Elementor + +### Categorias de Dynamic Tags JetEngine + +| Categoria | Tags Disponíveis | +|-----------|-----------------| +| **Post** | Post Title, Post URL, Post Date, Post Author, Featured Image, Post Terms | +| **Meta** | Meta Field (qualquer campo JetEngine) | +| **User** | User Name, User Email, User Role, User Meta | +| **Relations** | Relation Field (conteúdo relacionado) | +| **Options** | Option Field (JetEngine Global Options Pages) | +| **Macros** | JetEngine Macros (ver secção abaixo) | +| **Query** | Query Variable (parâmetros URL) | + +### Usar Meta Field Tag + +``` +Elemento Elementor > Campo de texto > ícone Dynamic Tags +→ JetEngine > Meta Field +→ Seleccionar meta key name +→ Field Type: auto / text / image / url / ... + +Para imagens (campo tipo media): +→ Field Type: Image +→ Image Size: thumbnail / medium / large / full + +Para URLs em botões: +→ Link > Dynamic Tag > Meta Field > Field Type: URL +``` + +### Tags em CSS Custom (background, cores) + +``` +Elemento > Style > Background > Dynamic Tag +→ Meta Field → campo cor HEX +→ Útil para cards coloridos por categoria +``` + +--- + +## Macros + +### Macros Built-in + +``` +%current_user_id% # ID do utilizador logado +%current_user_name% # Nome do utilizador +%current_user_email% # Email do utilizador +%current_post_id% # ID do post actual +%current_post_type% # Post type do post actual +%queried_object_id% # ID em arquivo/single +%queried_object_slug% # Slug em arquivo/single +%request_field|param_name% # Parâmetro URL: ?param_name=valor +%current_meta|field_name% # Meta field do post actual +%user_meta|field_name% # Meta field do utilizador logado +%current_taxonomy|tax_name% # Taxonomy do post actual +%current_timestamp% # Unix timestamp actual +%site_url% # URL do site +``` + +### Usar Macros em Query Builder + +``` +Exemplo: Listar imóveis favoritos do utilizador +Meta Query: +├── Field: favorito_de (campo que guarda array de IDs de utilizadores) +├── Operator: LIKE +└── Value: %current_user_id% + +Exemplo: Listar items criados pelo utilizador +Meta Query: +├── Field: cct_author_id (campo automático do CCT) +├── Operator: = +└── Value: %current_user_id% +``` + +### Macros em Textos + +``` +Texto: "Bem-vindo, %current_user_name%!" +→ Em runtime: "Bem-vindo, João Silva!" + +Em Heading Widget: activar Dynamic Tag > JetEngine Macros +→ Escrever a macro no campo Macro Value +``` + +### Criar Macro Custom (PHP) + +```php + 'minha_macro', + 'name' => 'Minha Macro Custom', + 'args' => [], // parâmetros opcionais + ]; + return $macros; +}); + +add_filter('jet-engine/listings/macros-result', function($result, $macro, $args) { + if ($macro === 'minha_macro') { + // Lógica da macro + $result = 'valor calculado'; + } + return $result; +}, 10, 3); +``` + +--- + +## Conditional Fields (Campos Condicionais) + +### Em Meta Boxes + +``` +Campo B só aparece quando Campo A = "sim" + +Meta Box > Campo B > Conditions: +├── Field: nome_campo_a +├── Operator: = +└── Value: sim +``` + +### Em Listing Templates (Visibility) + +``` +Elemento Elementor > Advanced > JetEngine Conditions: +├── Condition: Meta Field | Equals | "featured" +└── Effect: Show / Hide +``` + +--- + +## Global Options Pages + +Para configurações globais do site (telefone, email, horários, redes sociais). + +### Criar Options Page + +``` +JetEngine > Options Pages > Add New +├── Page Title: Informações Globais +├── Slug: informacoes-globais +└── Campos: Meta Box associado +``` + +### Usar em Elementor + +``` +Dynamic Tag > JetEngine > Option +→ Seleccionar Options Page +→ Seleccionar campo + +Exemplo: footer com telefone dinâmico +→ Options Page: Informações Globais > campo: telefone +→ Editar telefone em 1 lugar, actualiza em todo o site +``` + +--- + +## Profile Builder + +Sistema de áreas de conta para utilizadores logados. + +### Estrutura + +``` +JetEngine > Profile Builder +├── Pages (áreas da conta): +│ ├── Dashboard (página principal) +│ ├── Submissões (posts do utilizador) +│ ├── Favoritos +│ ├── Configurações (editar perfil) +│ └── [custom pages] +├── Access Rules: +│ ├── Login Required: YES +│ ├── User Roles: subscriber / author / ... +│ └── Redirect não-logados: página de login +└── Profile Menu Widget (Elementor) +``` + +### Criar Página de Perfil + +``` +1. JetEngine > Profile Builder > Add Page + Nome: Dashboard | Slug: dashboard + Template: Criar com Elementor + +2. No Template, usar Dynamic Tags: + → User Name, User Email, User Avatar + → Query Builder filtrado por %current_user_id% + +3. Adicionar Profile Menu Widget ao header/sidebar + → Mostra links para cada página do perfil + → Altera links consoante se está logado ou não +``` + +### Submissão de Conteúdo por Utilizadores + +``` +JetFormBuilder + Profile Builder: +1. Criar formulário com acção "Create Post" (CPT) +2. Acção: Set Author = Current User +3. Colocar formulário na página de perfil +4. Query Builder na página de listagem: autor = current_user_id +``` + +### Editar Perfil com JetFormBuilder + +```php +// JetFormBuilder Form: +// Acção: Update User +// Campos mapeados: +// ├── first_name → user first_name +// ├── last_name → user last_name +// ├── email → user email +// └── bio_custom → user_meta: bio_custom + +// Pre-fill automático: activar "Use data from:" → Current User +``` + +--- + +## Conditional Content por Utilizador + +### Mostrar Conteúdo Só a Logados + +``` +Elementor > Advanced > JetEngine Conditions: +Condition: Is User Logged In | Equals | True +Effect: Show (esconde elemento para não logados) +``` + +### Por Role + +``` +Condition: User Role | Contains | administrator +Effect: Show (só admins vêem este bloco) +``` + +### Por Meta do Utilizador + +``` +Condition: User Meta | Field: plano_subscricao | Equals | premium +Effect: Show (só utilizadores premium vêem este conteúdo) +``` + +--- + +## Repeater em Frontend + +### Listar Items de um Repeater + +``` +Meta Box com campo Repeater "galeria_destaques": +├── Sub-campo: imagem (media) +├── Sub-campo: titulo (text) +└── Sub-campo: link (url) + +Em Listing Template: +Adicionar widget "Dynamic Repeater" +→ Source: Meta Field → galeria_destaques +→ Criar template para cada item do repeater +``` + +--- + +*JetEngine Dynamic Content | Descomplicar® | 18-02-2026* diff --git a/wordpress/skills/jetengine/references/query-listings.md b/wordpress/skills/jetengine/references/query-listings.md new file mode 100644 index 0000000..2852f8d --- /dev/null +++ b/wordpress/skills/jetengine/references/query-listings.md @@ -0,0 +1,225 @@ +# JetEngine — Query Builder e Listings + +## Query Builder Avançado + +### Tipos de Query e Configuração + +#### Query Posts + +``` +Campos principais: +├── Post Type: CPT ou post/page +├── Post Status: publish / draft / any +├── Posts per page: N (ou -1 para todos) +├── Order: ASC / DESC +├── Order By: date / title / menu_order / meta_value / meta_value_num / rand +│ └── Se meta_value: seleccionar meta key +├── Meta Query (múltiplas condições): +│ ├── Field: meta key name +│ ├── Type: CHAR / NUMERIC / DATE +│ ├── Operator: = / != / > / < / BETWEEN / LIKE / IN / NOT IN / EXISTS +│ └── Value: valor ou macro (%current_user_id%) +└── Tax Query: + ├── Taxonomy: seleccionar taxonomy + ├── Operator: IN / NOT IN / AND + └── Terms: valores ou relação dinâmica +``` + +#### Query CCT + +``` +Campos principais: +├── Content Type: seleccionar CCT +├── Items per page: N +├── Order By: qualquer coluna do CCT +├── Filters (equivalente a Meta Query): +│ ├── Field: coluna do CCT +│ ├── Operator: = / != / > / LIKE / IN +│ └── Value: valor ou macro +└── Show items only for current user: activar para perfis +``` + +#### Query Relação + +``` +Objetivo: listar items relacionados ao post/item actual +├── Relation: seleccionar relação criada no JetEngine +├── Get children of: post actual / ID específico / macro +└── Post Type: tipo dos items relacionados +``` + +### Meta Query com Macros + +``` +Exemplo: listar projectos do utilizador logado +Meta Query: +├── Field: cliente_user_id +├── Operator: = +└── Value: %current_user_id% + +Exemplo: listar items de hoje +Meta Query: +├── Field: data_evento (timestamp) +├── Type: NUMERIC +├── Operator: >= +└── Value: %current_timestamp% +``` + +### Combinar Múltiplas Condições + +``` +Relation: AND (todas as condições verdadeiras) + OR (pelo menos uma verdadeira) + +Exemplo: imóveis em Lisboa com preço < 300k +Tax Query 1: Localização = Lisboa +Meta Query 1: Preço < 300000 +Relation: AND +``` + +--- + +## Listing Grid — Configuração Detalhada + +### Criar Listing Template + +``` +JetEngine > Listings > Add New +Nome: [CPT]-listing-card +Listing From: Posts / Terms / Users / CCT +Post Type: [seleccionar] +Editar com Elementor: +├── Usar Dynamic Tags em todos os campos +├── Post Title Widget → ou Text Widget com dynamic tag +├── Meta Field → adicionar Dynamic Tag > JetEngine > Meta Field +├── Post Featured Image → ou Image Widget com dynamic tag +└── Button → URL com dynamic tag > Post URL +``` + +### Listing Grid Widget — Parâmetros + +``` +Listing Item: [seleccionar template] +Use Custom Query: YES → seleccionar Query Builder +Items per page: 12 (padrão) +Not Found Text: "Sem resultados" +Loader: activar para UX com filtros +Columns: 1/2/3/4 (responsivo) +Equal Columns Height: YES para cards uniformes +``` + +### Paginação + +``` +Listing Grid > Pagination: +├── Type: Default WP / Load More / Infinity Scroll +├── Load More Button Text: "Carregar mais" +├── On Scroll: activar para infinity +└── Starting From: 1 +``` + +### Ordenação Dinâmica (Frontend) + +``` +Adicionar widget: JetSmartFilters > Sorting +├── Ligar ao mesmo Listing Grid +└── Opções: Date ASC/DESC, Title, Price, Custom Field +``` + +--- + +## Listing Map + +### Configuração + +``` +1. Activar Google Maps API Key: + JetEngine > Settings > Google Maps API Key + +2. Criar Meta Box com campo tipo Map no CPT + (O utilizador define latitude/longitude via picker no editor) + +3. Criar Listing Template tipo: Map Marker + Adicionar: Post Title, info a mostrar no popup + +4. Adicionar widget Listing Map ao Elementor + ├── Listing Item: [marker template] + ├── Use Custom Query: YES + ├── Map Field: seleccionar campo coordenadas + └── Map Options: zoom, altura, cluster +``` + +### Mapa + Listing Grid Sincronizados + +``` +Adicionar os dois widgets na mesma página +Ligar ao mesmo Query Builder +Activar "Synchronize with Listing Grid": YES no Map +→ Ao fazer hover no card, destaca pin no mapa +→ Ao fazer hover no pin, destaca card na lista +``` + +--- + +## Archive e Single Templates + +### Single CPT com Elementor (JetThemeCore ou Elementor Pro) + +``` +JetThemeCore > Templates > Add New > Single +Conditions: Post Type = [meu_cpt] +Editar com Elementor usando Dynamic Tags + +OU + +Elementor > Templates > Theme Builder > Single +Conditions: igual +``` + +### Archive Page + +``` +JetThemeCore > Templates > Add New > Archive +Conditions: Post Type Archive = [meu_cpt] +Adicionar: +├── Archive Title Widget +├── Listing Grid Widget (sem Custom Query — usa WP_Query do arquivo) +└── JetSmartFilters (ligado ao mesmo archive) +``` + +--- + +## JetSmartFilters — Integração Avançada + +### AJAX Reload vs Full Page + +``` +Provider: Listing Grid → AJAX (sem reload de página) +Provider: Archive → Pode ser AJAX ou URL based +Provider: WooCommerce → AJAX +``` + +### URL Based Filters (SEO Friendly) + +``` +JetSmartFilters > Filters > Edit +├── Query Variable: activar +├── URL Based: activar +└── Clean URL: activar + +Resultado: site.pt/imoveis/?cidade=Lisboa&preco=200000-400000 +(Em vez de AJAX puro — melhor para SEO e partilha de URL) +``` + +### Hierarquical Taxonomy Filter + +``` +Exemplo: País → Distrito → Concelho +├── Criar taxonomia com hierarquia +├── Filtro: Checkboxes com hierarquia activada +└── "Show children of selected": activar +``` + +--- + +*JetEngine Query & Listings | Descomplicar® | 18-02-2026* diff --git a/wordpress/skills/log.md b/wordpress/skills/log.md new file mode 100644 index 0000000..66e9c4d --- /dev/null +++ b/wordpress/skills/log.md @@ -0,0 +1 @@ +## 2026-06-30 init | Estrutura padrão diff --git a/wordpress/skills/rank-math/SKILL.md b/wordpress/skills/rank-math/SKILL.md new file mode 100644 index 0000000..308d635 --- /dev/null +++ b/wordpress/skills/rank-math/SKILL.md @@ -0,0 +1,135 @@ +--- +name: rank-math +description: Gestão programática do Rank Math SEO (Free e PRO) via WP-CLI em servidores CWP. Cobre auditoria SEO, meta em massa, schema markup, redirects, sitemaps, Instant Indexing, Analytics PRO, hooks/filtros, taxonomias WooCommerce, News/Video Sitemap, validação e rollback. Usar quando "rank math", "seo cli", "schema markup", "redirects seo", "instant indexing", "indexnow", "seo bulk", "rankmath pro". +layer: wiki +--- + +# /rank-math — Gestão Programática Rank Math SEO via WP-CLI + +Operações SEO WordPress completas via WP-CLI no servidor CWP. Free + PRO. + +**Manual completo:** `Hub/06-Operacoes/Documentacao/Manuais/WP-CLI/Rank-Math-WP-CLI-Manual-Definitivo.md` +**Quick Reference:** `Hub/06-Operacoes/Documentacao/Quick-Reference/QR-RankMath-WP-CLI.md` +**Pesquisa Claude:** `Hub/06-Operacoes/Documentacao/Manuais/WP-CLI/Rank-Math-SEO-WP-CLI-Skils-Pesquisa-Claude.md` +**Pesquisa Gemini:** `Hub/06-Operacoes/Documentacao/Manuais/WP-CLI/Rank-Math-SEO-WP-CLI-Skills-Pesquisa-Gemini.md` +**NotebookLM:** [WordPress Config CLI](https://notebooklm.google.com/notebook/fb2f26bd-8cb0-4d4c-bafc-4f1ebb51c51d) +**Skill relacionada:** `/seo-post` — optimizar posts individuais com pipeline completo + +--- + +## Contexto NotebookLM + +ANTES de executar, consultar notebooks para contexto especializado: + +| Notebook | ID | Consultar quando | +|----------|-----|-----------------| +| WordPress e Elementor | 5be0d1a6 | Sempre | +| Marketing Digital PT | 4c595973 | Para contexto SEO | + +``` +mcp__notebooklm__notebook_query({ + notebook_id: "5be0d1a6-00f2-4cd9-b835-978cb7721601", + query: "" +}) +``` + +--- + +## Uso + +``` +/rank-math audit SITE_PATH +/rank-math update-meta SITE_PATH +/rank-math sitemap SITE_PATH +/rank-math redirects SITE_PATH +/rank-math schema post ID SITE_PATH +/rank-math indexing SITE_PATH [URL|bulk] +/rank-math analytics SITE_PATH +/rank-math taxonomy SITE_PATH +/rank-math hooks SITE_PATH +/rank-math backup SITE_PATH +/rank-math provision SITE_PATH +``` + +--- + +## Contexto CWP — sempre obrigatorio + +```bash +# Formato base (PHP 8.3) +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root --path=/home/USER/public_html + +# Alias +wp83 --allow-root --path=/home/USER/public_html +``` + +**Acesso via MCP SSH:** +``` +servidor: server.descomplicar.pt (176.9.3.158) | porta: 9443 | user: root +``` + +**Prefixo de tabelas:** Sites podem ter prefixo custom (ex: `wpah_` em vez de `wp_`). Detectar primeiro: +```bash +PREFIX=$(wp db prefix --allow-root --path=$PATH) +# Usar $PREFIX em todas as queries SQL: ${PREFIX}posts, ${PREFIX}postmeta, etc. +``` + +**Unico comando nativo Rank Math:** +```bash +wp rankmath sitemap generate --allow-root --path=$PATH +``` + +Tudo o resto usa `wp post meta`, `wp option patch`, `wp eval` ou `wp db query`. + +**Options com defaults:** Muitas sub-keys (title_separator, strip_category_base, homepage_title, knowledgegraph_type) podem nao existir na BD se nunca foram alteradas — o Rank Math usa valores por defeito internos. `wp option pluck` retorna exit code 1 neste caso. Nao e erro — significa valor default. + +--- + +## Decision tree — qual comando usar + +| Operacao | Comando | +|----------|---------| +| Alterar meta de 1 post | `wp post meta update` | +| Alterar sub-key em option serializada | `wp option patch update` | +| Ler sub-key de option | `wp option pluck` | +| Schema complexo | `wp eval` com PHP | +| Redirects | `wp eval` com `\RankMath\Redirections\DB` | +| Bulk simples | shell loop com `wp post list \| while read` | +| Bulk complexo | `wp eval-file` com script PHP | +| SQL directo | apenas auditorias (seguido de `wp cache flush`) | +| Regenerar sitemap | `wp rankmath sitemap generate` | +| Instant Indexing | `wp eval` com IndexNow API ou classes RM | +| Side-effects RM | `wp eval` com `update_option()` (dispara hooks) | + +--- + +## 1. Auditoria SEO (/rank-math audit) + +### Passo 1 — diagnostico rapido + +```bash +PATH=/home/USER/public_html +PREFIX=$(wp db prefix --allow-root --path=$PATH) + +# Posts sem titulo SEO +wp db query "SELECT p.ID, p.post_title FROM ${PREFIX}posts p +LEFT JOIN ${PREFIX}postmeta pm ON p.ID=pm.post_id AND pm.meta_key='rank_math_title' +WHERE p.post_type='post' AND p.post_status='publish' +AND (pm.meta_value IS NULL OR pm.meta_value='');" --allow-root --path=$PATH + +# Posts sem descricao SEO +wp db query "SELECT p.ID, p.post_title FROM ${PREFIX}posts p +LEFT JOIN ${PREFIX}postmeta pm ON p.ID=pm.post_id AND pm.meta_key='rank_math_description' +WHERE p.post_type='post' AND p.post_status='publish' +AND (pm.meta_value IS NULL OR pm.meta_value='');" --allow-root --path=$PATH + +# Distribuicao de SEO scores +wp db query "SELECT + CASE WHEN CAST(meta_value AS UNSIGNED) >= 80 THEN 'Bom (80-100)' + WHEN CAST(meta_value AS UNSIGNED) >= 50 THEN 'OK (50-79)' + ELSE 'Fraco (0-49)' END AS faixa, + COUNT(*) AS total +FROM ${PREFIX}postmeta WHERE meta_key = 'rank_math_seo_score' GROUP BY faixa;" --allow-root --path=$PATH + +# Top 404s (ultimos 30 dias) +wp db query "SELECT uri, SUM(times_acce \ No newline at end of file diff --git a/wordpress/skills/rank-math/references/commands.md b/wordpress/skills/rank-math/references/commands.md new file mode 100644 index 0000000..eaa8cbe --- /dev/null +++ b/wordpress/skills/rank-math/references/commands.md @@ -0,0 +1,379 @@ +# Rank Math WP-CLI — Referência Completa de Comandos + +**Manual Hub:** `06-Operacoes/Documentacao/Manuais/Rank-Math-WP-CLI-Manual-Definitivo.md` + +--- + +## Arquitectura de Dados + +### Tabelas WordPress Standard + +| Tabela | Dados Rank Math | +|--------|-----------------| +| `wp_postmeta` | SEO por post: título, descrição, robots, schema, keywords | +| `wp_termmeta` | SEO por taxonomia (categories, tags) | +| `wp_usermeta` | SEO de páginas author archive | +| `wp_options` | Configurações globais do plugin | + +### Tabelas Custom Rank Math + +| Tabela | Conteúdo | +|--------|---------| +| `wp_rank_math_redirections` | Regras de redirect (301, 302, 410, etc.) | +| `wp_rank_math_redirections_cache` | Cache das regras | +| `wp_rank_math_404_logs` | Log de 404s com contadores | +| `wp_rank_math_analytics_objects` | Analytics (PRO) | +| `wp_rank_math_analytics_ga` | Google Analytics (PRO) | +| `wp_rank_math_analytics_gsc` | Search Console (PRO) | + +--- + +## Meta Keys Completas (wp_postmeta) + +### SEO Básico + +| Meta Key | Tipo | Exemplo | +|----------|------|---------| +| `rank_math_title` | string | `%title% %sep% %sitename%` | +| `rank_math_description` | string | Máx 160 chars | +| `rank_math_focus_keyword` | string CSV | `kw1,kw2,kw3` | +| `rank_math_pillar_content` | string | `on` / `off` | +| `rank_math_canonical_url` | string URL | `https://site.pt/url/` | +| `rank_math_seo_score` | int | 0-100 (calculado no editor) | + +### Robots e Indexação + +| Meta Key | Tipo | Valores | +|----------|------|---------| +| `rank_math_robots` | **array JSON** | `["noindex"]`, `["nofollow"]`, `["noindex","nofollow"]` | + +```bash +# CORRECTO +wp post meta update ID rank_math_robots '["noindex"]' --format=json --allow-root + +# ERRADO (string, não aplicará) +wp post meta update ID rank_math_robots "noindex" --allow-root +``` + +### Open Graph / Social + +| Meta Key | Tipo | Notas | +|----------|------|-------| +| `rank_math_facebook_image` | string URL | Imagem OG | +| `rank_math_facebook_title` | string | Título Facebook | +| `rank_math_facebook_description` | string | Descrição Facebook | +| `rank_math_twitter_card_type` | string | `summary_large_image` | +| `rank_math_twitter_title` | string | | +| `rank_math_twitter_description` | string | | +| `rank_math_twitter_image` | string URL | | + +### Schema + +| Meta Key | Tipo | Notas | +|----------|------|-------| +| `rank_math_schema_Article` | serialized PHP array | `wp eval` obrigatório | +| `rank_math_schema_FAQPage` | serialized PHP array | | +| `rank_math_schema_HowTo` | serialized PHP array | | +| `rank_math_schema_Product` | serialized PHP array | WooCommerce | +| `rank_math_schema_Recipe` | serialized PHP array | | +| `rank_math_schema_Review` | serialized PHP array | | +| `rank_math_schema_Event` | serialized PHP array | | +| `rank_math_schema_LocalBusiness` | serialized PHP array | | +| `rank_math_schema_VideoObject` | serialized PHP array | | + +### WooCommerce + +| Meta Key | Tipo | Notas | +|----------|------|-------| +| `rank_math_primary_category` | string (Term ID) | `"15"` | +| `rank_math_schema_Product` | serialized PHP array | Produto WC | + +--- + +## Options Globais (wp_options) + +### Options Principais + +| Option Name | Tipo | Conteúdo | +|-------------|------|---------| +| `rank-math-options-general` | serialized array | Config geral | +| `rank-math-options-titles` | serialized array | Títulos e meta por post-type | +| `rank-math-options-sitemap` | serialized array | Configuração sitemap | +| `rank_math_modules` | serialized array | Módulos activos/inactivos | +| `rank_math_schema_types` | serialized array | Tipos schema habilitados | + +### Sub-keys rank-math-options-general + +```bash +wp option pluck rank-math-options-general strip_category_base # on/off +wp option pluck rank-math-options-general breadcrumbs # on/off +wp option pluck rank-math-options-general knowledgegraph_type # person/company +wp option pluck rank-math-options-general url # URL empresa +wp option pluck rank-math-options-general name # Nome empresa/pessoa +``` + +### Sub-keys rank-math-options-titles + +```bash +wp option pluck rank-math-options-titles title_separator # - / | • … +wp option pluck rank-math-options-titles homepage_title # Título homepage +wp option pluck rank-math-options-titles homepage_description # Desc homepage +wp option pluck rank-math-options-titles pt_post_title # Título padrão posts +wp option pluck rank-math-options-titles pt_page_title # Título padrão pages +wp option pluck rank-math-options-titles pt_product_title # Título padrão products +``` + +### Sub-keys rank-math-options-sitemap + +```bash +wp option pluck rank-math-options-sitemap items_per_page # Default: 200 +wp option pluck rank-math-options-sitemap pt_post_sitemap # on/off +wp option pluck rank-math-options-sitemap pt_page_sitemap # on/off +wp option pluck rank-math-options-sitemap pt_product_sitemap # on/off +wp option pluck rank-math-options-sitemap pt_attachment_sitemap # on/off (default: off) +``` + +--- + +## Módulos Rank Math + +```bash +# Ver todos os módulos +wp option get rank_math_modules --format=json --allow-root + +# Activar módulo +wp option patch update rank_math_modules MODULE_NAME "1" --allow-root + +# Desactivar módulo +wp option patch update rank_math_modules MODULE_NAME "0" --allow-root +``` + +| Módulo | Slug | Função | +|--------|------|--------| +| SEO Analysis | `seo-analysis` | Score SEO no editor | +| Link Counter | `link-counter` | Contagem links internos/externos | +| Redirections | `redirections` | Sistema de redirects | +| 404 Monitor | `404-monitor` | Log de 404s | +| Schema | `rich-snippet` | Schema markup | +| Sitemap | `sitemap` | XML Sitemap | +| Instant Indexing | `instant-indexing` | Google Indexing API (PRO) | +| Local SEO | `local-seo` | Schema LocalBusiness | +| WooCommerce | `woocommerce` | SEO WooCommerce | + +--- + +## Leitura de Meta + +```bash +# Todos os meta do post +wp post meta list 42 --format=table --allow-root | grep rank_math + +# Meta específico +wp post meta get 42 rank_math_title --allow-root +wp post meta get 42 rank_math_description --allow-root +wp post meta get 42 rank_math_robots --allow-root + +# Meta de term +wp term meta get 15 rank_math_title --allow-root +wp term meta get 15 rank_math_description --allow-root +``` + +--- + +## Operações em Massa + +### Script de auditoria completo + +```bash +#!/bin/bash +PATH_WP="/home/USER/public_html" +WP="/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root --path=$PATH_WP" + +echo "=== AUDITORIA RANK MATH SEO ===" +echo "Site: $PATH_WP" +echo "Data: $(date)" + +echo -e "\n--- Posts sem título SEO ---" +$WP db query "SELECT p.ID, LEFT(p.post_title,50) as titulo FROM wp_posts p +LEFT JOIN wp_postmeta pm ON p.ID=pm.post_id AND pm.meta_key='rank_math_title' +WHERE p.post_type='post' AND p.post_status='publish' +AND (pm.meta_value IS NULL OR pm.meta_value='') +LIMIT 20;" + +echo -e "\n--- Posts sem descrição SEO ---" +$WP db query "SELECT p.ID, LEFT(p.post_title,50) as titulo FROM wp_posts p +LEFT JOIN wp_postmeta pm ON p.ID=pm.post_id AND pm.meta_key='rank_math_description' +WHERE p.post_type='post' AND p.post_status='publish' +AND (pm.meta_value IS NULL OR pm.meta_value='') +LIMIT 20;" + +echo -e "\n--- Top 10 404s ---" +$WP db query "SELECT uri, SUM(times_accessed) as total FROM wp_rank_math_404_logs +GROUP BY uri ORDER BY total DESC LIMIT 10;" + +echo -e "\n--- Módulos activos ---" +$WP option get rank_math_modules --format=json + +echo -e "\n--- Tamanho options ---" +$WP db query "SELECT option_name, LENGTH(option_value) as bytes FROM wp_options +WHERE option_name LIKE 'rank%' AND autoload='yes' ORDER BY bytes DESC;" + +echo "=== FIM AUDITORIA ===" +``` + +### Bulk: Aplicar título padrão a posts sem título + +```bash +wp eval ' +$posts = get_posts(["post_type"=>"post","numberposts"=>-1,"post_status"=>"publish"]); +$updated = 0; +foreach ($posts as $p) { + if (!get_post_meta($p->ID, "rank_math_title", true)) { + update_post_meta($p->ID, "rank_math_title", "%title% %sep% %sitename%"); + $updated++; + } +} +echo "$updated posts actualizados\n"; +' --allow-root --path=$PATH_WP +``` + +### Bulk: Aplicar descrição a partir do excerpt + +```bash +wp eval ' +$posts = get_posts(["post_type"=>"post","numberposts"=>-1,"post_status"=>"publish"]); +$updated = 0; +foreach ($posts as $p) { + if (!get_post_meta($p->ID, "rank_math_description", true) && $p->post_excerpt) { + $desc = wp_trim_words($p->post_excerpt, 20, "..."); + update_post_meta($p->ID, "rank_math_description", $desc); + $updated++; + } +} +echo "$updated posts actualizados\n"; +' --allow-root --path=$PATH_WP +``` + +--- + +## Schema — Exemplos Completos + +### Article (blog post) + +```bash +wp eval ' +$post_id = ID; +update_post_meta($post_id, "rank_math_schema_Article", [ + "metadata" => [ + "title"=>"Article", + "type"=>"custom", + "shortcode"=>"s-".uniqid(), + "isPrimary"=>"1" + ], + "@type"=>"Article", + "headline"=>"%seo_title%", + "description"=>"%seo_description%", + "url"=>"%url%", + "author"=>["@type"=>"Person","name"=>"%name%"], + "publisher"=>["@type"=>"Organization","name"=>"%sitename%","logo"=>""], + "datePublished"=>"%date(Y-m-dTH:i:sP)%", + "dateModified"=>"%modified(Y-m-dTH:i:sP)%", + "image"=>"%post_thumbnail%" +]); +echo "Article schema criado no post $post_id\n"; +' --user=1 --allow-root --path=$PATH_WP +``` + +### LocalBusiness (página contacto) + +```bash +wp eval ' +update_post_meta(ID, "rank_math_schema_LocalBusiness", [ + "metadata" => ["title"=>"LocalBusiness","type"=>"custom","shortcode"=>"s-".uniqid(),"isPrimary"=>"1"], + "@type"=>"LocalBusiness", + "name"=>"Nome Empresa", + "description"=>"%seo_description%", + "url"=>"%url%", + "email"=>"email@empresa.pt", + "telephone"=>"+351 XXX XXX XXX", + "address"=>["@type"=>"PostalAddress","streetAddress"=>"Rua X","addressLocality"=>"Cidade","postalCode"=>"XXXX-XXX","addressCountry"=>"PT"], + "geo"=>["@type"=>"GeoCoordinates","latitude"=>"38.7","longitude"=>"-9.1"], + "openingHoursSpecification"=>[ + ["@type"=>"OpeningHoursSpecification","dayOfWeek"=>["Monday","Tuesday","Wednesday","Thursday","Friday"],"opens"=>"09:00","closes"=>"18:00"] + ], + "image"=>"%post_thumbnail%" +]); +echo "LocalBusiness schema criado\n"; +' --user=1 --allow-root --path=$PATH_WP +``` + +--- + +## Instant Indexing (Google Indexing API - PRO) + +```bash +# Submeter URL individual +wp eval '\RankMath\Instant_Indexing\Api::submit("https://site.pt/url/", "URL_UPDATED"); echo "OK\n";' --allow-root --path=$PATH_WP + +# Verificar estado da API +wp option pluck rank-math-options-instant-indexing bing_api_key --allow-root --path=$PATH_WP +``` + +--- + +## Redirects — Referência Completa + +### Tipos de Comparação + +| comparison | Comportamento | +|-----------|---------------| +| `exact` | Match exacto do URL | +| `contains` | URL contém o pattern | +| `starts_with` | URL começa com o pattern | +| `ends_with` | URL termina com o pattern | +| `regex` | Regular expression | + +### Códigos HTTP + +| Código | Tipo | Uso | +|--------|------|-----| +| 301 | Moved Permanently | Redirect definitivo | +| 302 | Found | Redirect temporário | +| 307 | Temporary Redirect | Temporário (preserva método HTTP) | +| 410 | Gone | Conteúdo removido permanentemente | +| 451 | Unavailable For Legal | Removido por razões legais | + +--- + +## Tabelas Rank Math — Verificação + +```bash +# Ver tabelas custom +wp db query "SHOW TABLES LIKE '%rank_math%';" --allow-root --path=$PATH_WP + +# Estrutura tabela redirections +wp db query "DESCRIBE wp_rank_math_redirections;" --allow-root --path=$PATH_WP + +# Ver todos os redirects activos +wp db query "SELECT id, sources, url_to, header_code FROM wp_rank_math_redirections WHERE status='active';" --allow-root --path=$PATH_WP +``` + +--- + +## Free vs PRO — Funcionalidades WP-CLI + +| Funcionalidade | Free | PRO | Notas | +|---------------|------|-----|-------| +| `wp rankmath sitemap generate` | ✅ | ✅ | Único comando nativo | +| Meta por post | ✅ | ✅ | `wp post meta` | +| Options globais | ✅ | ✅ | `wp option patch` | +| Schema markup | ✅ | ✅ | `wp eval` | +| Redirections | ✅ | ✅ | `\RankMath\Redirections\DB` | +| 404 Monitor | ✅ | ✅ | `wp_rank_math_404_logs` | +| Instant Indexing | ❌ | ✅ | `\RankMath\Instant_Indexing\Api` | +| Analytics GSC | ❌ | ✅ | Tabelas analytics_gsc | +| Analytics GA | ❌ | ✅ | Tabelas analytics_ga | + +--- + +*Referência Rank Math WP-CLI | Descomplicar® | v1.0.0 | 18-02-2026* diff --git a/wordpress/skills/seo-post/SKILL.md b/wordpress/skills/seo-post/SKILL.md new file mode 100644 index 0000000..b4333a7 --- /dev/null +++ b/wordpress/skills/seo-post/SKILL.md @@ -0,0 +1,134 @@ +--- +name: seo-post +description: Optimizar posts WordPress com RankMath Pro via WP-CLI. Auditar, corrigir e aplicar SEO completo incluindo schema, OG, robots e links internos. Usar quando "seo post", "rankmath", "schema", "optimizar artigo", "seo wordpress". +context: fork +layer: wiki +--- + +# /seo-post — Optimizar Posts WordPress com RankMath Pro + +Modos: auditar (com ID), aplicar (com ID + dados), bulk (com lista IDs), novo (pipeline completo). + +## Constantes + +``` +SERVIDOR: server (via mcp__ssh-unified__ssh_execute) +WP_PATH: cd /home/ealmeida/public_html +WP_CLI: wp --allow-root +WP_USER: --user=2 (para wp eval) +MANUAL: Hub/06-Operacoes/Documentacao/Manuais/WP-CLI/Rank-Math-WP-CLI-Manual-Definitivo.md +``` + +## Modo auditar (/seo-post ID) + +Verifica estado SEO de um post e lista problemas. + +```bash +cd /home/ealmeida/public_html + +# 1. Dados do post +wp --allow-root post get POST_ID --fields=ID,post_title,post_name,post_status --format=table + +# 2. Todos os meta RankMath +wp --allow-root post meta list POST_ID --format=table | grep rank_math + +# 3. Thumbnail e alt text +THUMB_ID=$(wp --allow-root post meta get POST_ID _thumbnail_id) +wp --allow-root post meta get $THUMB_ID _wp_attachment_image_alt + +# 4. Schema no HTML +curl -s "URL_DO_POST" | grep -o '"@type":"[^"]*"' | sort -u +``` + +**Checklist de auditoria:** + +| Campo | Verificacao | +|-------|-----------| +| rank_math_title | Existe? 50-70 chars? Tem keyword? | +| rank_math_description | Existe? 150-160 chars? Tem keyword? | +| rank_math_focus_keyword | Existe? 1-3 keywords CSV? | +| rank_math_primary_category | Existe? ID valido? | +| rank_math_robots | Array? Tem ["index"]? | +| rank_math_advanced_robots | Array JSON? max-image-preview large? | +| rank_math_rich_snippet | "article"? | +| rank_math_snippet_article_type | "NewsArticle" ou "BlogPosting" ou "Article"? | +| rank_math_schema_* | Existe meta com schema? Tem isPrimary 1? | +| rank_math_facebook_title | Existe? | +| rank_math_facebook_image | Existe? URL valido? | +| rank_math_twitter_card_type | "summary_large_image"? | +| _thumbnail_id | Existe? Imagem real? | +| Alt text imagem | Tem keywords? | +| post_name (slug) | Curto? <40 chars? Tem keyword? | +| rank_math_seo_score | Existe? >0? Se N/A -> executar Passo 6 | + +**Output:** tabela com campo, estado (OK/FALHA), valor actual, accao sugerida. + +## Modo aplicar (/seo-post ID com dados) + +Aplica SEO completo a um post. Pedir ao utilizador: +- Titulo SEO (ou gerar a partir do post_title) +- Meta description +- Focus keywords (CSV) +- Tipo schema: NewsArticle (noticias) ou Article (guias) ou BlogPosting (blog) + +### Passo 1: Strings simples + +```bash +wp --allow-root post meta update POST_ID rank_math_title 'TITULO SEO' +wp --allow-root post meta update POST_ID rank_math_description 'META DESC' +wp --allow-root post meta update POST_ID rank_math_focus_keyword 'kw1,kw2,kw3' +wp --allow-root post meta update POST_ID rank_math_primary_category 'CAT_ID' +``` + +### Passo 2: Arrays (OBRIGATORIO --format=json) + +```bash +wp --allow-root post meta update POST_ID rank_math_robots '["index"]' --format=json +wp --allow-root post meta update POST_ID rank_math_advanced_robots '{"max-snippet":"-1","max-video-preview":"-1","max-image-preview":"large"}' --format=json +``` + +### Passo 3: Schema — DOIS formatos (AMBOS obrigatorios) + +```bash +# Legacy (dashboard RankMath) +wp --allow-root post meta update POST_ID rank_math_rich_snippet 'article' +wp --allow-root post meta update POST_ID rank_math_snippet_article_type 'TIPO' +# TIPO: NewsArticle (noticias), Article (guias), BlogPosting (blog) + +# Novo (schema real no HTML — via wp eval) +wp --allow-root eval ' +$schema = [ + "metadata" => ["title" => "TIPO", "type" => "custom", "shortcode" => "s-" . uniqid(), "isPrimary" => "1"], + "@type" => "TIPO", + "headline" => "%seo_title%", + "description" => "%seo_description%", + "keywords" => "%keywords%", + "image" => ["@type" => "ImageObject", "url" => "%post_thumbnail%"], + "author" => ["@type" => "Organization", "name" => "Descomplicar", "url" => "https://descomplicar.pt"], + "publisher" => ["@type" => "Organization", "name" => "Descomplicar", "url" => "https://descomplicar.pt"], + "datePublished" => "%date(Y-m-dTH:i:sP)%", + "dateModified" => "%modified(Y-m-dTH:i:sP)%", + "articleSection" => "%categories%" +]; +update_post_meta(POST_ID, "rank_math_schema_TIPO", $schema); +echo "Schema OK\n"; +' --user=2 +``` + +### Passo 4: Social / OG + +```bash +wp --allow-root post meta update POST_ID rank_math_facebook_title 'TITULO OG' +wp --allow-root post meta update POST_ID rank_math_facebook_description 'DESC OG' +wp --allow-root post meta update POST_ID rank_math_facebook_image 'IMAGE_URL' +wp --allow-root post meta update POST_ID rank_math_og_content_image 'IMAGE_URL' +wp --allow-root post meta update POST_ID rank_math_twitter_card_type 'summary_large_image' +``` + +### Passo 5: Slug (se necessario) + +```bash +wp --allow-root post update POST_ID --post_name='slug-curto-keyword' +``` + +### Passo 6: SEO Score (OBRIGATORIO — posts via CLI nao cal \ No newline at end of file diff --git a/wordpress/skills/woocommerce-cli/SKILL.md b/wordpress/skills/woocommerce-cli/SKILL.md new file mode 100644 index 0000000..53b30a6 --- /dev/null +++ b/wordpress/skills/woocommerce-cli/SKILL.md @@ -0,0 +1,161 @@ +--- +name: woocommerce-cli +description: Gestão WooCommerce via WP-CLI no servidor CWP. Cobre produtos, encomendas, clientes, shipping, gateways de pagamento, importação/exportação em massa e automação. +layer: wiki +--- + +# /woocommerce-cli — WooCommerce via WP-CLI no CWP + +Gestão completa de lojas WooCommerce via linha de comandos no servidor CWP. Cobre produtos, encomendas, clientes, configuração, automação e scripting. + +**Servidor:** server.descomplicar.pt (176.9.3.158) | porta SSH: 9443 +**Manual:** `Hub/06-Operacoes/Documentacao/Manuais/WooCommerce com WP-CLI_ Guia Completo.md` +**Skill relacionada:** `/woocommerce` — desenvolvimento e extensões WooCommerce + +--- + +## Contexto CWP — Regras Obrigatórias + +```bash +# 1. SEMPRE prefixar com PHP completo +# 2. SEMPRE --allow-root (CWP executa como root) +# 3. SEMPRE --user=1 em operações de escrita (mapeamento REST API) +# 4. SEMPRE --path= (múltiplos sites no mesmo servidor) + +# Formato base +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc \ + --user=1 --allow-root --path=/home/USER/public_html + +# Variável de conveniência para scripts +PATH_WP="/home/USER/public_html" +WP="/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root --path=$PATH_WP" +$WP wc product list --user=1 +``` + +### Versões PHP disponíveis + +| Alias | PHP | Path | +|-------|-----|------| +| `wp74` | 7.4 | `/opt/alt/php-fpm74/usr/bin/php` | +| `wp82` | 8.2 | `/opt/alt/php-fpm82/usr/bin/php` | +| `wp83` | 8.3 | `/opt/alt/php-fpm83/usr/bin/php` (recomendado) | + +### Parâmetros essenciais WC CLI + +| Parâmetro | Uso | +|-----------|-----| +| `--user=1` | Obrigatório em escrita (autenticação REST API) | +| `--porcelain` | Retorna apenas ID numérico (para scripts) | +| `--format=table\|json\|csv\|ids` | Formato do output | +| `--fields=id,name,price` | Limitar campos (reduz memória) | +| `--per_page=100` | Limite máximo da API (paginar para mais) | +| `--force` | Eliminar definitivamente (sem lixo) | + +--- + +## Produtos + +### Operações Comuns + +```bash +PATH_WP="/home/USER/public_html" + +# Listar produtos +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product list \ + --user=1 --fields=id,name,price,stock_quantity --format=table \ + --allow-root --path=$PATH_WP + +# Criar produto simples +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product create \ + --user=1 \ + --name="Produto Exemplo" \ + --type=simple \ + --regular_price="29.99" \ + --sku="PROD-001" \ + --manage_stock=true \ + --stock_quantity=100 \ + --status=publish \ + --allow-root --path=$PATH_WP + +# Actualizar preço e stock +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product update 456 \ + --user=1 \ + --regular_price="34.99" \ + --stock_quantity=50 \ + --allow-root --path=$PATH_WP + +# Eliminar definitivamente +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product delete 456 \ + --user=1 --force --allow-root --path=$PATH_WP +``` + +### Produto Variável (capturar ID) + +```bash +# 1. Criar produto pai (--porcelain retorna só o ID) +PARENT_ID=$(/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product create \ + --user=1 --name="T-Shirt" --type=variable \ + --attributes='[{"name":"Tamanho","variation":true,"visible":true,"options":["S","M","L","XL"]}]' \ + --porcelain --allow-root --path=$PATH_WP) + +# 2. Criar variação +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product_variation create $PARENT_ID \ + --user=1 \ + --regular_price="24.99" \ + --sku="TSHIRT-M" \ + --attributes='[{"name":"Tamanho","option":"M"}]' \ + --manage_stock=true --stock_quantity=30 \ + --allow-root --path=$PATH_WP +``` + +### Actualização em Massa por SKU + +```bash +#!/bin/bash +PATH_WP="/home/USER/public_html" +WP="/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root --path=$PATH_WP" + +IDS=$($WP wc product list --user=1 --sku="TSHIRT-*" --format=ids) +for ID in $IDS; do + $WP wc product update $ID --user=1 --stock_quantity=200 --porcelain +done +``` + +### Exportar Catálogo + +```bash +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product list \ + --user=1 --per_page=5000 --format=csv \ + --allow-root --path=$PATH_WP \ + > /home/USER/catalogo_$(date +%Y%m%d).csv +``` + +--- + +## Encomendas + +```bash +PATH_WP="/home/USER/public_html" + +# Listar encomendas em processamento +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shop_order list \ + --user=1 --status=processing \ + --fields=id,total,date_created \ + --allow-root --path=$PATH_WP + +# Actualizar estado +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shop_order update 355 \ + --user=1 --status=completed \ + --allow-root --path=$PATH_WP + +# Adicionar nota ao cliente +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc order_note create 355 \ + --user=1 \ + --note="Encomenda expedida. Rastreio: PT-99887766." \ + --customer_note=true \ + --allow-root --path=$PATH_WP + +# Conclusão massiva de todas as encomendas em processamento +WP="/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root --path=$PATH_WP" +for ID in $($WP wc shop_order list --user=1 --status=processing --format=ids); do + $WP wc shop_order update $ID --us \ No newline at end of file diff --git a/wordpress/skills/woocommerce-cli/references/commands.md b/wordpress/skills/woocommerce-cli/references/commands.md new file mode 100644 index 0000000..d7b9e78 --- /dev/null +++ b/wordpress/skills/woocommerce-cli/references/commands.md @@ -0,0 +1,621 @@ +# WooCommerce WP-CLI — Referência Completa (CWP) + +**Manual Hub:** `06-Operacoes/Documentacao/Manuais/WooCommerce com WP-CLI_ Guia Completo.md` + +--- + +## Namespace e Entidades Disponíveis + +O WooCommerce CLI opera sob `wp wc`. Todas as operações mapeiam para REST API v3. + +| Entidade | Comando Base | +|----------|-------------| +| `customer` | Contas, moradas, métricas | +| `product` | Inventário, preços, stock | +| `product_cat` / `product_tag` | Categorias e tags | +| `product_attribute` | Atributos globais | +| `product_variation` | Variações de produto variável | +| `shop_order` | Encomendas | +| `order_note` | Notas de encomenda | +| `shop_coupon` | Cupões de desconto | +| `setting` | Settings WooCommerce | +| `shipping_zone` | Zonas de envio | +| `shipping_zone_location` | Localizações por zona | +| `shipping_zone_method` | Métodos por zona | +| `payment_gateway` | Gateways de pagamento | +| `tax` | Taxas de imposto | +| `tax_class` | Classes de imposto | +| `tool` | Ferramentas de manutenção | +| `webhook` | Webhooks server-to-server | + +--- + +## Tipos de Produto — Exemplos Completos + +### Produto Simples + +```bash +PATH_WP="/home/USER/public_html" + +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product create \ + --user=1 \ + --name="T-Shirt Premium Algodão Orgânico" \ + --type=simple \ + --regular_price="29.99" \ + --sale_price="24.99" \ + --sku="TSHIRT-PREM-001" \ + --manage_stock=true \ + --stock_quantity=150 \ + --status=publish \ + --description="Descrição completa do produto." \ + --short_description="Descrição curta para listagens." \ + --allow-root --path=$PATH_WP +``` + +### Produto Virtual (sem envio) + +```bash +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product create \ + --user=1 \ + --name="Consulta Online 1h" \ + --type=simple \ + --virtual=true \ + --regular_price="75.00" \ + --sku="CONSULT-1H" \ + --status=publish \ + --allow-root --path=$PATH_WP +``` + +### Produto Downloadable + +```bash +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product create \ + --user=1 \ + --name="eBook Guia SEO 2026" \ + --type=simple \ + --virtual=true \ + --downloadable=true \ + --regular_price="19.90" \ + --sku="EBOOK-SEO-2026" \ + --downloads='[{"name":"eBook SEO 2026","file":"https://site.pt/ficheiros/ebook-seo-2026.pdf"}]' \ + --download_limit=3 \ + --download_expiry=365 \ + --allow-root --path=$PATH_WP +``` + +### Produto Externo/Afiliado + +```bash +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product create \ + --user=1 \ + --name="Software Cloud Parceiro" \ + --type=external \ + --regular_price="99.00" \ + --product_url="https://parceiro.com/checkout/123" \ + --button_text="Comprar na Loja do Parceiro" \ + --sku="EXT-SOFT-123" \ + --allow-root --path=$PATH_WP +``` + +### Produto Agrupado (Grouped) + +```bash +# 1. Criar produto pai agrupado +GROUP_ID=$(/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product create \ + --user=1 --name="Pack Bundle Completo" --type=grouped --sku="PACK-BUNDLE-001" \ + --porcelain --allow-root --path=$PATH_WP) + +# 2. Criar filho vinculado ao grupo +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product create \ + --user=1 \ + --name="Item A do Pack" \ + --type=simple \ + --regular_price="15.00" \ + --sku="PACK-ITEM-A" \ + --parent_id=$GROUP_ID \ + --allow-root --path=$PATH_WP +``` + +### Produto Variável com Variações + +```bash +# 1. Criar produto pai variável +PARENT_ID=$(/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product create \ + --user=1 \ + --name="Sapatilhas Running" \ + --type=variable \ + --attributes='[{"name":"Tamanho","variation":true,"visible":true,"options":["39","40","41","42","43"]},{"name":"Cor","variation":true,"visible":true,"options":["Preto","Branco"]}]' \ + --porcelain --allow-root --path=$PATH_WP) + +# 2. Criar variação (Tamanho 40, Cor Preto) +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product_variation create $PARENT_ID \ + --user=1 \ + --regular_price="89.99" \ + --sku="RUN-40-PT" \ + --attributes='[{"name":"Tamanho","option":"40"},{"name":"Cor","option":"Preto"}]' \ + --manage_stock=true \ + --stock_quantity=25 \ + --allow-root --path=$PATH_WP +``` + +### Produto com Categorias e Atributos Visíveis + +```bash +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product create \ + --user=1 \ + --name="Casaco Impermeável Inverno" \ + --type=simple \ + --regular_price="120.00" \ + --categories='[{"id":15},{"id":22}]' \ + --attributes='[{"name":"Material","visible":true,"options":["Poliéster","Gore-Tex"]},{"name":"Cor","visible":true,"options":["Preto","Azul Marinho"]}]' \ + --allow-root --path=$PATH_WP +``` + +--- + +## Gestão de Stock + +```bash +PATH_WP="/home/USER/public_html" + +# Actualizar stock de produto único +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product update 456 \ + --user=1 \ + --manage_stock=true \ + --stock_quantity=75 \ + --stock_status=instock \ + --allow-root --path=$PATH_WP + +# Colocar produto fora de stock (sem alterar quantidade) +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product update 456 \ + --user=1 --stock_status=outofstock \ + --allow-root --path=$PATH_WP + +# Actualizar stock em massa por prefixo SKU +WP="/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root --path=$PATH_WP" +for ID in $($WP wc product list --user=1 --sku="TSHIRT-*" --format=ids); do + $WP wc product update $ID --user=1 --stock_quantity=200 --porcelain +done +``` + +--- + +## Gestão de Encomendas + +### Consulta e Filtros + +```bash +PATH_WP="/home/USER/public_html" + +# Encomendas por estado +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shop_order list \ + --user=1 --status=processing \ + --fields=id,total,currency,date_created \ + --format=table \ + --allow-root --path=$PATH_WP + +# Estados disponíveis: pending, processing, on-hold, completed, cancelled, refunded, failed +``` + +### Actualizar Estado + +```bash +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shop_order update 355 \ + --user=1 --status=completed \ + --allow-root --path=$PATH_WP +``` + +### Adicionar Nota (Visível ao Cliente) + +```bash +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc order_note create 355 \ + --user=1 \ + --note="Expedido via CTT. Rastreio: PT-99887766." \ + --customer_note=true \ + --allow-root --path=$PATH_WP +``` + +### Conclusão Massiva com Relatório + +```bash +#!/bin/bash +PATH_WP="/home/USER/public_html" +WP="/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root --path=$PATH_WP" + +ORDER_IDS=$($WP wc shop_order list --user=1 --status=processing --format=ids) +TOTAL=0 + +for ID in $ORDER_IDS; do + $WP wc shop_order update $ID --user=1 --status=completed --porcelain + TOTAL=$((TOTAL+1)) + echo "[OK] Encomenda #$ID concluída." +done + +echo "Total processado: $TOTAL encomendas." +``` + +--- + +## Clientes + +```bash +PATH_WP="/home/USER/public_html" + +# Listar com métricas de lifetime value +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc customer list \ + --user=1 \ + --role=customer \ + --fields=id,email,orders_count,total_spent \ + --format=table \ + --allow-root --path=$PATH_WP + +# Criar cliente completo (B2B) +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc customer create \ + --user=1 \ + --email="empresa@exemplo.pt" \ + --first_name="Carlos" \ + --last_name="Mendes" \ + --username="carlosmendes_b2b" \ + --password="SenhaForte!2026" \ + --billing='{"first_name":"Carlos","last_name":"Mendes","company":"Empresa Lda","address_1":"Avenida da Liberdade 123","city":"Lisboa","postcode":"1250-140","country":"PT"}' \ + --shipping='{"first_name":"Carlos","last_name":"Mendes","company":"Armazém Empresa","address_1":"Rua da Indústria 45","city":"Sintra","postcode":"2710-000","country":"PT"}' \ + --allow-root --path=$PATH_WP +``` + +--- + +## Shipping Zones — Configuração Completa + +```bash +PATH_WP="/home/USER/public_html" + +# 1. Criar zona geográfica +ZONE_ID=$(/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shipping_zone create \ + --user=1 --name="Portugal Continental" \ + --porcelain --allow-root --path=$PATH_WP) + +# 2. Adicionar países à zona +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shipping_zone_location create $ZONE_ID \ + --user=1 --code="PT" --type=country \ + --allow-root --path=$PATH_WP + +# 3. Adicionar método de portes fixos +METHOD_ID=$(/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shipping_zone_method create $ZONE_ID \ + --user=1 --method_id=flat_rate \ + --porcelain --allow-root --path=$PATH_WP) + +# 4. Definir custo +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shipping_zone_method update $ZONE_ID $METHOD_ID \ + --user=1 --settings='{"cost":"3.99","title":"Portes Padrão"}' \ + --allow-root --path=$PATH_WP + +# 5. Adicionar envio gratuito acima de X€ +FREE_ID=$(/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shipping_zone_method create $ZONE_ID \ + --user=1 --method_id=free_shipping \ + --porcelain --allow-root --path=$PATH_WP) + +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shipping_zone_method update $ZONE_ID $FREE_ID \ + --user=1 --settings='{"requires":"min_amount","min_amount":"50"}' \ + --allow-root --path=$PATH_WP + +# Listar todas as zonas +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shipping_zone list \ + --user=1 --format=table --allow-root --path=$PATH_WP +``` + +--- + +## Payment Gateways + +```bash +PATH_WP="/home/USER/public_html" + +# Listar todos os gateways +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc payment_gateway list \ + --user=1 --fields=id,title,enabled --allow-root --path=$PATH_WP + +# Activar gateway +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc payment_gateway update bacs \ + --user=1 --enabled=true --allow-root --path=$PATH_WP + +# Desactivar gateway (emergência) +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc payment_gateway update paypal \ + --user=1 --enabled=false --allow-root --path=$PATH_WP + +# Configurar Stripe em modo teste +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc payment_gateway update stripe \ + --user=1 \ + --settings='{"testmode":"yes","test_publishable_key":"pk_test_XXXX","test_secret_key":"sk_test_XXXX"}' \ + --allow-root --path=$PATH_WP +``` + +--- + +## Tributação + +```bash +PATH_WP="/home/USER/public_html" + +# Criar taxa IVA 23% (Portugal) +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc tax create \ + --user=1 \ + --country=PT \ + --rate="23" \ + --name="IVA 23%" \ + --class=standard \ + --allow-root --path=$PATH_WP + +# Criar taxa reduzida 6% +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc tax create \ + --user=1 --country=PT --rate="6" --name="IVA 6%" --class=reduced-rate \ + --allow-root --path=$PATH_WP + +# Criar classe de taxa personalizada +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc tax_class create \ + --user=1 --name="Taxa Super Reduzida" \ + --allow-root --path=$PATH_WP + +# Activar cálculo de impostos +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp option update woocommerce_calc_taxes "yes" \ + --allow-root --path=$PATH_WP +``` + +--- + +## Cupões + +```bash +PATH_WP="/home/USER/public_html" + +# Criar cupão de desconto percentual +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shop_coupon create \ + --user=1 \ + --code="VERAO2026" \ + --discount_type=percent \ + --amount="15" \ + --usage_limit=500 \ + --expiry_date="2026-09-30" \ + --allow-root --path=$PATH_WP + +# Criar cupão de desconto fixo +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shop_coupon create \ + --user=1 \ + --code="DESCONTO10" \ + --discount_type=fixed_cart \ + --amount="10" \ + --minimum_amount="50" \ + --allow-root --path=$PATH_WP + +# Listar cupões activos +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc shop_coupon list \ + --user=1 --fields=id,code,amount,discount_type,usage_count \ + --format=table --allow-root --path=$PATH_WP +``` + +--- + +## Ferramentas de Manutenção + +```bash +PATH_WP="/home/USER/public_html" +WP="/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root --path=$PATH_WP" + +# Listar todas as ferramentas +$WP wc tool list --user=1 --fields=id,name,description --format=table + +# Limpar transients +$WP wc tool run clear_transients --user=1 + +# Recalcular contadores de taxonomias (categorias/tags) +$WP wc tool run recount_terms --user=1 + +# Eliminar variações órfãs +$WP wc tool run delete_orphaned_variations --user=1 + +# Limpar sessões e carrinhos abandonados +$WP wc tool run clear_sessions --user=1 + +# Regenerar imagens de produto +$WP wc tool run regenerate_thumbnails --user=1 + +# Regenerar dados de lookup (tabela de relatórios) +$WP wc tool run clear_lookup_table --user=1 + +# Sequência completa de limpeza (recomendada após alterações massivas) +$WP wc tool run delete_orphaned_variations --user=1 +$WP wc tool run recount_terms --user=1 +$WP wc tool run clear_sessions --user=1 +$WP wc tool run clear_transients --user=1 +$WP cache flush +$WP rewrite flush +echo "Limpeza concluída." +``` + +--- + +## WP All Import — Importação Massiva + +```bash +PATH_WP="/home/USER/public_html" + +# Verificar se plugin está activo +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp plugin is-active wp-all-import-pro \ + --allow-root --path=$PATH_WP && echo "Activo" || echo "Inactivo" + +# Executar perfil de importação pré-configurado (ID=5) +# Configurar mapeamentos no painel WP All Import primeiro +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp all-import run 5 \ + --force-run --disable-log \ + --allow-root --path=$PATH_WP + +# Listar perfis de importação +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp all-import status \ + --allow-root --path=$PATH_WP +``` + +--- + +## Importação via CSV (Script) + +```bash +#!/bin/bash +# Importar produtos a partir de CSV (colunas: SKU,TITULO,PRECO) +PATH_WP="/home/USER/public_html" +WP="/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root --path=$PATH_WP" +CSV="/home/USER/produtos.csv" +ERROS=0 +OK=0 + +tail -n +2 "$CSV" | while IFS=, read -r SKU TITULO PRECO; do + ID=$($WP wc product create \ + --user=1 \ + --sku="$SKU" \ + --name="$TITULO" \ + --regular_price="$PRECO" \ + --type=simple \ + --status=publish \ + --porcelain 2>/dev/null) + + if [ -n "$ID" ] && [ "$ID" -gt 0 ] 2>/dev/null; then + echo "[OK] $SKU → ID $ID" + OK=$((OK+1)) + else + echo "[ERRO] $SKU — falhou" + ERROS=$((ERROS+1)) + fi +done + +echo "Importação concluída. OK: $OK | Erros: $ERROS" +``` + +--- + +## Scripts de Manutenção + +### Normalização Preventiva de Dados + +```bash +#!/bin/bash +PATH_WP="/home/USER/public_html" +WP="/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root --path=$PATH_WP" + +echo "=== LIMPEZA WOOCOMMERCE ===" +echo "Site: $PATH_WP | $(date)" + +$WP wc tool run delete_orphaned_variations --user=1 --quiet && echo "[OK] Variações órfãs" +$WP wc tool run recount_terms --user=1 --quiet && echo "[OK] Contadores taxonomias" +$WP wc tool run clear_sessions --user=1 --quiet && echo "[OK] Sessões" +$WP wc tool run clear_transients --user=1 --quiet && echo "[OK] Transients" +$WP cache flush && echo "[OK] Object cache" +$WP rewrite flush && echo "[OK] Rewrite rules" +$WP db optimize --quiet && echo "[OK] BD optimizada" + +echo "=== CONCLUÍDO ===" +``` + +### Manutenção WooCommerce em Todos os Sites CWP + +```bash +#!/bin/bash +find /home -name wp-config.php -not -path "*/backup*" 2>/dev/null | while read config; do + dir=$(dirname "$config") + user=$(stat -c '%U' "$dir") + + php_fpm=$(ps aux | grep "php-fpm: pool ${user}" | grep -v grep | head -1 | grep -o 'php-fpm[0-9][0-9]' | head -1) + php_ver=${php_fpm:-php-fpm82} + php_bin="/opt/alt/${php_ver}/usr/bin/php" + WP="$php_bin /usr/local/bin/wp --allow-root --path=$dir" + + echo "=== $user ($dir) ===" + + # Verificar se WooCommerce está activo + if $WP plugin is-active woocommerce 2>/dev/null; then + $WP wc tool run clear_transients --user=1 --quiet 2>/dev/null + $WP wc tool run recount_terms --user=1 --quiet 2>/dev/null + echo " [WC] Limpeza WooCommerce concluída." + else + echo " [--] WooCommerce não activo." + fi +done +``` + +--- + +## Limitações e Bugs Conhecidos + +### Memory Exhaustion — Override CWP + +```bash +# -d memory_limit antes de /usr/local/bin/wp +/opt/alt/php-fpm83/usr/bin/php -d memory_limit=2G /usr/local/bin/wp wc product list \ + --user=1 --per_page=100 --format=ids \ + --allow-root --path=/home/USER/public_html + +# Para catálogos muito grandes: iterar com --per_page=100 e --page=N +for PAGE in 1 2 3 4 5; do + /opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc product list \ + --user=1 --per_page=100 --page=$PAGE --format=ids \ + --allow-root --path=/home/USER/public_html +done +``` + +### Bug `wp wc update` — Versão BD não actualiza + +```bash +# Verificar versão instalada +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp plugin get woocommerce \ + --field=version --allow-root --path=/home/USER/public_html + +# Forçar actualização manual do registo BD +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp option update woocommerce_db_version "9.X.X" \ + --allow-root --path=/home/USER/public_html +``` + +### Bypass Wizard de Onboarding + +```bash +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp option update woocommerce_onboarding_opt_in "yes" \ + --allow-root --path=/home/USER/public_html + +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp option update woocommerce_task_list_hidden "yes" \ + --allow-root --path=/home/USER/public_html + +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp option update woocommerce_setup_wizard_data \ + '{"setup_wizard":"completed"}' --allow-root --path=/home/USER/public_html +``` + +--- + +## Settings via wp_options + +Algumas configurações WooCommerce não têm endpoint CLI nativo. Usar `wp option update` directamente: + +```bash +PATH_WP="/home/USER/public_html" + +# Moeda +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp option update woocommerce_currency "EUR" \ + --allow-root --path=$PATH_WP + +# Posição do símbolo de moeda +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp option update woocommerce_currency_pos "right_space" \ + --allow-root --path=$PATH_WP + +# Separadores de preço (PT-PT) +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp option update woocommerce_price_thousand_sep "." \ + --allow-root --path=$PATH_WP +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp option update woocommerce_price_decimal_sep "," \ + --allow-root --path=$PATH_WP + +# País de base da loja +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp option update woocommerce_default_country "PT" \ + --allow-root --path=$PATH_WP + +# Activar impostos +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp option update woocommerce_calc_taxes "yes" \ + --allow-root --path=$PATH_WP +``` + +--- + +*Referência WooCommerce CLI CWP | Descomplicar® | v1.0.0 | 18-02-2026* diff --git a/wordpress/skills/woocommerce/SKILL.md b/wordpress/skills/woocommerce/SKILL.md new file mode 100644 index 0000000..5058c24 --- /dev/null +++ b/wordpress/skills/woocommerce/SKILL.md @@ -0,0 +1,190 @@ +--- +name: woocommerce +description: Desenvolvimento e optimização de lojas WooCommerce. Personalização de checkout, integração de gateways de pagamento portugueses (Multibanco, MB Way, IfthenPay), funcionalidades custom e performance. +layer: wiki +--- + +# /woocommerce - WooCommerce Development + +Desenvolvimento e optimização de lojas WooCommerce. + +## Quando Usar + +- Configurar loja WooCommerce +- Personalizar checkout +- Integrar gateways de pagamento PT +- Desenvolver funcionalidades custom +- Optimizar performance + +## Contexto NotebookLM + +ANTES de executar, consultar notebooks para contexto especializado: + +| Notebook | ID | Consultar quando | +|----------|-----|-----------------| +| WordPress e Elementor | 5be0d1a6 | Sempre | +| E-commerce Prático | 226e384e | Para estratégia e-commerce | + +``` +mcp__notebooklm__notebook_query({ + notebook_id: "5be0d1a6-00f2-4cd9-b835-978cb7721601", + query: "" +}) + +mcp__notebooklm__notebook_query({ + notebook_id: "226e384e-d4bc-48f4-bb82-7927360436cc", + query: "" +}) +``` + +Integrar insights do NotebookLM nas recomendações e decisões. + +### Procedimentos Relacionados +- `PROC-WiP-Starter-Template.md` — Template inicial para lojas WooCommerce + +--- + +## Hooks WooCommerce Essenciais + +### Actions + +```php +// Before/after cart +add_action('woocommerce_before_cart', 'show_cart_notice'); +add_action('woocommerce_after_cart', 'show_shipping_info'); + +// Checkout +add_action('woocommerce_before_checkout_form', 'show_checkout_notice'); +add_action('woocommerce_checkout_order_processed', 'after_order', 10, 3); + +// Product +add_action('woocommerce_before_single_product', 'show_product_notice'); +add_action('woocommerce_after_add_to_cart_button', 'add_custom_button'); + +// Admin +add_action('woocommerce_admin_order_data_after_billing_address', 'show_admin_meta'); +add_action('woocommerce_process_product_meta', 'save_product_meta'); +``` + +### Filters + +```php +// Modificar preço +add_filter('woocommerce_cart_item_price', 'custom_price', 10, 2); +add_filter('woocommerce_get_price_html', 'custom_price_html', 10, 2); + +// Checkout fields +add_filter('woocommerce_checkout_fields', 'custom_checkout_fields'); +add_filter('woocommerce_billing_fields', 'custom_billing_fields'); + +// Cart +add_filter('woocommerce_add_cart_item_data', 'add_cart_item_data', 10, 2); +add_filter('woocommerce_cart_item_name', 'custom_cart_item_name', 10, 3); + +// Emails +add_filter('woocommerce_email_subject_new_order', 'custom_email_subject', 10, 2); +``` + +## Gateways Portugal + +| Gateway | Plugin | Notas | +|---------|--------|-------| +| **MB Way** | IfthenPay / Eupago | Pagamento instantâneo | +| **Multibanco** | IfthenPay / Eupago | Referências MB | +| **Stripe** | Stripe for WooCommerce | Cartões + Apple/Google Pay | +| **PayPal** | WooCommerce PayPal | Standard e Express | + +### Configuração IfthenPay + +```php +// Webhook para confirmação automática +add_action('woocommerce_api_ifthenpay_webhook', 'handle_ifthenpay_callback'); + +function handle_ifthenpay_callback() { + $order_id = $_GET['order_id'] ?? null; + $status = $_GET['status'] ?? null; + + if ($status === 'success') { + $order = wc_get_order($order_id); + $order->payment_complete(); + } +} +``` + +## Customização Checkout + +```php +// Adicionar campo NIF +add_filter('woocommerce_checkout_fields', function($fields) { + $fields['billing']['billing_nif'] = [ + 'label' => 'NIF', + 'required' => true, + 'class' => ['form-row-wide'], + 'validate' => ['validate_nif'] + ]; + return $fields; +}); + +// Validar NIF +add_action('woocommerce_checkout_process', function() { + if (empty($_POST['billing_nif'])) { + wc_add_notice('NIF é obrigatório', 'error'); + } +}); + +// Guardar NIF +add_action('woocommerce_checkout_update_order_meta', function($order_id) { + if (!empty($_POST['billing_nif'])) { + update_post_meta($order_id, '_billing_nif', sanitize_text_field($_POST['billing_nif'])); + } +}); +``` + +## REST API + +```php +// Endpoint custom +add_action('rest_api_init', function() { + register_rest_route('wc/v3', '/products/featured', [ + 'methods' => 'GET', + 'callback' => function() { + $args = [ + 'status' => 'publish', + 'featured' => true, + 'limit' => 10 + ]; + $products = wc_get_products($args); + return rest_ensure_response($products); + } + ]); +}); +``` + +## WP-CLI WooCommerce + +```bash +# Listar produtos +wp wc product list --user=1 --format=table + +# Criar produto +wp wc product create --name="Produto Teste" --regular_price=99.99 --user=1 + +# Listar pedidos +wp wc order list --status=processing --user=1 + +# Actualizar stock +wp wc product update 123 --stock_quantity=50 --user=1 + +# Limpar transients +wp transient delete --all +``` + +## Integrações + +### Moloni (Facturação) + +```php +// Auto-criar factura após pedido pago +add_action('woocommerce_order_status_completed', 'create_moloni_invoice'); + +functi \ No newline at end of file diff --git a/wordpress/skills/wp-cli/SKILL.md b/wordpress/skills/wp-cli/SKILL.md new file mode 100644 index 0000000..d508584 --- /dev/null +++ b/wordpress/skills/wp-cli/SKILL.md @@ -0,0 +1,185 @@ +--- +name: wp-cli +description: Gestão WordPress via WP-CLI no servidor CWP. Cobre core, plugins, temas, base de dados, utilizadores, migração, search-replace e automação com suporte multi-PHP. +layer: wiki +--- + +# /wp-cli - Gestão WordPress via WP-CLI no CWP + +Operações WordPress via linha de comandos no servidor CWP (server.descomplicar.pt). Cobre core, plugins, temas, base de dados, utilizadores, migração e automação. + +**Servidor:** server.descomplicar.pt (176.9.3.158) | porta SSH: 9443 +**Fonte:** `Hub/06-Operacoes/Documentacao/Manuais/WP-CLI no CWP.md` +**NotebookLM:** [WordPress Config CLI](https://notebooklm.google.com/notebook/fb2f26bd-8cb0-4d4c-bafc-4f1ebb51c51d) + +--- + +## Contexto CWP — Regras Obrigatórias + +```bash +# 1. Usar sempre --allow-root (CWP executa como root) +# 2. Especificar sempre --path= (não fazer cd) +# 3. Usar o PHP correcto para cada utilizador + +# Formato base +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp COMANDO --allow-root --path=/home/USER/public_html + +# Aliases ~/.bashrc (se configurados) +alias wp74='/opt/alt/php-fpm74/usr/bin/php /usr/local/bin/wp --allow-root' +alias wp82='/opt/alt/php-fpm82/usr/bin/php /usr/local/bin/wp --allow-root' +alias wp83='/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root' +``` + +### Versões PHP disponíveis + +| Alias | PHP | Path | +|-------|-----|------| +| `wp74` | 7.4 | `/opt/alt/php-fpm74/usr/bin/php` | +| `wp80` | 8.0 | `/opt/alt/php-fpm80/usr/bin/php` | +| `wp81` | 8.1 | `/opt/alt/php-fpm81/usr/bin/php` | +| `wp82` | 8.2 | `/opt/alt/php-fpm82/usr/bin/php` | +| `wp83` | 8.3 | `/opt/alt/php-fpm83/usr/bin/php` | + +### Detectar PHP activo de um utilizador + +```bash +# Ver pool PHP-FPM do utilizador +ps aux | grep "php-fpm: pool USER" | grep -v grep | head -1 + +# Ou usar wp-auto.sh (auto-detect) +/root/wp-auto.sh --path=/home/USER/public_html plugin list +``` + +O script `wp-auto.sh` está em `scripts/wp-auto.sh` desta skill. + +--- + +## Core WordPress + +```bash +PATH=/home/USER/public_html + +# Verificar versão +wp core version --allow-root --path=$PATH + +# Actualizar WordPress +wp core update --allow-root --path=$PATH + +# Verificar integridade dos ficheiros +wp core verify-checksums --allow-root --path=$PATH + +# Instalar versão específica +wp core download --version=6.4.3 --force --allow-root --path=$PATH + +# Informações ambiente +wp --info --allow-root --path=$PATH +``` + +--- + +## Plugins + +```bash +# Listar todos os plugins +wp plugin list --allow-root --path=$PATH + +# Listar plugins desactualizados +wp plugin list --update=available --format=table --allow-root --path=$PATH + +# Actualizar todos os plugins +wp plugin update --all --allow-root --path=$PATH + +# Instalar e activar +wp plugin install akismet --activate --allow-root --path=$PATH + +# Activar / desactivar +wp plugin activate NOME --allow-root --path=$PATH +wp plugin deactivate NOME --allow-root --path=$PATH + +# Remover plugin +wp plugin delete NOME --allow-root --path=$PATH + +# Verificar integridade +wp plugin verify-checksums --all --allow-root --path=$PATH +``` + +--- + +## Temas + +```bash +# Listar temas +wp theme list --allow-root --path=$PATH + +# Instalar e activar +wp theme install hello-elementor --activate --allow-root --path=$PATH + +# Actualizar todos os temas +wp theme update --all --allow-root --path=$PATH + +# Activar tema +wp theme activate NOME --allow-root --path=$PATH +``` + +--- + +## Base de Dados + +```bash +# Exportar (backup) +wp db export /home/USER/backup_$(date +%Y%m%d_%H%M).sql --allow-root --path=$PATH + +# Importar (restaurar) +wp db import backup.sql --allow-root --path=$PATH + +# Optimizar tabelas +wp db optimize --allow-root --path=$PATH + +# Reparar tabelas corrompidas +wp db repair --allow-root --path=$PATH + +# Query directa +wp db query "SELECT option_name, option_value FROM wp_options WHERE option_name='siteurl';" --allow-root --path=$PATH + +# Tamanho tabelas +wp db query "SELECT table_name, ROUND((data_length+index_length)/1024/1024,2) AS MB FROM information_schema.tables WHERE table_schema=DATABASE() ORDER BY MB DESC LIMIT 20;" --allow-root --path=$PATH +``` + +--- + +## Migração de Site (Search-Replace) + +```bash +# Preview (dry-run) — SEMPRE primeiro +wp search-replace 'https://old.com' 'https://new.com' --dry-run --allow-root --path=$PATH + +# Executar após confirmar +wp search-replace 'https://old.com' 'https://new.com' --allow-root --path=$PATH + +# Com relatório +wp search-replace 'old.com' 'new.com' --report --allow-root --path=$PATH + +# Após migração: limpar cache e regenerar rewrite rules +wp cache flush --allow-root --path=$PATH +wp rewrite flush --allow-root --path=$PATH +``` + +--- + +## Utilizadores + +```bash +# Listar utilizadores +wp user list --allow-root --path=$PATH + +# Criar administrador +wp user create admin admin@site.pt --role=administrator --user_pass=SENHA --allow-root --path=$PATH + +# Redefinir password +wp user update USERNAME --user_pass=NOVA_SENHA --allow-root --path=$PATH + +# Adicionar papel a utilizador existente +wp user set-role USERNAME administrator --allow-root --path=$PATH + +# Remover utilizador (transferindo conteúdo) +wp user delete USERNAME \ No newline at end of file diff --git a/wordpress/skills/wp-cli/references/commands.md b/wordpress/skills/wp-cli/references/commands.md new file mode 100644 index 0000000..176713d --- /dev/null +++ b/wordpress/skills/wp-cli/references/commands.md @@ -0,0 +1,376 @@ +# WP-CLI no CWP — Referência Completa de Comandos + +**Servidor:** server.descomplicar.pt (176.9.3.158) | porta 9443 +**PHP padrão:** `/opt/alt/php-fpm83/usr/bin/php` + +--- + +## Formato Base + +```bash +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp GRUPO SUBCOMANDO [FLAGS] --allow-root --path=/home/USER/public_html +``` + +--- + +## Core WordPress + +```bash +wp core version # Versão actual +wp core update # Actualizar para latest +wp core update --version=6.4.3 --force # Versão específica +wp core download # Descarregar sem instalar +wp core verify-checksums # Verificar integridade ficheiros +wp core install --url=... --title=... \ + --admin_user=admin --admin_email=... # Instalar novo WordPress +wp core is-installed # Verificar se está instalado +wp core update-db # Actualizar base de dados após update +``` + +--- + +## Plugins + +```bash +wp plugin list # Listar todos +wp plugin list --status=inactive # Só inactivos +wp plugin list --update=available # Com updates disponíveis +wp plugin install SLUG # Instalar +wp plugin install SLUG --activate # Instalar e activar +wp plugin install SLUG --version=X.X # Versão específica +wp plugin activate SLUG # Activar +wp plugin deactivate SLUG # Desactivar +wp plugin deactivate --all # Desactivar todos (debug) +wp plugin delete SLUG # Remover ficheiros +wp plugin update SLUG # Actualizar plugin específico +wp plugin update --all # Actualizar todos +wp plugin update --all --dry-run # Preview de updates +wp plugin verify-checksums SLUG # Verificar integridade +wp plugin verify-checksums --all # Verificar todos +wp plugin search TERMO # Pesquisar no repo WordPress.org +wp plugin get SLUG # Info detalhada +wp plugin path SLUG # Path do plugin no servidor +``` + +--- + +## Temas + +```bash +wp theme list # Listar todos +wp theme install SLUG # Instalar +wp theme install SLUG --activate # Instalar e activar +wp theme activate SLUG # Activar tema +wp theme update SLUG # Actualizar +wp theme update --all # Actualizar todos +wp theme delete SLUG # Remover +wp theme get SLUG # Info detalhada +wp theme is-active SLUG # Verificar se activo +``` + +--- + +## Base de Dados + +```bash +wp db export /caminho/backup.sql # Exportar +wp db export - | gzip > backup.sql.gz # Exportar comprimido +wp db import backup.sql # Importar +wp db optimize # Optimizar tabelas +wp db repair # Reparar tabelas +wp db check # Verificar integridade +wp db size # Tamanho da BD +wp db tables # Listar tabelas +wp db prefix # Prefixo actual +wp db query "SQL;" # Query directa +wp db search "TERMO" # Pesquisar em toda a BD +wp db clean --tables=revision # Limpar revisões +``` + +--- + +## Search-Replace (Migração) + +```bash +# SEMPRE fazer dry-run primeiro +wp search-replace 'old.com' 'new.com' --dry-run + +# Executar +wp search-replace 'https://old.com' 'https://new.com' + +# Só numa tabela +wp search-replace 'old' 'new' wp_options wp_postmeta + +# Com relatório detalhado +wp search-replace 'old' 'new' --report-changed-only + +# Sem serialization (mais rápido, menos seguro) +wp search-replace 'old' 'new' --no-php + +# Número de linhas por batch (para BDs grandes) +wp search-replace 'old' 'new' --precise + +# Skip tabelas específicas +wp search-replace 'old' 'new' --skip-tables=wp_users +``` + +--- + +## Options WordPress + +```bash +wp option get NOME # Ler option +wp option update NOME VALOR # Actualizar (simples) +wp option patch update NOME SUBKEY VALOR # Actualizar sub-key (serialized) +wp option pluck NOME SUBKEY # Ler sub-key +wp option add NOME VALOR # Adicionar +wp option delete NOME # Apagar +wp option list # Listar todas +wp option list --search='rank*' # Filtrar por nome +wp option list --autoload=yes # Só com autoload +``` + +--- + +## Post Meta / User Meta / Term Meta + +```bash +# Post Meta +wp post meta list POST_ID # Listar meta de um post +wp post meta get POST_ID META_KEY # Ler valor +wp post meta update POST_ID META_KEY VAL # Actualizar +wp post meta add POST_ID META_KEY VAL # Adicionar +wp post meta delete POST_ID META_KEY # Apagar + +# Com formato JSON (para arrays/objects) +wp post meta update POST_ID META_KEY '["val1","val2"]' --format=json + +# Term Meta +wp term meta list TERM_ID +wp term meta get TERM_ID META_KEY +wp term meta update TERM_ID META_KEY VAL + +# User Meta +wp user meta list USER_ID +wp user meta get USER_ID META_KEY +wp user meta update USER_ID META_KEY VAL +``` + +--- + +## Posts e Conteúdo + +```bash +wp post list # Listar posts +wp post list --post_type=page # Só páginas +wp post list --post_status=draft # Só rascunhos +wp post get POST_ID # Info completa +wp post create --post_type=post \ + --post_title="Título" \ + --post_status=publish # Criar post +wp post update POST_ID --post_title="..." # Actualizar +wp post delete POST_ID # Apagar (lixo) +wp post delete POST_ID --force # Apagar definitivo +wp post generate --count=10 # Gerar posts de teste +``` + +--- + +## Utilizadores + +```bash +wp user list # Listar todos +wp user list --role=administrator # Filtrar por papel +wp user get USER_ID # Info utilizador +wp user get USERNAME --field=ID # Obter ID por username +wp user create LOGIN EMAIL \ + --role=administrator \ + --user_pass=SENHA # Criar +wp user update USER_ID --user_pass=SENHA # Alterar password +wp user update USER_ID --user_email=... # Alterar email +wp user set-role USER_ID administrator # Alterar papel +wp user delete USER_ID --reassign=1 # Apagar, transferindo conteúdo +wp user check-password USER_ID SENHA # Verificar password +wp user reset-password USER_ID # Reset password (envia email) +``` + +--- + +## Cache e Transientes + +```bash +wp cache flush # Limpar object cache +wp cache get KEY [GROUP] # Ler cache +wp transient delete --all # Apagar todos transientes +wp transient delete NOME # Apagar transiente específico +wp transient get NOME # Ler transiente +wp rewrite flush # Regenerar rewrite rules +wp rewrite list # Listar rules actuais +``` + +--- + +## Cron + +```bash +wp cron event list # Listar eventos agendados +wp cron event run HOOK_NAME # Executar agora +wp cron event delete HOOK_NAME # Apagar evento +wp cron event schedule HOOK cron now # Agendar evento +wp cron schedule list # Ver schedules disponíveis +wp cron test # Testar se cron está funcional +``` + +--- + +## wp eval — Execução PHP + +```bash +# Código PHP inline +wp eval 'echo PHP_VERSION."\n";' --allow-root --path=$PATH + +# Ficheiro PHP +wp eval-file script.php --allow-root --path=$PATH + +# Com parâmetros +wp eval 'global $wpdb; echo $wpdb->prefix;' --allow-root --path=$PATH + +# Ver constantes WordPress +wp eval 'echo WP_CONTENT_DIR."\n"; echo ABSPATH;' --allow-root --path=$PATH + +# Executar com utilizador específico +wp eval 'echo get_current_user_id();' --user=1 --allow-root --path=$PATH +``` + +--- + +## Multisite + +```bash +wp site list # Listar sites +wp site create --slug=subdomain # Criar site +wp site activate ID # Activar +wp site deactivate ID # Desactivar +wp site delete ID # Apagar + +# Executar comando em todos os sites +wp site list --field=url | xargs -I {} wp --url={} plugin list --allow-root --path=$PATH +``` + +--- + +## WooCommerce CLI + +```bash +wp wc product list # Listar produtos +wp wc product get ID # Produto específico +wp wc product create --name="Nome" \ + --regular_price="19.99" # Criar produto +wp wc product update ID --regular_price="29.99" # Actualizar +wp wc product delete ID # Apagar + +wp wc order list # Listar encomendas +wp wc order get ID # Encomenda específica +wp wc order update ID --status=completed # Mudar estado + +wp wc customer list # Listar clientes +wp wc shipping_zone list # Zonas de entrega +``` + +--- + +## Segurança e Diagnóstico + +```bash +# Verificar integridade completa +wp core verify-checksums --allow-root --path=$PATH +wp plugin verify-checksums --all --allow-root --path=$PATH + +# Configuração PHP activa +wp eval 'echo PHP_VERSION."\n".php_ini_loaded_file()."\n";' --allow-root --path=$PATH +wp eval 'echo ini_get("memory_limit")."\n".ini_get("max_execution_time");' --allow-root --path=$PATH + +# Ver configuração WordPress +wp option get siteurl --allow-root --path=$PATH +wp option get blogname --allow-root --path=$PATH +wp option get active_plugins --format=json --allow-root --path=$PATH + +# Verificar se WP_DEBUG activo +wp eval 'echo WP_DEBUG ? "DEBUG ON" : "DEBUG OFF";' --allow-root --path=$PATH + +# Listar ficheiros modificados recentemente (possível hack) +find /home/USER/public_html -name "*.php" -newer /home/USER/public_html/wp-config.php -not -path "*/wp-content/cache/*" 2>/dev/null | head -20 +``` + +--- + +## Scripts de Manutenção + +### Backup completo de um site + +```bash +#!/bin/bash +PATH_WP="/home/USER/public_html" +BACKUP_DIR="/media/ealmeida/Externo/LocalBackups/WP" +DATE=$(date +%Y%m%d_%H%M) +SITE=$(basename $(dirname $PATH_WP)) + +mkdir -p "$BACKUP_DIR" + +# Backup BD +/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp db export \ + "$BACKUP_DIR/${SITE}_db_${DATE}.sql" \ + --allow-root --path=$PATH_WP + +# Backup ficheiros +tar -czf "$BACKUP_DIR/${SITE}_files_${DATE}.tar.gz" \ + -C $(dirname $PATH_WP) public_html \ + --exclude="public_html/wp-content/cache" + +echo "Backup completo: $BACKUP_DIR" +``` + +### Manutenção semanal (todos os sites) + +```bash +#!/bin/bash +find /home -name wp-config.php -not -path "*/backup*" 2>/dev/null | while read config; do + dir=$(dirname "$config") + user=$(stat -c '%U' "$dir") + + # Detectar PHP do utilizador + php_fpm=$(ps aux | grep "php-fpm: pool ${user}" | grep -v grep | head -1 | grep -o 'php-fpm[0-9][0-9]' | head -1) + php_ver=${php_fpm:-php-fpm82} + php_bin="/opt/alt/${php_ver}/usr/bin/php" + + echo "=== $user ($dir) — PHP $php_ver ===" + + $php_bin /usr/local/bin/wp core update --allow-root --path="$dir" 2>/dev/null + $php_bin /usr/local/bin/wp plugin update --all --allow-root --path="$dir" 2>/dev/null + $php_bin /usr/local/bin/wp theme update --all --allow-root --path="$dir" 2>/dev/null + $php_bin /usr/local/bin/wp db optimize --allow-root --path="$dir" 2>/dev/null + $php_bin /usr/local/bin/wp cache flush --allow-root --path="$dir" 2>/dev/null +done +``` + +--- + +## Flags Globais Úteis + +| Flag | Descrição | +|------|-----------| +| `--allow-root` | Obrigatório no CWP (executa como root) | +| `--path=/home/USER/public_html` | Caminho da instalação WordPress | +| `--url=https://site.pt` | URL do site (importante em multisite) | +| `--user=1` | Executar como utilizador WordPress específico | +| `--format=json\|table\|csv\|ids` | Formato do output | +| `--fields=ID,name` | Campos a mostrar | +| `--debug` | Output de debug detalhado | +| `--quiet` | Sem output (para scripts) | +| `--dry-run` | Preview sem executar (onde disponível) | +| `--skip-plugins` | Não carregar plugins (troubleshooting) | +| `--skip-themes` | Não carregar temas | + +--- + +*WP-CLI CWP — Referência Completa | Descomplicar® | v1.0.0 | 18-02-2026* diff --git a/wordpress/skills/wp-cli/scripts/wp-auto.sh b/wordpress/skills/wp-cli/scripts/wp-auto.sh new file mode 100644 index 0000000..5c29a06 --- /dev/null +++ b/wordpress/skills/wp-cli/scripts/wp-auto.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# wp-auto.sh — WP-CLI com detecção automática de PHP no CWP +# Uso: /root/wp-auto.sh --path=/home/USER/public_html [comando wp-cli] +# Exemplo: /root/wp-auto.sh --path=/home/site/public_html plugin list + +# Pegar utilizador do directório de trabalho +if [[ "$*" == *"--path="* ]]; then + WP_PATH=$(echo "$@" | grep -o '\-\-path=[^ ]*' | cut -d= -f2) +else + WP_PATH=$(pwd) +fi + +USER=$(stat -c '%U' "$WP_PATH" 2>/dev/null || echo "nobody") + +# Encontrar versão PHP-FPM activa para este utilizador +PHP_FPM_PROCESS=$(ps aux | grep "php-fpm: pool ${USER}" | grep -v grep | head -n 1) +PHP_VERSION=$(echo "$PHP_FPM_PROCESS" | grep -o 'php-fpm[0-9][0-9]' | grep -o '[0-9][0-9]' | head -1) + +if [ -z "$PHP_VERSION" ]; then + echo "⚠ Usando PHP 8.2 (padrão — pool ${USER} não encontrado)" >&2 + PHP_PATH="/opt/alt/php-fpm82/usr/bin/php" +else + PHP_PATH="/opt/alt/php-fpm${PHP_VERSION}/usr/bin/php" + echo "ℹ PHP ${PHP_VERSION} detectado para utilizador ${USER}" >&2 +fi + +# Verificar se o PHP existe +if [ ! -f "$PHP_PATH" ]; then + echo "❌ PHP não encontrado: $PHP_PATH — usando PHP 8.3" >&2 + PHP_PATH="/opt/alt/php-fpm83/usr/bin/php" +fi + +# Executar WP-CLI +exec "$PHP_PATH" /usr/local/bin/wp --allow-root "$@" diff --git a/wordpress/skills/wp-dev/SKILL.md b/wordpress/skills/wp-dev/SKILL.md new file mode 100644 index 0000000..1f75779 --- /dev/null +++ b/wordpress/skills/wp-dev/SKILL.md @@ -0,0 +1,178 @@ +--- +name: wp-dev +description: Desenvolvimento WordPress especializado com Quality Gate 70+. Cria e modifica plugins seguindo WordPress Coding Standards, desenvolve temas child, integra WooCommerce e resolve problemas WordPress. +layer: wiki +--- + +# WordPress Plugin Developer + +Skill para desenvolvimento WordPress profissional seguindo padrões Descomplicar®. + +## Quando Usar + +- Criar ou modificar plugins WordPress +- Desenvolver temas ou child themes +- Integrar funcionalidades WooCommerce +- Resolver problemas específicos WordPress +- Criar custom post types, taxonomias, widgets + +## Quando NÃO Usar + +- Para operações CRM (usar /crm-ops) +- Para operações servidor/SSH genéricas (usar agente especializado) +- Para manutenção rotineira WP (usar /today às segundas) + +## Contexto NotebookLM + +ANTES de executar, consultar notebooks para contexto especializado: + +| Notebook | ID | Consultar quando | +|----------|-----|-----------------| +| WordPress e Elementor | 5be0d1a6 | Sempre | +| WordPress Config CLI | fb2f26bd-8cb0-4d4c-bafc-4f1ebb51c51d | Para WP-CLI e configuração | + +``` +mcp__notebooklm__notebook_query({ + notebook_id: "5be0d1a6-00f2-4cd9-b835-978cb7721601", + query: "" +}) + +mcp__notebooklm__notebook_query({ + notebook_id: "fb2f26bd-8cb0-4d4c-bafc-4f1ebb51c51d", + query: "" +}) +``` + +Integrar insights do NotebookLM nas recomendações e decisões. + +### Procedimentos Relacionados +- `PROC-WiP-Definicao.md` — Definição de projectos WordPress in a Package +- `PROC-WiP-Instalacao.md` — Instalação e configuração WiP +- `PROC-WiP-Gestao.md` — Gestão e manutenção WiP + +--- + +## Protocolo Obrigatório + +### 1. Pesquisa Inicial (MCP) +Antes de desenvolver, SEMPRE executar: +``` +mcp__mem_search_memories "[keywords wordpress]" +mcp__wikijs__search_pages "[plugin/funcionalidade]" +``` + +### 2. Quality Gate 70+ +Todo código WordPress deve atingir score mínimo 70/100: +- WordPress Coding Standards (WPCS) +- Funções documentadas com PHPDoc +- Hooks e filters bem estruturados +- Sem warnings/notices PHP +- Segurança: nonces, sanitização, escaping + +### 3. Assinatura Obrigatória +Todo ficheiro PHP deve incluir: +```php +prepare()` para queries + +## Performance + +- Enqueueing correcto: `wp_enqueue_script()`, `wp_enqueue_style()` +- Hooks no momento certo: `init`, `admin_init`, `wp_enqueue_scripts` +- Evitar queries em loops +- Usar transients para cache: `get_transient()`, `set_transient()` + +## Estrutura Plugin Standard + +``` +plugin-name/ +├── plugin-name.php # Ficheiro principal +├── includes/ +│ ├── class-plugin-name.php +│ └── class-plugin-name-admin.php +├── assets/ +│ ├── css/ +│ └── js/ +├── templates/ +├── languages/ +└── readme.txt +``` + +## Template Plugin Principal + +```php + **Nota:** Esta skill APLICA alteracoes. Para auditar sem alterar, usar `/security-check`. + +## Contexto NotebookLM + +ANTES de executar, consultar notebook para contexto: + +| Notebook | ID | Consultar quando | +|----------|-----|-----------------| +| WordPress e Elementor | 5be0d1a6 | Sempre | + +``` +mcp__notebooklm__notebook_query({ + notebook_id: "5be0d1a6-00f2-4cd9-b835-978cb7721601", + query: "wordpress security hardening best practices" +}) +``` + +--- + +## Uso + +``` +/wp-hardening descomplicar.pt +/wp-hardening all # todos os 16 sites +/wp-hardening descomplicar.pt --dry # apenas verificar, sem aplicar +``` + +**Argumento:** dominio do site (ver tabela de sites em /wp-update) ou `all`. +**Flag `--dry`:** apenas verifica estado actual sem aplicar alteracoes. + +--- + +## Sites WordPress no servidor + +| Conta | Site | Path | +|-------|------|------| +| carstuff | carstuff.pt | /home/carstuff/public_html | +| ealmeida | descomplicar.pt | /home/ealmeida/public_html | +| ealmeida | emanuelalmeida.pt | /home/ealmeida/emanuelalmeida.pt | +| ealmeida | ecommerce.descomplicar.pt | /home/ealmeida/ecommerce.descomplicar.pt | +| ealmeida | ecommerce-demo.descomplicar.pt | /home/ealmeida/ecommerce-demo.descomplicar.pt | +| ealmeida | starter.descomplicar.pt | /home/ealmeida/starter.descomplicar.pt | +| ealmeida | care.descomplicar.pt | /home/ealmeida/care.descomplicar.pt | +| ealmeida | e-commerce.descomplicar.pt | /home/ealmeida/e-commerce.descomplicar.pt | +| espiral | espiralsenior.pt | /home/espiral/public_html | +| espiral | dev.espiralsenior.pt | /home/espiral/dev.espiralsenior.pt | +| familycl | familyclinic.pt | /home/familycl/public_html | +| ignition | ignitionvortex.pt | /home/ignition/public_html | +| karate | karateclubedegaia.com | /home/karate/karateclubedegaia.com | +| sintri | sintricare.com.pt | /home/sintri/public_html | +| solarfv | solarfvengenharia.com | /home/solarfv/public_html | +| wtc | watercontrol.pt | /home/wtc/public_html | + +--- + +## Execucao + +### Passo 0: Identificar site e path + +Mapear o dominio fornecido para o path e conta do servidor usando a tabela acima. + +```bash +SITE="dominio.pt" +WP_PATH="/home/USER/public_html" +WP_USER="user" +``` + +### Passo 1: Verificar estado actual (antes) + +Executar via `mcp__ssh-unified__ssh_execute` no servidor `cwp`: + +```bash +# 1. XML-RPC activo? +curl -s -o /dev/null -w "%{http_code}" -X POST "${SITE}/xmlrpc.php" -d 'system.listMethods' + +# 2. DISALLOW_FILE_EDIT definido? +grep -c "DISALLOW_FILE_EDIT" ${WP_PATH}/wp-config.php + +# 3. Permissoes directórios (esperado: 755) +find ${WP_PATH} -type d -not -perm 755 | head -10 + +# 4. Permissoes ficheiros (esperado: 644) +find ${WP_PATH} -type f -not -perm 644 -not -name "wp-config.php" | head -10 + +# 5. Versao WP exposta no HTML? +curl -s ${SITE} | grep -o 'content="WordPress [0-9.]*"' | head -1 + +# 6. Versao WP exposta no feed? +curl -s ${SITE}/feed/ | grep -o '.*' | head -1 + +# 7. Directory listing activo? +curl -s -o /dev/null -w "%{http_code}" ${SITE}/wp-content/uploads/ + +# 8. wp-config.php permissoes (esperado: 400 ou 440) +stat -c "%a" ${WP_PATH}/wp-config.php + +# 9. .htaccess security headers? +grep -c "X-Frame-Options\|X-Content-Type-Options\|X-XSS-Protection\|Referrer-Policy\|Content-Security-Policy\|Strict-Transport-Security" ${WP_PATH}/.htaccess 2>/dev/null + +# 10. debug.log exposto? +test -f ${WP_PATH}/wp-content/debug.log && echo "EXPOSTO" || echo "OK" +``` + +Registar cada resultado como ANTES. + +### Passo 2: Aplicar hardening (se nao --dry) + +> **Regra:** Fazer backup de cada ficheiro ANTES de alterar. + +#### 2.1 Desactivar XML-RPC + +```bash +# Backup .htaccess +cp ${WP_PATH}/.htaccess ${WP_PATH}/.htaccess.bak.$(date +%Y%m%d) + +# Adicionar bloqueio XML-RPC ao .htaccess (antes de # BEGIN WordPress) +sed -i '/# BEGIN WordPress/i \ +# BEGIN Block XML-RPC\ +\ + Require all denied\ +\ +# END Block XML-RPC\ +' ${WP_PATH}/.htaccess +``` + +**Excepcao:** Se o site usa JetPack ou aplicacao mobile WP, NAO desactivar XML-RPC. Verificar primeiro: +```bash +sudo -u ${WP_USER} wp plugin list --status=active --path=${WP_PATH} | grep -i "jetpack" +``` + +#### 2.2 Desactivar file editing (DISALLOW_FILE_EDIT) + +```bash +# Backup wp-config.php +cp ${WP_PATH}/wp-config.php ${WP_PATH}/wp-config.php.bak.$(date +%Y%m%d) + +# Adicionar se nao existir +grep -q "DISALLOW_FILE_EDIT" ${WP_PATH}/wp-config.php || \ + sed -i "/\/\* That's all, stop editing/i define('DISALLOW_FILE_EDIT', true);" ${WP_PATH}/wp-config.php +``` + +#### 2.3 Corrigir permissoes + +```bash +# Directorios: 755 +find ${WP_PATH} -type d -exec chmod 755 {} \; + +# Ficheiros \ No newline at end of file diff --git a/wordpress/skills/wp-performance/SKILL.md b/wordpress/skills/wp-performance/SKILL.md new file mode 100644 index 0000000..e829387 --- /dev/null +++ b/wordpress/skills/wp-performance/SKILL.md @@ -0,0 +1,218 @@ +--- +name: wp-performance +description: Auditoria e optimização de performance WordPress. Analisa velocidade, caching, base de dados e assets. Usa Lighthouse, métricas Core Web Vitals e checklist sistemático. +layer: wiki +--- + +# /wp-performance - Auditoria Performance WordPress + +Checklist sistemático para auditar e optimizar performance de sites WordPress. + +## Contexto NotebookLM + +ANTES de executar, consultar notebooks para contexto especializado: + +| Notebook | ID | Consultar quando | +|----------|-----|-----------------| +| WordPress e Elementor | 5be0d1a6 | Sempre | + +``` +mcp__notebooklm__notebook_query({ + notebook_id: "5be0d1a6-00f2-4cd9-b835-978cb7721601", + query: "" +}) +``` + +Integrar insights do NotebookLM nas recomendações e decisões. + +### Procedimentos Relacionados +- `PROC-WordPress-Performance-Standard.md` — Standards de performance WP + +--- + +## Uso + +``` +/wp-performance https://site.pt +/wp-performance site.pt +``` + +--- + +## Execução + +### Passo 1: Lighthouse (Performance Geral) + +```javascript +// Auditoria Lighthouse mobile + desktop +const [mobile, desktop] = await Promise.all([ + mcp__lighthouse__get_performance_score({ url, device: "mobile" }), + mcp__lighthouse__get_performance_score({ url, device: "desktop" }) +]); + +const vitals = await mcp__lighthouse__get_core_web_vitals({ url }); +``` + +### Passo 2: Verificações Servidor (SSH) + +```javascript +// Se site está no servidor CWP (176.9.3.158) +const server_checks = [ + // GZIP activo? + `curl -sI -H 'Accept-Encoding: gzip' ${url} | grep -i 'content-encoding'`, + + // HTTP/2 activo? + `curl -sI --http2 ${url} | head -1`, + + // Certificado SSL válido? + `echo | openssl s_client -connect ${domain}:443 2>/dev/null | openssl x509 -noout -dates`, + + // PHP version + `php -v | head -1` +]; +``` + +### Passo 3: Verificações WordPress (WP-CLI via SSH) + +```javascript +// Se temos acesso SSH ao site +const wp_checks = [ + // Cache plugin activo? + `sudo -u ${user} wp plugin list --status=active | grep -E 'cache|w3|wp-super|litespeed'`, + + // Plugins activos (contar) + `sudo -u ${user} wp plugin list --status=active --format=count`, + + // Tema activo + `sudo -u ${user} wp theme list --status=active --format=csv`, + + // Tamanho da BD + `sudo -u ${user} wp db size --format=csv`, + + // Autoload options (problema comum) + `sudo -u ${user} wp db query "SELECT SUM(LENGTH(option_value)) as autoload_size FROM wp_options WHERE autoload='yes'" --skip-column-names`, + + // Revisões de posts (limpeza) + `sudo -u ${user} wp db query "SELECT COUNT(*) FROM wp_posts WHERE post_type='revision'" --skip-column-names`, + + // Transients expirados + `sudo -u ${user} wp transient delete --expired --network 2>/dev/null || echo 'N/A'` +]; +``` + +### Passo 4: Análise de Imagens + +```javascript +// Verificar imagens não optimizadas +const image_checks = [ + // Imagens grandes (>500KB) + `find ${wp_path}/wp-content/uploads -type f \\( -name "*.jpg" -o -name "*.png" \\) -size +500k | wc -l`, + + // WebP disponível? + `find ${wp_path}/wp-content/uploads -name "*.webp" | head -5`, + + // Total imagens + `find ${wp_path}/wp-content/uploads -type f \\( -name "*.jpg" -o -name "*.png" -o -name "*.webp" \\) | wc -l` +]; +``` + +--- + +## Output Template + +```markdown +# WP Performance Audit - [site.pt] + +**Data:** YYYY-MM-DD +**URL:** https://site.pt + +--- + +## Resumo Executivo + +| Métrica | Mobile | Desktop | Status | +|---------|--------|---------|--------| +| Performance | XX | XX | ✅/⚠️/❌ | +| LCP | X.Xs | X.Xs | ✅/⚠️/❌ | +| CLS | X.XX | X.XX | ✅/⚠️/❌ | +| TBT | XXXms | XXXms | ✅/⚠️/❌ | + +--- + +## Checklist Servidor + +| Item | Status | Nota | +|------|--------|------| +| GZIP | ✅/❌ | | +| HTTP/2 | ✅/❌ | | +| SSL | ✅/❌ | Expira: DD/MM | +| PHP Version | X.X | | + +--- + +## Checklist WordPress + +| Item | Status | Valor | +|------|--------|-------| +| Cache Plugin | ✅/❌ | [nome] | +| Plugins Activos | ⚠️ | XX (recomendado <20) | +| Tamanho BD | ⚠️ | XX MB | +| Autoload Size | ⚠️ | XX KB (recomendado <1MB) | +| Revisões | ⚠️ | XX (limpar se >100) | + +--- + +## Checklist Imagens + +| Item | Valor | Acção | +|------|-------|-------| +| Imagens >500KB | XX | Optimizar | +| WebP activo | ✅/❌ | Converter | +| Total imagens | XX | - | + +--- + +## Recomendações Prioritárias + +1. **[CRÍTICO]** Descrição... +2. **[ALTO]** Descrição... +3. **[MÉDIO]** Descrição... + +--- + +## Comandos de Correcção + +```bash +# Limpar revisões (manter últimas 5) +wp post delete $(wp post list --post_type='revision' --format=ids) --force + +# Limpar transients +wp transient delete --all + +# Optimizar BD +wp db optimize +``` + +--- + +*Gerado via /wp-performance - YYYY-MM-DD* +``` + +--- + +## Thresholds + +| Métrica | ✅ Bom | ⚠️ Médio | ❌ Mau | +|---------|--------|----------|--------| +| Performance Score | >70 | 50-70 | <50 | +| LCP | <2.5s | 2.5-4s | >4s | +| CLS | <0.1 | 0.1-0.25 | >0.25 | +| TBT | <200ms | 200-600ms | >600ms | +| Plugins | <20 | 20-30 | >30 | +| BD Size | <100MB | 100-500MB | >500MB | +| Autoload | <1MB | 1-2MB | >2MB | +| Revisões | <100 | 100-500 | >500 | + +--- + +## Sites WordPres \ No newline at end of file diff --git a/wordpress/skills/wp-translate/SKILL.md b/wordpress/skills/wp-translate/SKILL.md new file mode 100644 index 0000000..ed6b320 --- /dev/null +++ b/wordpress/skills/wp-translate/SKILL.md @@ -0,0 +1,157 @@ +--- +name: wp-translate +description: Tradução de plugins WordPress para PT-PT com DeepL Pro, glossário próprio e scripts de automação. Gere ficheiros .po/.mo/.json, corrige traduções PT-BR e faz deploy para starter.descomplicar.pt. +layer: wiki +--- + +# /wp-translate — Traduções WordPress PT-PT + +## Visão Geral + +Skill para traduzir plugins WordPress para Português Europeu (PT-PT) usando DeepL Pro com glossário, scripts de automação próprios e deploy directo para starter.descomplicar.pt. + +--- + +## Scripts Disponíveis + +**Localização local:** `/media/ealmeida/Dados/Dev/Scripts/translate-wp-plugin/` +**No servidor (tmp):** `/tmp/translate_missing.py`, `/tmp/fix_ptbr_safe.py` + +| Script | Função | +|--------|--------| +| `translate_missing.py` | Traduz strings vazias via DeepL Pro + glossário. Suporta batch 50 strings/pedido | +| `fix_ptbr_safe.py` | Corrige ~100 padrões PT-BR → PT-PT | +| `fix_malformed.py` | Corrige sintaxe .po mal formada | +| `batch_process_library.py` | Orquestra fix_malformed → fix_ptbr → translate → compile .mo para toda a biblioteca | +| `setup_glossary.py` | Cria/actualiza glossário DeepL (175 entradas WP PT-PT) | + +**Configuração (.env):** +``` +DEEPL_API_KEY=3c74e27a-f688-4de2-927b-e91da46cf9cd +DEEPL_GLOSSARY_ID=b9db5639-c201-479f-87af-adb81f112067 +``` + +--- + +## DeepL Pro + +- **Endpoint:** `api.deepl.com` (Pro — sem `:fx`) +- **Quota:** ~1,6M / 1 trilião de chars +- **Glossário:** 160 entradas brand names + termos WordPress (EN→PT) +- **Atenção:** DeepL também gera padrões PT-BR — sempre correr `fix_ptbr` ANTES E DEPOIS da tradução + +--- + +## Workflow: Plugin Individual + +```bash +# 1. No servidor — gerar .pot (se não existir) +wp --path=/home/ealmeida/starter.descomplicar.pt i18n make-pot \ + wp-content/plugins/PLUGIN/ \ + /tmp/PLUGIN-pt_PT.po \ + --domain=TEXT_DOMAIN --allow-root + +# 2. Traduzir com DeepL Pro +python3 /tmp/translate_missing.py /tmp/PLUGIN-pt_PT.po + +# 3. Corrigir PT-BR pós-tradução +python3 /tmp/fix_ptbr_safe.py /tmp/PLUGIN-pt_PT.po + +# 4. Para plugins React — gerar JSON para strings JS +wp --path=/home/ealmeida/starter.descomplicar.pt i18n make-json \ + /tmp/PLUGIN-pt_PT.po /path/to/languages/ --no-purge --allow-root + +# 5. Copiar para servidor +cp /tmp/PLUGIN-pt_PT.{po,mo} /home/ealmeida/starter.descomplicar.pt/wp-content/languages/plugins/ +chown ealmeida:ealmeida /home/ealmeida/starter.descomplicar.pt/wp-content/languages/plugins/PLUGIN-pt_PT.* +``` + +## Workflow: Biblioteca Completa + +```bash +python3 /media/ealmeida/Dados/Dev/Scripts/translate-wp-plugin/batch_process_library.py \ + /path/to/library +# Opções: --skip-translate, --dry-run, --only-ptbr +``` + +--- + +## Encontrar o Text Domain + +**Crítico:** O nome da pasta do plugin ≠ text domain. Sempre verificar: + +```bash +grep "Text Domain" /path/to/plugin/plugin-main.php +``` + +**Casos conhecidos de divergência:** +| Pasta | Text Domain | Ficheiro .po | +|-------|-------------|--------------| +| `pro-elements` | `elementor-pro` | `elementor-pro-pt_PT.po` | +| `branda-white-labeling` | `ub` | `ub-pt_PT.po` | +| `seo-by-rank-math` | `rank-math` | `rank-math-pt_PT.po` | + +--- + +## Plugins React/JS — Ficheiros JSON + +Plugins com `wp_set_script_translations()` precisam de um `.json` além do `.mo`. + +**Detectar:** +```bash +grep -r "wp_set_script_translations" /path/plugin/ --include="*.php" +``` + +**Gerar JSON:** +```bash +wp i18n make-json PLUGIN-pt_PT.po /path/languages/ --no-purge --allow-root +``` + +**Atenção ao MD5:** WordPress calcula `md5(relative_path_of_script)` para o nome do JSON. +Se o `source` no JSON não bater com o script registado, copiar o JSON com o MD5 correcto: + +```bash +# Encontrar qual script está registado +grep "wp_register_script\|wp_enqueue_script" plugin.php | grep "HANDLE" + +# Calcular MD5 do caminho relativo +python3 -c "import hashlib; print(hashlib.md5('app/index.js'.encode()).hexdigest())" + +# Copiar com nome correcto +cp PLUGIN-pt_PT-{md5_errado}.json PLUGIN-pt_PT-{md5_correcto}.json +``` + +**Exemplo real — ai-engine:** +- Handle `mwai` → script `app/index.js` → MD5: `2018087f584c4398b5c3a23fc0e5f9db` +- JSON gerado com source `app/i18n.js` → MD5: `0bdc92e05d8f3ab638aa855679db059e` +- Solução: copiar JSON com o MD5 de `app/index.js` + +--- + +## Padrões PT-BR Comuns (fix_ptbr) + +DeepL introduz PT-BR mesmo com `target_lang=PT-PT`. Correr fix_ptbr **depois** da tradução: + +| PT-BR | PT-PT | +|-------|-------| +| atualiz* | actualiz* | +| ativar/desativar | activar/desactivar | +| você/vocês | o utilizador/os utilizadores | +| excluir/excluído | eliminar/eliminado | +| acessar | aceder | +| compartilhar | partilhar | +| postagem/postagens | publicação/publicações | +| ativo/inativo | activo/inactivo | +| ativação/desativação | activação/desactivação | +| digite | introduza | +| clique | clique (OK) | + +--- + +## Servidor starter.descomplicar.pt + +``` +SSH: mcp__ssh-unified__ssh_execute server:"server" +Path traduções: /home/ealmeida/starter.descomplicar.pt/wp-content/languages/plugins/ +Loco Translate: /home/ealmeida/starter.descomplicar.pt/wp-content/languages/loco/plugins/ +WP-CLI: wp --path=/hom \ No newline at end of file diff --git a/wordpress/skills/wp-update/SKILL.md b/wordpress/skills/wp-update/SKILL.md new file mode 100644 index 0000000..44e85a6 --- /dev/null +++ b/wordpress/skills/wp-update/SKILL.md @@ -0,0 +1,153 @@ +--- +name: wp-update +description: Actualização segura de WordPress core, plugins e temas em todos os sites CWP. Inclui backups pré-actualização, verificação pós-actualização e relatório de estado. +disable-model-invocation: true +layer: wiki +--- + +# /wp-update - Actualização WordPress + +Actualização e verificação de todos os sites WordPress no servidor CWP (176.9.3.158). + +--- + +## SITES ACTIVOS (16) + +| Conta | Site | Notas | +|-------|------|-------| +| carstuff | carstuff.pt | | +| ealmeida | descomplicar.pt | principal | +| ealmeida | emanuelalmeida.pt | | +| ealmeida | ecommerce.descomplicar.pt | | +| ealmeida | ecommerce-demo.descomplicar.pt | | +| ealmeida | starter.descomplicar.pt | | +| ealmeida | care.descomplicar.pt | KiviCare | +| ealmeida | e-commerce.descomplicar.pt | | +| espiral | espiralsenior.pt | booking plugin desactivado | +| espiral | dev.espiralsenior.pt | | +| familycl | familyclinic.pt | KiviCare | +| ignition | ignitionvortex.pt | | +| karate | karateclubedegaia.com | | +| sintri | sintricare.com.pt | | +| solarfv | solarfvengenharia.com | | +| wtc | watercontrol.pt | | + +**Domínios expirados (excluídos):** jornadadoheroi.pt, tecoworking.pt, socialboost.pt + +--- + +## SCRIPT DE VERIFICAÇÃO + +**Local:** `/media/ealmeida/Dados/Dev/ClaudeDev/Claude-Scripts/wp-update/check-wp-sites.sh` +**No servidor:** `/root/scripts/check-wp-sites.sh` + +O script verifica: +- Código HTTP (200, 301, 403, 500, etc.) +- **Conteúdo da página** por erros WordPress específicos: + - "Ocorreu um erro crítico neste site" + - "There has been a critical error" + - "Fatal error:.*in /home/" + - "Error establishing a database connection" + +> **IMPORTANTE:** Códigos HTTP 200 NÃO garantem que o site está OK. +> WordPress pode devolver 200 com página de erro crítico. + +--- + +## WORKFLOW + +### 1. Verificação Inicial (OBRIGATÓRIO) + +Executar script de verificação no servidor: +```bash +/root/scripts/check-wp-sites.sh carstuff.pt descomplicar.pt emanuelalmeida.pt ecommerce.descomplicar.pt ecommerce-demo.descomplicar.pt starter.descomplicar.pt care.descomplicar.pt e-commerce.descomplicar.pt espiralsenior.pt dev.espiralsenior.pt familyclinic.pt ignitionvortex.pt karateclubedegaia.com sintricare.com.pt solarfvengenharia.com watercontrol.pt +``` + +**REGRA CRÍTICA:** Se site reportar ❌ → investigar e corrigir ANTES de actualizar. + +### 2. Actualização por Site + +Para cada site funcional: +```bash +# Actualizar plugins +wp plugin update --all --allow-root --path=/home/USER/PATH + +# Actualizar temas +wp theme update --all --allow-root --path=/home/USER/PATH + +# Actualizar core +wp core update --allow-root --path=/home/USER/PATH + +# Corrigir permissões (OBRIGATÓRIO) +chown -R USER:USER /home/USER/PATH/wp-content/ +``` + +### 3. Verificação Final (OBRIGATÓRIO) + +Re-executar script de verificação para confirmar que todos os sites continuam funcionais. + +### 4. Relatório Desk CRM (OBRIGATÓRIO) + +Após concluir as actualizações e verificação final, publicar relatório completo como comentário na **Discussão #52** ("Logs de Atualização de Websites") do **Projecto #69**. + +**Tool:** `mcp__desk-crm-v3__add_discussion_comment` +- `discussion_id`: 52 +- `staff_id`: 25 (AikTop) +- `content`: HTML formatado (template abaixo) + +**Template HTML do Relatório:** +```html +

🔄 Relatório WordPress Update - YYYY-MM-DD

+ +
Verificação Inicial
+
    +
  • ✅ X/16 sites OK
  • +
  • ❌ Y sites com problemas: [lista se houver]
  • +
+ +
Actualizações Aplicadas
+ + + + +
SitePluginsTemasCoreNotas
site.pt✅ 3/3✅ 1/1—
+ +

Sites sem alterações: [lista de sites já actualizados]

+ +
Falhas (Licenças Premium)
+ + + +
PluginSites AfectadosErro
plugin-namesite1, site2Unauthorized
+ +
Verificação Final
+
    +
  • ✅ X/16 sites OK após actualizações
  • +
+ +
Alertas Wordfence
+
    +
  • [Listar alertas Wordfence recentes da conta it@descomplicar.pt se existirem]
  • +
  • Sem alertas (se nenhum)
  • +
+ +
+

Relatório automático gerado por /wp-update v1.2.0 | AikTop

+``` + +**Regras do Relatório:** +- Verificar data actual com `mcp__mcp-time__current_time` antes de gerar +- Incluir TODOS os sites (16), mesmo os que não tinham updates +- Separar claramente sucessos de falhas +- Listar alertas Wordfence da pasta `INBOX.Wordpress.Alertas Wordfence` da conta `it` (últimos 7 dias) +- Se a verificação final detectar problemas, destacar em **vermelho** +- Omitir a tabela de Falhas se não houver nenhuma + +--- + +## PATHS DOS SITES + +| Site | Path | +|------|------| +| carstuff.pt | /home/carstuff/public_html | +| descompl \ No newline at end of file