diff --git a/wordpress/skills/mcp-tablepress/SKILL.md b/wordpress/skills/mcp-tablepress/SKILL.md new file mode 100644 index 0000000..0fd0dd9 --- /dev/null +++ b/wordpress/skills/mcp-tablepress/SKILL.md @@ -0,0 +1,115 @@ +--- +name: mcp-tablepress +description: MCP dedicado (node stdio, ligação `tablepress` em ~/.omp/agent/mcp.json) para gerir tabelas TablePress em descomplicar.pt via WP-CLI/SSH — listar tabelas, ler/exportar (CSV/HTML/JSON) 1 tabela completa (dados+options+visibilidade), configurações globais do plugin, actualizar dados (substituição total) ou nome/descrição de 1 tabela. Único MCP com o mapeamento completo de armazenamento do TablePress (option `tablepress_tables`, CPT `tablepress_table`, post meta `_tablepress_table_options`/`_tablepress_table_visibility`). Usar quando "tabela tablepress", "tablepress mcp", "exportar tabela tablepress", "editar dados tabela wordpress", "tablepress_table", "tablepress_tables option", "shortcode table id". +layer: wiki +--- + +# /mcp-tablepress — MCP dedicado ao TablePress + +Projecto em `/media/ealmeida/Dados/Dev/mcp-tablepress/` (TypeScript, SDK MCP oficial, stdio). Sem +código PHP novo no WordPress — cada tool executa `wp eval` com um snippet PHP estático (nunca +interpolado com dados externos) sobre o WP-CLI já instalado em `server.descomplicar.pt`. Toda a +entrada/saída viaja em JSON dentro de um envelope base64 por stdin/stdout — nunca interpolada na +linha de comando remota nem no código-fonte PHP. + +Não há skill de conhecimento separada para o TablePress — esta skill é a única documentação, +incluindo o mapeamento completo de armazenamento (abaixo). + +## Âmbito + +Ler, exportar e editar tabelas TablePress (dados, nome/descrição) e ler as configurações globais +do plugin. **Fora do âmbito v1** (risco de perda de dados sem reversão fácil): apagar tabela, +criar tabela nova de raiz, editar `options`/`visibility` de uma tabela (só dados/metadados de +texto), editar `tablepress_user_options` (preferências por-utilizador do editor, não são +"configurações globais"). + +## Site conhecido + +Confirmado por `wp plugin list --format=json` em todos os 8 sites reais do bundle (19-08-2026): +**só `descomplicar.pt` (produção) tem o TablePress instalado e activo** (v3.3.3). Os outros 7 +(`emanuelalmeida`, `starter`, `ccv`, `care`, `ecommerce-demo`, `e-commerce`, `ecommerce`) não o +têm. `tablepress_list_sites` devolve a lista com notas por site; qualquer tool aceita também um +path absoluto directo para uma instalação futura noutro site. + +## Mapeamento de armazenamento (confirmado por leitura do código-fonte do plugin) + +TablePress **não** guarda arrays PHP nativos em `wp_options` — grava sempre +`wp_json_encode($value, JSON_UNESCAPED_SLASHES)` como **string plana** dentro da option +(`classes/class-wp_option.php`, comentário do próprio autor: "Wraps the WordPress Options API, so +that (especially) arrays are stored as JSON, instead of being serialized by PHP"). Confirmado +empiricamente: `wp option get tablepress_tables` (sem `--format`) devolve +`{"last_id":1,"table_post":{"1":49571}}` cru; com `--format=json` devolve +`"{\"last_id\":1,\"table_post\":{\"1\":49571}}"` — **dupla codificação, corrompe qualquer escrita +subsequente**. Por isso este MCP nunca usa `wp option get/update --format=json` nem `wp post meta +get/update --format=json` — todas as leituras/escritas passam por `wp eval` com +`get_option()`/`json_decode()`/`wp_json_encode()`/`update_option()` do lado PHP. + +| Onde | O quê | Formato | +|---|---|---| +| Option `tablepress_tables` | `{"last_id": int, "table_post": {"": }}` — mapa entre o ID lógico da tabela (o usado no shortcode `[table id=X /]`) e o `post_id` do WordPress | String JSON plana | +| Option `tablepress_plugin_options` | Config global: `plugin_options_db_version`, `table_scheme_db_version`, `tablepress_version`, `custom_css`/`custom_css_minified`/`use_custom_css`, `message_donation_nag`, etc. | String JSON plana | +| Option `tablepress_user_options` | Preferências por-utilizador do editor (largura de coluna, menu admin) — **fora do âmbito deste MCP** | String JSON plana, chave por-utilizador via `TablePress_WP_User_Option` | +| Post CPT `tablepress_table` | 1 post por tabela. `post_title`=nome, `post_excerpt`=descrição, `post_content`=matriz de dados (`array>`) codificada em JSON, `post_author`, `post_modified`=última modificação | `post_content` é uma string JSON plana (não serialização WP) | +| Post meta `_tablepress_table_options` | Options de renderização da tabela: `table_head`/`table_foot` (nº de linhas), `alternating_row_colors`, `print_name`/`print_description`, `use_datatables` e sub-opções DataTables, `extra_css_classes`, `datatables_custom_commands` | String JSON plana | +| Post meta `_tablepress_table_visibility` | `{"rows": [1,1,0,...], "columns": [1,1,...]}` — 1/0 por linha/coluna (1=visível) | String JSON plana | + +**Gotcha de slashing** (confirmado por leitura de `models/model-post.php`): `wp_insert_post()`/ +`wp_update_post()` assumem input já "slashed" (aplicam `wp_unslash()` internamente) — o TablePress +faz sempre `wp_slash()` antes de chamar essas funções, e `update_post_meta()`/`add_post_meta()` +igual. Este MCP replica exactamente esse padrão em `wpcli.ts` (`wp_slash()` no conteúdo/título/ +excerpt antes de `wp_update_post()`), confirmado empiricamente por um round-trip byte-a-byte (ver +Verificação) — sem isto, backslashes literais (`\uXXXX` do JSON, `\n`/`\\` em células) seriam +corrompidos. + +Não existe comando WP-CLI custom (`wp help tablepress` confirma "not a registered command" na +v3.3.3) — todo o acesso é via `wp eval`. + +## Tools (8) + +| Tool | Read-only | Uso | +|---|---|---| +| `tablepress_list_sites` | sim | Aliases conhecidos, path WP, nota de estado do TablePress | +| `tablepress_get_status` | sim | Instalado/activo/versão — `wp plugin list` filtrado | +| `tablepress_list_tables` | sim | Todas as tabelas: ID lógico, nome, descrição, nº linhas/colunas, estado, última modificação | +| `tablepress_get_table` | sim | 1 tabela completa: `data` (matriz), `options` (renderização), `visibility` (linhas/colunas visíveis) — chamar antes de `tablepress_update_table_data` | +| `tablepress_get_global_options` | sim | `tablepress_plugin_options` completa (versões, custom CSS global, avisos) | +| `tablepress_export_table` | sim | Exporta 1 tabela em `csv`/`html`/`json` — réplica exacta de `TablePress_Export::export_table()` (mesma protecção contra CSV injection: prefixa `'` a células `=+-@` com chamadas de função perigosas) | +| `tablepress_update_table_data` | não | **Substituição total** de `data` (nunca merge — enviar a matriz completa). Invalida a cache de output da tabela (`tablepress_c_` transients) | +| `tablepress_update_table_meta` | não | Actualiza `name`/`description` (pelo menos um), sem tocar em dados/options/visibility | + +## Segurança + +Allowlist rígida: só as 2 options (`tablepress_tables`, `tablepress_plugin_options`), o CPT +`tablepress_table` e os 2 post meta fields listados acima — nenhum outro dado do WordPress é +tocado. Cada snippet PHP em `wpcli.ts` é uma constante estática hardcoded (nunca interpolada com +`table_id`, `data`, `name` ou `description`); todo o input variável viaja em JSON dentro de um +envelope base64 por stdin, decodificado remotamente com `base64 -d` antes de chegar ao `wp eval` — +nunca na linha de comando. `tablepress_update_table_data` valida no cliente (zod) que a matriz é +rectangular (todas as linhas com o mesmo nº de colunas da primeira) antes de enviar. + +## Verificação + +Construído e testado ponta-a-ponta contra produção (19-08-2026, único site com o plugin: a tabela +ID 1, post 49571, "WiP Comparativo de Planos", 41 linhas × 6 colunas): + +- `tablepress_get_status` confirmou `installed:true, active:true, version:"3.3.3"`. +- `tablepress_list_tables` devolveu a tabela real com 41 linhas/6 colunas, confirmado + cruzando com a leitura directa de `_tablepress_table_visibility` (arrays com 41/6 entradas). +- `tablepress_get_table` devolveu `data`/`options`/`visibility` idênticos aos lidos directamente + por `wp post get --field=post_content` e `wp post meta get` fora do MCP. +- `tablepress_get_global_options` devolveu a option `tablepress_plugin_options` byte-a-byte igual + à leitura directa (`custom_css`, versões, etc.). +- `tablepress_export_table` (formato `csv`) produziu output correcto com Unicode (emojis 🚀/✅, + acentuação PT) preservado. +- **Escrita `tablepress_update_table_data`**: lida a matriz actual via `tablepress_get_table`, + escrita de volta com o valor **já-corrente** (round-trip idempotente), e o `post_content` bruto + lido por SSH directo antes/depois deu **md5 idêntico** (`2c97a8e5...`) — confirma que a + codificação JSON e o `wp_slash()` não alteram o conteúdo real. +- **Escrita `tablepress_update_table_meta`**: mesmo teste com `name`/`description` já-correntes — + `post_title`/`post_excerpt` lidos por SSH directo antes/depois idênticos, e `post_content`/ + `_tablepress_table_options` confirmados intactos (a escrita de metadados não tocou nos dados). + +## Skills relacionadas + +Nenhuma skill de conhecimento separada existe para o TablePress — este documento cobre tudo. Ver +`wp-cli` para o padrão geral de gestão WordPress via WP-CLI/SSH usado por este MCP.