--- name: seriously-simple-podcasting description: Conhecimento profundo do Seriously Simple Podcasting (Castos, plugin `seriously-simple-podcasting`) — arquitectura, CPT `podcast` (episódios) e taxonomia `series` (shows), meta fields custom, REST API nativo (o que é escrita-capaz vs read-only), wp_options de definições de show (`ss_podcasting_*`), categorias iTunes/Apple Podcasts, feed RSS, e o estado real em emanuelalmeida.pt (39 episódios, 8 shows, sem addon Castos/Pro). Usar quando "seriously simple podcasting", "podcast wordpress", "episódio podcast", "show podcast", "feed rss podcast", "categorias itunes", "apple podcasts categoria", "castos", "ss_podcasting", "cpt podcast", ou qualquer trabalho de configuração/estratégia de podcast que não seja apenas chamar o MCP. Para execução directa (CRUD de episódios/shows), usar a tool MCP `mcp-seriously-simple-podcasting`. layer: wiki --- # /seriously-simple-podcasting — Seriously Simple Podcasting (Castos) — conhecimento de plugin Plugin `seriously-simple-podcasting` (Free, `SSP_VERSION` 3.17.0), instalado e activo em **emanuelalmeida.pt**. **Sem addon Castos/Pro** — não há `fluentcampaign-pro`-equivalente neste site (confirmado: pasta `php/` do plugin não tem addon Pro, `ssp_is_connected_to_castos()` devolve falso, sem hospedagem/sincronização externa de ficheiros). Mapeamento feito por leitura completa do código-fonte (`wp-content/plugins/seriously-simple-podcasting/php/`) via SSH, 19-08-2026, antes de construir o MCP `mcp-seriously-simple-podcasting`. --- ## 0. Free vs addon Castos (não instalado aqui) | | Free (activo) | Addon Castos/Pro (ausente) | |---|---|---| | Episódios (CPT `podcast`), shows (taxonomia `series`), feed RSS | ✅ core | — | | Upload/hosting de ficheiros de áudio | ❌ (URL externo só) | ✅ hosting Castos + analytics avançado | | Sincronização automática (`podmotor_*` meta) | campos existem mas vazios (nunca usados) | ✅ | | Transcrições, capítulos | não encontrado no código lido (sem módulo dedicado nesta versão) | — | Todos os 39 episódios reais têm `audio_file` a apontar para `episodes.castos.com` (CDN legado de uma ligação Castos anterior, hoje desligada) — os ficheiros continuam a servir de lá, mas o plugin já não está autenticado/sincronizado com a conta. --- ## 1. Onde vivem os dados ### 1.1 Episódios — CPT `podcast` (constante `SSP_CPT_PODCAST`) Post standard (`show_in_rest => true`), **sem tabela própria** — tudo em `wp_posts`/`wp_postmeta`. Meta fields registados via `register_meta()` (todos `show_in_rest => true`, confirmado em `CPT_Podcast_Handler::register_meta()`): | Meta key | Tipo | Nota | |---|---|---| | `episode_type` | `audio`\|`video` | | | `audio_file` | URL | ficheiro (ou stream) do episódio | | `cover_image` / `cover_image_id` | URL / attachment ID | imagem quadrada, `cover_image_id` é interno (não escrever directamente) | | `duration` | texto | ex. `00:32:14`, calculado automaticamente se possível, mas aceita override manual | | `filesize` / `filesize_raw` | texto / bytes | `filesize_raw` é interno/calculado, usado no RSS — não escrever directamente | | `date_recorded` | `Y-m-d` | distinto de `post_date` (data de publicação) | | `explicit` / `block` | checkbox (`'on'`\|`''`) | `block` esconde de directórios iTunes/Google | | `itunes_episode_number` / `itunes_season_number` | número | tags iTunes WWDC 2017 | | `itunes_title` | texto | título específico para o feed iTunes (sem número de episódio/show) | | `itunes_episode_type` | `full`\|`trailer`\|`bonus` | | | `podmotor_file_id` / `podmotor_episode_id` / `castos_file_data` / `sync_status` | — | só-Castos, sempre vazios neste site | ### 1.2 Shows — taxonomia `series` (função `ssp_series_taxonomy()`, devolve `'series'`) Termo hierárquico, `show_in_rest => true`, `rest_base => 'series'`. Um episódio pode pertencer a 0-N shows (`wp_set_post_terms`). Tags normais (`post_tag`) também estão ligadas ao CPT por omissão (filtro `ssp_use_post_tags`, `true` neste site) — existe também uma taxonomia alternativa `podcast_tags`, mas só é registada se `ssp_use_post_tags` for desligado (não é o caso aqui). ### 1.3 Definições de show — `wp_options`, NUNCA numa tabela/post Cada show tem um bloco de opções `ss_podcasting_data_{campo}_{series_id}` (título, subtítulo, descrição, autor, imagem, owner_name/email, idioma, copyright, category/subcategory 1-3) **mais** duas excepções sem o infixo `data_`: `ss_podcasting_explicit_{series_id}` e `ss_podcasting_complete_{series_id}` (gotcha — ver §6). Confirmado por SQL directo em `emanuelalmeida.pt`: 18 opções distintas escritas para o show "Afirmações" (id 120). Existe também um conjunto **sem sufixo `_{series_id}`** — os defaults globais do site (usados quando um show não tem override próprio), lidos em `Rest_Api_Controller::get_default_podcast_settings()`. --- ## 2. REST API — o que é escrita-capaz vs read-only (achado central) | Endpoint | Leitura | Escrita | |---|---|---| | `GET/POST/PUT /wp/v2/podcast` | ✅ episódios completos + todos os meta fields do §1.1 | ✅ (CPT standard, `show_in_rest`, capacidades `edit_podcasts` mapeadas para editor/administrator) | | `GET/POST/PUT /wp/v2/series` | ✅ termos + **campos extra injectados** (title/subtitle/author/owner_name/owner_email/language/copyright/image/category1-3/explicit_option/complete_option) | ❌ os campos extra são só-leitura — `register_rest_field()` em `Rest_Api_Controller::create_api_series_fields()` só regista `get_callback`, **sem `update_callback`**. Confirmado lendo o código-fonte; um `PUT` no termo não altera nenhuma destas definições. | | `GET /ssp/v1/episodes` | ✅ query cross-post-type (namespace próprio) | endpoint dedicado só para `podmotor_episode_id`/`audio_file` (uso interno Castos) | **Implicação prática:** episódios podem ser geridos 100% via REST nativo (Application Password), mas **definições de show só podem ser escritas via `wp_options` directamente** (WP-CLI `wp option update` ou, como o MCP faz, `update_option()` dentro de um `wp eval`). É por isto que `mcp-seriously-simple-podcasting` usa o bootstrap WordPress completo (`wp eval`) para tudo, em vez de misturar REST para episódios e SQL para shows — um único mecanismo, sempre consistente. --- ## 3. wp-admin — páginas principais | Página | Conteúdo | |---|---| | **Podcasting → All Episodes** | lista de episódios (CPT `podcast`), com metabox de todos os campos do §1.1 | | **Podcasting → Add New Episode** | criação, campo de show (taxonomia `series`) na sidebar | | **Podcasting → Settings → General** | defaults globais do site | | **Podcasting → Settings → Feed Details** | por show (selector "feed-series" no topo) — título/subtítulo/owner/categorias/idioma/copyright/imagem — é aqui que se editam manualmente as opções do §1.3 | | **Podcasting → Settings → Hosting** | ligação Castos (desligada neste site) | | **Podcasting → Settings → Import** | importar de outro feed RSS | --- ## 4. Categorias iTunes/Apple Podcasts 19 categorias de topo (`Arts`, `Business`, `Comedy`, `Education`, `Fiction`, `Government`, `History`, `Health & Fitness`, `Kids & Family`, `Leisure`, `Music`, `News`, `Religion & Spirituality`, `Science`, `Society & Culture`, `Sports`, `Technology`, `True Crime`, `TV & Film`), a maioria com subcategorias próprias (`Government`/`History`/`Technology`/ `True Crime` não têm) — é a taxonomia oficial Apple Podcasts, lida de `php/config/settings/feed-categories.php` e `feed-subcategories.php`. Cada show suporta até 3 pares categoria/subcategoria (`category`/`subcategory`, `category2`/`subcategory2`, `category3`/`subcategory3`). Lista completa disponível na tool `ssp_get_itunes_categories` do MCP (sem chamada SSH — é referência estática). --- ## 5. Feed RSS URL construído a partir de `home_url()` + `feed/podcast` (ou `?feed=podcast` sem permalinks bonitos) + `/{slug-do-show}` para o feed de um show específico. Cada show tem o seu próprio feed filtrado (`Episode_Repository::get_feed_url()`); o feed "geral" (sem `series_id`) inclui episódios de todos os shows. --- ## 6. Estado real em emanuelalmeida.pt (verificado 19-08-2026) - **39 episódios**, todos `publish`, distribuídos por **8 shows**: Meditação (11), DDE Desafio Detox Emocional (10), Afirmações (8), Reprogramação mental (6), Motivacionais (3), + 3 shows menores/vazios (incl. "Emanuel Almeida", 0 episódios). `audio_file` sempre aponta para o CDN legado `episodes.castos.com` (ligação Castos desligada, ficheiros continuam a servir de lá). - **Nenhum episódio marcado `explicit`** (único valor visto na coluna: `''`). - Plugins activos relevantes no mesmo site: Rank Math SEO PRO, Wordfence, WP Meteor, WP Fastest Cache, `seguranca-descomplicar` — nenhum interfere com REST/feeds do SSP nesta verificação (`curl` a `/wp-json/wp/v2/podcast` e `/feed/podcast/...` devolveram 200 sem bloqueio). --- ## 7. Gotchas | Sintoma | Causa | Nota | |---|---|---| | `wp/v2/series` devolve `explicit_option`/`complete_option` sempre vazios ou iguais ao default global, mesmo com override por show definido | Bug do próprio plugin: `series_get_field_value()` faz fallback genérico para `ss_podcasting_data_{campo}_{series_id}`, mas `explicit`/`complete` são gravados em `ss_podcasting_{campo}_{series_id}` (sem `data_`) — o REST nunca encontra o override | Ler via `ssp_get_series_settings` do MCP (lê directamente com o prefixo correcto) em vez de confiar no REST nativo para estes dois campos | | `PUT /wp/v2/series/{id}` com `title`/`owner_email`/etc no payload não faz nada | Campos são `get_callback`-only (§2) | Escrever via `ssp_update_series_settings` do MCP (`update_option`) | | `ssp_delete_series`/qualquer verificação de "show tem episódios" baseada em `term->count` dá 0 mesmo com episódios associados | `term_taxonomy.count` do WordPress só conta posts **publicados** — episódios em `draft`/`pending`/`future` não entram na contagem | Não assumir "count=0 → seguro apagar"; confirmar sempre com `ssp_list_episodes` incluindo `status=any` antes de remover um show | | Nenhum registo de transcrições/capítulos encontrado no código | Este site usa a versão Free sem addon; não há módulo de transcrição na árvore lida (`grep -i transcript` só encontra uma referência de string solta num metabox, sem implementação funcional associada) | Não assumir suporte — verificar de novo se o plugin for actualizado/o addon Castos for religado | --- ## Fonte Leitura completa do código-fonte `seriously-simple-podcasting` 3.17.0 via SSH em emanuelalmeida.pt (`php/classes/handlers/class-cpt-podcast-handler.php`, `class-series-handler.php`, `php/classes/repositories/class-episode-repository.php`, `php/classes/rest/class-rest-api-controller.php`, `class-episodes-rest-controller.php`, `php/classes/controllers/class-settings-controller.php`, `php/config/settings/*.php`, `php/includes/ssp-functions.php`), cruzada com `SHOW TABLES`/`DESCRIBE`/agregações reais via SQL e chamadas REST reais (`curl`), 19-08-2026 — sessão de construção do MCP `mcp-seriously-simple-podcasting`. Ver essa skill para a lista completa de 14 tools programáticas.