FrequencIA

WordPress podcast plugin with AI pipeline: automatic transcription, AI summaries, Podcasting 2.0 chapters, RSS feeds, and Gutenberg blocks.


Information

Author:

ROBOTSTXT

Download

Price:

€120.00

Requirements

Version:

2.3.0

WordPress:

7.0

7.1

PHP >=

8.2

Changelog

2.3.0

_Release date: 2026-08-11_

Highlights

  • Chart.js charts and world map for statistics, IAB-aligned download filtering, daily rollup tables, and 3-tier configurable data retention.

Added

  • Chart.js integration — line charts for monthly/daily download trends (interactive tooltips, smooth curves), doughnut charts for client breakdowns, replacing inline SVG sparklines.
  • World map (jsVectorMap) for country breakdowns — chloropleth view shaded by download count with hover tooltips.
  • IAB-aligned filtering — 60-second byte-threshold filter (IabConfig), expanded and filterable bot/crawler detection list, is_iab_compliant flag stored on raw events.
  • Daily rollup tablespodcast_download_daily, _daily_country, _daily_client for fast pre-aggregated queries at day/episode/country/client granularity.
  • Platform stats schemapodcast_platform_stats and podcast_platform_episode_map tables (infrastructure for Spotify/Apple CSV import).
  • 3-tier data retention — raw events (384 days), daily rollups (3650 days / ~10 years), monthly rollups (36 months). All configurable in Settings → Stats. 0 = unlimited.

Changed

  • Stats page and REST endpoint queries now read from daily rollup tables instead of the raw events table.
  • Stats seeder (wp podcast stats seed) now runs the Aggregator automatically and populates daily country/client rollup tables.
  • Database schema version bumped to 3.

Compatibility

  • WordPress: 7.0 – 7.1
  • PHP: 8.2 – 8.5

2.2.0

_Release date: 2026-08-11_

Highlights

  • Per-episode statistics drill-down and custom date-range filtering.

Added

  • Per-episode statistics detail view — each episode in the “All episodes” table has a “View” button linking to a detail page with all-time / 7-day / 30-day totals, monthly and daily trend charts, and top countries/clients.
  • Per-month/day episode breakdown — each month/day row in the trend tables has a “View” button showing which episodes drove downloads in that period, with top countries/clients.
  • Custom date-range filter — date-range picker on the Stats overview with episodes, countries, and clients scoped to the chosen range.

Compatibility

  • WordPress: 7.0 – 7.1
  • PHP: 8.2 – 8.5

2.1.0

_Release date: 2026-08-11_

Highlights

  • Statistics dashboard redesign, customizable AI prompts, manual companion blog post creation, and a corrected review-to-publish flow.

Added

  • Statistics page redesign — inline SVG line charts (no JS library dependency), two-pane layout with monthly (trailing 12 months) and daily (last 12 days) trends, zero-filled calendar axes, top episodes/countries/clients each split into trailing-12-months vs last-month tables, and a full “All episodes” table with date, episode number, channel/season, and lifetime downloads. Dates rendered via the site’s Settings → General date format.
  • Customizable AI prompts — 3-tier priority (channel override → general setting → built-in default) for the summary/chapters and blog-post prompts. Settings → AI tab and Channel edit screen expose textareas with “Reset to default” buttons and collapsible default-prompt previews. The {paragraphs} placeholder is supported; the strict JSON response contract is always auto-appended (non-editable) so processing can never break parsing.
  • Companion blog post — manual creation — a dedicated “Companion Blog Post” meta box appears on approved episodes with a “Create blog post” button. Generation uses the episode’s final title (post-approval), so the slug is correct. Once created: “Edit blog post” link + “Regenerate” button (while still a draft). New REST endpoint POST /episode/{id}/generate-blog-post. “Generating…” visual feedback during the OpenAI call.
  • Quick Add “Process now” button — AJAX force-retry on the Quick Add progress page, bypassing Action Scheduler’s exponential backoff for immediate feedback on transient failures.

Changed

  • Approve/Discard no longer auto-publishes — both actions now save the episode as a draft instead of publishing immediately, so a human always takes a separate explicit step (set publish date, add featured image, etc.) before going live. Button labels updated: “Approve and Draft” and “Discard AI and Save as Draft”. The public RSS feed, stats table, and front-end episode list correctly exclude draft episodes.
  • Blog post generation moved out of Phase B — the automatic maybe_generate_blog_post() step was removed; the global “generate by default” toggle and per-episode toggle meta were removed. Blog post creation is now exclusively manual via the button above.
  • CLAUDE.md REST endpoint table updated to reflect the new approve/discard draft behavior and the new generate-blog-post route.

Fixed

  • Quick Add media picker not workingQuickAddPage::enqueue_admin_assets() compared the admin hook suffix against a hardcoded string that didn’t match what WordPress generates for CPT submenu pages. Now captures the actual hook returned by add_submenu_page() (same pattern already used by SettingsPage and ImportPage).
  • strip_tags(null) deprecation on Settings page via CPT URLStatsPage::register() called add_submenu_page() synchronously during init instead of deferring to the admin_menu action, registering the Statistics submenu before WordPress built the CPT’s own default submenu items. WordPress then wrongly promoted Statistics as the menu’s “real parent”, breaking title resolution for every page under the FrequencIA menu when accessed via edit.php?post_type=podcast_episode&page=.... Fixed by moving add_submenu_page() into an admin_menu callback (matching every other admin page class in the plugin).

Tests

  • 698 tests, PHPCS + PHPStan L9 clean, preflight 6/6 PASS.
  • New test files: StatsPageTest, PromptSettingsTest. Updated: QuickAddPageTest, EpisodeMetaBoxTest, EpisodeActionsEndpointTest, PhaseBTest, SummaryClientTest, ChannelFieldsTest, SettingsPageTest, EpisodeMetaTest.
  • Added http_calls capture and number_format_i18n() stub to test bootstrap.

Compatibility

  • WordPress: 7.0 – 7.1
  • PHP: 8.2 – 8.5
  • MariaDB: 11.4+

i18n

  • 604 strings in .pot (was 539). .po files synced via msgmerge. .mo files compiled. 66 untranslated strings pending translation (es_ES, ca).

2.0.1

_Release date: 2026-08-10_

Highlights

  • Security hardening, documentation restructure, and a dev-dependency CVE fix.

Security

  • EpisodeActionsEndpoint::save_chapters() — added is_safe_upload_path() containment check (validate_file() + uploads-basedir prefix match) before every file_put_contents() call. Defense-in-depth against path traversal on both the existing-attachment and new-attachment branches.

Changed

  • readme.txt restructured to match the project template: changelog trimmed to 3 latest versions + link to changelog.txt; added Using the plugin section (WP-CLI commands + REST API table); added

PODCAST_TRANSCRIBE_MODEL to Extra Configurations; updated Compliance section with WordPress APIs Security + Plugin Check links; fixed FAQ answer about JavaScript builds.

  • CLAUDE.md Current version section updated from stale v1.7.0 to v2.0.0 with full release history (v1.6.0 – v2.0.0).

Fixed

  • CVE-2026-67434 in squizlabs/php_codesniffer (OS command injection). Dev-only dependency updated 3.13.5 → 3.13.6.

Compatibility

  • WordPress: 7.0 – 7.1
  • PHP: 8.2 – 8.5
  • MariaDB: 11.4+

Tests

  • PHPCS: 0 errors, 0 warnings.
  • PHPStan level 9: 0 errors.
  • PHPUnit: 657 tests, 0 failures (15 skipped: integration).
  • Preflight: 6/6 PASS.

2.0.0

_Release date: 2026-08-01_

Highlights

  • Dual-call transcription: gpt-transcribe for a higher-quality summary transcript, Whisper retained for subtitles and chapter timing.

Added

  • Dual-call transcription pipeline — Phase A sends the audio to gpt-transcribe (content layer) in addition to Whisper (timing layer). Subtitles and chapter timestamps are unchanged.
  • Transcription-model opt-out — Settings → AI and the PODCAST_TRANSCRIBE_MODEL constant (default gpt-transcribe). Set to whisper-1 to skip the second transcription (single-call, lower cost).
  • Per-channel transcription keywords — host names, sponsors, products, and recurring topics passed to gpt-transcribe to improve recognition.

Changed

  • _podcast_transcript_text now stores the gpt-transcribe plain text; Whisper segment timestamps are stored separately in _podcast_chapter_anchors. Pre-2.0.0 and importer episodes continue to work unchanged.

Security

  • GptTranscribeClient enforces mutually-exclusive language / languages; keywords sanitized to single-line, tag-free, capped values.

Compatibility

  • WordPress: 7.0 · PHP: 8.2 – 8.5 · MariaDB: 11.4+

Tests

  • 657 tests, PHPCS + PHPStan L9 clean.

1.11.3

_Release date: 2026-07-28_

Changed

  • Clarified title prefix descriptions in Settings and ChannelFields: no placeholders needed, text only (e.g. “LR”). The episode number is automatic.

Compatibility

  • WordPress: 7.0 · PHP: 8.2 – 8.5 · MariaDB: 11.4+

Tests

  • 621 tests, PHPCS + PHPStan L9 clean, preflight 6/6 PASS.

1.11.2

_Release date: 2026-07-28_

Highlights

  • Subscribe bar redesign, SSP stats date fix, title prefix hierarchy.

Added

  • Subscribe bar horizontal layout + configurable placement. Links now render as a horizontal flex row (logos on one line, wraps on narrow screens). New placement setting: above player / below player / hidden. Global option + per-channel override.

Fixed

  • SSP stats import dates. SSP stores date as a Unix timestamp integer, not a MySQL datetime. build_timestamp() now detects pure-digit values and converts via gmdate().
  • Title prefix parent hierarchy. resolve_prefix() now walks the channel parent chain (child → parent → … → global) instead of checking only the first assigned channel.

Compatibility

  • WordPress: 7.0 · PHP: 8.2 – 8.5 · MariaDB: 11.4+

Tests

  • 621 tests, PHPCS + PHPStan L9 clean, preflight 6/6 PASS.

1.11.1

_Release date: 2026-07-28_

Highlights

  • AJAX batched statistics import with live progress bar, date validation fix, TODO cleanup.

Added

  • AJAX statistics import. StatsImportAjax drives batched imports (5000 events per request) over admin-ajax with a live progress bar — no more timeouts on large SSP catalogs. Mirrors the catalog importer pattern.

Fixed

  • Statistics date validation. Invalid/unparseable timestamps are now rejected (event skipped) instead of writing 0000-00-00 to MySQL. build_timestamp() validates via strtotime() + gmdate().
  • TODO cleanup. All completed items marked; stale entries removed.

Compatibility

  • WordPress: 7.0 · PHP: 8.2 – 8.5 · MariaDB: 11.4+

Tests

  • 621 tests, PHPCS + PHPStan L9 clean, preflight 6/6 PASS.

1.11.0

_Release date: 2026-07-28_

Highlights

  • AI-generated companion blog post, brand SVG logos for subscribe links, and stats importer column-detection fix.

Added

  • AI companion blog post. Phase B optionally generates a native WordPress draft post from the transcript — a ready-to-edit article (show notes, recap, SEO landing page) sitting alongside the episode. Toggle: global default in Settings → AI (“Companion blog post”), per-episode override via _podcast_generate_blog_post. Prompt is filterable (frequencia_ai_blog_post_prompt). Re-run safe: updates draft content, never touches published posts. Traceability: _podcast_blog_post_id + _podcast_source_episode.
  • Brand SVG logos for Apple Podcasts, Spotify, iVoox, Amazon Music, and RSS in the subscribe bar. Platform definitions now support an optional svg key; the renderer uses it when available, falls back to the letter-circle for platforms without a brand icon.

Fixed

  • Statistics importer column detection. SSP stats table schemas differ across versions (id vs stat_id, event_date+event_time vs date). The importer now detects the PK and date column names at runtime using SELECT with dynamic access. Default batch limit 5000 to avoid timeout on large catalogs.

Compatibility

  • WordPress: 7.0 · PHP: 8.2 – 8.5 · MariaDB: 11.4+

Tests

  • 621 tests, PHPCS + PHPStan L9 clean, preflight 6/6 PASS.

1.10.1

_Release date: 2026-07-28_

Highlights

  • Statistics importer (SSP → FrequencIA), full-reset pipeline button, and ghost CPT for deactivated SSP.

Added

  • Statistics importer (SSP). Reads from wp_ssp_stats, maps episode IDs via the catalog importer’s IdMap, writes through Tracker::write(). Cursor-based idempotency. CLI: wp podcast stats import-stats ssp [--limit=N] [--aggregate]. Admin panel: detection + import button on the Import page.
  • “Full reset” button. REST endpoint clears all AI meta, cancels AS jobs, re-queues the full pipeline (Phase A → B → chapters).
  • Ghost podcast CPT. Registers a minimal hidden CPT when SSP data exists but SSP is deactivated, silencing map_meta_cap notices.

Fixed

  • map_meta_cap notice for orphaned SSP podcast post type.
  • Admin menu: Add Person submenu highlighting works.

Changed

  • Composer patches: PHPStan 2.2.6, WPCS 3.4.1. bin/deploy.sh hardened.

Known issues

  • Admin menu highlighting for Channels/Seasons taxonomy pages unresolved on WP 7.0. Deferred.

Compatibility

  • WordPress: 7.0 · PHP: 8.2 – 8.5 · MariaDB: 11.4+

Tests

  • 618 tests, PHPCS + PHPStan L9 clean, preflight 6/6 PASS.

1.10.0

_Release date: 2026-07-27_

Highlights

  • Subscribe links bar above the player on single-episode pages, and cover-image validation surfaced at the episode editor and import log.

Added

  • Subscribe links. Per-channel and global subscribe URLs (Apple Podcasts, Spotify, iVoox, YouTube Music, Amazon Music, Pocket Casts, Overcast, RSS) rendered as a “Subscribe” block above the audio/video players on single-episode pages. Three link styles: text only, icons only, or icons + text. Defaults: brand-coloured circle + first letter per platform (RSS gets the classic fan icon). Per-channel override; RSS auto-fills from the channel feed URL. Platform list and icons are filterable (frequencia_subscribe_platforms, frequencia_subscribe_icon). New Settings → Subscribe tab for global URLs; new “Subscribe Links” section in ChannelFields.
  • Cover image validation. New MediaCoverValidator reads the cached attachment metadata and checks Apple Podcasts specs: JPEG/PNG MIME, 1:1 aspect ratio, ≥1400 px minimum, ≤500 KB recommendation. Warnings are surfaced as an admin notice on the episode edit screen and as WARN entries in the import log. MediaHooks::META_ constants that CoverValidator reads are now public.

Changed

  • bin/deploy.sh: hardens the post-deploy composer install by force-registering PHPCS installed_paths — the --no-dev + restore cycle was silently losing the WPCS standards registration.
  • AGENTS-deploy.md: documented that release ZIPs must be extracted and inspected under /tmp/, never inside the live plugin directory.

Fixed

  • composer.json: restored the allow-plugins.dealerdirect/phpcodesniffer-composer-installer config that was lost during an earlier tooling reinstall.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5
  • MariaDB: 11.4+

Tests

  • PHPCS: 0 errors, 0 warnings. PHPStan level 9: 0 errors. PHPUnit: 610 tests, 0 failures (1 pre-existing skip). Preflight: 6/6 PASS. AI audit: docs/audit-pre-deploy-1.10.0.md.

1.9.3

_Release date: 2026-07-27_

Highlights

  • Statistics retention polish, full i18n coverage (es + ca), CBR admin note for source MP3s, and five catalog-importer improvements. Includes the v1.9.2-prep audit fixes (uninstall cleanup, deactivation hook).

Added

  • Statistics retention pruning. Daily Action Scheduler job frequencia_stats_prune (spec §6) deletes raw download events from {prefix}podcast_download older than the configured TTL (default 90 days; 0 = retain forever). Chunked DELETE ... LIMIT 50000 per run. Monthly rollup and per-episode postmeta are never touched. Pruning is gated by the opt-in (no-op while statistics are disabled).
  • Settings → Stats tab. Opt-in checkbox (podcast_stats_enabled) and retention-days input (podcast_stats_retention_days, 0–3650) now in the GUI (previously CLI/option-only).
  • wp podcast stats prune [--limit=N] WP-CLI subcommand.
  • CBR bitrate-mode admin note. When the source MP3 is VBR/ABR, the attachment form shows an amber informational note. FrequencIA does not re-encode audio.
  • Importer: channel-mapping preview. The Import admin page lists each detected source’s channels with the planned action (“will create” / “will update term N”) before the operator runs the import.
  • Importer: SSP recording date. SSP’s date_recorded meta is migrated to _podcast_recorded_date (data preservation only; no editor UI yet).
  • Importer: Podlove social-service URLs. The optional podlove_modules_contributors_service table is read; the first valid http(s) URL per contributor is stored as _podcast_person_url.
  • Importer: Podlove voice→person mapping. The optional podlove_modules_voiceassignment table is read (gracefully; no-op when the module is inactive); raw transcript voice labels are resolved to the mapped contributor’s name in the WebVTT output.

Changed

  • i18n: all 282 missing strings translated to es_ES and ca following the project style guides (vós/imperative for ca; tú for es; «» quotes; suprimir for delete; complement for plugin). .pot regenerated (523 strings), .mo compiled, 8 JS .json regenerated. Native-speaker review still recommended before public release.
  • Test stub: WpdbSpy::query() now pops from a return_query stack (defaults to true); checked()/selected()/disabled() default $two = true — matching WordPress core.
  • bin/deploy.sh: exclude CHANGELOG.md from the release ZIP (canonical changelog is changelog.txt; the Keep-a-Changelog-format CHANGELOG.md has drifted since v1.7.0).

Fixed

  • StatsEndpoint::register() triggered _doing_it_wrong on every admin page load because register_rest_route() ran on init instead of rest_api_init. Now hooks rest_api_init via a dedicated register_routes() callback.
  • uninstall.php now cleans up the statistics subsystem per spec §5: cancels 3 stats AS hooks; deletes 4 stats options; removes the GeoIP database; and, on the data-removal opt-in, drops {prefix}podcast_download + _monthly and the _podcast_downloads_total/7d/30d postmeta.
  • frequencia_deactivate() now unschedules all three stats AS hooks alongside podcast_process_episode.
  • Settings → Stats retention notice distinguishes “paused” (statistics disabled) from “0 days effective”.
  • Importer transcript/chapter idempotency. A standalone re-run of Phase 12.6 now overwrites the existing attachment in place instead of orphaning the old one.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5
  • MariaDB: 11.4+

Tests

  • PHPCS: 0 errors, 0 warnings. PHPStan level 9: 0 errors. PHPUnit: 588 tests, 0 failures (1 pre-existing skip). Preflight: 6/6 PASS. AI audit: docs/audit-pre-deploy-1.9.3.md.

1.9.1

_Release date: 2026-07-17_

Highlights

  • Security hardening: resolves all 2 WARNING + 2 INFO findings from the v1.9.0 clean-context audit.

Fixed

  • ClientIp now validates REMOTE_ADDR against a filterable trusted-proxy list (frequencia_trusted_proxies, default: localhost) before honouring X-Forwarded-For / CF-Connecting-IP. Prevents header spoofing → dedup manipulation.
  • GeoIpUpdater validates the downloaded mmdb end-to-end: opens it with the MaxMind reader and resolves 8.8.8.8 before installing. Rejects corrupt/tampered files.
  • TrackingEndpoint: source parameter whitelist-validated (feed/player/download/embed); unknown values default to download.
  • Aggregator::upsert_monthly: REPLACE INTO instead of deprecated ON DUPLICATE KEY UPDATE ... VALUES() (MariaDB 11.4+ future-proofing).

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5
  • MariaDB: 11.4+

Tests

  • PHPCS: 0 errors, 0 warnings. PHPStan level 9: 0 errors. PHPUnit: 573 tests. Preflight: 6/6 PASS.

1.9.0

_Release date: 2026-07-17_

Highlights

  • Statistics module: anonymous download/play counting with GeoIP, client detection, monthly trends, and a REST API.

Added

  • Statistics module (5 phases, per docs/stats-module-spec.md):

StatsTracker — writes raw download events with hash(salt + IP + UA) de-dup key; bot/HEAD/range filtering.
StatsAggregator — cursor-based hourly aggregation: deduped per (day, listener-hash); postmeta totals + monthly rollup upsert.
StatsTrackingEndpoint — rewrite /frequencia/media/{id}/{kind}/ → record hit → 302 redirect. Always registered; records only when opt-in is on.
StatsGeoIp + GeoIpUpdater — MaxMind DB reader (custom country_code schema); monthly AS download from ip.robotstxt.es with magic-marker validation.
StatsClientDetector — 17 podcatcher UA patterns.
AdminStatsPage — at-a-glance, 12-month CSS-bar trend, top episodes/countries/clients. manage_options gated.
StatsStatsEndpointGET /frequencia/v1/stats REST read.
CliStatsCommandwp podcast stats seed/aggregate.
– Episode-list “Downloads” column.
bin/preflight.sh — automated pre-deploy verification (6 sections).

  • Database schema v2{prefix}podcast_download (raw events) + {prefix}podcast_download_monthly (rollup). FREQUENCIA_DB_VERSION → 2.
  • Composer dependency: maxmind-db/reader ^1.13.

Changed

  • Media import: follows HTTP redirects; external files referenced as URL-attachments when download is off; local files reused without copy. Imports the source featured image (_thumbnail_id).

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5
  • MariaDB: 11.4+

Tests

  • PHPCS: 0 errors, 0 warnings. PHPStan level 9: 0 errors. PHPCompatibility 8.2–8.5: 0 errors. PHPUnit: 573 tests, 0 failures. Preflight: 6/6 PASS. Security audit performed (docs/security-audit-1.9.0.md).

1.8.3

_Release date: 2026-07-17_

Highlights

  • Importer robustness: recover from a stale source-to-target map after episodes are deleted, and import the source featured image.

Fixed

  • Re-importing after the imported episodes were deleted produced an empty episode list. The importer trusted the persistent IdMap even when its target post IDs no longer existed (deleted), so it either skipped them (skip_existing) or wrote meta to dead IDs. Importer::import_episodes now verifies the mapped target post still exists; if not, it imports a fresh post and updates the map.

Added

  • Featured image import: EpisodeRecord.featured_image_id carries the source _thumbnail_id. Importer::set_episode_meta resolves the cover preferring a valid local attachment (foreign/dangling source IDs are ignored via local_attachment_id()), else resolves the cover_image URL through MediaResolver, and sets both _podcast_episode_cover_id and the WP featured image (set_post_thumbnail).

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5
  • MariaDB: 11.4+

Tests

  • PHPCS: 0 errors, 0 warnings. PHPStan level 9: 0 errors. PHPCompatibility 8.2–8.5: 0 errors. PHPUnit: 573 tests, 0 failures (1 pre-existing skip). Dedicated security audit performed (docs/security-audit-1.8.3.md).

1.8.2

_Release date: 2026-07-17_

Highlights

  • Catalog importer fixes: the AJAX run works on WP 7.0, respects Limit/Offset, and resolves media correctly.

Fixed

  • AJAX import returned 403 -1 on every batch under WordPress 7.0: check_ajax_referer() only inspects $_REQUEST['_ajax_nonce']/_wpnonce, not the bare nonce key the client sends. It is now passed explicitly as the query arg.
  • AJAX import ignored the form’s Limit/Offset fields (it imported the whole catalog). The first batch now records the start offset + total-episode cap; each batch’s slice is capped by the remaining allowance; the run finishes at min(total, start_offset + limit).

Changed

  • MediaResolver follows HTTP redirects to the final media URL, then: existing local attachment → reuse; local file on disk → reference (no copy); remote file → download when --download-media is on, else create a URL-only attachment whose guid is the final URL (wp_get_attachment_url() returns it verbatim, so feed/player stream from the origin). Idempotent via a _podcast_source_url meta lookup.

Maintenance

  • Database schema v2: {prefix}podcast_download (raw events) and {prefix}podcast_download_monthly (rollup) created for the upcoming statistics module. No tracking code yet — tables are empty and harmless. FREQUENCIA_DB_VERSION → 2.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5
  • MariaDB: 11.4+

Tests

  • PHPCS: 0 errors, 0 warnings. PHPStan level 9: 0 errors. PHPCompatibility 8.2–8.5: 0 errors. PHPUnit: 572 tests, 0 failures (1 pre-existing skip).

1.8.1

_Release date: 2026-07-16_

Highlights

  • Cleaner episode list: deduplicated columns in a fixed order.

Changed

  • EpisodeColumns::add_columns now returns a fixed column order (No. → Channel / Season → Title → Duration → Type → AI Status → Author → Date) and drops the auto-added taxonomy-podcast_channel / taxonomy-podcast_season columns that duplicated the merged “Channel / Season” column.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5

Tests

  • PHPCS: 0 errors, 0 warnings. PHPStan level 9: 0 errors. PHPUnit: 568 tests, 0 failures (1 pre-existing skip).

1.8.0

_Release date: 2026-07-16_

Highlights

  • Live, batched catalog import with a progress bar (no timeouts), plus real-data importer fixes and a fully clean PHPCS/PHPStan pass.

Added

  • Batched import over admin-ajax: the admin Import page streams a real run in batches of 15 with a live progress bar and scrolling per-item log, avoiding PHP timeouts on large catalogs. Dry runs still submit synchronously; WP-CLI is unchanged.
  • Importer::run_batch() imports an episode slice; new import_transcripts_for() / import_chapters_for() scope transcript and chapter work to the current batch, so the persistent source-to-target IdMap no longer causes duplicate attachments across batches.
  • Source detection now shows live channel/season/person/episode counts per detected source; a dry run reports the planned counts instead of always-zero.
  • Episode number falls back to the leading digits of the post title when the source’s itunes_episode_number meta is empty (common with Seriously Simple Podcasting).

Changed

  • Only published (post_status = publish) episodes are imported/counted; drafts, future and trash are skipped.
  • WordPress.DB.DirectDatabaseQuery scoped off for the importer source readers in .phpcs.xml (they exist to read foreign plugin tables directly; no WP API covers this).

Fixed

  • Transcript and chapter attachments were duplicated when an import re-iterated the full persistent IdMap.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5
  • MariaDB: 11.4+

Tests

  • PHPCS: 0 errors, 0 warnings. PHPStan level 9: 0 errors. PHPCompatibility 8.2–8.5: 0 errors. PHPUnit: 568 tests, 0 failures (1 pre-existing skip).

1.7.0

_Release date: 2026-07-06_

Highlights

  • Numeric global seasons, episode title-prefix format, and a podcast:updateFrequency feed tag.

Added

  • Episode title-prefix format — N.PREFIX - Title in feed and website (not editor); per-channel prefix (max 64) with global fallback; number applied to full episodes only.
  • “ — per-channel + global field, emitted in the RSS feed.

Changed

  • Season terms are now numeric (name = slug = integer; “Season 3” → “3”); removed the unused _podcast_season_channel_id meta.
  • Merged the Channel and Season admin list columns into one “Channel / Season” column.

Maintenance

  • Regenerated the translation template (.pot, 483 strings); documented the external CBR validator warning.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5

Tests

  • PHPCS: 0 errors. PHPStan level 9: 0 errors. PHPUnit: 570 tests (15 skipped).

1.6.0

_Release date: 2026-07-06_

Highlights

  • Catalog importer from Podlove Podcast Publisher and Seriously Simple Podcasting.

Added

  • Catalog importer — migrate channels, seasons, persons, episodes, transcripts, and chapters from Podlove or Seriously Simple Podcasting. Idempotent, non-destructive, GUID-preserving; AI pipeline suppressed on import. WP-CLI (wp podcast import, wp podcast import-status) and an admin Import page.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5

Tests

  • PHPCS: 0 errors. PHPStan level 9: 0 errors.

1.5.0

_Release date: 2026-07-01_

Highlights

  • Multi-language subtitle translation and granular per-player placement.

Added

  • Subtitle translation: per-channel “Translate subtitles” toggle + “Subtitle languages” multi-select. Whisper returns word-level timestamps; subtitles use short word-grouped cues. The spoken language is auto-detected; the transcript is translated (OpenAI) into each additional selected language, producing one subtitle track per language. The player renders a per language with srclang/label.
  • Granular player placement: independent before/after/none for the audio and video players, plus a “player order” setting (video-first / audio-first) for when both share a slot. Backwards-compatible with the legacy single-player setting.

Changed

  • WhisperClient requests both segment and word granularities.
  • WebVTTFormatter exposes cues() / format_cues(); word-grouped cues with a segment fallback.
  • Player renders multiple subtitle elements (was a single hardcoded srclang="es").

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5

Tests

  • PHPCS: 0 errors. PHPStan level 9: 0 errors. PHPCompatibility 8.2–8.5: 0 errors. composer audit: 0 advisories. PHPUnit: 217 unit tests, 0 failures.

1.4.0

_Release date: 2026-07-01_

Highlights

  • Correct, flag-based rewrite-rule flushing and iTunes episode-numbering feed compliance.

Added

  • FlushManager: rewrite rules flush only on activation, episode-slug change, or plugin version change. Covers the WP updater (upgrader_process_complete) and a plugins_loaded version-compare fallback for manual / Git / rsync deploys.
  • Optional episode-number title prefix in the RSS feed (Settings → Podcast → Feeds).

Fixed

  • “ omitted for trailer/bonus episodes (Apple Podcasts spec).
  • frequencia_activate() registers the CPT before flushing, so episode permalinks work right after activation.
  • _podcast_video_duration cleaned up on uninstall.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5

Tests

  • PHPCS: 0 errors. PHPStan level 9: 0 errors. PHPCompatibility 8.2–8.5: 0 errors. composer audit: 0 advisories. PHPUnit: 214 unit tests, 0 failures.

1.3.0

_Release date: 2026-06-30_

Highlights

  • Video duration tracking and video-by-default playback for episodes with both audio and video.

Added

  • _podcast_video_duration meta field: the MP4 length is auto-filled (server-side + Block Editor), shown in the editor sidebar, and used in the video RSS feed’s “.

Changed

  • Episodes with both an MP3 and an MP4 now show the video player by default (captions + chapters), instead of the audio player.
  • MediaHooks now syncs both audio and video durations; the editor sidebar shows separate “Audio duration” and “Video duration” fields.
  • The video RSS feed prefers the video duration for “.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5

Tests

  • PHPCS: 0 errors. PHPStan level 9: 0 errors. PHPCompatibility 8.2–8.5: 0 errors. composer audit: 0 advisories. PHPUnit: 206 unit tests, 0 failures.

1.2.0

_Release date: 2026-06-29_

Highlights

  • Quick Add Episode: a one-screen creation flow that runs the full AI pipeline automatically and tracks progress live.

Added

  • Quick Add Episode screen (FrequencIA → Quick Add): pick MP3 (required), optional MP4, channel, and season; creates a draft titled “Episode N”, auto-queues the AI pipeline, and shows an inline progress stepper (Created → Queued → Transcribing → Summarizing → Ready for review) that polls until review, then links to the editor.
  • Episode number auto-increment: new episodes get the next sequential number (highest existing + 1) for Block Editor, classic, and programmatic saves.
  • Duration auto-fill in the Block Editor: selecting an audio file populates the duration immediately from attachment metadata.
  • Timestamped transcript: Phase A stores [HH:MM:SS]-prefixed segments so the LLM anchors chapter start times to the real audio.
  • REST endpoint GET /frequencia/v1/episode/{id}/status (status, activity log, edit URL, error).

Changed

  • “Quick Add” is the first submenu under the FrequencIA menu.
  • package.json version kept in sync with the plugin header.

Fixed

  • Settings page “Select image” button did nothing (media uploader never enqueued; inline JS checked wp.media too early).
  • Chapter timestamps did not match the audio: ChaptersFormatter now accepts MM:SS, and the LLM is fed real Whisper segment timestamps.
  • Episode number field was always empty (auto-increment was never implemented).
  • Duration field stayed empty after attaching audio (server-side auto-fill overwritten by the REST meta save).
  • Test suite drift: missing sanitize_title stub, stale meta field count, version stub mismatch, test-isolation bug skipping 3 tests.
  • readme.txt changelog was missing the 1.1.0 entry.

Security

  • Security audit passed (OWASP/WordPress hardening). Risk: Low.
  • Quick Add form: nonce + edit_posts capability check; REST status route gated by edit_post permission callback.
  • No sensitive data (API keys, paths) exposed via the new REST endpoint.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5
  • MariaDB: 11.4+

Tests

  • PHPCS: 0 errors (WordPress + WordPress-Docs + WordPress-Extra + PHPCompatibilityWP).
  • PHPStan: level 9, 0 errors.
  • PHPUnit: 219 tests, 0 failures (14 integration tests skip without WP_TESTS_DIR).
  • PHPCompatibility scan: 8.2–8.5, 0 errors.
  • composer audit: 0 advisories.

1.1.0

_Release date: 2026-06-25_

Added

  • Block Editor sidebar panels for all episode metadata and a People panel with roles.
  • AI Status panel: processing event log, stuck detection, re-queue via REST API.
  • AI Content panel persists after publication: transcript download, editable summary/chapters.
  • REST endpoints: requeue / approve / discard / regen / save-ai-content.
  • Regenerate summary and title via background Action Scheduler job.
  • Spanish (es_ES) and Catalan (ca) translations including Block Editor JS JSON.

Fixed

  • Block Editor iframe buttons converted to fetch() REST calls.
  • Summary copied to post_content on first approval.
  • Chapters startTime conversion; duration MIME detection broadened.
  • Action Scheduler bootstrap; episode number defaulting; feed URLs with plain permalinks.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5

1.0.0

_Release date: 2026-06-24_

Highlights

  • Initial stable release: full AI podcast pipeline, multi-standard RSS, HTML5 player, Gutenberg blocks.

Added

  • Full AI pipeline: transcription (Whisper), summarization and chapters (GPT), editorial review.
  • Multi-standard RSS feeds (RSS 2.0, iTunes, Podcasting 2.0) per channel.
  • HTML5 player with speed/skip/chapters/WebVTT; episode-player, episode-list, subscribe blocks.
  • WP 7.0 Connectors API integration; async processing queue with retries.
  • WP-CLI commands: process, status, reprocess-all, flush-cache.
  • Rate limiting; complete uninstall.php.

Compatibility

  • WordPress: 7.0
  • PHP: 8.2 – 8.5

0.2.0

_Release date: 2026-06-23_

  • Phase 1: CPTs, taxonomies, meta fields, DB schema, PHP 8.2 enums.

0.1.0

_Release date: 2026-06-23_

  • Phase 0: plugin scaffolding and development tooling.