feat(wordpress): adiciona plugin wordpress (agents, skills, knowledge e metadados do projeto)
This commit is contained in:
@@ -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"]
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# CHANGELOG — wordpress
|
||||||
|
|
||||||
|
## 0.1.0 — 2026-06-30
|
||||||
|
### Adicionado
|
||||||
|
- Estrutura padrão (PROC-DEV-STANDARD)
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# MEMORY.md — wordpress
|
||||||
|
|
||||||
|
## 2026-06-30
|
||||||
|
- Estrutura padrão aplicada via propagate-structure.sh
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# wordpress
|
||||||
|
|
||||||
|
Subprojecto wordpress do ecossistema Descomplicar.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# STATUS.md — wordpress
|
||||||
|
|
||||||
|
**Versão:** 0.1 | **Data:** 2026-06-30 | **Agente:** —
|
||||||
|
|
||||||
|
## Estado actual
|
||||||
|
- Em curso: —
|
||||||
|
- Bloqueios: —
|
||||||
|
- Próximos passos: —
|
||||||
@@ -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)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# CHANGELOG — agents
|
||||||
|
|
||||||
|
## 0.1.0 — 2026-06-30
|
||||||
|
### Adicionado
|
||||||
|
- Estrutura padrão (PROC-DEV-STANDARD)
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# MEMORY.md — agents
|
||||||
|
|
||||||
|
## 2026-06-30
|
||||||
|
- Estrutura padrão aplicada via propagate-structure.sh
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# agents
|
||||||
|
|
||||||
|
Subprojecto agents do ecossistema Descomplicar.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# STATUS.md — agents
|
||||||
|
|
||||||
|
**Versão:** 0.1 | **Data:** 2026-06-30 | **Agente:** —
|
||||||
|
|
||||||
|
## Estado actual
|
||||||
|
- Em curso: —
|
||||||
|
- Bloqueios: —
|
||||||
|
- Próximos passos: —
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"task_id": null,
|
||||||
|
"project_id": null,
|
||||||
|
"customer_id": null,
|
||||||
|
"gitea_repo": null
|
||||||
|
}
|
||||||
@@ -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:"<tema>"
|
||||||
|
```
|
||||||
|
- 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
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# agents
|
||||||
|
|
||||||
|
## Documentação
|
||||||
|
|
||||||
|
- [README](README.md)
|
||||||
|
- [AGENTS](AGENTS.md)
|
||||||
|
- [STATUS](STATUS.md)
|
||||||
|
- [MEMORY](MEMORY.md)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
## 2026-06-30 init | Estrutura padrão
|
||||||
@@ -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,
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"task_id": null,
|
||||||
|
"project_id": null,
|
||||||
|
"customer_id": null,
|
||||||
|
"gitea_repo": null
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# wordpress
|
||||||
|
|
||||||
|
## Documentação
|
||||||
|
|
||||||
|
- [README](README.md)
|
||||||
|
- [AGENTS](AGENTS.md)
|
||||||
|
- [STATUS](STATUS.md)
|
||||||
|
- [MEMORY](MEMORY.md)
|
||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
## 2026-06-30 init | Estrutura padrão
|
||||||
@@ -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)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# CHANGELOG — skills
|
||||||
|
|
||||||
|
## 0.1.0 — 2026-06-30
|
||||||
|
### Adicionado
|
||||||
|
- Estrutura padrão (PROC-DEV-STANDARD)
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# MEMORY.md — skills
|
||||||
|
|
||||||
|
## 2026-06-30
|
||||||
|
- Estrutura padrão aplicada via propagate-structure.sh
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# skills
|
||||||
|
|
||||||
|
Subprojecto skills do ecossistema Descomplicar.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# STATUS.md — skills
|
||||||
|
|
||||||
|
**Versão:** 0.1 | **Data:** 2026-06-30 | **Agente:** —
|
||||||
|
|
||||||
|
## Estado actual
|
||||||
|
- Em curso: —
|
||||||
|
- Bloqueios: —
|
||||||
|
- Próximos passos: —
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
```
|
||||||
@@ -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'
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Branda menu builder for SITENAME
|
||||||
|
* Generated by /branda-menu skill
|
||||||
|
*/
|
||||||
|
|
||||||
|
function branda_id(\$slug) {
|
||||||
|
return 'menu_item_' . substr(base_convert(md5(\$slug), 16, 32), 0, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
function native_item(\$subs = array()) {
|
||||||
|
return array(
|
||||||
|
'title' => '', '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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
<?php
|
||||||
|
// Interceptar antes de gravar para validação externa
|
||||||
|
add_action('jet-form-builder/custom-action/analise_risco', function($request, $action_handler) {
|
||||||
|
|
||||||
|
$dados = $request->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
|
||||||
|
<?php
|
||||||
|
// Recalcular Indexer após bulk update
|
||||||
|
add_action('meu_evento_pos_atualizacao', function() {
|
||||||
|
if (function_exists('jet_smart_filters')) {
|
||||||
|
jet_smart_filters()->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
|
||||||
|
<?php
|
||||||
|
// Injectar limites automáticos num filtro (ex: baseado no role do utilizador)
|
||||||
|
add_filter('jet-smart-filters/filter-instance/args', function($args, $filter_instance) {
|
||||||
|
|
||||||
|
// Só aplicar ao filtro #2550
|
||||||
|
if ((int) $args['filter_id'] !== 2550) {
|
||||||
|
return $args;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forçar range baseado em contexto (ex: permissões do utilizador)
|
||||||
|
$args['current_value'] = [
|
||||||
|
'min' => '100',
|
||||||
|
'max' => '500',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Forçar AJAX
|
||||||
|
$args['apply_type'] = 'ajax';
|
||||||
|
|
||||||
|
return $args;
|
||||||
|
|
||||||
|
}, 10, 2);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Forçar Re-indexação após SQL Massivo
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
// Pipeline completo pós-sync ERP (exemplo: n8n aciona via HTTP)
|
||||||
|
add_action('rest_api_init', function() {
|
||||||
|
register_rest_route('descomplicar/v1', '/reindex', [
|
||||||
|
'methods' => '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*
|
||||||
@@ -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*
|
||||||
@@ -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*
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"task_id": null,
|
||||||
|
"project_id": null,
|
||||||
|
"customer_id": null,
|
||||||
|
"gitea_repo": null
|
||||||
|
}
|
||||||
@@ -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: "<adaptar ao contexto do pedido do utilizador>"
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
Integrar insights do NotebookLM nas recomendações e decisões.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Estrutura Custom Widget
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Custom Elementor Widget
|
||||||
|
*
|
||||||
|
* @author Descomplicar® Crescimento Digital
|
||||||
|
* @link https://descomplicar.pt
|
||||||
|
* @copyright 2026 Descomplicar®
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Custom_Widget extends \Elementor\Widget_Base {
|
||||||
|
|
||||||
|
public function get_name() {
|
||||||
|
return 'custom-widget';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_title() {
|
||||||
|
return 'Custom Widget';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_icon() {
|
||||||
|
return 'eicon-code';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_categories() {
|
||||||
|
return ['general'];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function register_controls() {
|
||||||
|
$this->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();
|
||||||
|
?>
|
||||||
|
<div class="custom-widget">
|
||||||
|
<h2 class="title"><?php echo esc_html($settings['title']); ?></h2>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Registar Widget
|
||||||
|
|
||||||
|
```php
|
||||||
|
// functions.php ou plugin
|
||||||
|
add_action('elementor/widgets/register', function($widgets_manager) {
|
||||||
|
require_once(__DIR__ . '/widgets/custom-widget.php');
|
||||||
|
$widgets_manager->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
|
||||||
@@ -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
|
||||||
|
<?php
|
||||||
|
add_action('rest_api_init', function () {
|
||||||
|
register_rest_route('agencia-ai/v1', '/atualizar-layout', [
|
||||||
|
'methods' => '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
|
||||||
|
<?php
|
||||||
|
// Herdeiro da classe base de Dynamic Tags
|
||||||
|
class IA_Agente_Metrica_Tag extends \Elementor\Core\DynamicTags\Tag {
|
||||||
|
|
||||||
|
public function get_name() { return 'tag-agente-ia'; }
|
||||||
|
public function get_title() { return 'Relatório Dinâmico IA'; }
|
||||||
|
public function get_group() { return 'text'; }
|
||||||
|
public function get_categories() { return [\Elementor\Modules\DynamicTags\Module::TEXT_CATEGORY]; }
|
||||||
|
|
||||||
|
// Render lê do Transients API — o agente IA popula externamente
|
||||||
|
public function render() {
|
||||||
|
$dados = get_transient('ia_agente_ultima_metrica');
|
||||||
|
echo $dados ? wp_kses_post($dados) : 'A aguardar sincronização...';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Registar
|
||||||
|
add_action('elementor/dynamic_tags/register', function($manager) {
|
||||||
|
$manager->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', '<p>Taxa de conversão: 4.2%</p>', 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*
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# skills
|
||||||
|
|
||||||
|
## Documentação
|
||||||
|
|
||||||
|
- [README](README.md)
|
||||||
|
- [AGENTS](AGENTS.md)
|
||||||
|
- [STATUS](STATUS.md)
|
||||||
|
- [MEMORY](MEMORY.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%
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Plugin Name: Descomplicar JetEngine Bridge
|
||||||
|
* Description: API Endpoint customizado para manipulação atómica de CCTs e Relações JetEngine.
|
||||||
|
* Expõe /descomplicar/v1/manage para integração com n8n e agentes IA.
|
||||||
|
* Version: 1.1.0
|
||||||
|
* Author: Descomplicar® Crescimento Digital
|
||||||
|
* Author URI: https://descomplicar.pt
|
||||||
|
*
|
||||||
|
* Instalar em: /wp-content/mu-plugins/descomplicar-jet-bridge.php
|
||||||
|
* Autenticação: WordPress Application Passwords
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||||
|
|
||||||
|
class Descomplicar_Jet_Bridge {
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
add_action( 'rest_api_init', [ $this, 'register_routes' ] );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function register_routes() {
|
||||||
|
register_rest_route( 'descomplicar/v1', '/manage', [
|
||||||
|
'methods' => '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();
|
||||||
@@ -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
|
||||||
|
<?php
|
||||||
|
// Usar CCT Data Handler (mantém hooks, validações e cache)
|
||||||
|
// Mais seguro que SQL directo para escrita
|
||||||
|
|
||||||
|
$cct_slug = 'faturas';
|
||||||
|
$item_data = [
|
||||||
|
'titulo' => '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
|
||||||
|
<?php
|
||||||
|
// Método 1: process_relation (simples, para connect/disconnect)
|
||||||
|
// IMPORTANTE: Executar após o hook 'init' com prioridade > 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
|
||||||
|
<?php
|
||||||
|
// CPTs usam funções standard do WordPress
|
||||||
|
$post_data = [
|
||||||
|
'post_title' => '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
|
||||||
|
<?php
|
||||||
|
// Adicionar novo CPT à configuração do JetEngine
|
||||||
|
// CUIDADO: substitui configurações existentes se não fizer merge
|
||||||
|
|
||||||
|
$current_cpts = get_option('jet_engine_cpt', []);
|
||||||
|
|
||||||
|
$new_cpt = [
|
||||||
|
'slug' => '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
|
||||||
|
<?php
|
||||||
|
// Hook: jet-engine/meta-boxes/register-instances
|
||||||
|
// Ideal para plugins de agência (controlo por código, imutável pelo cliente)
|
||||||
|
|
||||||
|
add_action('jet-engine/meta-boxes/register-instances', function($meta_manager) {
|
||||||
|
|
||||||
|
$meta_fields = [
|
||||||
|
[
|
||||||
|
'title' => '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
|
||||||
|
<?php
|
||||||
|
// Ficheiro: import_cct_data.php
|
||||||
|
// Executar: wp eval-file import_cct_data.php
|
||||||
|
|
||||||
|
if (!class_exists('\Jet_Engine\Modules\Custom_Content_Types\Module')) {
|
||||||
|
WP_CLI::error('Módulo CCT não está activo.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$cct_slug = 'veiculos';
|
||||||
|
$manager = \Jet_Engine\Modules\Custom_Content_Types\Module::instance()->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
|
||||||
|
<?php
|
||||||
|
// Limpar cache de listagens após SQL bulk update
|
||||||
|
\Jet_Engine\Query_Builder\Manager::instance()->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
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Plugin Name: JetEngine AI Agent Endpoints
|
||||||
|
* Description: Endpoints seguros para criação de CCTs e Relações via n8n
|
||||||
|
* Must Use: sim — colocar em /wp-content/mu-plugins/
|
||||||
|
*/
|
||||||
|
|
||||||
|
add_action('rest_api_init', function() {
|
||||||
|
// Endpoint para criar item CCT
|
||||||
|
register_rest_route('jet-agent/v1', '/cct/(?P<slug>[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*
|
||||||
@@ -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
|
||||||
|
<?php
|
||||||
|
// Registar macro custom
|
||||||
|
add_filter('jet-engine/listings/macros-list', function($macros) {
|
||||||
|
$macros[] = [
|
||||||
|
'id' => '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*
|
||||||
@@ -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*
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
## 2026-06-30 init | Estrutura padrão
|
||||||
@@ -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: "<adaptar ao contexto do pedido do utilizador>"
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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 <comando> --allow-root --path=/home/USER/public_html
|
||||||
|
|
||||||
|
# Alias
|
||||||
|
wp83 <comando> --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
|
||||||
@@ -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*
|
||||||
@@ -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
|
||||||
@@ -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 <ENTIDADE> <OP> \
|
||||||
|
--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
|
||||||
@@ -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*
|
||||||
@@ -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: "<adaptar ao contexto do pedido do utilizador>"
|
||||||
|
})
|
||||||
|
|
||||||
|
mcp__notebooklm__notebook_query({
|
||||||
|
notebook_id: "226e384e-d4bc-48f4-bb82-7927360436cc",
|
||||||
|
query: "<adaptar ao contexto e-commerce do pedido>"
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
@@ -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
|
||||||
@@ -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*
|
||||||
@@ -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 "$@"
|
||||||
@@ -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: "<adaptar ao contexto do pedido do utilizador>"
|
||||||
|
})
|
||||||
|
|
||||||
|
mcp__notebooklm__notebook_query({
|
||||||
|
notebook_id: "fb2f26bd-8cb0-4d4c-bafc-4f1ebb51c51d",
|
||||||
|
query: "<adaptar ao contexto de WP-CLI e configuração WordPress>"
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* [Nome do Plugin/Ficheiro]
|
||||||
|
*
|
||||||
|
* @author Descomplicar® Crescimento Digital
|
||||||
|
* @link https://descomplicar.pt
|
||||||
|
* @copyright 2025 Descomplicar®
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Segurança WordPress (OBRIGATÓRIO)
|
||||||
|
|
||||||
|
- **Sanitizar inputs**: `sanitize_text_field()`, `sanitize_email()`, `absint()`
|
||||||
|
- **Escapar outputs**: `esc_html()`, `esc_attr()`, `esc_url()`
|
||||||
|
- **Nonces para forms**: `wp_nonce_field()`, `wp_verify_nonce()`
|
||||||
|
- **AJAX nonces**: `check_ajax_referer()`
|
||||||
|
- **Capability checks**: `current_user_can()` antes de acções admin
|
||||||
|
- **Prepared statements**: `$wpdb->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
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Plugin Name
|
||||||
|
*
|
||||||
|
* @package PluginName
|
||||||
|
* @author Descomplicar® Crescimento Digital
|
||||||
|
* @copyright 2025 Descomplicar®
|
||||||
|
* @license GPL-2.0-or-later
|
||||||
|
*
|
||||||
|
* @wordpress-plugin
|
||||||
|
* Plugin Name: Plugin Name
|
||||||
|
* Plugin URI: https://descomplicar.pt/plugin-name
|
||||||
|
* Description: Descrição do plugin.
|
||||||
|
* Version: 1.0.0
|
||||||
|
* Requires at least: 6.0
|
||||||
|
* Requires PHP: 8.0
|
||||||
|
* Author: Descomplicar®
|
||||||
|
* Author URI: https://descomplicar.pt
|
||||||
|
* Text Domain: plugin-name
|
||||||
|
* License: GPL v2 or later
|
||||||
|
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
|
define('PLUGIN_NAME_VERSION', '1.0.0');
|
||||||
|
define('PLUGIN_NAME_PATH', plugin_dir_path(__FILE__));
|
||||||
|
define('PLUGIN_NAME_URL', plugin_dir_url(__FILE__));
|
||||||
|
|
||||||
|
// Autoloader ou includes
|
||||||
|
require_once PLUGIN_NAME_PATH . 'includes/class-plugin-name.php';
|
||||||
|
|
||||||
|
// Inicialização
|
||||||
|
function plugin_name_init() {
|
||||||
|
load_plugin_textdomain('plugin-name', false, dirname(plugin_basename(__FILE__)) . '/languages/');
|
||||||
|
}
|
||||||
|
add_action('plugins_loaded', 'plugin_name_init');
|
||||||
|
|
||||||
|
// Activação
|
||||||
|
register_activation_hook(__FILE__, 'plugin_name_activate');
|
||||||
|
function plugin_name_activate() {
|
||||||
|
// Criar tabelas, opções, etc.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desactivação
|
||||||
|
register_deactivation_hook(__FILE__, 'plugin_name_deactivate');
|
||||||
|
function plugin_name_deactivate() {
|
||||||
|
// Limpeza
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Checklist Antes de Entregar
|
||||||
|
|
||||||
|
- [ ] Assinatura Descomplicar® em todos os ficheiros
|
||||||
|
- [ ] Segurança: nonces, sanitização, escaping
|
||||||
|
- [ ] WordPress Coding Standards
|
||||||
|
- [ ] Sem erros PHP (php -l)
|
||||||
|
- [ ] Textdomain para traduções
|
||||||
|
- [ ] Uninstall hook para limpeza
|
||||||
@@ -0,0 +1,158 @@
|
|||||||
|
---
|
||||||
|
name: wp-hardening
|
||||||
|
description: Aplicar hardening de seguranca standard a sites WordPress via SSH. Desactiva XML-RPC, file editing, directory listing, esconde versao WP, verifica permissoes e security headers.
|
||||||
|
layer: wiki
|
||||||
|
---
|
||||||
|
|
||||||
|
# /wp-hardening - Hardening WordPress
|
||||||
|
|
||||||
|
Aplica medidas de hardening standard a sites WordPress no servidor CWP (176.9.3.158).
|
||||||
|
|
||||||
|
> **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 '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName></methodCall>'
|
||||||
|
|
||||||
|
# 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 '<generator>.*</generator>' | 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\
|
||||||
|
<Files xmlrpc.php>\
|
||||||
|
Require all denied\
|
||||||
|
</Files>\
|
||||||
|
# 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
|
||||||
@@ -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: "<adaptar ao contexto do pedido do utilizador>"
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
<h4>🔄 Relatório WordPress Update - YYYY-MM-DD</h4>
|
||||||
|
|
||||||
|
<h5>Verificação Inicial</h5>
|
||||||
|
<ul>
|
||||||
|
<li>✅ X/16 sites OK</li>
|
||||||
|
<li>❌ Y sites com problemas: [lista se houver]</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h5>Actualizações Aplicadas</h5>
|
||||||
|
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse:collapse;width:100%">
|
||||||
|
<tr style="background:#f0f0f0"><th>Site</th><th>Plugins</th><th>Temas</th><th>Core</th><th>Notas</th></tr>
|
||||||
|
<tr><td>site.pt</td><td>✅ 3/3</td><td>✅ 1/1</td><td>—</td><td></td></tr>
|
||||||
|
<!-- uma linha por site com alterações -->
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p><strong>Sites sem alterações:</strong> [lista de sites já actualizados]</p>
|
||||||
|
|
||||||
|
<h5>Falhas (Licenças Premium)</h5>
|
||||||
|
<table border="1" cellpadding="5" cellspacing="0" style="border-collapse:collapse;width:100%">
|
||||||
|
<tr style="background:#fff3cd"><th>Plugin</th><th>Sites Afectados</th><th>Erro</th></tr>
|
||||||
|
<tr><td>plugin-name</td><td>site1, site2</td><td>Unauthorized</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h5>Verificação Final</h5>
|
||||||
|
<ul>
|
||||||
|
<li>✅ X/16 sites OK após actualizações</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h5>Alertas Wordfence</h5>
|
||||||
|
<ul>
|
||||||
|
<li>[Listar alertas Wordfence recentes da conta it@descomplicar.pt se existirem]</li>
|
||||||
|
<li>Sem alertas (se nenhum)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<p><em>Relatório automático gerado por /wp-update v1.2.0 | AikTop</em></p>
|
||||||
|
```
|
||||||
|
|
||||||
|
**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
|
||||||
Reference in New Issue
Block a user