feat: sync all plugins, skills, agents updates
New plugins: core-tools New skills: auto-expense, ticket-triage, design, security-check, aiktop-tasks, daily-digest, imap-triage, index-update, mindmap, notebooklm, proc-creator, tasks-overview, validate-component, perfex-module, report, calendar-manager New agents: design-critic, design-generator, design-lead, design-prompt-architect, design-researcher, compliance-auditor, metabase-analyst, gitea-integration-specialist Updated: all plugin configs, knowledge datasets, existing skills Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
572
wordpress/skills/branda-menu/SKILL.md
Normal file
572
wordpress/skills/branda-menu/SKILL.md
Normal file
@@ -0,0 +1,572 @@
|
||||
---
|
||||
name: branda-menu
|
||||
description: >
|
||||
Organiza o menu admin WordPress via Branda (branda-white-labeling) em seccoes Descomplicar standard. Computa Branda IDs a partir de slugs WP, constroi menu custom com itens nativos reordenados + section headers, e guarda programaticamente via WP-CLI. Use when "branda menu", "organizar menu admin", "menu wordpress", "admin sidebar", "reorganizar admin".
|
||||
author: Descomplicar Crescimento Digital
|
||||
version: 1.0.0
|
||||
quality_score: 85
|
||||
user_invocable: true
|
||||
category: wordpress
|
||||
tags: [branda, wordpress, admin-menu, white-labeling, wip]
|
||||
desk_project: 69
|
||||
allowed-tools: Read, Write, Edit, Bash, mcp__ssh-unified, mcp__memory-supabase
|
||||
mcps: ssh-unified, memory-supabase
|
||||
dependencies:
|
||||
mcps: [ssh-unified]
|
||||
plugins: [branda-white-labeling]
|
||||
triggers:
|
||||
- "User mentions 'branda menu', 'organizar menu', 'admin sidebar'"
|
||||
- "User asks to reorganize WordPress admin menu"
|
||||
- "Setting up new WiP site admin customization"
|
||||
---
|
||||
|
||||
# /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, nao para render) |
|
||||
|
||||
### Algoritmo de ID (critico)
|
||||
|
||||
O Branda mapeia slugs WordPress para IDs internos usando:
|
||||
|
||||
```php
|
||||
function branda_id($slug) {
|
||||
return "menu_item_" . substr(base_convert(md5($slug), 16, 32), 0, 12);
|
||||
}
|
||||
```
|
||||
|
||||
**Exemplo:** `index.php` -> `menu_item_42ho017e7jo0`
|
||||
|
||||
Este algoritmo e determinista. O mesmo slug gera sempre o mesmo ID, independente do site.
|
||||
|
||||
### 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 (ex: Descomplicar) |
|
||||
| **Native item** | `was_native: 1`, campos vazios | Item WP real, nome preenchido dinamicamente |
|
||||
| **Hidden item** | `is_hidden: "1"`, `was_native: 1` | Item WP escondido do menu |
|
||||
|
||||
### Mecanismo de merge (parse_args_deep)
|
||||
|
||||
Na renderizacao, o Branda faz merge do menu configurado com o menu WP real:
|
||||
- Itens nativos no config: aparecem na posicao configurada
|
||||
- Itens nativos **nao** no config: inseridos na posicao default (aparecem misturados!)
|
||||
- Itens custom: aparecem na posicao configurada
|
||||
- Submenus vazios `[]`: auto-preenchidos com submenus reais do WP
|
||||
|
||||
**Regra critica:** Incluir **todos** os itens nativos no config (visiveis na posicao desejada OU hidden). Se faltar algum, aparece na posicao default e quebra a organizacao.
|
||||
|
||||
---
|
||||
|
||||
## Seccoes Standard Descomplicar (9)
|
||||
|
||||
Todo site WiP deve ter o menu organizado nestas 9 seccoes, nesta ordem:
|
||||
|
||||
| # | Seccao | Dashicon | Conteudo tipico |
|
||||
|---|--------|----------|----------------|
|
||||
| 1 | **Suporte** | dashicons-admin-tools | Link Descomplicar (desk.descomplicar.pt) |
|
||||
| 2 | **Admin** | dashicons-admin-generic | Painel, Utilizadores, Opcoes, Plugins, Ferramentas |
|
||||
| 3 | **Conteudo** | dashicons-admin-page | Paginas, CPTs do projecto, Artigos, Multimedia, ACF |
|
||||
| 4 | **Design** | dashicons-admin-appearance | Elementor, Modelos, Jeg Kit, Apresentacao |
|
||||
| 5 | **Marketing** | dashicons-megaphone | FluentCRM, Fluent Forms, Rank Math, WhatsApp, etc. |
|
||||
| 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 |
|
||||
|
||||
**Notas:**
|
||||
- Seccao Idiomas so aparece se site for multilingue
|
||||
- CPTs especificos do projecto (Tours, Servicos, etc.) vao em Conteudo
|
||||
- Plugins sectoriais (KiviCare, WooCommerce, etc.) podem ter seccao propria entre Marketing e Idiomas
|
||||
|
||||
---
|
||||
|
||||
## Itens tipicamente hidden
|
||||
|
||||
Estes itens nativos devem ser incluidos no config com `is_hidden: "1"`:
|
||||
|
||||
| Slug | Motivo |
|
||||
|------|--------|
|
||||
| `separator1`, `separator2`, `separator-last` | Separadores nativos substituidos por section headers |
|
||||
| `edit-comments.php` | Comentarios raramente usados |
|
||||
| `hello-elementor` | Pagina tema redundante com themes.php |
|
||||
| `elementor` | Menu Elementor duplicado (ja existe elementor-home) |
|
||||
|
||||
---
|
||||
|
||||
## Procedimento
|
||||
|
||||
### Passo 1: Verificar pre-requisitos
|
||||
|
||||
```bash
|
||||
# Via MCP SSH - verificar Branda activo e modulo menu activo
|
||||
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
|
||||
|
||||
Obter lista de plugins activos e menu WP via WP-CLI. Como WP-CLI nao carrega todos os menus admin, usar este metodo combinado:
|
||||
|
||||
**Opcao A (preferida): mu-plugin temporario**
|
||||
|
||||
```bash
|
||||
# Criar mu-plugin que captura menu no proximo page load
|
||||
mcp__ssh-unified__ssh_execute server:"server" command:"cat > /home/USER/SITE/wp-content/mu-plugins/capture-menu.php << 'PHPEOF'
|
||||
<?php
|
||||
/**
|
||||
* Temporary mu-plugin to capture native admin menu for Branda
|
||||
* Auto-removes after capture
|
||||
*/
|
||||
add_action('admin_menu', function() {
|
||||
if (!current_user_can('manage_options')) return;
|
||||
if (get_option('_branda_menu_captured')) return;
|
||||
|
||||
global \$menu, \$submenu;
|
||||
|
||||
// Save raw menu data
|
||||
update_option('_branda_menu_capture', array(
|
||||
'menu' => \$menu,
|
||||
'submenu' => \$submenu,
|
||||
'captured_at' => time()
|
||||
));
|
||||
update_option('_branda_menu_captured', true);
|
||||
|
||||
// Self-destruct
|
||||
@unlink(__FILE__);
|
||||
}, 999999);
|
||||
PHPEOF
|
||||
echo 'mu-plugin criado'
|
||||
"
|
||||
```
|
||||
|
||||
Depois, gerar cookie de auth e disparar um page load admin:
|
||||
```bash
|
||||
# Gerar cookie auth via WP-CLI
|
||||
mcp__ssh-unified__ssh_execute server:"server" command:"wp eval '
|
||||
\$expiration = time() + 300;
|
||||
\$cookie = wp_generate_auth_cookie(1, \$expiration, \"logged_in\");
|
||||
echo \$cookie;
|
||||
' --allow-root --path=/home/USER/SITE"
|
||||
|
||||
# Disparar page load admin com curl (substituir COOKIE e HASH)
|
||||
mcp__ssh-unified__ssh_execute server:"server" command:"curl -s -o /dev/null -w '%{http_code}' -b 'wordpress_logged_in_HASH=COOKIE' https://SITE/wp-admin/"
|
||||
```
|
||||
|
||||
Depois ler a captura:
|
||||
```bash
|
||||
mcp__ssh-unified__ssh_execute server:"server" command:"wp eval '
|
||||
\$cap = get_option(\"_branda_menu_capture\");
|
||||
if (\$cap) {
|
||||
foreach (\$cap[\"menu\"] as \$pos => \$item) {
|
||||
if (count(\$item) >= 3) {
|
||||
\$slug = \$item[2];
|
||||
\$title = strip_tags(\$item[0]);
|
||||
echo \"\$pos. \$title => \$slug\n\";
|
||||
}
|
||||
}
|
||||
}
|
||||
' --allow-root --path=/home/USER/SITE"
|
||||
```
|
||||
|
||||
**Opcao B (alternativa): Chrome DevTools**
|
||||
|
||||
Se tiver acesso ao browser, navegar ao wp-admin e executar JS:
|
||||
```javascript
|
||||
Array.from(document.querySelectorAll('#adminmenu > li')).forEach((li, i) => {
|
||||
const a = li.querySelector('a');
|
||||
if (a) {
|
||||
const name = a.querySelector('.wp-menu-name')?.textContent?.trim() || a.textContent?.trim();
|
||||
const href = a.getAttribute('href') || '';
|
||||
console.log(i + '. ' + name + ' => ' + href);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Passo 3: Mapear itens para seccoes
|
||||
|
||||
Com a lista de itens nativos, mapear cada um para a seccao correcta.
|
||||
|
||||
**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.
|
||||
|
||||
### Passo 4: Construir e guardar o menu
|
||||
|
||||
Criar um PHP script no servidor e executar com `wp eval-file`:
|
||||
|
||||
```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"
|
||||
```
|
||||
|
||||
### Passo 5: Verificar
|
||||
|
||||
```bash
|
||||
# Contar itens no config
|
||||
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: navegar ao wp-admin e confirmar que o menu esta organizado nas 9 seccoes.
|
||||
|
||||
### Passo 6: Limpar
|
||||
|
||||
```bash
|
||||
# Remover script temporario
|
||||
mcp__ssh-unified__ssh_execute server:"server" command:"rm -f /tmp/branda-menu-SITE.php"
|
||||
|
||||
# Limpar captura temporaria (se usou mu-plugin)
|
||||
mcp__ssh-unified__ssh_execute server:"server" command:"wp eval '
|
||||
delete_option(\"_branda_menu_capture\");
|
||||
delete_option(\"_branda_menu_captured\");
|
||||
echo \"Limpo\";
|
||||
' --allow-root --path=/home/USER/SITE"
|
||||
|
||||
# Garantir mu-plugin removido
|
||||
mcp__ssh-unified__ssh_execute server:"server" command:"rm -f /home/USER/SITE/wp-content/mu-plugins/capture-menu.php 2>/dev/null; echo ok"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Adaptar para sites especificos
|
||||
|
||||
### 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();
|
||||
// $menu[branda_id('wc-admin&path=/analytics/overview')] = native_item(); // Analytics WC
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Menu nao muda apos guardar
|
||||
|
||||
1. Limpar cache: `wp cache flush --allow-root`
|
||||
2. Verificar modulo activo: `admin/menu.php` em `ultimatebranding_activated_modules`
|
||||
3. Verificar role: config usa key `administrator` (nao `admin`)
|
||||
|
||||
### Itens nativos aparecem fora das seccoes
|
||||
|
||||
Causa: item nativo nao incluido no config (inserido na posicao default pelo parse_args_deep).
|
||||
Fix: Identificar o slug do item, computar o Branda ID, adicionar ao config (visivel ou hidden).
|
||||
|
||||
### Separadores nativos aparecem
|
||||
|
||||
Causa: separadores com slugs diferentes dos standard (`separator1`, `separator2`, `separator-last`).
|
||||
Fix: Verificar slugs via captura do menu nativo, adicionar como hidden.
|
||||
|
||||
### Menu items custom aparecem em duplicado
|
||||
|
||||
Causa: o mesmo item existe como custom link E como native item.
|
||||
Fix: Remover o custom link, manter apenas o native item na posicao correcta.
|
||||
|
||||
### CSS para esconder separadores em falta
|
||||
|
||||
Adicionar ao CSS custom do Branda (ub_admin_css) como fallback:
|
||||
```css
|
||||
#adminmenu li.wp-menu-separator { display: none !important; }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Branda activo e modulo `admin/menu.php` activo
|
||||
- [ ] Menu nativo extraido (todos os itens identificados)
|
||||
- [ ] Todos os itens nativos incluidos no config (visiveis ou hidden)
|
||||
- [ ] 9 seccoes criadas na ordem standard
|
||||
- [ ] CPTs do projecto na seccao Conteudo
|
||||
- [ ] Verificado visualmente no browser
|
||||
- [ ] Script temporario e capturas removidos
|
||||
- [ ] Permissoes corrigidas: `chown -R USER:USER /home/USER/SITE/`
|
||||
|
||||
---
|
||||
|
||||
*Skill v1.0.0 | 26-02-2026 | Descomplicar*
|
||||
241
wordpress/skills/crocoblock/SKILL.md
Normal file
241
wordpress/skills/crocoblock/SKILL.md
Normal file
@@ -0,0 +1,241 @@
|
||||
---
|
||||
name: crocoblock
|
||||
description: >
|
||||
Crocoblock ecosystem development with all JetPlugins for Elementor. Covers plugin selection, licensing, installation,
|
||||
configuration and integration between JetEngine, JetSmartFilters, JetWooBuilder, JetElements, JetPopup, JetFormBuilder,
|
||||
JetTabs, JetBlocks, JetSearch, JetBooking, JetThemeCore, JetReviews, JetTricks, JetCompareWishlist.
|
||||
This skill should be used when the user asks about "crocoblock", "jet plugins", "jetelements", "jetwoobuilder",
|
||||
"jetpopup", "jetsmartfilters", "jettabs", "jetformbuilder", "jetblocks", "jetbooking", "jetreviews",
|
||||
"jetthemecore", "crocoblock license", "instalar crocoblock", "activar jet plugins", "ecosystem crocoblock",
|
||||
"crocoblock subscription", "jet plugin escolher", "qual jet plugin usar", "crocoblock vs", "filtros ajax elementor",
|
||||
"listing woocommerce elementor", "popup elementor crocoblock", "booking elementor", "reviews elementor".
|
||||
author: Descomplicar® Crescimento Digital
|
||||
version: 1.0.0
|
||||
user_invocable: true
|
||||
tags: [wordpress, elementor, crocoblock, jetengine, jetelements, jetsmartfilters, jetformbuilder]
|
||||
allowed-tools: Read, Write, Edit, Bash, mcp__ssh-unified__ssh_execute, mcp__notebooklm__notebook_query, mcp__dify-kb__dify_kb_retrieve_segments
|
||||
category: dev
|
||||
quality_score: 80
|
||||
updated: "2026-02-18T00:00:00Z"
|
||||
---
|
||||
|
||||
# /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 Comum
|
||||
|
||||
### Plugin não activa após upload
|
||||
|
||||
```bash
|
||||
# Verificar se Elementor está activo (dependência)
|
||||
$WP plugin list --search=elementor --fields=name,status
|
||||
|
||||
# Verificar erros PHP
|
||||
$WP eval 'error_reporting(E_ALL); ini_set("display_errors", 1);' --allow-root --path=$PATH
|
||||
|
||||
# Limpar transients após activar
|
||||
$WP transient delete --all --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
### Conflito entre versões
|
||||
|
||||
```
|
||||
Regra: Manter todos os JetPlugins na mesma major version
|
||||
Verificar: account.crocoblock.com > Changelogs para breaking changes
|
||||
```
|
||||
|
||||
### Listings não actualizam após filtrar
|
||||
|
||||
```bash
|
||||
# Regenerar CSS Elementor
|
||||
$WP elementor flush-css --regenerate --allow-root --path=$PATH
|
||||
|
||||
# Limpar cache de objecto
|
||||
$WP cache flush --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
## Padrões de Uso por Tipo de Site
|
||||
|
||||
### Site Corporativo / Portfolio
|
||||
|
||||
```
|
||||
JetEngine (CPT: Projecto, Serviço, Testemunho)
|
||||
+ JetSmartFilters (filtrar por categoria/tag)
|
||||
+ JetElements (timeline, animações)
|
||||
```
|
||||
|
||||
### E-commerce Avançado
|
||||
|
||||
```
|
||||
WooCommerce + JetEngine (meta boxes extra)
|
||||
+ JetWooBuilder (templates produto, categoria, cart)
|
||||
+ JetCompareWishlist
|
||||
+ JetSmartFilters (filtros loja)
|
||||
```
|
||||
|
||||
### Directório / Listagem de Negócios
|
||||
|
||||
```
|
||||
JetEngine (CPT: Negócio, com Relations para Categoria/Localização)
|
||||
+ JetSmartFilters (filtros AJAX por localização, categoria, preço)
|
||||
+ JetSearch (pesquisa instantânea)
|
||||
+ JetEngine Maps (mapa de listagens)
|
||||
```
|
||||
|
||||
### Portal com Accounts de Utilizador
|
||||
|
||||
```
|
||||
JetEngine (CPT, Profile Builder)
|
||||
+ JetFormBuilder (submissão de conteúdo por utilizador)
|
||||
+ JetEngine Relations (conteúdo associado ao utilizador)
|
||||
```
|
||||
|
||||
### Site com Reservas
|
||||
|
||||
```
|
||||
JetBooking (calendário + disponibilidade)
|
||||
+ JetFormBuilder (form de reserva)
|
||||
+ JetEngine (meta boxes de propriedade/serviço)
|
||||
```
|
||||
|
||||
## JetEngine MCP Server (v3.8.0+)
|
||||
|
||||
A partir do JetEngine 3.8.0, existe integração nativa com agentes IA via **MCP Server**:
|
||||
|
||||
```
|
||||
WP Admin > JetEngine > AI Command Center > Enable MCP Server
|
||||
→ Claude pode inspecionar schema completo (CPTs, CCTs, Relações, Queries)
|
||||
→ e criar/modificar estruturas via linguagem natural
|
||||
```
|
||||
|
||||
Usar `references/automation.md` para detalhes sobre Formless Actions, JetSmartFilters Indexer e pipelines de automação.
|
||||
|
||||
## Referências Adicionais
|
||||
|
||||
- **`references/plugins.md`** — Referência detalhada de cada plugin (widgets, configurações, casos de uso avançados)
|
||||
- **`references/patterns.md`** — Padrões de integração avançados (multi-relation, filtros aninhados, profile builder completo)
|
||||
- **`references/automation.md`** — MCP Server nativo, JetFormBuilder Formless Actions, JetSmartFilters Indexer, Kits export/import, cache e riscos críticos
|
||||
|
||||
---
|
||||
|
||||
**Versão**: 1.1.0 | **Autor**: Descomplicar® | **Data**: 18-02-2026
|
||||
294
wordpress/skills/crocoblock/references/automation.md
Normal file
294
wordpress/skills/crocoblock/references/automation.md
Normal file
@@ -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*
|
||||
220
wordpress/skills/crocoblock/references/patterns.md
Normal file
220
wordpress/skills/crocoblock/references/patterns.md
Normal file
@@ -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*
|
||||
240
wordpress/skills/crocoblock/references/plugins.md
Normal file
240
wordpress/skills/crocoblock/references/plugins.md
Normal file
@@ -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*
|
||||
@@ -2,17 +2,21 @@
|
||||
name: elementor
|
||||
description: >
|
||||
Advanced development with Elementor Pro and Crocoblock ecosystem. Creates custom widgets, configures Theme Builder, develops with JetEngine, JetWooBuilder, optimizes performance and troubleshoots issues.
|
||||
Also covers programmatic automation: deploy pipelines, kit import, replace-urls, flush-css, MySQL manipulation of _elementor_data, REST API endpoints, Dynamic Tags, CSS cache invalidation.
|
||||
Use when building Elementor sites, creating custom widgets, configuring theme templates, developing with Crocoblock, or when user mentions
|
||||
"elementor", "custom widget", "theme builder", "jetengine", "crocoblock", "jetwoobuilder", "page builder", "elementor pro".
|
||||
"elementor", "custom widget", "theme builder", "jetengine", "crocoblock", "jetwoobuilder", "page builder", "elementor pro",
|
||||
"deploy elementor", "pipeline elementor", "elementor kit import", "elementor replace-urls", "elementor flush-css",
|
||||
"automação elementor", "elementor programático", "elementor mysql", "rebranding elementor", "elementor rest api",
|
||||
"elementor dynamic tag", "elementor cache", "elementor agente ia", "elementor wp-cli".
|
||||
author: Descomplicar® Crescimento Digital
|
||||
version: 1.1.0
|
||||
version: 1.2.0
|
||||
user_invocable: true
|
||||
tags: [wordpress, elementor, pagebuilder, crocoblock, jetengine, widgets]
|
||||
tags: [wordpress, elementor, pagebuilder, crocoblock, jetengine, widgets, automation, wpcli]
|
||||
desk_task: 1478
|
||||
allowed-tools: Read, Write, Edit, Bash, mcp__ssh-unified__ssh_execute, mcp__dify-kb__dify_kb_retrieve_segments
|
||||
allowed-tools: Read, Write, Edit, Bash, mcp__ssh-unified__ssh_execute, mcp__notebooklm__notebook_query, mcp__dify-kb__dify_kb_retrieve_segments
|
||||
category: dev
|
||||
quality_score: 75
|
||||
updated: "2026-02-04T18:00:00Z"
|
||||
quality_score: 80
|
||||
updated: "2026-02-18T00:00:00Z"
|
||||
---
|
||||
|
||||
# /elementor - Elementor Development
|
||||
@@ -237,14 +241,21 @@ Elementor > Settings > Advanced > Breakpoints
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Widget não aparece
|
||||
### Widget não aparece / CSS desactualizado
|
||||
|
||||
```bash
|
||||
# Limpar cache Elementor
|
||||
wp elementor flush-css --allow-root
|
||||
# CWP — SEMPRE com prefixo PHP completo
|
||||
PHP="/opt/alt/php-fpm83/usr/bin/php"
|
||||
WP="$PHP /usr/local/bin/wp --allow-root --path=/home/USER/public_html"
|
||||
|
||||
# Regenerar ficheiros CSS
|
||||
wp elementor replace_urls --old=http --new=https --allow-root
|
||||
# Regenerar CSS (após qualquer alteração programática)
|
||||
$WP elementor flush-css --regenerate
|
||||
|
||||
# Substituição segura de URLs (NUNCA usar wp search-replace directamente)
|
||||
$WP elementor replace-urls https://antigo.com https://novo.com
|
||||
|
||||
# Sincronizar BD após update do plugin
|
||||
$WP elementor update db
|
||||
```
|
||||
|
||||
### Erro após update
|
||||
@@ -264,6 +275,20 @@ Elementor > Tools > Version Control > Rollback
|
||||
5. Limitar widgets por página
|
||||
```
|
||||
|
||||
## Automação Programática (WP-CLI / MySQL / REST API)
|
||||
|
||||
Para deploy automatizado, pipelines IA, migração em massa e manipulação programática do Elementor sem GUI, consultar:
|
||||
|
||||
**`references/automation.md`** — Referência completa com:
|
||||
- Pipeline de deploy CWP (kit import + replace-urls + flush-css)
|
||||
- Estrutura `_elementor_data` JSON e queries MySQL com `JSON_REPLACE`
|
||||
- REST API custom endpoint (com `wp_slash`, cache invalidation)
|
||||
- PHP Dynamic Tags para conteúdo runtime (requer Pro)
|
||||
- Geração de Kit ZIP em Python
|
||||
- Rebranding global via `elementor_active_kit`
|
||||
- Regras críticas (NUNCA `wp search-replace` em `_elementor_data`)
|
||||
- MCP Elementor (Ultimate Elementor MCP, ~60 tools)
|
||||
|
||||
## Datasets Dify
|
||||
|
||||
| Dataset | ID | Prioridade |
|
||||
@@ -275,4 +300,10 @@ Elementor > Tools > Version Control > Rollback
|
||||
|
||||
---
|
||||
|
||||
**Versão**: 1.0.0 | **Autor**: Descomplicar®
|
||||
## Referências Adicionais
|
||||
|
||||
- **`references/automation.md`** — Automação programática completa (WP-CLI pipelines, MySQL, REST API, PHP Hooks, Kits, CSS)
|
||||
|
||||
---
|
||||
|
||||
**Versão**: 1.2.0 | **Autor**: Descomplicar® | **Actualizado**: 18-02-2026
|
||||
|
||||
417
wordpress/skills/elementor/references/automation.md
Normal file
417
wordpress/skills/elementor/references/automation.md
Normal file
@@ -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*
|
||||
295
wordpress/skills/jetengine/SKILL.md
Normal file
295
wordpress/skills/jetengine/SKILL.md
Normal file
@@ -0,0 +1,295 @@
|
||||
---
|
||||
name: jetengine
|
||||
description: >
|
||||
JetEngine development: Custom Post Types (CPT), Custom Content Types (CCT), Meta Boxes, Taxonomies,
|
||||
Relations, Query Builder, Listing Grid, Listing Map, Dynamic Content, Dynamic Tags, Macros, Profile Builder,
|
||||
REST API, and headless/programmatic automation for AI agents and n8n integration.
|
||||
This skill should be used when the user asks about "jetengine", "jet engine", "custom post type jetengine",
|
||||
"meta box jetengine", "relations jetengine", "query builder jetengine", "listing grid", "listing map",
|
||||
"jetengine dynamic content", "jetengine macros", "profile builder jetengine", "cct jetengine",
|
||||
"custom content type", "jetengine cct", "jetengine rest api", "jetengine n8n", "jetengine sql",
|
||||
"jetengine automação", "jetengine headless", "wp_jet_rel_default", "wp_jet_cct", "jetengine relations",
|
||||
"conteúdo dinâmico elementor jetengine", "jetengine filtros", "jetengine repeater".
|
||||
author: Descomplicar® Crescimento Digital
|
||||
version: 1.0.0
|
||||
user_invocable: true
|
||||
tags: [wordpress, elementor, crocoblock, jetengine, cpt, cct, listings, dynamic-content]
|
||||
allowed-tools: Read, Write, Edit, Bash, mcp__ssh-unified__ssh_execute, mcp__notebooklm__notebook_query, mcp__dify-kb__dify_kb_retrieve_segments
|
||||
category: dev
|
||||
quality_score: 85
|
||||
updated: "2026-02-18T00:00:00Z"
|
||||
---
|
||||
|
||||
# /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% # ID do post actual
|
||||
%queried_object_id% # ID do objecto em arquivo/single
|
||||
%request_field|name% # Parâmetro URL (?name=valor)
|
||||
%current_meta|field_name% # Meta field do post actual
|
||||
%user_meta|field_name% # Meta field do utilizador logado
|
||||
```
|
||||
|
||||
### Usar Macros em Widgets Elementor
|
||||
|
||||
```
|
||||
Textos: escrever macro directamente no campo de texto
|
||||
Links: usar em URL field
|
||||
Queries: usar em Meta Query → Valor = macro
|
||||
```
|
||||
|
||||
### Profile Builder
|
||||
|
||||
```
|
||||
JetEngine > Profile Builder > Add New
|
||||
├── Criar páginas de conta (Dashboard, Submissões, etc.)
|
||||
├── Cada página = Elementor Template
|
||||
├── Acesso: utilizadores logados, por role, por condição
|
||||
└── Menu de Profile: widget JetEngine Profile Menu
|
||||
```
|
||||
|
||||
## Dify KB — Consultar Antes de Implementar
|
||||
|
||||
```javascript
|
||||
// Dataset Crocoblock (JetEngine incluído)
|
||||
mcp__dify-kb__dify_kb_retrieve_segments({
|
||||
dataset_id: "bdf85c26-1824-4021-92d1-be20501b35ac",
|
||||
query: "[funcionalidade JetEngine]"
|
||||
})
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problema | Causa | Solução |
|
||||
|----------|-------|---------|
|
||||
| Listing não mostra resultados | Query sem posts ou condição errada | Debug Query: activar `WP_DEBUG` e verificar |
|
||||
| Dynamic Tag retorna vazio | Campo meta não preenchido ou nome errado | Verificar key do meta field em JetEngine > Meta Boxes |
|
||||
| Relações não aparecem | rel_id errado ou sem items relacionados | Verificar nome da relação em JetEngine > Relations |
|
||||
| CCT não aparece no REST | REST API não activada | JetEngine > Content Types > Edit > Enable REST API |
|
||||
| Filtros não funcionam | Listing ID errado no filtro | JetEngine Listing Grid > copiar ID do widget |
|
||||
|
||||
## Bridge Plugin — Deploy para Integração n8n
|
||||
|
||||
Para integração headless com n8n ou agentes IA, fazer deploy do MU plugin incluído:
|
||||
|
||||
```bash
|
||||
PHP="/opt/alt/php-fpm83/usr/bin/php"
|
||||
WP="$PHP /usr/local/bin/wp --allow-root --path=/home/USER/public_html"
|
||||
|
||||
# Copiar bridge plugin para mu-plugins (via SSH)
|
||||
# O ficheiro está em: assets/descomplicar-jet-bridge.php (nesta skill)
|
||||
scp descomplicar-jet-bridge.php server.descomplicar.pt:/home/USER/public_html/wp-content/mu-plugins/
|
||||
|
||||
# Verificar que está activo (MU plugins carregam automaticamente)
|
||||
$WP plugin list --skip-plugins --skip-themes # MU plugins não aparecem aqui — normal
|
||||
```
|
||||
|
||||
**Endpoint exposto:** `POST /wp-json/descomplicar/v1/manage`
|
||||
|
||||
**Acções disponíveis:**
|
||||
| Acção | Descrição |
|
||||
|-------|-----------|
|
||||
| `create_cct_item` | Criar item num CCT |
|
||||
| `update_cct_item` | Actualizar item (`_ID` em item_data) |
|
||||
| `get_cct_item` | Ler item por ID |
|
||||
| `delete_cct_item` | Eliminar item |
|
||||
| `manage_relation` | Criar/remover relação (connect: true/false) |
|
||||
|
||||
```bash
|
||||
# Testar endpoint (exemplo: criar fatura)
|
||||
curl -X POST https://site.pt/wp-json/descomplicar/v1/manage \
|
||||
-H "Authorization: Basic $(echo -n 'user:app-password' | base64)" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"action": "create_cct_item",
|
||||
"cct_slug": "faturas",
|
||||
"item_data": { "titulo": "Fatura #001", "valor": 500 }
|
||||
}'
|
||||
```
|
||||
|
||||
## JetEngine MCP Server (v3.8.0+)
|
||||
|
||||
A partir da versão 3.8.0, o JetEngine tem **MCP Server nativo**:
|
||||
|
||||
```
|
||||
WP Admin > JetEngine > AI Command Center > Enable MCP Server
|
||||
→ Agentes IA podem inspecionar e criar CPTs/CCTs/Relations via linguagem natural
|
||||
→ Claude consegue ler o schema completo e instanciar estruturas directamente
|
||||
```
|
||||
|
||||
## Referências Adicionais
|
||||
|
||||
- **`assets/descomplicar-jet-bridge.php`** — MU Plugin pronto a deployar: CRUD CCT + Relations via REST API
|
||||
- **`references/automation.md`** — BD completa (CCT, Relations meta, Custom Meta Storage), WP-CLI batch, PHP hooks, REST API avançada (store_items_type, filtros CCT), cache e guardrails
|
||||
- **`references/query-listings.md`** — Query Builder avançado, Listing Map, paginação, ordenação dinâmica
|
||||
- **`references/dynamic-content.md`** — Dynamic Tags, Profile Builder, Macros, Conditional Fields
|
||||
|
||||
---
|
||||
|
||||
**Versão**: 1.1.0 | **Autor**: Descomplicar® | **Data**: 18-02-2026
|
||||
226
wordpress/skills/jetengine/assets/descomplicar-jet-bridge.php
Normal file
226
wordpress/skills/jetengine/assets/descomplicar-jet-bridge.php
Normal file
@@ -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();
|
||||
668
wordpress/skills/jetengine/references/automation.md
Normal file
668
wordpress/skills/jetengine/references/automation.md
Normal file
@@ -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*
|
||||
271
wordpress/skills/jetengine/references/dynamic-content.md
Normal file
271
wordpress/skills/jetengine/references/dynamic-content.md
Normal file
@@ -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*
|
||||
225
wordpress/skills/jetengine/references/query-listings.md
Normal file
225
wordpress/skills/jetengine/references/query-listings.md
Normal file
@@ -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*
|
||||
295
wordpress/skills/rank-math/SKILL.md
Normal file
295
wordpress/skills/rank-math/SKILL.md
Normal file
@@ -0,0 +1,295 @@
|
||||
---
|
||||
name: rank-math
|
||||
description: This skill should be used when the user asks to "optimizar SEO wordpress",
|
||||
"rank math wp-cli", "configurar rank math", "audit rank math", "update meta SEO",
|
||||
"schema markup wordpress", "redirects rank math", "sitemap wordpress", "bulk SEO update",
|
||||
"rank math CWP", "titles meta descriptions wp-cli", "configurar sitemap wordpress",
|
||||
"noindex wordpress", "rank math robots". Manages Rank Math SEO plugin via WP-CLI
|
||||
on CWP servers.
|
||||
author: Descomplicar® Crescimento Digital
|
||||
version: 1.0.0
|
||||
quality_score: 80
|
||||
user_invocable: true
|
||||
---
|
||||
|
||||
# /rank-math - Gestão Rank Math SEO via WP-CLI
|
||||
|
||||
Operações de SEO WordPress via WP-CLI no servidor CWP (server.descomplicar.pt). Cobre auditoria, configuração em massa, schema markup, redirects e sitemap.
|
||||
|
||||
**Manual completo:** `Hub/06-Operacoes/Documentacao/Manuais/Rank-Math-WP-CLI-Manual-Definitivo.md`
|
||||
**Quick Reference:** `Hub/06-Operacoes/Documentacao/Quick-Reference/QR-RankMath-WP-CLI.md`
|
||||
**NotebookLM:** [WordPress Config CLI](https://notebooklm.google.com/notebook/fb2f26bd-8cb0-4d4c-bafc-4f1ebb51c51d)
|
||||
|
||||
---
|
||||
|
||||
## Uso
|
||||
|
||||
```
|
||||
/rank-math audit https://site.pt
|
||||
/rank-math update-meta /home/USER/public_html
|
||||
/rank-math sitemap /home/USER/public_html
|
||||
/rank-math redirects /home/USER/public_html
|
||||
/rank-math schema post ID /home/USER/public_html
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Contexto CWP — Sempre Obrigatório
|
||||
|
||||
**PHP 8.3 no CWP:**
|
||||
```bash
|
||||
# Formato base
|
||||
/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp <comando> --allow-root --path=/home/USER/public_html
|
||||
|
||||
# Alias ~/.bashrc (se configurado)
|
||||
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
|
||||
```
|
||||
|
||||
**Único comando nativo Rank Math:**
|
||||
```bash
|
||||
wp rankmath sitemap generate --allow-root --path=/home/USER/public_html
|
||||
```
|
||||
Tudo o resto usa `wp post meta`, `wp option patch`, `wp eval` ou `wp db query`.
|
||||
|
||||
---
|
||||
|
||||
## Workflow: Auditoria SEO (/rank-math audit)
|
||||
|
||||
### Passo 1 — Diagnóstico rápido
|
||||
|
||||
```bash
|
||||
PATH=/home/USER/public_html
|
||||
|
||||
# Posts sem título SEO
|
||||
wp db query "SELECT p.ID, p.post_title 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='');" --allow-root --path=$PATH
|
||||
|
||||
# Posts sem descrição SEO
|
||||
wp db query "SELECT p.ID, p.post_title 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='');" --allow-root --path=$PATH
|
||||
|
||||
# Top 404s (últimos 30 dias)
|
||||
wp db query "SELECT uri, SUM(times_accessed) as total FROM wp_rank_math_404_logs
|
||||
GROUP BY uri ORDER BY total DESC LIMIT 20;" --allow-root --path=$PATH
|
||||
|
||||
# Tamanho options (detetar bloat WooCommerce)
|
||||
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;" --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
### Passo 2 — Estado módulos
|
||||
|
||||
```bash
|
||||
wp option pluck rank_math_modules --allow-root --path=$PATH
|
||||
wp option pluck rank-math-options-general strip_category_base --allow-root --path=$PATH
|
||||
wp option pluck rank-math-options-titles title_separator --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow: Actualizar Meta SEO (/rank-math update-meta)
|
||||
|
||||
### Meta key individual
|
||||
|
||||
```bash
|
||||
# Título SEO
|
||||
wp post meta update ID rank_math_title "%title% %sep% %sitename%" --allow-root --path=$PATH
|
||||
|
||||
# Descrição SEO (<160 chars)
|
||||
wp post meta update ID rank_math_description "Texto conciso da página." --allow-root --path=$PATH
|
||||
|
||||
# Focus keyword
|
||||
wp post meta update ID rank_math_focus_keyword "keyword1,keyword2" --allow-root --path=$PATH
|
||||
|
||||
# Robots (ARRAY JSON — obrigatório --format=json)
|
||||
wp post meta update ID rank_math_robots '["noindex"]' --format=json --allow-root --path=$PATH
|
||||
|
||||
# Canonical URL
|
||||
wp post meta update ID rank_math_canonical_url "https://site.pt/url/" --allow-root --path=$PATH
|
||||
|
||||
# Pillar content
|
||||
wp post meta update ID rank_math_pillar_content "on" --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
### Bulk update (wp eval)
|
||||
|
||||
```bash
|
||||
# Aplicar título padrão a todos os posts sem título
|
||||
wp eval '
|
||||
$posts = get_posts(["numberposts"=>-1,"post_status"=>"publish"]);
|
||||
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%");
|
||||
}
|
||||
}
|
||||
echo count($posts)." posts processados\n";
|
||||
' --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow: Options Globais (/rank-math options)
|
||||
|
||||
**Regra crítica:** SEMPRE usar `wp option patch`, NUNCA `wp option update` em options serializadas.
|
||||
|
||||
```bash
|
||||
# Separador de título
|
||||
wp option patch update rank-math-options-titles title_separator "-" --allow-root --path=$PATH
|
||||
|
||||
# Remover base de categoria do URL
|
||||
wp option patch update rank-math-options-general strip_category_base "on" --allow-root --path=$PATH
|
||||
|
||||
# Verificar sub-key
|
||||
wp option pluck rank-math-options-titles title_separator --allow-root --path=$PATH
|
||||
|
||||
# LER option completa (diagnóstico)
|
||||
wp option get rank-math-options-general --format=json --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow: Schema Markup (/rank-math schema)
|
||||
|
||||
Schema é armazenado como array PHP em `rank_math_schema_{Type}`. Usar `wp eval` (não JSON directo).
|
||||
|
||||
```bash
|
||||
# Criar schema Article num post
|
||||
wp eval '
|
||||
update_post_meta(ID, "rank_math_schema_Article", [
|
||||
"metadata" => ["title"=>"Article","type"=>"custom","shortcode"=>"s-".uniqid(),"isPrimary"=>"1"],
|
||||
"@type"=>"Article",
|
||||
"headline"=>"%seo_title%",
|
||||
"description"=>"%seo_description%",
|
||||
"author"=>["@type"=>"Person","name"=>"%name%"],
|
||||
"datePublished"=>"%date(Y-m-dTH:i:sP)%",
|
||||
"dateModified"=>"%modified(Y-m-dTH:i:sP)%"
|
||||
]);
|
||||
echo "Schema criado\n";
|
||||
' --user=1 --allow-root --path=$PATH
|
||||
|
||||
# Criar schema FAQ
|
||||
wp eval '
|
||||
update_post_meta(ID, "rank_math_schema_FAQPage", [
|
||||
"metadata" => ["title"=>"FAQ","type"=>"custom","shortcode"=>"s-".uniqid(),"isPrimary"=>"1"],
|
||||
"@type"=>"FAQPage",
|
||||
"mainEntity"=>[
|
||||
["@type"=>"Question","name"=>"Pergunta 1","acceptedAnswer"=>["@type"=>"Answer","text"=>"Resposta 1"]],
|
||||
["@type"=>"Question","name"=>"Pergunta 2","acceptedAnswer"=>["@type"=>"Answer","text"=>"Resposta 2"]]
|
||||
]
|
||||
]);
|
||||
echo "FAQ Schema criado\n";
|
||||
' --user=1 --allow-root --path=$PATH
|
||||
|
||||
# Apagar schema corrompido
|
||||
wp post meta delete ID rank_math_schema_Article --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow: Redirects (/rank-math redirects)
|
||||
|
||||
```bash
|
||||
# Criar redirect 301
|
||||
wp eval '
|
||||
\RankMath\Redirections\DB::add([
|
||||
"id"=>"",
|
||||
"sources"=>[["pattern"=>"/url-antiga/","comparison"=>"exact"]],
|
||||
"url_to"=>"/url-nova/",
|
||||
"header_code"=>301,
|
||||
"status"=>"active",
|
||||
]);
|
||||
echo "Redirect criado\n";
|
||||
' --allow-root --path=$PATH
|
||||
|
||||
# Redirect com wildcard
|
||||
wp eval '
|
||||
\RankMath\Redirections\DB::add([
|
||||
"id"=>"",
|
||||
"sources"=>[["pattern"=>"/blog/","comparison"=>"contain"]],
|
||||
"url_to"=>"/artigos/",
|
||||
"header_code"=>301,
|
||||
"status"=>"active",
|
||||
]);
|
||||
echo "Redirect wildcard criado\n";
|
||||
' --allow-root --path=$PATH
|
||||
|
||||
# Apagar redirect por ID
|
||||
wp eval '\RankMath\Redirections\DB::delete(42); echo "Redirect apagado\n";' --allow-root --path=$PATH
|
||||
|
||||
# Limpar logs 404 (após resolver)
|
||||
wp db query "TRUNCATE TABLE wp_rank_math_404_logs;" --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Workflow: Sitemap (/rank-math sitemap)
|
||||
|
||||
```bash
|
||||
# Regenerar sitemap
|
||||
wp rankmath sitemap generate --allow-root --path=$PATH
|
||||
|
||||
# Excluir post-type do sitemap
|
||||
wp option patch update rank-math-options-sitemap pt_attachment_sitemap "off" --allow-root --path=$PATH
|
||||
|
||||
# Verificar setting
|
||||
wp option pluck rank-math-options-sitemap pt_post_sitemap --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Sequência de Cache (Sempre Após Alterações)
|
||||
|
||||
```bash
|
||||
wp cache flush --allow-root --path=$PATH
|
||||
wp transient delete --all --allow-root --path=$PATH
|
||||
wp rewrite flush --allow-root --path=$PATH
|
||||
wp rankmath sitemap generate --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
> Alterações via `wp db query` não invalidam Redis/Memcached. Sempre executar `wp cache flush`.
|
||||
|
||||
---
|
||||
|
||||
## Gotchas Críticos
|
||||
|
||||
| Problema | Causa | Solução |
|
||||
|----------|-------|---------|
|
||||
| Robots não aplicam | Injectado como string, não array | `'["noindex"]' --format=json` |
|
||||
| Options corrompidas | `wp option update` em option serializada | Sempre `wp option patch` |
|
||||
| Alteração não visível | Object cache (Redis) em memória | `wp cache flush` |
|
||||
| Schema quebra editor | JSON inválido em `rank_math_schema_*` | `wp post meta delete ID rank_math_schema_*` |
|
||||
| Sitemap 404 no Nginx | Faltam rewrite rules | Adicionar regras ao server block |
|
||||
|
||||
---
|
||||
|
||||
## Variáveis Dinâmicas Frequentes
|
||||
|
||||
`%title%` · `%sitename%` · `%sep%` · `%excerpt%` · `%category%` · `%currentyear%` · `%seo_title%` · `%seo_description%` · `%post_thumbnail%` · `%url%` · `%name%`
|
||||
|
||||
---
|
||||
|
||||
## Recursos Adicionais
|
||||
|
||||
### Referências
|
||||
|
||||
- **`references/commands.md`** — Referência completa de todos os comandos, meta keys, options e módulos
|
||||
|
||||
### Documentação Hub
|
||||
|
||||
- **Manual:** `Hub/06-Operacoes/Documentacao/Manuais/Rank-Math-WP-CLI-Manual-Definitivo.md` (17 secções)
|
||||
- **QR:** `Hub/06-Operacoes/Documentacao/Quick-Reference/QR-RankMath-WP-CLI.md`
|
||||
- **NotebookLM:** [WordPress Config CLI](https://notebooklm.google.com/notebook/fb2f26bd-8cb0-4d4c-bafc-4f1ebb51c51d) (4 fontes)
|
||||
|
||||
---
|
||||
|
||||
*Rank Math SEO via WP-CLI | Descomplicar® | v1.0.0 | 18-02-2026*
|
||||
379
wordpress/skills/rank-math/references/commands.md
Normal file
379
wordpress/skills/rank-math/references/commands.md
Normal file
@@ -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*
|
||||
271
wordpress/skills/woocommerce-cli/SKILL.md
Normal file
271
wordpress/skills/woocommerce-cli/SKILL.md
Normal file
@@ -0,0 +1,271 @@
|
||||
---
|
||||
name: woocommerce-cli
|
||||
description: This skill should be used when the user asks to "gerir woocommerce linha de
|
||||
comandos", "woocommerce wp-cli", "criar produto woocommerce cli", "actualizar stock
|
||||
woocommerce cli", "gerir encomendas woocommerce cli", "importar produtos woocommerce",
|
||||
"exportar produtos woocommerce", "configurar shipping woocommerce cli", "payment gateway
|
||||
woocommerce cli", "limpar cache woocommerce cli", "bulk update woocommerce", "woocommerce
|
||||
cwp", "wc cli cwp", "wp wc product", "wp wc shop_order", "configurar woocommerce servidor",
|
||||
"scripting woocommerce", "automacao woocommerce cli". WooCommerce management via WP-CLI
|
||||
on CWP server (server.descomplicar.pt) covering products, orders, customers, shipping,
|
||||
payments, and automation.
|
||||
author: Descomplicar® Crescimento Digital
|
||||
version: 1.0.0
|
||||
quality_score: 80
|
||||
user_invocable: true
|
||||
---
|
||||
|
||||
# /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 --user=1 --status=completed --porcelain
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Clientes
|
||||
|
||||
```bash
|
||||
# Listar clientes com métricas
|
||||
/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc customer list \
|
||||
--user=1 --fields=id,email,orders_count,total_spent \
|
||||
--format=table --allow-root --path=$PATH_WP
|
||||
|
||||
# Criar cliente
|
||||
/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc customer create \
|
||||
--user=1 \
|
||||
--email="cliente@exemplo.pt" \
|
||||
--first_name="João" \
|
||||
--last_name="Silva" \
|
||||
--billing='{"address_1":"Rua X","city":"Lisboa","postcode":"1000-001","country":"PT"}' \
|
||||
--allow-root --path=$PATH_WP
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configurações da Loja
|
||||
|
||||
```bash
|
||||
PATH_WP="/home/USER/public_html"
|
||||
|
||||
# Listar ferramentas disponíveis
|
||||
/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp wc tool list \
|
||||
--user=1 --fields=id,name --allow-root --path=$PATH_WP
|
||||
|
||||
# Sequência de limpeza pós-alterações (executar sempre após mudanças)
|
||||
WP="/opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp --allow-root --path=$PATH_WP"
|
||||
$WP wc tool run clear_transients --user=1 # Limpar transients WC
|
||||
$WP wc tool run recount_terms --user=1 # Recalcular contadores
|
||||
$WP wc tool run delete_orphaned_variations --user=1 # Variações órfãs
|
||||
$WP cache flush # Object cache
|
||||
$WP rewrite flush # Rewrite rules
|
||||
|
||||
# Listar payment 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
|
||||
|
||||
# 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cron do Sistema (CWP)
|
||||
|
||||
Desactivar WP-Cron virtual — adicionar em `wp-config.php`:
|
||||
|
||||
```php
|
||||
define('DISABLE_WP_CRON', true);
|
||||
```
|
||||
|
||||
Configurar cron real (`crontab -e` como root):
|
||||
|
||||
```bash
|
||||
* * * * * /opt/alt/php-fpm83/usr/bin/php /usr/local/bin/wp cron event run --due-now --quiet --allow-root --path=/home/USER/public_html > /dev/null 2>&1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Erros Comuns
|
||||
|
||||
| Erro | Causa | Solução |
|
||||
|------|-------|---------|
|
||||
| `Error: This does not appear to be a WooCommerce installation` | WooCommerce inactivo | `wp plugin activate woocommerce` |
|
||||
| `Error: Sorry, you cannot list resources` | Falta `--user=` | Adicionar `--user=1` |
|
||||
| `PHP Fatal error: memory` | Catálogo grande | Adicionar `-d memory_limit=2G` antes de `/usr/local/bin/wp` |
|
||||
| `wp wc update` não actualiza BD | Bug conhecido | `wp option update woocommerce_db_version "X.X.X"` manual |
|
||||
| Wizard de onboarding bloqueia | Sem comando CLI | `wp option update woocommerce_task_list_hidden "yes"` |
|
||||
|
||||
---
|
||||
|
||||
## Recursos Adicionais
|
||||
|
||||
### Referência Completa
|
||||
|
||||
- **`references/commands.md`** — Todos os tipos de produto (variável, externo, agrupado, virtual, downloadable), shipping zones completo, tributação, cupões, WP All Import, scripts de automação
|
||||
|
||||
### Manual Hub
|
||||
|
||||
- **`Hub/06-Operacoes/Documentacao/Manuais/WooCommerce com WP-CLI_ Guia Completo.md`** — Guia completo adaptado para CWP (v2.0)
|
||||
|
||||
### Skills Relacionadas
|
||||
|
||||
- **`/woocommerce`** — Desenvolvimento WooCommerce (PHP, hooks, extensões)
|
||||
- **`/wp-cli`** — WP-CLI geral no CWP (core, plugins, temas, BD)
|
||||
|
||||
---
|
||||
|
||||
*WooCommerce CLI no CWP | Descomplicar® | v1.0.0 | 18-02-2026*
|
||||
621
wordpress/skills/woocommerce-cli/references/commands.md
Normal file
621
wordpress/skills/woocommerce-cli/references/commands.md
Normal file
@@ -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*
|
||||
@@ -9,7 +9,7 @@ version: 1.1.0
|
||||
user_invocable: true
|
||||
tags: [wordpress, woocommerce, ecommerce, checkout, payments, multibanco]
|
||||
desk_task: 1479
|
||||
allowed-tools: Read, Write, Edit, Bash, mcp__ssh-unified__ssh_execute, mcp__dify-kb__dify_kb_retrieve_segments
|
||||
allowed-tools: Read, Write, Edit, Bash, mcp__ssh-unified__ssh_execute, mcp__notebooklm__notebook_query, mcp__dify-kb__dify_kb_retrieve_segments
|
||||
category: dev
|
||||
quality_score: 75
|
||||
updated: "2026-02-04T18:00:00Z"
|
||||
@@ -235,6 +235,10 @@ add_filter('woocommerce_product_query', function($q) {
|
||||
### Como Consultar
|
||||
|
||||
```javascript
|
||||
# PRIMARIO: NotebookLM (Gemini 2.5 RAG)
|
||||
# mcp__notebooklm__notebook_query({notebook_id: "5be0d1a6-00f2-4cd9-b835-978cb7721601", query: "<tema>"}) // WordPress e Elementor
|
||||
# FALLBACK: Dify KB (se NotebookLM insuficiente)
|
||||
|
||||
// Hooks e customizações WooCommerce
|
||||
mcp__dify-kb__dify_kb_retrieve_segments({
|
||||
dataset_id: "9da0b2b9-5051-4b99-b9f6-20bf35067092",
|
||||
|
||||
332
wordpress/skills/wp-cli/SKILL.md
Normal file
332
wordpress/skills/wp-cli/SKILL.md
Normal file
@@ -0,0 +1,332 @@
|
||||
---
|
||||
name: wp-cli
|
||||
description: This skill should be used when the user asks to "wp-cli cwp", "gerir
|
||||
wordpress linha de comandos", "actualizar plugins wp-cli", "backup wordpress cli",
|
||||
"migrar site wordpress", "search replace wordpress", "criar utilizador wordpress cli",
|
||||
"wp-cli no servidor", "wp-cli allow-root", "comandos wordpress server",
|
||||
"actualizar wordpress servidor", "modo manutencao wordpress", "wp db export",
|
||||
"wp plugin update server", "wp core update cwp". WP-CLI management on CWP server
|
||||
(server.descomplicar.pt) with multi-PHP support.
|
||||
author: Descomplicar® Crescimento Digital
|
||||
version: 1.0.0
|
||||
quality_score: 80
|
||||
user_invocable: true
|
||||
---
|
||||
|
||||
# /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 --reassign=1 --allow-root --path=$PATH
|
||||
|
||||
# Actualizar email admin
|
||||
wp option update admin_email "novo@email.pt" --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cache e Transientes
|
||||
|
||||
```bash
|
||||
# Limpar object cache (Redis/Memcached)
|
||||
wp cache flush --allow-root --path=$PATH
|
||||
|
||||
# Apagar todos os transientes
|
||||
wp transient delete --all --allow-root --path=$PATH
|
||||
|
||||
# Regenerar rewrite rules
|
||||
wp rewrite flush --allow-root --path=$PATH
|
||||
|
||||
# Sequência completa pós-alteração
|
||||
wp cache flush --allow-root --path=$PATH && \
|
||||
wp transient delete --all --allow-root --path=$PATH && \
|
||||
wp rewrite flush --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Modo Manutenção
|
||||
|
||||
```bash
|
||||
# Activar modo manutenção
|
||||
wp maintenance-mode activate --allow-root --path=$PATH
|
||||
|
||||
# Verificar estado
|
||||
wp maintenance-mode status --allow-root --path=$PATH
|
||||
|
||||
# Desactivar
|
||||
wp maintenance-mode deactivate --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cron WordPress
|
||||
|
||||
```bash
|
||||
# Listar eventos cron
|
||||
wp cron event list --allow-root --path=$PATH
|
||||
|
||||
# Executar evento manualmente
|
||||
wp cron event run HOOK_NAME --allow-root --path=$PATH
|
||||
|
||||
# Ver schedules disponíveis
|
||||
wp cron schedule list --allow-root --path=$PATH
|
||||
|
||||
# Apagar evento
|
||||
wp cron event delete HOOK_NAME --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Operações em Massa (Todos os Sites)
|
||||
|
||||
```bash
|
||||
# Encontrar todas as instalações WordPress
|
||||
find /home -name wp-config.php -not -path "*/backup*" 2>/dev/null | while read config; do
|
||||
dir=$(dirname "$config")
|
||||
user=$(stat -c '%U' "$dir")
|
||||
echo "=== $user: $dir ==="
|
||||
done
|
||||
|
||||
# Actualizar todos os sites (com PHP auto-detect)
|
||||
find /home -name wp-config.php -not -path "*/backup*" 2>/dev/null | while read config; do
|
||||
dir=$(dirname "$config")
|
||||
user=$(stat -c '%U' "$dir")
|
||||
echo "--- Actualizando $user ---"
|
||||
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}
|
||||
/opt/alt/${php_ver}/usr/bin/php /usr/local/bin/wp core update --allow-root --path="$dir" 2>/dev/null
|
||||
/opt/alt/${php_ver}/usr/bin/php /usr/local/bin/wp plugin update --all --allow-root --path="$dir" 2>/dev/null
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Erros Comuns e Soluções
|
||||
|
||||
| Erro | Causa | Solução |
|
||||
|------|-------|---------|
|
||||
| `Operation not permitted` | Sem `--allow-root` | Adicionar `--allow-root` |
|
||||
| `PHP Fatal error: memory` | Limite memória | `define('WP_MEMORY_LIMIT','256M')` no wp-config.php |
|
||||
| `max_execution_time exceeded` | Timeout em ops longas | `--exec-time=300` ou php.ini |
|
||||
| `Error establishing database connection` | BD em baixo | `wp db check --allow-root` |
|
||||
| `Warning: Could not get lock` | Outro processo activo | `wp cli cache clear --allow-root` |
|
||||
| PHP version wrong | Site usa PHP diferente | `ps aux \| grep "pool USER"` para detectar |
|
||||
|
||||
---
|
||||
|
||||
## Diagnóstico Rápido
|
||||
|
||||
```bash
|
||||
# Informações completas do ambiente
|
||||
wp --info --allow-root --path=$PATH
|
||||
|
||||
# Verificar conectividade BD
|
||||
wp db check --allow-root --path=$PATH
|
||||
|
||||
# Ver configuração PHP activa
|
||||
wp eval 'echo PHP_VERSION."\n".php_ini_loaded_file()."\n".ini_get("memory_limit")."\n";' --allow-root --path=$PATH
|
||||
|
||||
# Ver URL e email admin
|
||||
wp option get siteurl --allow-root --path=$PATH
|
||||
wp option get admin_email --allow-root --path=$PATH
|
||||
|
||||
# Listar utilizadores admin
|
||||
wp user list --role=administrator --allow-root --path=$PATH
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Recursos Adicionais
|
||||
|
||||
### Scripts
|
||||
|
||||
- **`scripts/wp-auto.sh`** — Auto-detecta PHP do utilizador e executa WP-CLI com a versão correcta
|
||||
|
||||
### Referências
|
||||
|
||||
- **`references/commands.md`** — Referência completa: todos os comandos com flags, WooCommerce CLI, options, wp eval avançado
|
||||
|
||||
### Documentação Hub
|
||||
|
||||
- **Manual:** `Hub/06-Operacoes/Documentacao/Manuais/WP-CLI no CWP.md`
|
||||
- **NotebookLM:** [WordPress Config CLI](https://notebooklm.google.com/notebook/fb2f26bd-8cb0-4d4c-bafc-4f1ebb51c51d)
|
||||
- **Skill relacionada:** `/rank-math` — operações Rank Math SEO via WP-CLI
|
||||
|
||||
---
|
||||
|
||||
*WP-CLI no CWP | Descomplicar® | v1.0.0 | 18-02-2026*
|
||||
376
wordpress/skills/wp-cli/references/commands.md
Normal file
376
wordpress/skills/wp-cli/references/commands.md
Normal file
@@ -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/Dados/GDrive/Backups/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*
|
||||
34
wordpress/skills/wp-cli/scripts/wp-auto.sh
Executable file
34
wordpress/skills/wp-cli/scripts/wp-auto.sh
Executable file
@@ -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 "$@"
|
||||
@@ -303,7 +303,7 @@ Em caso de dúvidas ou para aprofundar conhecimento, consultar os seguintes data
|
||||
|
||||
```javascript
|
||||
// Desenvolvimento de plugins WordPress
|
||||
mcp__dify-kb__dify_kb_retrieve_segments({
|
||||
mcp__notebooklm__notebook_query, mcp__dify-kb__dify_kb_retrieve_segments({
|
||||
dataset_id: "9da0b2b9-5051-4b99-b9f6-20bf35067092",
|
||||
query: "plugin development hooks filters"
|
||||
})
|
||||
|
||||
266
wordpress/skills/wp-translate/SKILL.md
Normal file
266
wordpress/skills/wp-translate/SKILL.md
Normal file
@@ -0,0 +1,266 @@
|
||||
---
|
||||
name: wp-translate
|
||||
description: >
|
||||
Tradução WordPress PT-PT com DeepL Pro, glossário e scripts próprios. Use when translating WordPress plugins to PT-PT, fixing PT-BR translations, handling .po/.mo/.json files, working with Loco Translate, deploying translations to starter.descomplicar.pt, or when user mentions "tradução", "translate", "pt-pt", "pt-br", ".po", ".mo", "loco", "deepl wordpress".
|
||||
author: Descomplicar® Crescimento Digital
|
||||
version: 1.0.0
|
||||
quality_score: 100
|
||||
user_invocable: true
|
||||
category: wordpress
|
||||
tags: [wordpress, traducao, pt-pt, deepl, po, mo, gettext, loco-translate, i18n]
|
||||
desk_task: 1580
|
||||
desk_project: 65
|
||||
allowed-tools: Read, Write, Edit, Bash, mcp__ssh-unified, mcp__deepl, mcp__memory-supabase
|
||||
mcps: ssh-unified, deepl, memory-supabase
|
||||
---
|
||||
|
||||
# /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=/home/ealmeida/starter.descomplicar.pt [...] --allow-root
|
||||
```
|
||||
|
||||
**Permissões obrigatórias após operações root:**
|
||||
```bash
|
||||
chown ealmeida:ealmeida /home/ealmeida/starter.descomplicar.pt/wp-content/languages/plugins/PLUGIN-pt_PT.*
|
||||
```
|
||||
|
||||
**Deploy completo:**
|
||||
```bash
|
||||
# Copiar .po + .mo + .json
|
||||
cp /tmp/PLUGIN-pt_PT.{po,mo} /home/.../languages/plugins/
|
||||
# Se React: copiar também os .json
|
||||
chown ealmeida:ealmeida /home/.../languages/plugins/PLUGIN-pt_PT*
|
||||
wp --path=... cache flush --allow-root
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verificação de Estado
|
||||
|
||||
```bash
|
||||
# Strings em falta em todos os plugins
|
||||
python3 -c "
|
||||
from pathlib import Path; import polib
|
||||
for f in sorted(Path('languages/plugins').glob('*-pt_PT.po')):
|
||||
po = polib.pofile(str(f))
|
||||
empty = len(po.untranslated_entries())
|
||||
if empty: print(f'{f.name}: {empty} em falta')
|
||||
"
|
||||
|
||||
# PT-BR residual após tradução
|
||||
grep -rn "atualiz\|ativar\|você\b\|excluir\b" languages/plugins/*.po
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Problemas Conhecidos
|
||||
|
||||
### Python 3.6 no servidor
|
||||
Scripts locais usam type hints Python 3.9+. Para correr no servidor:
|
||||
- Remover anotações `-> type` das funções
|
||||
- Não usar `from __future__ import annotations` (não funciona no 3.6)
|
||||
- `tuple[str, list]` → usar `Tuple` de typing
|
||||
|
||||
### msgfmt vs polib
|
||||
`msgfmt 0.19.8.1` recusa .po com strings mal formadas. Usar sempre **polib** para compilar:
|
||||
```python
|
||||
po = polib.pofile('file.po')
|
||||
po.save_as_mofile('file.mo')
|
||||
```
|
||||
|
||||
### Glossário Pro vs Free
|
||||
Glossário criado com chave `:fx` (Free) não funciona na conta Pro e vice-versa.
|
||||
Fix: `python3 setup_glossary.py` após mudar de chave API.
|
||||
|
||||
### XML tag_handling quebra com &
|
||||
`tag_handling='xml'` falha com strings como "Settings & Tools".
|
||||
Fix actual: tokens Unicode `⟦0⟧` como placeholders (implementado em translate_missing.py v2.1+).
|
||||
|
||||
### Strings hardcoded em bundles JS compilados
|
||||
Plugins com React que não usam `__()` nas strings de UI (ex: `subtitle:"text"`) não podem ser traduzidos.
|
||||
Não é possível sem modificar o bundle compilado. Aceitar e documentar.
|
||||
|
||||
### Loco Translate "Write protected"
|
||||
Ficheiros criados por root via SSH ficam inacessíveis ao web server.
|
||||
Fix: `chown ealmeida:ealmeida` nos ficheiros de tradução.
|
||||
|
||||
---
|
||||
|
||||
## Compilar .mo após Edições Manuais
|
||||
|
||||
```python
|
||||
import polib
|
||||
po = polib.pofile('/path/to/file.po')
|
||||
po.save('/path/to/file.po') # salva o .po actualizado
|
||||
po.save_as_mofile('/path/to/file.mo')
|
||||
```
|
||||
|
||||
## Re-gerar JSON após Edições ao .po
|
||||
|
||||
```bash
|
||||
wp i18n make-json file-pt_PT.po /path/languages/ --no-purge --allow-root
|
||||
# Depois sempre copiar com MD5 correcto se necessário
|
||||
chown ealmeida:ealmeida /path/languages/file-pt_PT-*.json
|
||||
wp --path=... cache flush --allow-root
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Estado da Biblioteca (starter.descomplicar.pt — 25-02-2026)
|
||||
|
||||
- **21 plugins** com ficheiros .po activos
|
||||
- **Cobertura:** 100% em todos os plugins (excl. webp-express sem suporte i18n)
|
||||
- **Strings hardcoded** não traduzíveis: ~7 subtítulos no ai-engine (limitação do plugin)
|
||||
- **Loco Translate path:** `languages/loco/plugins/` para pro-elements (elementor-pro)
|
||||
|
||||
---
|
||||
|
||||
*Skill v1.0.0 | 25-02-2026 | Descomplicar®*
|
||||
@@ -4,7 +4,7 @@ description: WordPress core, plugins, and themes update management. Safely updat
|
||||
WordPress components with backups. Use when user mentions "wordpress update", "wp
|
||||
update", "update plugins", "update themes", "wordpress maintenance".
|
||||
author: Descomplicar® Crescimento Digital
|
||||
version: 1.1.0
|
||||
version: 1.2.0
|
||||
quality_score: 75
|
||||
user_invocable: true
|
||||
desk_task: 1553
|
||||
@@ -91,6 +91,63 @@ chown -R USER:USER /home/USER/PATH/wp-content/
|
||||
|
||||
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
|
||||
@@ -161,11 +218,27 @@ Workflow segunda-feira:
|
||||
2. Executa verificação inicial
|
||||
3. Reporta estado dos sites
|
||||
4. Propõe actualizações pendentes
|
||||
5. Após conclusão, publica relatório na Discussão #52 (Projecto #69)
|
||||
|
||||
## INTEGRAÇÃO DESK CRM
|
||||
|
||||
- **Projecto:** #69 (Manutenção Websites)
|
||||
- **Discussão:** #52 (Logs de Atualização de Websites)
|
||||
- **Staff:** 25 (AikTop) para comentários automáticos
|
||||
- **Tool:** `mcp__desk-crm-v3__add_discussion_comment`
|
||||
- **Wordfence Alerts:** Conta IMAP `it`, pasta `INBOX.Wordpress.Alertas Wordfence`
|
||||
|
||||
---
|
||||
|
||||
## CHANGELOG
|
||||
|
||||
### v1.2.0 (2026-02-08)
|
||||
- Adicionado Passo 4: Relatório automático Desk CRM
|
||||
- Relatório publicado como comentário na Discussão #52 (Projecto #69)
|
||||
- Template HTML completo com tabelas de actualizações e falhas
|
||||
- Integração Wordfence: verifica alertas recentes da conta IMAP it@
|
||||
- Staff AikTop (ID 25) como autor dos relatórios
|
||||
|
||||
### v1.1.0 (2026-02-02)
|
||||
- Script movido para `/media/ealmeida/Dados/Dev/ClaudeDev/Claude-Scripts/wp-update/`
|
||||
- Removidos domínios expirados da lista (jornadadoheroi, tecoworking, socialboost)
|
||||
|
||||
Reference in New Issue
Block a user