c7b2258471502a8b12a934350ebf1879a5c06aea
12 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
09b61cc950 |
feat(0.7.0): WordPress.org submission prep — full Plugin Check clean
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>
|
||
|
|
224fccd6c4 |
feat(0.6.3): discreet "buy me a coffee" support link
Tiny footer line inside the Updates panel on Settings + matching line at the bottom of the Credits + thanks card on About. Pulled from a single RADIO_SUPPORT_URL constant so both stay in sync. Conditional render — if the constant is empty, the link is silently hidden, so forks can strip funding with one line. Design intent: muted (12px, admin-theme-coloured, subtle top divider). Reads as housekeeping not a sales pitch — no yellow BMC brand chrome. Dark-theme divider override so it stays subtle on the dark surface. Files: radio.php (version, RADIO_SUPPORT_URL constant default https://buymeacoffee.com/davidtkeane), inc/updater.php (link in Updates panel), inc/about.php (link in Credits + thanks card; rotate v0.6.3 → latest, v0.6.2 → earlier list), assets/css/radio.css (.radio-support-link + dark-theme override), CHANGELOG.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
32a3040e39 |
feat(0.6.2): current version badge on Settings page
Small grey pill follows the "Radio — Settings" H1 — 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 so it stays readable when theme=dark.
Files: radio.php (version), inc/settings.php (<span> inside H1),
assets/css/radio.css (.radio-version-badge + dark override),
inc/about.php (rotate v0.6.2 into latest expanded slot, v0.6.1 into
earlier-releases list), CHANGELOG.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
7a747b829b |
fix(0.6.1): About page restructure — balance the layout
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. - Three short cards on top (What / Who / Credits) — equal-height, balanced row. Credits gets equal billing instead of being a fourth card buried under a wall of version notes. - Version history is its own full-width card below. Only the latest release is shown in full; earlier releases collapse to one line each. 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 via the existing "View the full CHANGELOG.md →" link. Single source of truth. Files: 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 (drop dead .radio-about-card--versions rules; add .radio-about-versions + __latest + __earlier; dark-theme overrides). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
0dc3a220d9 |
feat(0.6.0): pop-out mini-player — continuous background play across admin nav
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.
Pop-out window
- Small "↗ Pop out" button beside the Play button on both the main
Radio page and the Dashboard widget.
- Opens a 380×560 standalone window via window.open() with a window
name of `radio_popout` so a second click re-focuses the existing
popup rather than spawning a new one.
- Popup renders at admin-post.php?action=radio_popout&play=1 — a new
admin_post_radio_popout hook outputs a full standalone HTML page
(custom DOCTYPE / head / body, no WP admin chrome).
- Theme follows radio_state['theme'] via body class radio-theme-{...}.
- Includes the full player (now-playing block with dancing bars +
Web Audio visualizer, play, mute, volume, station dropdown, error
slot). Close button calls window.close().
Auto-resume + single-stream invariant
- cfg.autoPlay is true when the popup URL carries &play=1. radio.js
auto-calls audio.play() 200 ms after init. Same-origin user-gesture
popups are exempt from autoplay-blocking on every modern browser.
- On pop-out click, every other audio surface in the parent tab is
paused so there is only ever one stream playing.
State stays in sync
- Popup uses the SAME radio_save_state AJAX + track-logging endpoint.
Station / volume changes persist to user_meta; track history keeps
accumulating from whichever surface is playing.
Edge cases
- Inside the popup, cfg.popoutUrl is '' so bindPopOut hides any
Pop-out button it finds (would be infinite otherwise).
- Popup blocked by browser → clear alert tells the user to allow
popups for this site.
Files
- radio.php (version, popoutUrl in localized config, admin_post
handler + full standalone HTML renderer)
- inc/admin-page.php + inc/dashboard-widget.php (Pop-out button
beside Play)
- assets/css/radio.css (.radio-player__popout styling)
- assets/js/radio.js (bindPopOut function; autoPlay branch in
bindPlayer)
- inc/about.php + CHANGELOG.md (history entries)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
2bd501d610 |
feat(0.5.0): track history + favourites with four search providers
Quietly log every track that scrolls past the player to a per-user
history (capped 500). A star button promotes the good ones to a
separate Favourites tab that doesn't age out. Each row has four
search-provider deep links so you can find the track on whichever
service you use.
Storage
Two new user_meta keys (separate from radio_state so frequent
inserts don't churn the player-state blob):
- radio_history — capped FIFO of last 500 played tracks
- radio_favourites — uncapped user-starred list
New page: Radio → History
- History tab: capped FIFO list, newest first.
- Favourites tab: starred tracks (uncapped).
- Each row: when (relative + full timestamp on hover) / station /
artist — title / four search links / favourite-star toggle.
- Filter by artist/title (live, client-side) + by station (dropdown).
- Clear history button (favourites preserved).
- Search providers: Spotify, YouTube, Apple Music, Bandcamp.
Deep-link URLs only — no API keys, no third-party JS.
Auto-logging during playback
fetchTrack (existing 30s SomaFM poll loop) now hands new tracks to
logTrackIfNew → POST to wp_ajax_radio_log_track. Dedup client-side
(lastLoggedSig) AND server-side (against last entry in user_meta).
Junk filtered server-side: (unknown) artist, missing artist/title.
New AJAX endpoints
- radio_log_track (nonce radio_save_state — player pages)
- radio_toggle_favourite (nonce radio_history — history page only)
- radio_clear_history (nonce radio_history — history page only)
Files
- radio.php (version, require new include, submenu page, asset
enqueue hook adds radio_page_radio-history, three AJAX endpoints,
three new localized strings)
- inc/history.php (NEW — storage helpers + admin page renderer)
- assets/css/radio.css (history table, toolbar, search-link pills,
favourite star, dark-theme overrides)
- assets/js/radio.js (logTrackIfNew wired into fetchTrack;
bindHistoryPage handles filter/favourite/clear)
- inc/about.php (history entry)
- CHANGELOG.md (full entry)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
f5feca7dfa |
feat(0.4.0): now-playing indicator — dancing bars + Web Audio visualizer
Two-layer "this is playing right now" visual:
(1) CSS dancing bars — four tiny vertical bars next to the "Now Playing"
label, staggered `@keyframes` pulse while audio plays. Pure CSS, no
JS dependency, tints to the user's WP admin colour scheme via
var(--wp-admin-theme-color). Driven by a single `.is-playing` class
on `.radio-player` toggled from the existing play/pause/error
handlers. Always works.
(2) Web Audio frequency visualizer (progressive upgrade) — on first play,
builds AudioContext + AnalyserNode + canvas drawing pipeline. When
the analyser starts returning real (non-zero) data, hides the bars
and shows the canvas with live frequency bars. Falls back to bars
if AudioContext is unavailable, createMediaElementSource throws, or
the analyser returns all-zeros for >2s (CORS silently blocking).
State machine on player._vizState: no-webaudio / init-failed /
cors-blocked / ok.
`<audio>` element gained `crossorigin="anonymous"` so Web Audio can read
the stream data (SomaFM serves the CORS headers).
Files: radio.php (version), inc/admin-page.php + inc/dashboard-widget.php
(.radio-player__indicator with .radio-player__bars + canvas; crossorigin
on audio), assets/css/radio.css (indicator, bars, radio-bars-dance
keyframes, canvas size), assets/js/radio.js (tryVisualizer,
startVizLoop, stopVizLoop; play/pause/error handlers wire the loop and
toggle is-playing), inc/about.php (history entry).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
a56fd7aff7 |
fix(0.3.2): play-button glyph baseline — drop dashicon for Unicode ▶ / ‖
The dashicon used for the play/pause icon was rendering visibly below the button text — dashicon font metrics sit the glyph low inside its own box, so even with `inline-flex` centering the symbol looked like it was on a separate row from the word "Play". Swap dashicons-controls-play / dashicons-controls-pause for plain Unicode glyphs (▶ / ‖) which render on the text baseline like any other character. Flex container changed to align-items: baseline. font-variant-emoji: text on the glyph span to keep platforms that might otherwise pick up an emoji variant of ▶ as monochrome text. Files: radio.php (version), inc/admin-page.php + inc/dashboard-widget.php (dashicon span → glyph span), assets/css/radio.css (drop dashicon-sizing rule, add .radio-player__play-glyph, baseline alignment), assets/js/radio.js (setPlayIcon swaps glyph textContent instead of dashicon className), inc/about.php (history entry). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
774e7f9958 |
fix(0.3.1): My Radio layout polish + drop dark-auto
Real-screen review of v0.3.0 surfaced a contrast bug and several layout issues. Quick patch. - Drop @media prefers-color-scheme dark for theme=auto. WP admin has no native dark mode, so OS-dark made our light text sit on the still- white WP postbox = unreadable. `auto` now behaves as light; `dark` remains as an explicit choice. - theme=dark now actually reads: the player surface itself goes dark (#1d2327 bg + subtle border + padding) so the light text has somewhere to land instead of fighting the white WP postbox. - .radio-wrap max-width 880px — player no longer stretches edge-to-edge. - Drop the .radio-intro max-width:720px cap so the intro fits one line. - Volume slider fixed at flex:0 0 auto / width:220px — % label sits next to the slider instead of pinned to the far edge. - Station dropdown capped at 360px (was width:100%). - Play-button dashicon shrunk 18px → 14px so it sits on the button-text baseline instead of looking like a second row. Files: radio.php, assets/css/radio.css, inc/about.php, CHANGELOG.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
c5a4b28b29 |
feat(0.3.0): dark theme, mute, media keys, current-track + 2nd-look fixes
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> |
||
|
|
3e6994461e |
feat: v0.2.0 — UI rebuilt to WordPress admin standards
v0.1.0 worked but felt like a third-party React widget bolted on
top of WordPress. v0.2.0 makes the player visually native to the
WP admin: postbox container, standard Play/Pause button with text
label, admin-colour-scheme aware accents, dashboard widget no
longer renders a card inside a card.
CHANGES
- inc/admin-page.php: main page now wraps the player in a
.postbox > .postbox-header (with h2.hndle) > .inside structure.
Custom rounded card / shadow stripped.
- inc/dashboard-widget.php: bare .radio-player content; WP already
wraps dashboard widgets in a postbox, was double-card before.
- inc/about.php: version-history card promotes v0.2.0 to latest,
demotes v0.1.0.
- assets/css/radio.css: rewrite. Strip custom shadows + oversized
typography. Adopt WP body-text defaults. Use
var(--wp-admin-theme-color, #2271b1) for volume-slider accent +
link colours so the plugin picks up whichever admin colour
scheme the user has chosen. About-page cards now use the
postbox-style gray header + 1px border pattern.
- assets/js/radio.js: setPlayIcon() also flips the visible text
label ("Play" ↔ "Pause"), not just the icon class. mirrorSelection()
also updates the [data-radio-genre] element so the genre label
stays in sync across surfaces.
- radio.php: Version: 0.1.0 -> 0.2.0; BUDDY_VERSION constant
bumped likewise.
- CHANGELOG.md: new [0.2.0] entry explaining the visual overhaul.
NET EFFECT
- Same 44 stations, same audio path, same persistence, same
updater, same AJAX endpoint. Pure visual change.
- The plugin now looks like part of WordPress admin instead of a
guest widget.
- Closer to WP.org submission criteria — plugin reviewers look
for native-styled plugins.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
a22ddfb6d3 |
chore: initial commit — Radio v0.1.0 (Phase A complete)
First release of a-radio — a free, focused SomaFM player for the
WordPress admin. Extracted-and-rebuilt from RangerPlex's RadioPlayer
component, simplified along the way (no Node CORS proxy needed; the
browser plays SomaFM streams directly).
Phase A deliverables — all in this commit:
PLAYER SURFACES
- Dashboard widget on WP Admin → Dashboard (compact: play/pause +
station select + volume).
- Dedicated admin page at WP Admin → Radio → My Radio (larger
layout, station genre badge, volume %% display).
- Both surfaces share the same JS — picking a station on one mirrors
to the other within the same admin session.
STATIONS
- 44 SomaFM stations grouped by 10 genres (Ambient / Electronic /
Lounge / Rock / Metal / Jazz / World / Reggae / Holiday / Specials).
- Ported verbatim from RangerPlex's RadioPlayer.tsx.
- Default station: Groove Salad (most popular SomaFM channel, safe
ambient/coding pick).
STATE
- Per-user state stored in user_meta under key `radio_state`:
{ station_id, volume, theme, last_played_at }.
- Settings page lets the user pick default station, default volume,
theme (auto/light/dark), and hide the dashboard widget.
- AJAX endpoint `radio_save_state` persists changes without a page
reload. Nonce-protected, capability-checked, only known keys
accepted, station validated against the list, volume clamped to
[0,1].
UPDATES
- Self-hosted updater wired to Gitea (ranger/a-radio) from commit 1.
- Direct port of Buddy's inc/updater.php with BUDDY_* → RADIO_* and
buddy_* → radio_* renames. Same 12h-success / 1h-error caching.
ARCHITECTURE
- No `wp` prefix (trademark policy).
- GPL v2+ public Gitea repo from day one.
- Vanilla JS only — no React, no webpack, no minified-only files.
- CSS-only animations, all assets local.
- Single H1 per admin page.
- Direct HTML5 <audio> playback (SomaFM has CORS headers; no PHP
audio proxy needed). This is the key simplification vs RangerPlex.
COMPLIANCE
- "Powered by SomaFM" credit displayed on both player surfaces with
link to somafm.com. About page invites users to donate to SomaFM
directly.
PHASE PROGRESSION (not in this commit)
- Phase B — Settings polish + retry on transient stream errors +
README.md formatted for WP.org submission.
- Phase C — Now-playing metadata via SomaFM's per-station song
history endpoint (this is where the RangerPlex proxy logic ports
to — server-side, for metadata not audio).
- Phase D — [ranger_radio] shortcode for frontend embedding.
- Phase E — Favorites system.
- Phase F — Multi-provider (Radio Paradise / NTS / KEXP / BBC).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|