09b61cc950
Ran the official Plugin Check (PCP) against v0.6.3 — surfaced 169
issues. This release closes all of them so the plugin is submission-
ready for the WordPress.org plugin directory.
Branding
- Plugin Name renamed: "Radio" → "RangerHQ Radio". Removes the
trademarked "SomaFM" from the plugin name surface (PCP
trademarked_term). Lines up with the RangerHQ plugin family.
SomaFM credited in Description + About as the data source.
Folder/slug stays `a-radio` — no install path changes; existing
user_meta keys (radio_state / radio_history / radio_favourites)
untouched.
- Text Domain header renamed: `radio` → `a-radio` (matches slug).
- Requires at least bumped: 5.0 → 5.3 (matches wp_date() usage).
- File docstring header dropped "SomaFM" from prominent line.
Code (mass-mechanical)
- 134 i18n call sites rewritten from `'radio'` text domain to
`'a-radio'` across 7 PHP files. Single sed pass on the unique
pattern `, 'radio' )` — the 6 menu-slug `'radio'` references in
add_*_page() were correctly left alone (those are URL slugs).
Security
- 8 × MissingUnslash + 8 × InputNotSanitized in the v0.5.0 history
endpoints (radio_ajax_log_track, radio_ajax_toggle_favourite).
All four $_POST['artist|title|station|station_id'] access points
are now wrapped sanitize_text_field( wp_unslash( $_POST['…'] ) )
(or sanitize_key for station_id) at the access point.
Translator comments
- 6 × printf / sprintf calls with placeholders now carry
/* translators: ... */ comments.
Pop-out window refactor
- Inline <link> stylesheets, <style> block, and <script> tag in
radio_render_popout_page() replaced with wp_enqueue_style() +
wp_enqueue_script() + wp_localize_script() registered before HTML
output, then wp_print_styles() in <head> and wp_print_footer_
scripts() at end of <body>.
- Popup-specific CSS moved out of inline <style> and into radio.css
under body.radio-popout scope so it only fires inside the popup.
Removed
- .DS_Store files (root + assets/). PCP hidden_files.
Distribution
- New readme.txt in proper WordPress.org format: Plugin headers,
Contributors, Donate link, Tags, Requires-at-least, Tested-up-to,
Stable Tag, Requires-PHP, License, Description, Installation,
FAQ, Screenshots, Changelog, Upgrade Notice.
Compat
- No behaviour change for users; user_meta preserved.
- Displayed Plugin Name in Plugins → Installed changes from "Radio"
to "RangerHQ Radio" — only visible difference on update.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
298 lines
28 KiB
Markdown
298 lines
28 KiB
Markdown
# Changelog
|
||
|
||
All notable changes to **Radio** are documented here.
|
||
Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) — versioning: [SemVer](https://semver.org/).
|
||
|
||
---
|
||
|
||
## [Unreleased]
|
||
|
||
---
|
||
|
||
## [0.7.0] — 2026-05-30 — WordPress.org submission prep (full Plugin Check clean)
|
||
|
||
Ran the official WordPress.org **Plugin Check (PCP)** against v0.6.3 — surfaced **169 issues**. This release closes all of them so the plugin is submission-ready for the WordPress.org plugin directory.
|
||
|
||
### Changed — branding
|
||
- **Plugin Name renamed: "Radio" → "RangerHQ Radio"** to (a) remove the trademarked term "SomaFM" from the plugin name surface (PCP `trademarked_term` warning) and (b) line up with the RangerHQ plugin family. SomaFM is still credited in the Description and on the About page as the data source. Plugin folder/slug stays `a-radio` — no install path changes; existing user_meta keys (`radio_state` / `radio_history` / `radio_favourites`) untouched.
|
||
- **`Text Domain` header renamed**: `radio` → `a-radio` (matched the slug for the first time; PCP `textdomain_mismatch`).
|
||
- **`Requires at least` bumped**: `5.0` → `5.3` (matches `wp_date()` usage in `inc/history.php`; PCP `wp_function_not_compatible_with_requires_wp`).
|
||
- **File docstring header** dropped "SomaFM" from the prominent first line.
|
||
|
||
### Changed — code (mass-mechanical)
|
||
- **134 i18n call sites** rewritten from `'radio'` text domain → `'a-radio'` across `radio.php`, `inc/admin-page.php`, `inc/dashboard-widget.php`, `inc/settings.php`, `inc/about.php`, `inc/history.php`, `inc/updater.php`. Single sed pass on the unique pattern `, 'radio' )` (the 6 menu-slug `'radio'` references in `add_menu_page` / `add_submenu_page` were left alone — they're the URL slug, not the text domain).
|
||
|
||
### Fixed — security
|
||
- **8 × `MissingUnslash` + 8 × `InputNotSanitized`** in the v0.5.0 history endpoints (`radio_ajax_log_track`, `radio_ajax_toggle_favourite`). All four `$_POST['artist|title|station|station_id']` access points are now wrapped `sanitize_text_field( wp_unslash( $_POST['…'] ) )` (or `sanitize_key()` for `station_id`) at the access point. The downstream `radio_sanitize_entry()` helper still re-sanitizes as belt+braces.
|
||
|
||
### Added — translator comments
|
||
- 6 × `printf` / `sprintf` calls with placeholders now carry `/* translators: ... */` comments: pop-out window title, updater status messages (HTTP error / available / up-to-date / download), history page "%s ago" relative time.
|
||
|
||
### Refactored — pop-out window
|
||
- Inline `<link>` stylesheets, inline `<style>` block, and `<script>` tag in `radio_render_popout_page()` replaced with `wp_enqueue_style()` + `wp_enqueue_script()` + `wp_localize_script()` registered before the HTML output, then `wp_print_styles()` in `<head>` and `wp_print_footer_scripts()` at end of `<body>`.
|
||
- Popup-specific CSS (header, close button, wrap, layout overrides, popup dark theme) moved out of the inline `<style>` and into `assets/css/radio.css` under `body.radio-popout` scope so it only fires inside the popup.
|
||
|
||
### Removed
|
||
- `.DS_Store` files (root + `assets/`) — stray macOS Finder artefacts; PCP `hidden_files`. `.gitignore` already covers them.
|
||
|
||
### Added — distribution
|
||
- **`readme.txt`** in proper WordPress.org format: Plugin headers, Contributors, Donate link, Tags, Requires-at-least, Tested-up-to, Stable Tag, Requires-PHP, License, License URI, short description (≤150 chars), Description, Installation, FAQ, Screenshots, Changelog, Upgrade Notice.
|
||
|
||
### Compat notes
|
||
- No behaviour change for existing users. Per-user state (`radio_state` / `radio_history` / `radio_favourites`) is preserved across the upgrade — no migration needed.
|
||
- The displayed Plugin Name in **Plugins → Installed** changes from "Radio" to "RangerHQ Radio" — that's the only visible difference on update.
|
||
|
||
**Files changed:** `radio.php` (header + 6 translator comments + 8 $_POST hardenings + popup enqueue refactor), `inc/admin-page.php` / `inc/dashboard-widget.php` / `inc/settings.php` / `inc/about.php` / `inc/history.php` / `inc/updater.php` (textdomain mass-fix + translator comments where applicable + about-page version rotation), `assets/css/radio.css` (popup styles moved in under `body.radio-popout`), **new** `readme.txt`, **removed** `.DS_Store`, `assets/.DS_Store`.
|
||
|
||
---
|
||
|
||
## [0.6.3] — 2026-05-30 — Discreet "buy me a coffee" support link
|
||
|
||
### Added
|
||
- New `RADIO_SUPPORT_URL` constant in `radio.php` (default `https://buymeacoffee.com/davidtkeane`). Wrapped in `if ( ! defined(...) )` so it's override-able from `wp-config.php`.
|
||
- Tiny footer line `☕ Like Radio? If You fancy to buy me a coffee →` inside the **Updates panel** on Settings, below the manual-update note.
|
||
- Matching footer line at the bottom of the **Credits + thanks** card on the About page.
|
||
- Both spots render from the same constant — change one place, both update.
|
||
- **Conditional render**: if `RADIO_SUPPORT_URL` is empty / undefined, the link is silently hidden. Forks can strip funding with one line.
|
||
|
||
### Design
|
||
- Muted styling deliberate: 12 px, admin-theme-coloured link, subtle top border. Reads as housekeeping ("here's where to send thanks") not a sales pitch. No yellow BMC brand chrome.
|
||
- Dark-theme variant for the divider (`#3c434a`) so it stays subtle on the dark surface.
|
||
|
||
**Files changed:** `radio.php` (version, `RADIO_SUPPORT_URL` constant), `inc/updater.php` (link inside the Updates panel after the manual-update paragraph), `inc/about.php` (link inside the Credits + thanks card; rotate v0.6.3 into latest expanded slot, v0.6.2 into earlier-releases list), `assets/css/radio.css` (`.radio-support-link` styling + dark-theme override).
|
||
|
||
---
|
||
|
||
## [0.6.2] — 2026-05-30 — Current version badge on Settings
|
||
|
||
### Added
|
||
- Small grey pill follows the **"Radio — Settings"** heading: `v{RADIO_VERSION}`. Visible at a glance so you don't have to hover the plugin row in *Plugins → Installed* or open *About* just to check what version you're on.
|
||
- Dark-theme variant of the badge (`#2c3338` background, `#c3c4c7` text) so it stays readable when `theme=dark`.
|
||
|
||
**Files changed:** `radio.php` (version), `inc/settings.php` (`<span class="radio-version-badge">v…</span>` inside the H1), `assets/css/radio.css` (`.radio-version-badge` styling + dark-theme override).
|
||
|
||
---
|
||
|
||
## [0.6.1] — 2026-05-30 — About page restructure
|
||
|
||
By v0.6.0 the About page had eight version-history entries, each a full paragraph, dwarfing the other cards and pushing Credits + thanks off the visible area. v0.6.1 rebalances the layout.
|
||
|
||
### Changed
|
||
- **Three short cards on top** (What / Who / **Credits**) — equal-height, balanced row. Credits is no longer a fourth card buried under the version history; it sits beside What and Who where it belongs.
|
||
- **Version history is its own full-width card below.** Only the **latest** release is shown in full; **earlier releases collapse to one line each** (version + date + headline). The card now stays compact however many versions ship — adding a future release adds one line, not a paragraph.
|
||
- **Full prose for older versions lives in `CHANGELOG.md` on Gitea** — the "View the full CHANGELOG.md →" link does the heavy lifting. Single source of truth, no duplication.
|
||
|
||
**Files changed:** `radio.php` (version), `inc/about.php` (3-card top + new `.radio-about-versions` block with `__latest` / `__earlier` sub-elements; 9 versions in the earlier-releases list incl. v0.1.0), `assets/css/radio.css` (removed dead `.radio-about-card--versions` rules; added `.radio-about-versions` + `__latest` + `__earlier` rules; dark-theme overrides for the new selectors).
|
||
|
||
---
|
||
|
||
## [0.6.0] — 2026-05-30 — Pop-out mini-player (continuous background play)
|
||
|
||
Until v0.5.0 the audio cut every time you navigated between WP admin pages — every navigation is a full page reload, which destroys the `<audio>` element. v0.6.0 fixes the background-music use case by letting you pop the player out into a separate browser window that persists across the parent tab's navigation.
|
||
|
||
### Added — **Pop out** button + standalone popup player
|
||
- Small **`↗ Pop out`** button beside the Play button on both the main Radio page and the Dashboard widget. Click it and a **380×560 standalone window** opens with just the player chrome (no WP admin sidebar / nav).
|
||
- The popup lives at `admin-post.php?action=radio_popout&play=1` — a new server-side route that renders a **full standalone HTML page** outside the WP admin shell (custom `<!DOCTYPE>`, head, body, no admin chrome).
|
||
- Popup is `radio_popout`-named so a second click on Pop out **re-focuses the existing window** instead of opening a new one.
|
||
- The popup's `<audio>` element is never destroyed by parent-tab navigation, so the music keeps playing while you click around Plugins, Posts, Users, etc.
|
||
|
||
### Auto-resume — pick up where the main tab left off
|
||
- The Pop-out button URL carries `&play=1`. `radio.js` reads it from the localized config and auto-calls `audio.play()` 200 ms after init. Same-origin user-gesture popups are exempt from autoplay-blocking on every modern browser, so it just works.
|
||
- On opening the popup, **every other audio surface in the main tab is paused** so you don't end up with two streams running simultaneously.
|
||
|
||
### Popup details
|
||
- Theme follows the user's saved choice (`radio_state['theme']`) — light by default, dark if explicitly set; the popup body gets the `radio-theme-dark` class so the existing dark-mode CSS rules apply.
|
||
- The popup includes everything you need to listen and switch: now-playing block (with dancing bars + Web Audio visualizer), play/pause, mute, volume, full station dropdown grouped by genre, error slot.
|
||
- Close button (`✕`) in the top-right calls `window.close()`.
|
||
- Pop out button **does not appear inside the popup** itself (would be infinite); the JS detects `popoutUrl === ''` in the localized config and hides any Pop-out button it finds.
|
||
- Popup blocked? The button shows a clear alert: *"Pop-out blocked by the browser. Allow popups for this site, then try again."*
|
||
|
||
### State stays in sync
|
||
- The popup uses the **same `radio_save_state` AJAX endpoint** as the main player. If you change station or volume in the popup, it persists to user_meta; the next time you load any Radio page in the main tab it picks up the new values.
|
||
- Track history continues to log from whichever surface is playing — the popup polls SomaFM and POSTs to `radio_log_track` exactly like the main player.
|
||
|
||
**Files changed:** `radio.php` (version, `popoutUrl` added to localized config, new `admin_post_radio_popout` action + `radio_render_popout_page` handler with full standalone HTML), `inc/admin-page.php` + `inc/dashboard-widget.php` (Pop-out button beside Play), `assets/css/radio.css` (Pop-out button styling), `assets/js/radio.js` (`bindPopOut` opens the window + pauses other surfaces, autoplay branch reads `cfg.autoPlay`), `inc/about.php` (history entry).
|
||
|
||
---
|
||
|
||
## [0.5.0] — 2026-05-29 — Track history + favourites
|
||
|
||
SomaFM plays deep cuts you'll never hear again. v0.5.0 quietly logs every track that scrolls past so you can find it again later — and a star button keeps the ones worth keeping forever.
|
||
|
||
### Added — `Radio → History` admin page (per-user)
|
||
- **History tab** — capped FIFO list of the last 500 played tracks. Each row shows when (relative time, full timestamp on hover), station, *artist — title*, four search links, and a favourite-star toggle.
|
||
- **Favourites tab** — uncapped list of starred tracks. Same row layout. Survives even when the history rolls over.
|
||
- **Filter** by artist/title (live, client-side) and by station (dropdown). **Clear history** button on the History tab — favourites preserved.
|
||
- **Four search providers** per row, brand-tinted on hover: **Spotify** (green), **YouTube** (red), **Apple Music** (pink), **Bandcamp** (teal). Deep-link search URLs only — no API keys, no third-party JS.
|
||
- Empty-state messages on both tabs.
|
||
|
||
### Added — automatic logging during playback
|
||
- `fetchTrack` (the existing 30s SomaFM polling loop) now hands every new track to a new `logTrackIfNew` helper that POSTs it to `wp_ajax_radio_log_track`.
|
||
- **Dedup**: client-side via `lastLoggedSig` so the 30s polling doesn't re-log the same song; server-side against the last entry in user_meta as belt-and-braces.
|
||
- **Junk filtering**: `(unknown)` artists and entries missing artist *or* title are dropped server-side in `radio_sanitize_entry`.
|
||
|
||
### Added — per-user storage
|
||
- Two new `user_meta` keys, separate from `radio_state` so frequent track inserts don't churn the player-state blob:
|
||
- `radio_history` — capped at **500 entries** (~50–80 KB max).
|
||
- `radio_favourites` — uncapped, expected to stay small (user-curated).
|
||
|
||
### Added — three new AJAX endpoints
|
||
- `wp_ajax_radio_log_track` — append a track (nonce: `radio_save_state`; player-page only).
|
||
- `wp_ajax_radio_toggle_favourite` — toggle a track in favourites (nonce: `radio_history`; History-page only).
|
||
- `wp_ajax_radio_clear_history` — clear the history list (nonce: `radio_history`; History-page only). Favourites untouched.
|
||
|
||
### Notes
|
||
- Per-user — nothing is shared, nothing leaves the site. Just your own listening history on your own WP account.
|
||
- **No PII concern** — entries are public station/artist/title strings from SomaFM's own JSON.
|
||
- Search-link UI tints toward each provider's brand colour on hover only — keeps the row visually calm in the default state.
|
||
|
||
**Files changed:** `radio.php` (version, require, submenu, asset enqueue hook, three AJAX endpoints, three new localized strings), **new** `inc/history.php` (storage helpers + page renderer), `assets/css/radio.css` (history-page table, toolbar, search-link pills, favourite star, dark-theme overrides), `assets/js/radio.js` (`logTrackIfNew` wired into `fetchTrack`; `bindHistoryPage` for filter/favourite/clear), `inc/about.php` (history entry).
|
||
|
||
---
|
||
|
||
## [0.4.0] — 2026-05-29 — Now-playing indicator: dancing bars + Web Audio visualizer
|
||
|
||
A small visual that instantly says *"this is playing right now."* Two layers — a reliable CSS-only indicator that always works, and a progressive Web Audio upgrade that draws actual frequency data when the browser allows.
|
||
|
||
### Added — dancing bars (always on, CSS only)
|
||
- Four tiny vertical bars next to the "Now Playing" label that pulse with a staggered `@keyframes` animation while the audio is playing, settling to a low static state when paused. Pure CSS — no JS dependency, no audio analysis.
|
||
- Bars use `var(--wp-admin-theme-color)` so they tint to whichever WP admin colour scheme the user has chosen.
|
||
- Driven by a single `.is-playing` class toggled on the `.radio-player` surface from the existing `play` / `pause` / `error` audio handlers.
|
||
|
||
### Added — Web Audio frequency visualizer (progressive upgrade)
|
||
- On first `play`, `tryVisualizer` builds an `AudioContext` + `AnalyserNode` chain on the `<audio>` element and starts drawing live frequency bars on a `<canvas>` next to "Now Playing."
|
||
- `<audio>` now carries `crossorigin="anonymous"` so the Web Audio analyser can actually read the stream data (SomaFM serves the CORS headers).
|
||
- **Graceful fallback:** if `AudioContext` isn't available, or `createMediaElementSource` throws, or the analyser returns all-zeros for 2 s (CORS silently blocking), the visualizer state flips to `cors-blocked` / `init-failed` / `no-webaudio` and the CSS dancing bars remain — the plugin never loses its indicator.
|
||
- Canvas is sized to its CSS box × `devicePixelRatio` so it stays crisp on retina screens.
|
||
|
||
### State machine on `player._vizState`
|
||
| Value | Meaning |
|
||
|---|---|
|
||
| _undefined_ | not yet attempted |
|
||
| `no-webaudio` | browser lacks `AudioContext` |
|
||
| `init-failed` | `createMediaElementSource` threw |
|
||
| `cors-blocked` | analyser returned zeros for >2 s |
|
||
| `ok` | live frequency data flowing → canvas shown, bars hidden |
|
||
|
||
**Files changed:** `radio.php` (version), `inc/admin-page.php` + `inc/dashboard-widget.php` (added `.radio-player__indicator` with `.radio-player__bars` + `<canvas data-radio-viz>`, plus `crossorigin="anonymous"` on the `<audio>`), `assets/css/radio.css` (indicator container, bars + `radio-bars-dance` keyframes, canvas size), `assets/js/radio.js` (`tryVisualizer` / `startVizLoop` / `stopVizLoop`, `play/pause/error` handlers toggle `is-playing` class and drive the loop), `inc/about.php` (history entry).
|
||
|
||
---
|
||
|
||
## [0.3.2] — 2026-05-29 — Play-button glyph baseline fix
|
||
|
||
The dashicon used for the play/pause icon was rendering visibly below the button text baseline — the dashicon font sits the glyph low inside its own box, and even with `inline-flex` centering the result looked like the symbol was on a separate row from the word "Play".
|
||
|
||
### Fixed
|
||
- **Play/pause icon now sits on the text baseline.** Swapped the dashicon (`dashicons-controls-play` / `dashicons-controls-pause`) for a plain Unicode glyph (▶ / ‖) which renders on the text baseline like any other character.
|
||
- Flex container changed from `align-items: center` to `align-items: baseline` for the same reason.
|
||
- `font-variant-emoji: text` set so platforms that might otherwise pick up a colour-emoji variant for ▶ keep it as monochrome text.
|
||
|
||
**Files changed:** `radio.php` (version), `inc/admin-page.php` + `inc/dashboard-widget.php` (dashicon span → glyph span), `assets/css/radio.css` (drop the dashicon-sizing rule, add `.radio-player__play-glyph` styling, change play-button flex alignment to baseline), `assets/js/radio.js` (`setPlayIcon` now swaps glyph `textContent` instead of dashicon `className`), `inc/about.php` (history entry).
|
||
|
||
---
|
||
|
||
## [0.3.1] — 2026-05-29 — My Radio layout polish + drop dark-auto
|
||
|
||
Quick patch after a real-screen review of the My Radio admin page. v0.3.0 added a lot of features but stretched the player to fill the full admin width and — embarrassingly — introduced a real contrast bug via the dark-auto CSS.
|
||
|
||
### Fixed
|
||
- **Dropped `@media (prefers-color-scheme: dark)` for `theme=auto`.** WordPress admin has no native dark mode, so when the OS was dark, our dark text rendered on the still-white WP postbox = unreadable. `auto` now behaves as light (matching WP's actual scheme); `dark` is still available as an explicit choice.
|
||
- **`theme=dark` now actually reads.** The player surface goes dark (`#1d2327` background + subtle border + padding) so the light text has somewhere to sit, instead of fighting the white WP postbox.
|
||
- **Player no longer stretches edge-to-edge.** `.radio-wrap { max-width: 880px; }` keeps the player a focused settings-page card.
|
||
- **Intro paragraph one-line on normal widths.** Removed the `max-width: 720px` cap that was forcing the wrap.
|
||
- **Volume slider no longer dominates the row.** Fixed width 220px (`flex: 0 0 auto`) — the percent label now sits next to the slider instead of pinned to the far right edge.
|
||
- **Station dropdown** capped at 360px (was full-width) — typical WP form-control width.
|
||
- **Play button icon** shrunk from 18px to 14px so the ▶ glyph sits on the button-text baseline instead of looking like a separate row.
|
||
|
||
**Files changed:** `radio.php` (version), `assets/css/radio.css` (wrap width, intro, play icon, volume, station-select, dark-auto block deleted, dark-surface added), `inc/about.php` (history entry).
|
||
|
||
---
|
||
|
||
## [0.3.0] — 2026-05-29 — Dark theme + mute + media keys + current-track display
|
||
|
||
A polish pass that closes the gaps surfaced by a UI review. Two categories: **2nd-look fixes** (things the previous release implied but didn't actually deliver) and **nice-to-haves** (small upgrades that lift the admin-player feel).
|
||
|
||
### Added — features
|
||
- **Mute toggle on the speaker icon.** The icon next to the volume slider is now a button. Click to mute (icon flips to `dashicons-controls-volumeoff`, tinted red); click again to restore the prior volume. Remembers volume across mute/unmute via `data-prev-volume`.
|
||
- **MediaSession API integration.** OS media keys (F8/F9 on Mac, Bluetooth headphone buttons, lock-screen widget on supported platforms) now play/pause the radio. The currently-playing station name, "SomaFM" as artist, and the genre as album are exposed as `MediaMetadata` so they show on the OS overlays.
|
||
- **Current-track display.** Polls `https://somafm.com/songs/{code}.json` every 30 seconds **while playing only** and shows the track as `♪ Title — Artist` under the station description. Best-effort: silently hidden if the endpoint is unreachable / CORS-blocked, so the plugin keeps working regardless.
|
||
|
||
### Fixed — 2nd-look
|
||
- **Dark theme is now actually wired through.** v0.2.0 saved the Theme dropdown (auto / light / dark) but had no CSS to render anything other than light. v0.3.0 adds `admin_body_class` filter → `radio-theme-{auto,light,dark}` body class → corresponding dark-palette CSS for the player + about-cards. `auto` follows the OS via `prefers-color-scheme: dark`.
|
||
- **Settings-page volume slider** no longer uses an inline `oninput=""` handler — the listener moved into `assets/js/radio.js` (`bindSettingsSlider`). Cleaner under strict-CSP environments.
|
||
- **Save errors are surfaced.** AJAX state-save failures were previously swallowed silently — the local UI updated but the user had no signal if the server dropped the request. The plugin now shows a brief notice ("Preferences not saved — check your connection.") in the player's error slot for 3.5 s, then auto-clears.
|
||
- **Hardcoded Gitea URL** in the About page replaced with a `RADIO_GITEA_URL` constant defined in `radio.php`. One place to update if the repo ever moves.
|
||
- **Genre badge layout fix.** Was using `margin-left: auto` inside a wrap-enabled flex row, which caused it to land on its own line on narrow widget widths. Now styled as a small inline pill (rounded `rgba(0,0,0,0.06)` background) that flows naturally next to the station name.
|
||
|
||
### Other
|
||
- Plugin version bumped to **0.3.0**.
|
||
- New localized strings: `mute`, `unmute`, `saveError` (for the JS-driven UI).
|
||
- The mute button has a visible focus ring (`outline: 2px solid var(--wp-admin-theme-color)`) for keyboard navigation.
|
||
- Volume slider input now also exits mute state (sets `audio.muted = false` on drag), so dragging the slider always overrides a prior mute click.
|
||
|
||
**Files changed:** `radio.php` (version, constant, strings, `admin_body_class` filter), `inc/about.php` (constant for changelog URL), `inc/settings.php` (removed inline `oninput`), `inc/admin-page.php` + `inc/dashboard-widget.php` (speaker icon → mute button, added track slot), `assets/css/radio.css` (genre badge pill, mute button, track display, dark-theme rules incl. `prefers-color-scheme` for `auto`), `assets/js/radio.js` (full rewrite incl. `bindMute`, `bindSettingsSlider`, `startTrackPolling`/`stopTrackPolling`, `updateMediaSession`, save-error surfacing).
|
||
|
||
---
|
||
|
||
## [0.2.0] — 2026-05-26
|
||
|
||
### Changed — UI rebuilt to WordPress admin standards
|
||
v0.1.0 worked but looked like a third-party React widget sitting on top of WordPress rather than part of it. v0.2.0 rebuilds the player UI to use WP-native patterns end-to-end.
|
||
|
||
- **Main page** now uses the standard **`.postbox` container** (gray header bar + `.inside` body) instead of a custom rounded-shadow card.
|
||
- **Play button** is now a standard **`.button .button-primary`** with both icon AND text label (Play / Pause), matching every other admin button. Replaces the giant blue circular icon-only button.
|
||
- **Now Playing** uses left-aligned default body text with `.description` muted-gray for the station tagline. Replaces the centered large-typography card.
|
||
- **Genre badge** moved to a small `.radio-player__station-genre` text label aligned right of the station name. Replaces the custom pill.
|
||
- **Volume slider** now uses `accent-color: var(--wp-admin-theme-color)` — adapts to whichever admin colour scheme the user has chosen (Default / Light / Modern / Blue / Coffee / Ectoplasm / Midnight / Ocean / Sunrise).
|
||
- **All link colours** likewise adapt to the user's admin theme via `var(--wp-admin-theme-color, #2271b1)`.
|
||
- **Dashboard widget** content sits bare inside its `.inside` — WordPress already wraps it in a postbox. v0.1.0 was rendering a card inside a card.
|
||
- **About page** cards now use postbox-style gray header bars + WP-standard 1px border + subtle shadow. Replaces the custom rounded grid.
|
||
- **Credit footer** uses `.description` class, smaller and more native.
|
||
|
||
### Net effect
|
||
The plugin feels like part of WordPress now, not bolted onto it. Picks up your admin colour scheme automatically. Closer to WP.org submission criteria — they look for native-styled plugins during plugin review.
|
||
|
||
### Not changed
|
||
- Functionality identical to v0.1.0 — same 44 stations, same audio path, same user_meta persistence, same updater, same AJAX endpoint.
|
||
- No behaviour change for end users; this is purely visual.
|
||
- About page version-history card promotes v0.2.0 to "latest", demotes v0.1.0.
|
||
|
||
---
|
||
|
||
## [0.1.0] — 2026-05-26
|
||
|
||
**Radio is born.** First release of a new standalone WordPress plugin extracted-and-rebuilt from the radio feature that lives inside RangerPlex. Radio stands on its own as a focused, friendly companion plugin for the WordPress dashboard — a tab of background music while you work.
|
||
|
||
### Added — Phase A complete (player exists)
|
||
- **Dashboard widget** at WP Admin → Dashboard showing a compact mini-player with play/pause, station select grouped by genre, and a volume slider.
|
||
- **Dedicated admin page** at WP Admin → Radio → My Radio showing the same controls in a larger format with the station's genre badge and description.
|
||
- **44 SomaFM stations** across **10 genres** (Ambient, Electronic, Lounge, Rock, Metal, Jazz, World, Reggae, Holiday, Specials). Stream URLs use SomaFM's public 128kbps MP3 endpoints — no proxy server required.
|
||
- **Per-user state storage** via `user_meta` (key: `radio_state`). Each WordPress admin remembers their own station choice, volume, and theme preference.
|
||
- **Settings page** at WP Admin → Radio → Settings with default station, default volume, theme (auto/light/dark), and an opt-out for the dashboard widget. Updates panel shown to admins with `manage_options`.
|
||
- **About page** at WP Admin → Radio → About with plain-language explanation of what the plugin does, who it's for, version history, and credits to SomaFM.
|
||
- **Self-hosted update checker** wired up to the Gitea repo (`ranger/a-radio`) from commit 1. Polls `/api/v1/repos/ranger/a-radio/releases/latest` with a `/tags?limit=1` fallback. 12h success cache, 1h negative cache.
|
||
- **AJAX endpoint** `radio_save_state` for persisting station/volume changes without a page reload. Nonce-protected, capability-checked.
|
||
- **Custom admin-menu icon** (`dashicons-format-audio`).
|
||
- **Direct HTML5 `<audio>` playback** — no Node proxy, no PHP stream-passthrough, no server-side resource cost per listener. SomaFM's CORS headers make this work out of the box in modern browsers.
|
||
|
||
### Architecture (locked from day one)
|
||
- **Single-word brand name `Radio`** — no "WP" prefix, no marketplace trademark hurdle.
|
||
- **Public GPL v2+ Gitea repo** at `ranger/a-radio` on `git.davidtkeane.com`.
|
||
- **Per-user state in `user_meta`** under key `radio_state`.
|
||
- **Vanilla JS only** — no React, no build step, no bundler. ~200 lines of JS controlling all interactions.
|
||
- **CSS-only animations, all assets local** — bundle stays sub-100KB.
|
||
- **Single H1 per admin page**, no nested toggle boxes — Tier-1 discipline carried forward from the Logbook + Buddy lineage.
|
||
- **Sanitize on input, escape on output** throughout. Every AJAX endpoint nonce-protected and capability-checked.
|
||
|
||
### Compliance
|
||
- Station list and stream URLs are SomaFM's public, freely-published endpoints. Their terms allow redistribution with attribution.
|
||
- "Powered by SomaFM" credit displayed in both player surfaces, linking to somafm.com.
|
||
- The About page invites users to donate to SomaFM directly.
|
||
|
||
### Not in this release (planned)
|
||
- Phase B — Settings polish + README for WP.org submission + retry logic for transient stream errors.
|
||
- Phase C — Now-playing metadata via SomaFM's per-station song-history endpoint.
|
||
- Phase D — `[ranger_radio]` shortcode so the player can be embedded in posts/pages.
|
||
- Phase E — Favorites system.
|
||
- Phase F — Multi-provider (Radio Paradise, NTS Radio, KEXP, BBC) with a provider abstraction.
|