# 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*
