Closes the gaps from a UI review of v0.2.0. Added - Mute toggle: speaker icon is now a button; remembers prior volume. - MediaSession API: OS media keys / headphone buttons / lock-screen widget play/pause the radio. Metadata exposes station + SomaFM + genre. - Current-track display: polls https://somafm.com/songs/{code}.json every 30s while playing; shown as `♪ Title — Artist` under the description. Best-effort — silently hidden if CORS-blocked / unreachable. Fixed (2nd-look) - Dark theme now actually renders. v0.2.0 saved the dropdown but had no CSS — add `admin_body_class` filter + `radio-theme-{auto,light,dark}` CSS for the player + about-cards. `auto` follows OS prefers-color-scheme. - Settings-page volume slider: removed inline `oninput`; wired in radio.js via `bindSettingsSlider()`. Cleaner under strict CSP. - Save errors surface as a transient notice instead of being swallowed. - Gitea changelog URL moved into `RADIO_GITEA_URL` constant. - Genre badge restyled as an inline pill (was using `margin-left: auto` which wrapped poorly on narrow widget widths). Files - radio.php (version, constant, strings, body-class filter) - inc/about.php (use constant, add 0.3.0 history entry) - inc/settings.php (drop inline oninput) - inc/admin-page.php + inc/dashboard-widget.php (mute button, track slot) - assets/css/radio.css (pill, mute, track, dark-theme rules) - assets/js/radio.js (rewrite: mute, MediaSession, track polling, settings slider, save-error surfacing) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.1 KiB
Changelog
All notable changes to Radio are documented here. Format: Keep a Changelog 1.1.0 — versioning: SemVer.
[Unreleased]
[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 viadata-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
MediaMetadataso they show on the OS overlays. - Current-track display. Polls
https://somafm.com/songs/{code}.jsonevery 30 seconds while playing only and shows the track as♪ Title — Artistunder 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_classfilter →radio-theme-{auto,light,dark}body class → corresponding dark-palette CSS for the player + about-cards.autofollows the OS viaprefers-color-scheme: dark. - Settings-page volume slider no longer uses an inline
oninput=""handler — the listener moved intoassets/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_URLconstant defined inradio.php. One place to update if the repo ever moves. - Genre badge layout fix. Was using
margin-left: autoinside 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 (roundedrgba(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 = falseon 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
.postboxcontainer (gray header bar +.insidebody) instead of a custom rounded-shadow card. - Play button is now a standard
.button .button-primarywith 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
.descriptionmuted-gray for the station tagline. Replaces the centered large-typography card. - Genre badge moved to a small
.radio-player__station-genretext 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
.descriptionclass, 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/latestwith a/tags?limit=1fallback. 12h success cache, 1h negative cache. - AJAX endpoint
radio_save_statefor 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-radioongit.davidtkeane.com. - Per-user state in
user_metaunder keyradio_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.