1 Commits

Author SHA1 Message Date
ranger 340cbb2487 v0.7.5 — WordPress.org slug rename: a-radio → rangerhq-radio
A third-party AI-driven naming check flagged `a-radio` as too
generic for the wp.org Plugin Directory (single common functional
word, no distinguishing prefix). The verdict was advisory but
defensible — short generic slugs are increasingly rejected as the
directory grows past 60K plugins. Fixing it preemptively is cheaper
than facing a rejection at submission time.

The new slug `rangerhq-radio` matches the public display name
"RangerHQ Radio" (unchanged) and lines up with the rest of the
RangerHQ plugin family: `rangerhq-spatial`, `rangerhq-glyph`,
now `rangerhq-radio`.

Changes (packaging only — no player behaviour change):
* Text Domain `a-radio` → `rangerhq-radio` across all 125 i18n
  call sites via in-place sed (esc_html__, _e, __, esc_attr_e
  and their friends). PHP lint clean post-rename.
* `Text Domain:` plugin header in radio.php line 15 → `rangerhq-radio`.
* `RADIO_GITEA_URL` constant value → new Gitea repo URL.
* README.md install link → new repo URL.
* readme.txt FAQ Gitea link → new repo URL.
* readme.txt Stable tag → 0.7.5.
* inc/about.php — v0.7.5 in "latest" slot; v0.7.4 demoted.

Unchanged deliberately (would have been pure churn):
* Plugin Name header "RangerHQ Radio" — already correct.
* Plugin URI.
* Internal constants `RADIO_*` — don't have to match slug.
* User-meta keys `radio_state` / `radio_history` /
  `radio_favourites` — renaming would orphan every existing
  user's settings on upgrade.
* HTML `data-radio-*` attributes — JS controller's element
  selectors in radio.js, not slug-related.
* CSS class names `radio-player`, `radio-about-*` — internal
  scoping.
* Main plugin file name `radio.php`.

Migration: existing Gitea-installed copies need their folder
renamed on disk (a-radio → rangerhq-radio) + reactivation in
WP admin. No data loss because all user-facing state lives in
user_meta under unchanged keys.

This commit is the file content for v0.7.5; the annotated tag
and push will follow the Gitea repo rename (ranger/a-radio →
ranger/rangerhq-radio) so the new tag lives in the new URL
space from the start.
2026-05-30 04:55:39 +01:00
9 changed files with 182 additions and 131 deletions
+44
View File
@@ -9,6 +9,50 @@ Format: [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) — versi
--- ---
## [0.7.5] — 2026-05-30 — WordPress.org slug rename: `a-radio` → `rangerhq-radio`
A third-party AI-driven naming-check tool (run via Plugin Check's Claude AI connector against the v0.7.4 build) flagged the slug as too generic for the wp.org Plugin Directory:
> The display name "a-radio" is too generic. The term "radio" is a broadly used, common functional word, and the single-letter prefix "a-" does not add meaningful distinctiveness or describe what the plugin actually does. With 60,000+ plugins in the directory, a name this short and generic makes it hard for users to identify the plugin and distinguish it from others.
The verdict was advisory (not the official wp.org reviewer) but defensible — single-word generic slugs are increasingly rejected by human reviewers as the directory grows. Better to fix it preemptively than face a rejection at submission time.
The new slug `rangerhq-radio` matches the public display name "RangerHQ Radio" (which is unchanged) and lines up with the rest of the RangerHQ plugin family: `rangerhq-spatial`, `rangerhq-glyph`, now `rangerhq-radio`. Consistent prefix, distinctive enough for the directory, descriptive of what the plugin does.
### Changed
- **Plugin slug** `a-radio``rangerhq-radio`. The slug is the plugin's folder name + the URL fragment at `wordpress.org/plugins/<slug>/`. Folder renamed on disk; Gitea repository moved from `ranger/a-radio` to `ranger/rangerhq-radio` (history + tags + issues preserved by Gitea's rename).
- **Text Domain** `a-radio``rangerhq-radio` to match the slug (wp.org best practice + PCP `textdomain_mismatch` requirement). All 125 i18n call sites updated via in-place `sed` across every `*.php` file: `__()`, `_e()`, `esc_html__()`, `esc_html_e()`, `esc_attr__()`, `esc_attr_e()`, and the translator-comment arguments. PHP lint clean post-rename.
- **`Text Domain:` plugin header** in `radio.php` line 15 updated to match.
- **`RADIO_GITEA_URL` constant** value updated from `https://git.davidtkeane.com/ranger/a-radio` to `https://git.davidtkeane.com/ranger/rangerhq-radio` to follow the Gitea repo rename. The constant name stays the same (internal naming; no churn).
- **Install URL in root `README.md`** — repo link in the install step updated.
- **Gitea issue link in `readme.txt` FAQ** — updated to the new repo URL.
- **`readme.txt` Stable tag** → `0.7.5`.
- **`inc/about.php` Version history** — v0.7.5 rotated into the "latest" slot; v0.7.4 demoted to a one-liner in the earlier-releases list.
### Unchanged (deliberately — would have been pure churn)
- **Plugin Name header** (`RangerHQ Radio`) — already correct, distinctive, and brand-aligned.
- **Plugin URI** (`https://icanhelp.ie/radio`).
- **Internal PHP constants** (`RADIO_VERSION`, `RADIO_FILE`, `RADIO_PATH`, `RADIO_URL`, `RADIO_BASENAME`, `RADIO_GITEA_URL`, `RADIO_SUPPORT_URL`, `RADIO_META_KEY`). Constants don't have to match the slug; renaming them would have rippled through every PHP file for zero functional benefit.
- **User-meta keys** (`radio_state`, `radio_history`, `radio_favourites`). Renaming would have orphaned every existing user's settings + history + favourites on upgrade.
- **HTML `data-radio-*` attributes** in the player markup (`data-radio-play`, `data-radio-viz`, `data-radio-station`, etc.) — these are the JS controller's element selectors in `radio.js`, not slug-related. They share the word "radio" by coincidence; renaming would have required corresponding `radio.js` changes for zero benefit.
- **CSS class names** (`radio-player`, `radio-player__*`, `radio-about-*`, etc.) — same reasoning. Internal scoping.
- **Main plugin file name** (`radio.php`). WordPress doesn't require the main file to be named after the slug; it just has to exist in the slug folder. Many plugins ship with `<slug>/<short-name>.php`. Keeping `radio.php` saved a rename + a corresponding update to every git reference.
### Migration
- **wp.org installs** (once accepted): no migration — wp.org will accept the plugin under the new slug from day one.
- **Existing Gitea-installed copies** (the local dev install at `/Users/ranger/Local Sites/plugin-test/.../a-radio/` was renamed in-place to `.../rangerhq-radio/` as part of this release; M5 or other Gitea installs would need the same): deactivate the plugin in WP admin (so WP releases its hold on `a-radio/radio.php`), rename the folder on disk, reactivate via the new entry at `rangerhq-radio/radio.php`. WordPress's `active_plugins` option in `wp_options` is keyed on the basename (`folder/file.php`), so a folder rename appears to WP as an uninstall + a new install — but no data is lost because all user-facing state lives in `user_meta` under unchanged keys (`radio_state` / `radio_history` / `radio_favourites`).
- **Tags + git history**: preserved across the Gitea repo rename. The annotated tag for v0.7.5 was pushed AFTER the Gitea repo rename so it lives in the new URL space from the start.
### Why the slug matters even though "RangerHQ Radio" is fine
WordPress.org reviewers evaluate two strings independently — the **display name** (Plugin Name header, what users see in their admin) and the **slug** (folder name, what appears in the URL at `wordpress.org/plugins/<slug>/`). They have to be distinct enough that:
- Users can find the plugin via wp.org search.
- The URL is recognisable and not easily confused with other plugins.
- The slug doesn't collide with an already-registered plugin name.
"RangerHQ Radio" was always fine as the display name. The slug `a-radio` was the weak link — short, generic, with a non-descriptive prefix. `rangerhq-radio` is none of those things.
---
## [0.7.4] — 2026-05-30 — WordPress.org submission cleanup (updater out, LICENSE in) ## [0.7.4] — 2026-05-30 — WordPress.org submission cleanup (updater out, LICENSE in)
Walks back the Update URI guard pattern from v0.7.3 and replaces it with the simpler, actually-correct answer: just remove the custom updater entirely. The WordPress.org Plugin Check tool (PCP) raised `plugin_updater_detected` on the v0.7.3 build with the message *"Including An Update Checker / Changing Updates functionality. Plugin Updater detected. Use of the Update URI header is not allowed in plugins hosted on WordPress.org."* PCP scans the source as-shipped, not as-distributed, so the build-time `sed` strip we relied on in v0.7.3 never had a chance to run before the scan — and the scanner flagged both the header and the `inc/updater.php` file itself. Two options remained: (a) keep dancing around PCP with branches and build scripts, or (b) accept that WordPress.org is the canonical update channel once a plugin is hosted there and drop the custom system. We went with (b). Walks back the Update URI guard pattern from v0.7.3 and replaces it with the simpler, actually-correct answer: just remove the custom updater entirely. The WordPress.org Plugin Check tool (PCP) raised `plugin_updater_detected` on the v0.7.3 build with the message *"Including An Update Checker / Changing Updates functionality. Plugin Updater detected. Use of the Update URI header is not allowed in plugins hosted on WordPress.org."* PCP scans the source as-shipped, not as-distributed, so the build-time `sed` strip we relied on in v0.7.3 never had a chance to run before the scan — and the scanner flagged both the header and the `inc/updater.php` file itself. Two options remained: (a) keep dancing around PCP with branches and build scripts, or (b) accept that WordPress.org is the canonical update channel once a plugin is hosted there and drop the custom system. We went with (b).
+1 -1
View File
@@ -12,7 +12,7 @@ A small, focused, free WordPress plugin that drops a SomaFM radio player into yo
## Installation ## Installation
1. Download the latest release `.zip` from [git.davidtkeane.com/ranger/a-radio/releases](https://git.davidtkeane.com/ranger/a-radio/releases) 1. Download the latest release `.zip` from [git.davidtkeane.com/ranger/rangerhq-radio/releases](https://git.davidtkeane.com/ranger/rangerhq-radio/releases)
2. WP Admin → Plugins → Add New → Upload Plugin 2. WP Admin → Plugins → Add New → Upload Plugin
3. Activate 3. Activate
4. Look at **WP Admin → Dashboard** for the mini-player, or **WP Admin → Radio** 4. Look at **WP Admin → Dashboard** for the mini-player, or **WP Admin → Radio**
+32 -31
View File
@@ -14,48 +14,48 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
function radio_render_about_page() { function radio_render_about_page() {
if ( ! current_user_can( 'read' ) ) { if ( ! current_user_can( 'read' ) ) {
wp_die( esc_html__( 'You do not have permission to view this page.', 'a-radio' ) ); wp_die( esc_html__( 'You do not have permission to view this page.', 'rangerhq-radio' ) );
} }
$count = count( radio_get_stations_flat() ); $count = count( radio_get_stations_flat() );
?> ?>
<div class="wrap radio-about-wrap"> <div class="wrap radio-about-wrap">
<h1><?php esc_html_e( 'About Radio', 'a-radio' ); ?></h1> <h1><?php esc_html_e( 'About Radio', 'rangerhq-radio' ); ?></h1>
<!-- ── Top row: three short cards (What / Who / Credits) ── --> <!-- ── Top row: three short cards (What / Who / Credits) ── -->
<div class="radio-about-grid"> <div class="radio-about-grid">
<div class="radio-about-card"> <div class="radio-about-card">
<h2><?php esc_html_e( 'What Radio does', 'a-radio' ); ?></h2> <h2><?php esc_html_e( 'What Radio does', 'rangerhq-radio' ); ?></h2>
<p> <p>
<?php <?php
printf( printf(
/* translators: %d = station count */ /* translators: %d = station count */
esc_html__( 'Adds a small, focused radio player to your WordPress dashboard. %d hand-curated SomaFM stations across 10 genres — ambient, electronic, lounge, rock, metal, jazz, world, reggae, holiday and specials. Plays in your admin pages while you work. Your chosen station + volume persist per user.', 'a-radio' ), esc_html__( 'Adds a small, focused radio player to your WordPress dashboard. %d hand-curated SomaFM stations across 10 genres — ambient, electronic, lounge, rock, metal, jazz, world, reggae, holiday and specials. Plays in your admin pages while you work. Your chosen station + volume persist per user.', 'rangerhq-radio' ),
(int) $count (int) $count
); );
?> ?>
</p> </p>
<p> <p>
<?php esc_html_e( 'Audio plays directly in your browser via HTML5 — no server-side proxy, no extra services to host, no third-party tracking. Just an <audio> element pointed at SomaFM\'s public streams.', 'a-radio' ); ?> <?php esc_html_e( 'Audio plays directly in your browser via HTML5 — no server-side proxy, no extra services to host, no third-party tracking. Just an <audio> element pointed at SomaFM\'s public streams.', 'rangerhq-radio' ); ?>
</p> </p>
</div> </div>
<div class="radio-about-card"> <div class="radio-about-card">
<h2><?php esc_html_e( 'Who Radio is for', 'a-radio' ); ?></h2> <h2><?php esc_html_e( 'Who Radio is for', 'rangerhq-radio' ); ?></h2>
<p> <p>
<?php esc_html_e( 'Anyone who likes background music while working in the WordPress admin. Coders, writers, support agents, content editors. The 44 SomaFM stations cover a wide enough range that there\'s something for any mood — from coding-focus ambient (Groove Salad, Drone Zone) to drive-time electronic (DEF CON Radio, Beat Blender) to mellow lounge (Lush, Secret Agent) to specifically-quirky picks (SF 10-33 mixes ambient with San Francisco public-safety radio).', 'a-radio' ); ?> <?php esc_html_e( 'Anyone who likes background music while working in the WordPress admin. Coders, writers, support agents, content editors. The 44 SomaFM stations cover a wide enough range that there\'s something for any mood — from coding-focus ambient (Groove Salad, Drone Zone) to drive-time electronic (DEF CON Radio, Beat Blender) to mellow lounge (Lush, Secret Agent) to specifically-quirky picks (SF 10-33 mixes ambient with San Francisco public-safety radio).', 'rangerhq-radio' ); ?>
</p> </p>
</div> </div>
<div class="radio-about-card"> <div class="radio-about-card">
<h2><?php esc_html_e( 'Credits + thanks', 'a-radio' ); ?></h2> <h2><?php esc_html_e( 'Credits + thanks', 'rangerhq-radio' ); ?></h2>
<p> <p>
<?php <?php
printf( printf(
wp_kses( wp_kses(
/* translators: %s = link to somafm.com */ /* translators: %s = link to somafm.com */
__( 'All stations and streams are provided by %s — an independent, listener-supported, commercial-free internet radio network broadcasting from San Francisco since 2000. Radio is just a small WordPress wrapper around their public streams. If you enjoy this plugin, please consider donating to SomaFM directly.', 'a-radio' ), __( 'All stations and streams are provided by %s — an independent, listener-supported, commercial-free internet radio network broadcasting from San Francisco since 2000. Radio is just a small WordPress wrapper around their public streams. If you enjoy this plugin, please consider donating to SomaFM directly.', 'rangerhq-radio' ),
array( 'a' => array( 'href' => true, 'target' => true, 'rel' => true ) ) array( 'a' => array( 'href' => true, 'target' => true, 'rel' => true ) )
), ),
'<a href="https://somafm.com/support/" target="_blank" rel="noopener">SomaFM</a>' '<a href="https://somafm.com/support/" target="_blank" rel="noopener">SomaFM</a>'
@@ -63,11 +63,11 @@ function radio_render_about_page() {
?> ?>
</p> </p>
<p> <p>
<?php esc_html_e( 'Plugin author: David Keane. Part of the RangerHQ plugin family. GPL v2 or later. Source on Gitea.', 'a-radio' ); ?> <?php esc_html_e( 'Plugin author: David Keane. Part of the RangerHQ plugin family. GPL v2 or later. Source on Gitea.', 'rangerhq-radio' ); ?>
</p> </p>
<?php if ( defined( 'RADIO_SUPPORT_URL' ) && RADIO_SUPPORT_URL ) : ?> <?php if ( defined( 'RADIO_SUPPORT_URL' ) && RADIO_SUPPORT_URL ) : ?>
<a class="radio-support-link" href="<?php echo esc_url( RADIO_SUPPORT_URL ); ?>" target="_blank" rel="noopener"> <a class="radio-support-link" href="<?php echo esc_url( RADIO_SUPPORT_URL ); ?>" target="_blank" rel="noopener">
<?php esc_html_e( 'Like Radio? If You fancy to buy me a coffee →', 'a-radio' ); ?> <?php esc_html_e( 'Like Radio? If You fancy to buy me a coffee →', 'rangerhq-radio' ); ?>
</a> </a>
<?php endif; ?> <?php endif; ?>
</div> </div>
@@ -76,38 +76,39 @@ function radio_render_about_page() {
<!-- ── Version history: latest in full, earlier as one-liners ── --> <!-- ── Version history: latest in full, earlier as one-liners ── -->
<div class="radio-about-versions"> <div class="radio-about-versions">
<h2><?php esc_html_e( 'Version history', 'a-radio' ); ?></h2> <h2><?php esc_html_e( 'Version history', 'rangerhq-radio' ); ?></h2>
<div class="radio-about-versions__latest"> <div class="radio-about-versions__latest">
<span class="ver">v0.7.4</span> &mdash; 30 May 2026 <span class="latest"><?php esc_html_e( 'latest', 'a-radio' ); ?></span> <span class="ver">v0.7.5</span> &mdash; 30 May 2026 <span class="latest"><?php esc_html_e( 'latest', 'rangerhq-radio' ); ?></span>
<p> <p>
<?php esc_html_e( 'WordPress.org submission cleanup. Removed the self-hosted Gitea updater (`inc/updater.php`) and the `Update URI` header from `radio.php` — WordPress.org explicitly disallows both for hosted plugins (Plugin Check `plugin_updater_detected`). Updates now flow through WordPress.org as the canonical channel. Added a top-level LICENSE file with the full GPL v2 text and GPL header blocks to the CSS and JS assets so the licensing of every shipped file is explicit. No user-visible behaviour changes for the player — only the small `Updates` panel that used to sit at the bottom of Radio → Settings is gone.', 'a-radio' ); ?> <?php esc_html_e( 'WordPress.org slug rename: a-radio → rangerhq-radio. The previous slug was too generic for the directory (single common functional word, no distinguishing prefix); the new slug matches the public display name and lines up with the rest of the RangerHQ plugin family. Text Domain renamed to match across all 125 i18n call sites. Gitea repository moved. No user-visible behaviour change in the player; this is a packaging change only. Internal constants and user-meta keys are unchanged so settings, history, and favourites survive intact.', 'rangerhq-radio' ); ?>
</p> </p>
</div> </div>
<h3><?php esc_html_e( 'Earlier releases', 'a-radio' ); ?></h3> <h3><?php esc_html_e( 'Earlier releases', 'rangerhq-radio' ); ?></h3>
<ul class="radio-about-versions__earlier"> <ul class="radio-about-versions__earlier">
<li><span class="ver">v0.7.3</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Privacy section in readme + SomaFM terms-of-use link (Update URI guard pattern from this release was walked back in v0.7.4 — Plugin Check disallows it for wp.org-hosted plugins regardless of header value)', 'a-radio' ); ?></li> <li><span class="ver">v0.7.4</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'wp.org submission cleanup — removed self-hosted updater + Update URI header (PCP plugin_updater_detected); added LICENSE file + per-asset GPL headers', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.7.2</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Screenshots + correct wp.org contributor handle (ir240474)', 'a-radio' ); ?></li> <li><span class="ver">v0.7.3</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Privacy section in readme + SomaFM terms-of-use link (Update URI guard pattern from this release was walked back in v0.7.4 — Plugin Check disallows it for wp.org-hosted plugins regardless of header value)', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.7.1</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Plugin Check follow-up — Tested-up-to bumped to 7.0, .DS_Store re-cleanup', 'a-radio' ); ?></li> <li><span class="ver">v0.7.2</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Screenshots + correct wp.org contributor handle (ir240474)', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.7.0</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'WordPress.org submission prep — full Plugin Check clean (169 → 4 issues, branding, textdomain, security, popup refactor, readme.txt)', 'a-radio' ); ?></li> <li><span class="ver">v0.7.1</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Plugin Check follow-up — Tested-up-to bumped to 7.0, .DS_Store re-cleanup', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.6.3</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Discreet buy-me-a-coffee support link (Updates panel + Credits card)', 'a-radio' ); ?></li> <li><span class="ver">v0.7.0</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'WordPress.org submission prep — full Plugin Check clean (169 → 4 issues, branding, textdomain, security, popup refactor, readme.txt)', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.6.2</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Current version badge on the Settings page', 'a-radio' ); ?></li> <li><span class="ver">v0.6.3</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Discreet buy-me-a-coffee support link (Updates panel + Credits card)', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.6.1</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'About page restructure — balanced 3-card top row + compact version history', 'a-radio' ); ?></li> <li><span class="ver">v0.6.2</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Current version badge on the Settings page', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.6.0</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Pop-out mini-player — continuous background play across admin navigation', 'a-radio' ); ?></li> <li><span class="ver">v0.6.1</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'About page restructure — balanced 3-card top row + compact version history', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.5.0</span> <span class="ver-date">29 May 2026</span> &mdash; <?php esc_html_e( 'Track history + favourites (Spotify / YouTube / Apple Music / Bandcamp search links)', 'a-radio' ); ?></li> <li><span class="ver">v0.6.0</span> <span class="ver-date">30 May 2026</span> &mdash; <?php esc_html_e( 'Pop-out mini-player — continuous background play across admin navigation', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.4.0</span> <span class="ver-date">29 May 2026</span> &mdash; <?php esc_html_e( 'Now-playing indicator — dancing bars + Web Audio frequency visualizer', 'a-radio' ); ?></li> <li><span class="ver">v0.5.0</span> <span class="ver-date">29 May 2026</span> &mdash; <?php esc_html_e( 'Track history + favourites (Spotify / YouTube / Apple Music / Bandcamp search links)', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.3.2</span> <span class="ver-date">29 May 2026</span> &mdash; <?php esc_html_e( 'Play-button glyph baseline fix (dashicon → Unicode ▶ / ‖)', 'a-radio' ); ?></li> <li><span class="ver">v0.4.0</span> <span class="ver-date">29 May 2026</span> &mdash; <?php esc_html_e( 'Now-playing indicator — dancing bars + Web Audio frequency visualizer', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.3.1</span> <span class="ver-date">29 May 2026</span> &mdash; <?php esc_html_e( 'My Radio layout polish + dropped dark-auto', 'a-radio' ); ?></li> <li><span class="ver">v0.3.2</span> <span class="ver-date">29 May 2026</span> &mdash; <?php esc_html_e( 'Play-button glyph baseline fix (dashicon → Unicode ▶ / ‖)', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.3.0</span> <span class="ver-date">29 May 2026</span> &mdash; <?php esc_html_e( 'Dark theme + mute + OS media keys + SomaFM current-track display', 'a-radio' ); ?></li> <li><span class="ver">v0.3.1</span> <span class="ver-date">29 May 2026</span> &mdash; <?php esc_html_e( 'My Radio layout polish + dropped dark-auto', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.2.0</span> <span class="ver-date">26 May 2026</span> &mdash; <?php esc_html_e( 'UI rebuilt to WordPress admin standards', 'a-radio' ); ?></li> <li><span class="ver">v0.3.0</span> <span class="ver-date">29 May 2026</span> &mdash; <?php esc_html_e( 'Dark theme + mute + OS media keys + SomaFM current-track display', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.1.0</span> <span class="ver-date">26 May 2026</span> &mdash; <?php esc_html_e( 'First release — 44 SomaFM stations, dashboard widget + dedicated admin page, per-user state, self-hosted Gitea updater', 'a-radio' ); ?></li> <li><span class="ver">v0.2.0</span> <span class="ver-date">26 May 2026</span> &mdash; <?php esc_html_e( 'UI rebuilt to WordPress admin standards', 'rangerhq-radio' ); ?></li>
<li><span class="ver">v0.1.0</span> <span class="ver-date">26 May 2026</span> &mdash; <?php esc_html_e( 'First release — 44 SomaFM stations, dashboard widget + dedicated admin page, per-user state, self-hosted Gitea updater', 'rangerhq-radio' ); ?></li>
</ul> </ul>
<a class="radio-about-changelog-link" <a class="radio-about-changelog-link"
href="<?php echo esc_url( RADIO_GITEA_URL . '/src/branch/main/CHANGELOG.md' ); ?>" href="<?php echo esc_url( RADIO_GITEA_URL . '/src/branch/main/CHANGELOG.md' ); ?>"
target="_blank" rel="noopener"> target="_blank" rel="noopener">
<?php esc_html_e( 'View the full CHANGELOG.md →', 'a-radio' ); ?> <?php esc_html_e( 'View the full CHANGELOG.md →', 'rangerhq-radio' ); ?>
</a> </a>
</div> </div>
+12 -12
View File
@@ -12,7 +12,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
function radio_render_main_page() { function radio_render_main_page() {
if ( ! current_user_can( 'read' ) ) { if ( ! current_user_can( 'read' ) ) {
wp_die( esc_html__( 'You do not have permission to view this page.', 'a-radio' ) ); wp_die( esc_html__( 'You do not have permission to view this page.', 'rangerhq-radio' ) );
} }
$state = radio_get_state(); $state = radio_get_state();
@@ -21,13 +21,13 @@ function radio_render_main_page() {
$count = count( radio_get_stations_flat() ); $count = count( radio_get_stations_flat() );
?> ?>
<div class="wrap radio-wrap"> <div class="wrap radio-wrap">
<h1><?php esc_html_e( 'Radio', 'a-radio' ); ?></h1> <h1><?php esc_html_e( 'Radio', 'rangerhq-radio' ); ?></h1>
<p class="radio-intro"> <p class="radio-intro">
<?php <?php
printf( printf(
/* translators: %d = number of stations */ /* translators: %d = number of stations */
esc_html__( 'A tab of background music for your WordPress admin. %d hand-curated SomaFM stations across 10 genres — free, no ads, no tracking.', 'a-radio' ), esc_html__( 'A tab of background music for your WordPress admin. %d hand-curated SomaFM stations across 10 genres — free, no ads, no tracking.', 'rangerhq-radio' ),
(int) $count (int) $count
); );
?> ?>
@@ -35,7 +35,7 @@ function radio_render_main_page() {
<div class="postbox"> <div class="postbox">
<div class="postbox-header"> <div class="postbox-header">
<h2 class="hndle"><?php esc_html_e( 'Player', 'a-radio' ); ?></h2> <h2 class="hndle"><?php esc_html_e( 'Player', 'rangerhq-radio' ); ?></h2>
</div> </div>
<div class="inside"> <div class="inside">
<div class="radio-player" data-radio-surface="main"> <div class="radio-player" data-radio-surface="main">
@@ -45,7 +45,7 @@ function radio_render_main_page() {
<span class="radio-player__bars"><span></span><span></span><span></span><span></span></span> <span class="radio-player__bars"><span></span><span></span><span></span><span></span></span>
<canvas class="radio-player__viz" data-radio-viz hidden></canvas> <canvas class="radio-player__viz" data-radio-viz hidden></canvas>
</span> </span>
<span class="radio-player__label"><?php esc_html_e( 'Now Playing', 'a-radio' ); ?></span> <span class="radio-player__label"><?php esc_html_e( 'Now Playing', 'rangerhq-radio' ); ?></span>
<span class="radio-player__station-name" data-radio-name><?php echo esc_html( $station['name'] ); ?></span> <span class="radio-player__station-name" data-radio-name><?php echo esc_html( $station['name'] ); ?></span>
<span class="radio-player__station-genre" data-radio-genre><?php echo esc_html( $station['genre'] ); ?></span> <span class="radio-player__station-genre" data-radio-genre><?php echo esc_html( $station['genre'] ); ?></span>
<p class="radio-player__station-desc" data-radio-desc><?php echo esc_html( $station['description'] ); ?></p> <p class="radio-player__station-desc" data-radio-desc><?php echo esc_html( $station['description'] ); ?></p>
@@ -55,24 +55,24 @@ function radio_render_main_page() {
<div class="radio-player__controls"> <div class="radio-player__controls">
<button type="button" class="button button-primary radio-player__play" data-radio-play> <button type="button" class="button button-primary radio-player__play" data-radio-play>
<span class="radio-player__play-glyph" data-radio-play-glyph aria-hidden="true">&#9654;</span> <span class="radio-player__play-glyph" data-radio-play-glyph aria-hidden="true">&#9654;</span>
<span data-radio-play-label><?php esc_html_e( 'Play', 'a-radio' ); ?></span> <span data-radio-play-label><?php esc_html_e( 'Play', 'rangerhq-radio' ); ?></span>
</button> </button>
<button type="button" class="button radio-player__popout" data-radio-popout title="<?php esc_attr_e( 'Open in a pop-out window — keeps playing while you navigate the admin', 'a-radio' ); ?>"> <button type="button" class="button radio-player__popout" data-radio-popout title="<?php esc_attr_e( 'Open in a pop-out window — keeps playing while you navigate the admin', 'rangerhq-radio' ); ?>">
<span aria-hidden="true">↗</span> <?php esc_html_e( 'Pop out', 'a-radio' ); ?> <span aria-hidden="true">↗</span> <?php esc_html_e( 'Pop out', 'rangerhq-radio' ); ?>
</button> </button>
<div class="radio-player__volume"> <div class="radio-player__volume">
<button type="button" class="radio-player__mute" data-radio-mute aria-label="<?php esc_attr_e( 'Mute', 'a-radio' ); ?>"> <button type="button" class="radio-player__mute" data-radio-mute aria-label="<?php esc_attr_e( 'Mute', 'rangerhq-radio' ); ?>">
<span class="dashicons dashicons-controls-volumeon" aria-hidden="true"></span> <span class="dashicons dashicons-controls-volumeon" aria-hidden="true"></span>
</button> </button>
<input type="range" min="0" max="100" value="<?php echo esc_attr( (int) round( $state['volume'] * 100 ) ); ?>" data-radio-volume aria-label="<?php esc_attr_e( 'Volume', 'a-radio' ); ?>"> <input type="range" min="0" max="100" value="<?php echo esc_attr( (int) round( $state['volume'] * 100 ) ); ?>" data-radio-volume aria-label="<?php esc_attr_e( 'Volume', 'rangerhq-radio' ); ?>">
<span class="radio-player__volume-pct" data-radio-volume-pct><?php echo esc_html( (int) round( $state['volume'] * 100 ) ); ?>%</span> <span class="radio-player__volume-pct" data-radio-volume-pct><?php echo esc_html( (int) round( $state['volume'] * 100 ) ); ?>%</span>
</div> </div>
</div> </div>
<div class="radio-player__station-select"> <div class="radio-player__station-select">
<label for="radio-station-main"><?php esc_html_e( 'Station', 'a-radio' ); ?></label> <label for="radio-station-main"><?php esc_html_e( 'Station', 'rangerhq-radio' ); ?></label>
<select id="radio-station-main" data-radio-station> <select id="radio-station-main" data-radio-station>
<?php foreach ( $stations as $genre => $entries ) : <?php foreach ( $stations as $genre => $entries ) :
if ( empty( $entries ) ) { continue; } if ( empty( $entries ) ) { continue; }
@@ -100,7 +100,7 @@ function radio_render_main_page() {
printf( printf(
wp_kses( wp_kses(
/* translators: %s = link to somafm.com */ /* translators: %s = link to somafm.com */
__( 'Stations and streams provided by %s — an independent, listener-supported, commercial-free internet radio network. Please consider supporting them.', 'a-radio' ), __( 'Stations and streams provided by %s — an independent, listener-supported, commercial-free internet radio network. Please consider supporting them.', 'rangerhq-radio' ),
array( 'a' => array( 'href' => true, 'target' => true, 'rel' => true ) ) array( 'a' => array( 'href' => true, 'target' => true, 'rel' => true ) )
), ),
'<a href="https://somafm.com/" target="_blank" rel="noopener">SomaFM</a>' '<a href="https://somafm.com/" target="_blank" rel="noopener">SomaFM</a>'
+9 -9
View File
@@ -21,7 +21,7 @@ function radio_register_dashboard_widget() {
wp_add_dashboard_widget( wp_add_dashboard_widget(
'radio_dashboard_widget', 'radio_dashboard_widget',
__( 'Radio', 'a-radio' ), __( 'Radio', 'rangerhq-radio' ),
'radio_render_dashboard_widget' 'radio_render_dashboard_widget'
); );
} }
@@ -38,7 +38,7 @@ function radio_render_dashboard_widget() {
<span class="radio-player__bars"><span></span><span></span><span></span><span></span></span> <span class="radio-player__bars"><span></span><span></span><span></span><span></span></span>
<canvas class="radio-player__viz" data-radio-viz hidden></canvas> <canvas class="radio-player__viz" data-radio-viz hidden></canvas>
</span> </span>
<span class="radio-player__label"><?php esc_html_e( 'Now Playing', 'a-radio' ); ?></span> <span class="radio-player__label"><?php esc_html_e( 'Now Playing', 'rangerhq-radio' ); ?></span>
<span class="radio-player__station-name" data-radio-name><?php echo esc_html( $station['name'] ); ?></span> <span class="radio-player__station-name" data-radio-name><?php echo esc_html( $station['name'] ); ?></span>
<span class="radio-player__station-genre" data-radio-genre><?php echo esc_html( $station['genre'] ); ?></span> <span class="radio-player__station-genre" data-radio-genre><?php echo esc_html( $station['genre'] ); ?></span>
<p class="radio-player__station-desc" data-radio-desc><?php echo esc_html( $station['description'] ); ?></p> <p class="radio-player__station-desc" data-radio-desc><?php echo esc_html( $station['description'] ); ?></p>
@@ -48,24 +48,24 @@ function radio_render_dashboard_widget() {
<div class="radio-player__controls"> <div class="radio-player__controls">
<button type="button" class="button button-primary radio-player__play" data-radio-play> <button type="button" class="button button-primary radio-player__play" data-radio-play>
<span class="radio-player__play-glyph" data-radio-play-glyph aria-hidden="true">&#9654;</span> <span class="radio-player__play-glyph" data-radio-play-glyph aria-hidden="true">&#9654;</span>
<span data-radio-play-label><?php esc_html_e( 'Play', 'a-radio' ); ?></span> <span data-radio-play-label><?php esc_html_e( 'Play', 'rangerhq-radio' ); ?></span>
</button> </button>
<button type="button" class="button radio-player__popout" data-radio-popout title="<?php esc_attr_e( 'Open in a pop-out window — keeps playing while you navigate', 'a-radio' ); ?>"> <button type="button" class="button radio-player__popout" data-radio-popout title="<?php esc_attr_e( 'Open in a pop-out window — keeps playing while you navigate', 'rangerhq-radio' ); ?>">
<span aria-hidden="true">↗</span> <?php esc_html_e( 'Pop out', 'a-radio' ); ?> <span aria-hidden="true">↗</span> <?php esc_html_e( 'Pop out', 'rangerhq-radio' ); ?>
</button> </button>
<div class="radio-player__volume"> <div class="radio-player__volume">
<button type="button" class="radio-player__mute" data-radio-mute aria-label="<?php esc_attr_e( 'Mute', 'a-radio' ); ?>"> <button type="button" class="radio-player__mute" data-radio-mute aria-label="<?php esc_attr_e( 'Mute', 'rangerhq-radio' ); ?>">
<span class="dashicons dashicons-controls-volumeon" aria-hidden="true"></span> <span class="dashicons dashicons-controls-volumeon" aria-hidden="true"></span>
</button> </button>
<input type="range" min="0" max="100" value="<?php echo esc_attr( (int) round( $state['volume'] * 100 ) ); ?>" data-radio-volume aria-label="<?php esc_attr_e( 'Volume', 'a-radio' ); ?>"> <input type="range" min="0" max="100" value="<?php echo esc_attr( (int) round( $state['volume'] * 100 ) ); ?>" data-radio-volume aria-label="<?php esc_attr_e( 'Volume', 'rangerhq-radio' ); ?>">
<span class="radio-player__volume-pct" data-radio-volume-pct><?php echo esc_html( (int) round( $state['volume'] * 100 ) ); ?>%</span> <span class="radio-player__volume-pct" data-radio-volume-pct><?php echo esc_html( (int) round( $state['volume'] * 100 ) ); ?>%</span>
</div> </div>
</div> </div>
<div class="radio-player__station-select"> <div class="radio-player__station-select">
<label for="radio-station-widget"><?php esc_html_e( 'Station', 'a-radio' ); ?></label> <label for="radio-station-widget"><?php esc_html_e( 'Station', 'rangerhq-radio' ); ?></label>
<select id="radio-station-widget" data-radio-station> <select id="radio-station-widget" data-radio-station>
<?php foreach ( $stations as $genre => $entries ) : <?php foreach ( $stations as $genre => $entries ) :
if ( empty( $entries ) ) { continue; } if ( empty( $entries ) ) { continue; }
@@ -90,7 +90,7 @@ function radio_render_dashboard_widget() {
printf( printf(
wp_kses( wp_kses(
/* translators: %s = link to somafm.com */ /* translators: %s = link to somafm.com */
__( 'Powered by %s', 'a-radio' ), __( 'Powered by %s', 'rangerhq-radio' ),
array( 'a' => array( 'href' => true, 'target' => true, 'rel' => true ) ) array( 'a' => array( 'href' => true, 'target' => true, 'rel' => true ) )
), ),
'<a href="https://somafm.com/" target="_blank" rel="noopener">SomaFM</a>' '<a href="https://somafm.com/" target="_blank" rel="noopener">SomaFM</a>'
+16 -16
View File
@@ -133,7 +133,7 @@ function radio_search_urls( $artist, $title ) {
/** Render the History admin page (tabs: History / Favourites). */ /** Render the History admin page (tabs: History / Favourites). */
function radio_render_history_page() { function radio_render_history_page() {
if ( ! current_user_can( 'read' ) ) { if ( ! current_user_can( 'read' ) ) {
wp_die( esc_html__( 'You do not have permission to view this page.', 'a-radio' ) ); wp_die( esc_html__( 'You do not have permission to view this page.', 'rangerhq-radio' ) );
} }
$tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'history'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- tab-switch only, no state change $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'history'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- tab-switch only, no state change
@@ -163,15 +163,15 @@ function radio_render_history_page() {
$nonce = wp_create_nonce( 'radio_history' ); $nonce = wp_create_nonce( 'radio_history' );
?> ?>
<div class="wrap radio-history-wrap"> <div class="wrap radio-history-wrap">
<h1><?php esc_html_e( 'Radio — Track history', 'a-radio' ); ?></h1> <h1><?php esc_html_e( 'Radio — Track history', 'rangerhq-radio' ); ?></h1>
<h2 class="nav-tab-wrapper"> <h2 class="nav-tab-wrapper">
<a href="<?php echo esc_url( $hist_url ); ?>" class="nav-tab <?php echo $tab === 'history' ? 'nav-tab-active' : ''; ?>"> <a href="<?php echo esc_url( $hist_url ); ?>" class="nav-tab <?php echo $tab === 'history' ? 'nav-tab-active' : ''; ?>">
<?php esc_html_e( 'History', 'a-radio' ); ?> <?php esc_html_e( 'History', 'rangerhq-radio' ); ?>
<span class="radio-tab-count">(<?php echo (int) count( $all_history ); ?>)</span> <span class="radio-tab-count">(<?php echo (int) count( $all_history ); ?>)</span>
</a> </a>
<a href="<?php echo esc_url( $fav_url ); ?>" class="nav-tab <?php echo $tab === 'favourites' ? 'nav-tab-active' : ''; ?>"> <a href="<?php echo esc_url( $fav_url ); ?>" class="nav-tab <?php echo $tab === 'favourites' ? 'nav-tab-active' : ''; ?>">
★ <?php esc_html_e( 'Favourites', 'a-radio' ); ?> ★ <?php esc_html_e( 'Favourites', 'rangerhq-radio' ); ?>
<span class="radio-tab-count">(<?php echo (int) count( $all_favourites ); ?>)</span> <span class="radio-tab-count">(<?php echo (int) count( $all_favourites ); ?>)</span>
</a> </a>
</h2> </h2>
@@ -179,24 +179,24 @@ function radio_render_history_page() {
<?php if ( empty( $entries ) ) : ?> <?php if ( empty( $entries ) ) : ?>
<p class="radio-history-empty"> <p class="radio-history-empty">
<?php if ( $tab === 'favourites' ) : ?> <?php if ( $tab === 'favourites' ) : ?>
<?php esc_html_e( 'No favourites yet — star a track on the History tab to save it here.', 'a-radio' ); ?> <?php esc_html_e( 'No favourites yet — star a track on the History tab to save it here.', 'rangerhq-radio' ); ?>
<?php else : ?> <?php else : ?>
<?php esc_html_e( 'No tracks logged yet. Play some music in the Radio player — tracks will appear here as they play.', 'a-radio' ); ?> <?php esc_html_e( 'No tracks logged yet. Play some music in the Radio player — tracks will appear here as they play.', 'rangerhq-radio' ); ?>
<?php endif; ?> <?php endif; ?>
</p> </p>
<?php else : ?> <?php else : ?>
<div class="radio-history-toolbar"> <div class="radio-history-toolbar">
<input type="search" id="radio-history-search" placeholder="<?php esc_attr_e( 'Filter by artist or title…', 'a-radio' ); ?>" /> <input type="search" id="radio-history-search" placeholder="<?php esc_attr_e( 'Filter by artist or title…', 'rangerhq-radio' ); ?>" />
<select id="radio-history-station"> <select id="radio-history-station">
<option value=""><?php esc_html_e( 'All stations', 'a-radio' ); ?></option> <option value=""><?php esc_html_e( 'All stations', 'rangerhq-radio' ); ?></option>
<?php foreach ( $stations_in_list as $sid => $sname ) : ?> <?php foreach ( $stations_in_list as $sid => $sname ) : ?>
<option value="<?php echo esc_attr( $sid ); ?>"><?php echo esc_html( $sname ); ?></option> <option value="<?php echo esc_attr( $sid ); ?>"><?php echo esc_html( $sname ); ?></option>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
<?php if ( $tab === 'history' ) : ?> <?php if ( $tab === 'history' ) : ?>
<button type="button" id="radio-history-clear" class="button radio-history-clear" data-nonce="<?php echo esc_attr( $nonce ); ?>"> <button type="button" id="radio-history-clear" class="button radio-history-clear" data-nonce="<?php echo esc_attr( $nonce ); ?>">
🗑 <?php esc_html_e( 'Clear history', 'a-radio' ); ?> 🗑 <?php esc_html_e( 'Clear history', 'rangerhq-radio' ); ?>
</button> </button>
<?php endif; ?> <?php endif; ?>
</div> </div>
@@ -204,11 +204,11 @@ function radio_render_history_page() {
<table class="widefat radio-history-table"> <table class="widefat radio-history-table">
<thead> <thead>
<tr> <tr>
<th class="when"><?php esc_html_e( 'When', 'a-radio' ); ?></th> <th class="when"><?php esc_html_e( 'When', 'rangerhq-radio' ); ?></th>
<th class="station"><?php esc_html_e( 'Station', 'a-radio' ); ?></th> <th class="station"><?php esc_html_e( 'Station', 'rangerhq-radio' ); ?></th>
<th class="track"><?php esc_html_e( 'Artist — Title', 'a-radio' ); ?></th> <th class="track"><?php esc_html_e( 'Artist — Title', 'rangerhq-radio' ); ?></th>
<th class="search"><?php esc_html_e( 'Search', 'a-radio' ); ?></th> <th class="search"><?php esc_html_e( 'Search', 'rangerhq-radio' ); ?></th>
<th class="fav"><span class="screen-reader-text"><?php esc_html_e( 'Favourite', 'a-radio' ); ?></span>★</th> <th class="fav"><span class="screen-reader-text"><?php esc_html_e( 'Favourite', 'rangerhq-radio' ); ?></span>★</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -222,7 +222,7 @@ function radio_render_history_page() {
<td class="when" title="<?php echo esc_attr( wp_date( 'j M Y, H:i', (int) $e['at'] ) ); ?>"> <td class="when" title="<?php echo esc_attr( wp_date( 'j M Y, H:i', (int) $e['at'] ) ); ?>">
<?php <?php
/* translators: %s = human-readable time difference, e.g. "2 minutes" */ /* translators: %s = human-readable time difference, e.g. "2 minutes" */
printf( esc_html__( '%s ago', 'a-radio' ), esc_html( $ago ) ); printf( esc_html__( '%s ago', 'rangerhq-radio' ), esc_html( $ago ) );
?> ?>
</td> </td>
<td class="station"><?php echo esc_html( $e['station'] ); ?></td> <td class="station"><?php echo esc_html( $e['station'] ); ?></td>
@@ -243,7 +243,7 @@ function radio_render_history_page() {
data-station="<?php echo esc_attr( $e['station'] ); ?>" data-station="<?php echo esc_attr( $e['station'] ); ?>"
data-station-id="<?php echo esc_attr( $e['station_id'] ); ?>" data-station-id="<?php echo esc_attr( $e['station_id'] ); ?>"
data-nonce="<?php echo esc_attr( $nonce ); ?>" data-nonce="<?php echo esc_attr( $nonce ); ?>"
aria-label="<?php echo $is_fav ? esc_attr__( 'Remove from favourites', 'a-radio' ) : esc_attr__( 'Add to favourites', 'a-radio' ); ?>"> aria-label="<?php echo $is_fav ? esc_attr__( 'Remove from favourites', 'rangerhq-radio' ) : esc_attr__( 'Add to favourites', 'rangerhq-radio' ); ?>">
<?php echo $is_fav ? '★' : '☆'; ?> <?php echo $is_fav ? '★' : '☆'; ?>
</button> </button>
</td> </td>
+14 -14
View File
@@ -10,7 +10,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; }
function radio_render_settings_page() { function radio_render_settings_page() {
if ( ! current_user_can( 'read' ) ) { if ( ! current_user_can( 'read' ) ) {
wp_die( esc_html__( 'You do not have permission to view this page.', 'a-radio' ) ); wp_die( esc_html__( 'You do not have permission to view this page.', 'rangerhq-radio' ) );
} }
// Handle form submission. // Handle form submission.
@@ -38,7 +38,7 @@ function radio_render_settings_page() {
$state['hide_dashboard_widget'] = $hide_widget ? 1 : 0; $state['hide_dashboard_widget'] = $hide_widget ? 1 : 0;
update_user_meta( $user_id, RADIO_META_KEY, $state ); update_user_meta( $user_id, RADIO_META_KEY, $state );
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Settings saved.', 'a-radio' ) . '</p></div>'; echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Settings saved.', 'rangerhq-radio' ) . '</p></div>';
} }
$state = radio_get_state(); $state = radio_get_state();
@@ -47,7 +47,7 @@ function radio_render_settings_page() {
?> ?>
<div class="wrap radio-settings-wrap"> <div class="wrap radio-settings-wrap">
<h1> <h1>
<?php esc_html_e( 'Radio — Settings', 'a-radio' ); ?> <?php esc_html_e( 'Radio — Settings', 'rangerhq-radio' ); ?>
<span class="radio-version-badge">v<?php echo esc_html( RADIO_VERSION ); ?></span> <span class="radio-version-badge">v<?php echo esc_html( RADIO_VERSION ); ?></span>
</h1> </h1>
@@ -57,7 +57,7 @@ function radio_render_settings_page() {
<table class="form-table" role="presentation"> <table class="form-table" role="presentation">
<tr> <tr>
<th scope="row"> <th scope="row">
<label for="default_station"><?php esc_html_e( 'Default station', 'a-radio' ); ?></label> <label for="default_station"><?php esc_html_e( 'Default station', 'rangerhq-radio' ); ?></label>
</th> </th>
<td> <td>
<select id="default_station" name="default_station"> <select id="default_station" name="default_station">
@@ -74,14 +74,14 @@ function radio_render_settings_page() {
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
<p class="description"> <p class="description">
<?php esc_html_e( 'The station that loads when you open Radio in a fresh tab.', 'a-radio' ); ?> <?php esc_html_e( 'The station that loads when you open Radio in a fresh tab.', 'rangerhq-radio' ); ?>
</p> </p>
</td> </td>
</tr> </tr>
<tr> <tr>
<th scope="row"> <th scope="row">
<label for="default_volume"><?php esc_html_e( 'Default volume', 'a-radio' ); ?></label> <label for="default_volume"><?php esc_html_e( 'Default volume', 'rangerhq-radio' ); ?></label>
</th> </th>
<td> <td>
<input type="range" id="default_volume" name="default_volume" min="0" max="100" value="<?php echo esc_attr( (int) round( $state['volume'] * 100 ) ); ?>" aria-describedby="default_volume_label"> <input type="range" id="default_volume" name="default_volume" min="0" max="100" value="<?php echo esc_attr( (int) round( $state['volume'] * 100 ) ); ?>" aria-describedby="default_volume_label">
@@ -91,34 +91,34 @@ function radio_render_settings_page() {
<tr> <tr>
<th scope="row"> <th scope="row">
<label for="theme"><?php esc_html_e( 'Theme', 'a-radio' ); ?></label> <label for="theme"><?php esc_html_e( 'Theme', 'rangerhq-radio' ); ?></label>
</th> </th>
<td> <td>
<select id="theme" name="theme"> <select id="theme" name="theme">
<option value="auto" <?php selected( $state['theme'], 'auto' ); ?>><?php esc_html_e( 'Auto (match WP admin colour scheme)', 'a-radio' ); ?></option> <option value="auto" <?php selected( $state['theme'], 'auto' ); ?>><?php esc_html_e( 'Auto (match WP admin colour scheme)', 'rangerhq-radio' ); ?></option>
<option value="light" <?php selected( $state['theme'], 'light' ); ?>><?php esc_html_e( 'Light', 'a-radio' ); ?></option> <option value="light" <?php selected( $state['theme'], 'light' ); ?>><?php esc_html_e( 'Light', 'rangerhq-radio' ); ?></option>
<option value="dark" <?php selected( $state['theme'], 'dark' ); ?>><?php esc_html_e( 'Dark', 'a-radio' ); ?></option> <option value="dark" <?php selected( $state['theme'], 'dark' ); ?>><?php esc_html_e( 'Dark', 'rangerhq-radio' ); ?></option>
</select> </select>
</td> </td>
</tr> </tr>
<tr> <tr>
<th scope="row"> <th scope="row">
<?php esc_html_e( 'Dashboard widget', 'a-radio' ); ?> <?php esc_html_e( 'Dashboard widget', 'rangerhq-radio' ); ?>
</th> </th>
<td> <td>
<label> <label>
<input type="checkbox" name="hide_dashboard_widget" value="1" <?php checked( $hide_widget ); ?>> <input type="checkbox" name="hide_dashboard_widget" value="1" <?php checked( $hide_widget ); ?>>
<?php esc_html_e( 'Hide the Radio widget from the WordPress Dashboard', 'a-radio' ); ?> <?php esc_html_e( 'Hide the Radio widget from the WordPress Dashboard', 'rangerhq-radio' ); ?>
</label> </label>
<p class="description"> <p class="description">
<?php esc_html_e( 'When checked, Radio is only accessible from the dedicated admin page (WP Admin → Radio → My Radio).', 'a-radio' ); ?> <?php esc_html_e( 'When checked, Radio is only accessible from the dedicated admin page (WP Admin → Radio → My Radio).', 'rangerhq-radio' ); ?>
</p> </p>
</td> </td>
</tr> </tr>
</table> </table>
<?php submit_button( __( 'Save Changes', 'a-radio' ), 'primary', 'radio_settings_submit' ); ?> <?php submit_button( __( 'Save Changes', 'rangerhq-radio' ), 'primary', 'radio_settings_submit' ); ?>
</form> </form>
</div> </div>
<?php <?php
+46 -46
View File
@@ -5,14 +5,14 @@
* Plugin Name: RangerHQ Radio * Plugin Name: RangerHQ Radio
* Plugin URI: https://icanhelp.ie/radio * Plugin URI: https://icanhelp.ie/radio
* Description: A small, focused internet radio player for your WordPress admin. 44 hand-curated stations from SomaFM across 10 genres — ambient, electronic, lounge, rock, metal, jazz, world, reggae, holiday, specials. Plays via HTML5 audio; per-user station + volume + history + favourites; pop-out window for continuous background play. * Description: A small, focused internet radio player for your WordPress admin. 44 hand-curated stations from SomaFM across 10 genres — ambient, electronic, lounge, rock, metal, jazz, world, reggae, holiday, specials. Plays via HTML5 audio; per-user station + volume + history + favourites; pop-out window for continuous background play.
* Version: 0.7.4 * Version: 0.7.5
* Requires at least: 5.3 * Requires at least: 5.3
* Requires PHP: 7.4 * Requires PHP: 7.4
* Author: David Keane * Author: David Keane
* Author URI: https://rangersmyth.xyz/ * Author URI: https://rangersmyth.xyz/
* License: GPL v2 or later * License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html * License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: a-radio * Text Domain: rangerhq-radio
* *
* @package RangerHQ_Radio * @package RangerHQ_Radio
* *
@@ -27,12 +27,12 @@
if ( ! defined( 'ABSPATH' ) ) { exit; } if ( ! defined( 'ABSPATH' ) ) { exit; }
// Plugin coordinates. // Plugin coordinates.
if ( ! defined( 'RADIO_VERSION' ) ) { define( 'RADIO_VERSION', '0.7.4' ); } if ( ! defined( 'RADIO_VERSION' ) ) { define( 'RADIO_VERSION', '0.7.5' ); }
if ( ! defined( 'RADIO_FILE' ) ) { define( 'RADIO_FILE', __FILE__ ); } if ( ! defined( 'RADIO_FILE' ) ) { define( 'RADIO_FILE', __FILE__ ); }
if ( ! defined( 'RADIO_PATH' ) ) { define( 'RADIO_PATH', plugin_dir_path( __FILE__ ) ); } if ( ! defined( 'RADIO_PATH' ) ) { define( 'RADIO_PATH', plugin_dir_path( __FILE__ ) ); }
if ( ! defined( 'RADIO_URL' ) ) { define( 'RADIO_URL', plugin_dir_url( __FILE__ ) ); } if ( ! defined( 'RADIO_URL' ) ) { define( 'RADIO_URL', plugin_dir_url( __FILE__ ) ); }
if ( ! defined( 'RADIO_BASENAME' ) ) { define( 'RADIO_BASENAME', plugin_basename( __FILE__ ) ); } if ( ! defined( 'RADIO_BASENAME' ) ) { define( 'RADIO_BASENAME', plugin_basename( __FILE__ ) ); }
if ( ! defined( 'RADIO_GITEA_URL' ) ) { define( 'RADIO_GITEA_URL', 'https://git.davidtkeane.com/ranger/a-radio' ); } if ( ! defined( 'RADIO_GITEA_URL' ) ) { define( 'RADIO_GITEA_URL', 'https://git.davidtkeane.com/ranger/rangerhq-radio' ); }
if ( ! defined( 'RADIO_SUPPORT_URL' ) ) { define( 'RADIO_SUPPORT_URL', 'https://buymeacoffee.com/davidtkeane' ); } if ( ! defined( 'RADIO_SUPPORT_URL' ) ) { define( 'RADIO_SUPPORT_URL', 'https://buymeacoffee.com/davidtkeane' ); }
// Includes — each file owns one concern. // Includes — each file owns one concern.
@@ -52,8 +52,8 @@ require_once RADIO_PATH . 'inc/history.php'; // Track history + favouri
add_action( 'admin_menu', 'radio_register_admin_menu' ); add_action( 'admin_menu', 'radio_register_admin_menu' );
function radio_register_admin_menu() { function radio_register_admin_menu() {
add_menu_page( add_menu_page(
__( 'Radio', 'a-radio' ), __( 'Radio', 'rangerhq-radio' ),
__( 'Radio', 'a-radio' ), __( 'Radio', 'rangerhq-radio' ),
'read', // any logged-in user with read access has their own radio 'read', // any logged-in user with read access has their own radio
'radio', 'radio',
'radio_render_main_page', 'radio_render_main_page',
@@ -67,8 +67,8 @@ function radio_register_admin_menu() {
// form gotcha). // form gotcha).
add_submenu_page( add_submenu_page(
'radio', 'radio',
__( 'My Radio', 'a-radio' ), __( 'My Radio', 'rangerhq-radio' ),
__( 'My Radio', 'a-radio' ), __( 'My Radio', 'rangerhq-radio' ),
'read', 'read',
'radio', 'radio',
'' ''
@@ -76,8 +76,8 @@ function radio_register_admin_menu() {
add_submenu_page( add_submenu_page(
'radio', 'radio',
__( 'Settings', 'a-radio' ), __( 'Settings', 'rangerhq-radio' ),
__( 'Settings', 'a-radio' ), __( 'Settings', 'rangerhq-radio' ),
'manage_options', 'manage_options',
'radio-settings', 'radio-settings',
'radio_render_settings_page' 'radio_render_settings_page'
@@ -85,8 +85,8 @@ function radio_register_admin_menu() {
add_submenu_page( add_submenu_page(
'radio', 'radio',
__( 'Track history', 'a-radio' ), __( 'Track history', 'rangerhq-radio' ),
__( 'History', 'a-radio' ), __( 'History', 'rangerhq-radio' ),
'read', 'read',
'radio-history', 'radio-history',
'radio_render_history_page' 'radio_render_history_page'
@@ -94,8 +94,8 @@ function radio_register_admin_menu() {
add_submenu_page( add_submenu_page(
'radio', 'radio',
__( 'About', 'a-radio' ), __( 'About', 'rangerhq-radio' ),
__( 'About', 'a-radio' ), __( 'About', 'rangerhq-radio' ),
'read', 'read',
'radio-about', 'radio-about',
'radio_render_about_page' 'radio_render_about_page'
@@ -140,19 +140,19 @@ function radio_enqueue_admin_assets( $hook ) {
'nonce' => wp_create_nonce( 'radio_save_state' ), 'nonce' => wp_create_nonce( 'radio_save_state' ),
'popoutUrl' => admin_url( 'admin-post.php?action=radio_popout' ), 'popoutUrl' => admin_url( 'admin-post.php?action=radio_popout' ),
'strings' => array( 'strings' => array(
'play' => __( 'Play', 'a-radio' ), 'play' => __( 'Play', 'rangerhq-radio' ),
'pause' => __( 'Pause', 'a-radio' ), 'pause' => __( 'Pause', 'rangerhq-radio' ),
'loading' => __( 'Loading…', 'a-radio' ), 'loading' => __( 'Loading…', 'rangerhq-radio' ),
'error' => __( 'Stream error — try another station.', 'a-radio' ), 'error' => __( 'Stream error — try another station.', 'rangerhq-radio' ),
'saveError' => __( 'Preferences not saved — check your connection.', 'a-radio' ), 'saveError' => __( 'Preferences not saved — check your connection.', 'rangerhq-radio' ),
'mute' => __( 'Mute', 'a-radio' ), 'mute' => __( 'Mute', 'rangerhq-radio' ),
'unmute' => __( 'Unmute', 'a-radio' ), 'unmute' => __( 'Unmute', 'rangerhq-radio' ),
'nowPlaying' => __( 'Now Playing', 'a-radio' ), 'nowPlaying' => __( 'Now Playing', 'rangerhq-radio' ),
'volume' => __( 'Volume', 'a-radio' ), 'volume' => __( 'Volume', 'rangerhq-radio' ),
'station' => __( 'Station', 'a-radio' ), 'station' => __( 'Station', 'rangerhq-radio' ),
'addFav' => __( 'Add to favourites', 'a-radio' ), 'addFav' => __( 'Add to favourites', 'rangerhq-radio' ),
'removeFav' => __( 'Remove from favourites', 'a-radio' ), 'removeFav' => __( 'Remove from favourites', 'rangerhq-radio' ),
'clearConfirm' => __( 'Clear all track history? (Favourites are kept.)', 'a-radio' ), 'clearConfirm' => __( 'Clear all track history? (Favourites are kept.)', 'rangerhq-radio' ),
), ),
) ); ) );
} }
@@ -241,7 +241,7 @@ function radio_ajax_clear_history() {
add_action( 'admin_post_radio_popout', 'radio_render_popout_page' ); add_action( 'admin_post_radio_popout', 'radio_render_popout_page' );
function radio_render_popout_page() { function radio_render_popout_page() {
if ( ! current_user_can( 'read' ) ) { if ( ! current_user_can( 'read' ) ) {
wp_die( esc_html__( 'You do not have permission to view this page.', 'a-radio' ) ); wp_die( esc_html__( 'You do not have permission to view this page.', 'rangerhq-radio' ) );
} }
$state = radio_get_state(); $state = radio_get_state();
@@ -258,16 +258,16 @@ function radio_render_popout_page() {
'popoutUrl' => '', // already in popout — no further popouts 'popoutUrl' => '', // already in popout — no further popouts
'autoPlay' => isset( $_GET['play'] ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- query flag only, no state change 'autoPlay' => isset( $_GET['play'] ), // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- query flag only, no state change
'strings' => array( 'strings' => array(
'play' => __( 'Play', 'a-radio' ), 'play' => __( 'Play', 'rangerhq-radio' ),
'pause' => __( 'Pause', 'a-radio' ), 'pause' => __( 'Pause', 'rangerhq-radio' ),
'loading' => __( 'Loading…', 'a-radio' ), 'loading' => __( 'Loading…', 'rangerhq-radio' ),
'error' => __( 'Stream error — try another station.', 'a-radio' ), 'error' => __( 'Stream error — try another station.', 'rangerhq-radio' ),
'saveError' => __( 'Preferences not saved — check your connection.', 'a-radio' ), 'saveError' => __( 'Preferences not saved — check your connection.', 'rangerhq-radio' ),
'mute' => __( 'Mute', 'a-radio' ), 'mute' => __( 'Mute', 'rangerhq-radio' ),
'unmute' => __( 'Unmute', 'a-radio' ), 'unmute' => __( 'Unmute', 'rangerhq-radio' ),
'nowPlaying' => __( 'Now Playing', 'a-radio' ), 'nowPlaying' => __( 'Now Playing', 'rangerhq-radio' ),
'volume' => __( 'Volume', 'a-radio' ), 'volume' => __( 'Volume', 'rangerhq-radio' ),
'station' => __( 'Station', 'a-radio' ), 'station' => __( 'Station', 'rangerhq-radio' ),
), ),
); );
@@ -289,15 +289,15 @@ function radio_render_popout_page() {
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php <title><?php
/* translators: %s = currently playing station name */ /* translators: %s = currently playing station name */
printf( esc_html__( 'Radio — %s', 'a-radio' ), esc_html( $station['name'] ) ); printf( esc_html__( 'Radio — %s', 'rangerhq-radio' ), esc_html( $station['name'] ) );
?></title> ?></title>
<?php wp_print_styles(); /* dashicons + radio.css; popup-specific overrides scoped under body.radio-popout in radio.css */ ?> <?php wp_print_styles(); /* dashicons + radio.css; popup-specific overrides scoped under body.radio-popout in radio.css */ ?>
</head> </head>
<body class="radio-popout radio-theme-<?php echo esc_attr( $theme ); ?>"> <body class="radio-popout radio-theme-<?php echo esc_attr( $theme ); ?>">
<div class="radio-popout-header"> <div class="radio-popout-header">
<h1><?php esc_html_e( 'Radio', 'a-radio' ); ?></h1> <h1><?php esc_html_e( 'Radio', 'rangerhq-radio' ); ?></h1>
<button type="button" class="radio-popout-close" onclick="window.close()" title="<?php esc_attr_e( 'Close', 'a-radio' ); ?>">✕</button> <button type="button" class="radio-popout-close" onclick="window.close()" title="<?php esc_attr_e( 'Close', 'rangerhq-radio' ); ?>">✕</button>
</div> </div>
<div class="radio-popout-wrap"> <div class="radio-popout-wrap">
@@ -308,7 +308,7 @@ function radio_render_popout_page() {
<span class="radio-player__bars"><span></span><span></span><span></span><span></span></span> <span class="radio-player__bars"><span></span><span></span><span></span><span></span></span>
<canvas class="radio-player__viz" data-radio-viz hidden></canvas> <canvas class="radio-player__viz" data-radio-viz hidden></canvas>
</span> </span>
<span class="radio-player__label"><?php esc_html_e( 'Now Playing', 'a-radio' ); ?></span> <span class="radio-player__label"><?php esc_html_e( 'Now Playing', 'rangerhq-radio' ); ?></span>
<span class="radio-player__station-name" data-radio-name><?php echo esc_html( $station['name'] ); ?></span> <span class="radio-player__station-name" data-radio-name><?php echo esc_html( $station['name'] ); ?></span>
<span class="radio-player__station-genre" data-radio-genre><?php echo esc_html( $station['genre'] ); ?></span> <span class="radio-player__station-genre" data-radio-genre><?php echo esc_html( $station['genre'] ); ?></span>
<p class="radio-player__station-desc" data-radio-desc><?php echo esc_html( $station['description'] ); ?></p> <p class="radio-player__station-desc" data-radio-desc><?php echo esc_html( $station['description'] ); ?></p>
@@ -318,19 +318,19 @@ function radio_render_popout_page() {
<div class="radio-player__controls"> <div class="radio-player__controls">
<button type="button" class="button button-primary radio-player__play" data-radio-play> <button type="button" class="button button-primary radio-player__play" data-radio-play>
<span class="radio-player__play-glyph" data-radio-play-glyph aria-hidden="true">&#9654;</span> <span class="radio-player__play-glyph" data-radio-play-glyph aria-hidden="true">&#9654;</span>
<span data-radio-play-label><?php esc_html_e( 'Play', 'a-radio' ); ?></span> <span data-radio-play-label><?php esc_html_e( 'Play', 'rangerhq-radio' ); ?></span>
</button> </button>
<div class="radio-player__volume"> <div class="radio-player__volume">
<button type="button" class="radio-player__mute" data-radio-mute aria-label="<?php esc_attr_e( 'Mute', 'a-radio' ); ?>"> <button type="button" class="radio-player__mute" data-radio-mute aria-label="<?php esc_attr_e( 'Mute', 'rangerhq-radio' ); ?>">
<span class="dashicons dashicons-controls-volumeon" aria-hidden="true"></span> <span class="dashicons dashicons-controls-volumeon" aria-hidden="true"></span>
</button> </button>
<input type="range" min="0" max="100" value="<?php echo esc_attr( (int) round( $state['volume'] * 100 ) ); ?>" data-radio-volume aria-label="<?php esc_attr_e( 'Volume', 'a-radio' ); ?>"> <input type="range" min="0" max="100" value="<?php echo esc_attr( (int) round( $state['volume'] * 100 ) ); ?>" data-radio-volume aria-label="<?php esc_attr_e( 'Volume', 'rangerhq-radio' ); ?>">
<span class="radio-player__volume-pct" data-radio-volume-pct><?php echo esc_html( (int) round( $state['volume'] * 100 ) ); ?>%</span> <span class="radio-player__volume-pct" data-radio-volume-pct><?php echo esc_html( (int) round( $state['volume'] * 100 ) ); ?>%</span>
</div> </div>
</div> </div>
<div class="radio-player__station-select"> <div class="radio-player__station-select">
<label for="radio-station-popout"><?php esc_html_e( 'Station', 'a-radio' ); ?></label> <label for="radio-station-popout"><?php esc_html_e( 'Station', 'rangerhq-radio' ); ?></label>
<select id="radio-station-popout" data-radio-station> <select id="radio-station-popout" data-radio-station>
<?php foreach ( $stations as $genre => $entries ) : <?php foreach ( $stations as $genre => $entries ) :
if ( empty( $entries ) ) { continue; } if ( empty( $entries ) ) { continue; }
+8 -2
View File
@@ -4,7 +4,7 @@ Donate link: https://buymeacoffee.com/davidtkeane
Tags: radio, music, audio, internet radio, background music Tags: radio, music, audio, internet radio, background music
Requires at least: 5.3 Requires at least: 5.3
Tested up to: 7.0 Tested up to: 7.0
Stable tag: 0.7.4 Stable tag: 0.7.5
Requires PHP: 7.4 Requires PHP: 7.4
License: GPLv2 or later License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html License URI: https://www.gnu.org/licenses/gpl-2.0.html
@@ -62,7 +62,7 @@ No — RangerHQ Radio is admin-only. It adds a player to the WordPress dashboard
= Can I add my own stations? = = Can I add my own stations? =
Not via the admin yet. The station list is hard-coded in `inc/stations.php` (44 SomaFM stations). If you'd like to add custom stations or other internet radio sources, please open an issue on the [Gitea repo](https://git.davidtkeane.com/ranger/a-radio). Not via the admin yet. The station list is hard-coded in `inc/stations.php` (44 SomaFM stations). If you'd like to add custom stations or other internet radio sources, please open an issue on the [Gitea repo](https://git.davidtkeane.com/ranger/rangerhq-radio).
= The pop-out window doesn't open. = = The pop-out window doesn't open. =
@@ -86,6 +86,9 @@ SomaFM's track-info endpoint (`somafm.com/songs/{station}.json`) is fetched best
== Changelog == == Changelog ==
= 0.7.5 =
* WordPress.org slug rename: `a-radio` → `rangerhq-radio`. The previous slug was flagged as too generic for the wp.org Plugin Directory (single common functional word, no distinguishing prefix). The new slug matches the public display name "RangerHQ Radio" and lines up with the rest of the RangerHQ plugin family (`rangerhq-spatial`, `rangerhq-glyph`). Text Domain renamed to match — all 125 i18n call sites updated. Gitea repository moved to https://git.davidtkeane.com/ranger/rangerhq-radio. No user-visible behaviour change in the player; this is a packaging change only. Plugin Name stays "RangerHQ Radio"; internal constants (`RADIO_*`) and user-meta keys (`radio_state` / `radio_history` / `radio_favourites`) are unchanged so settings + history + favourites all survive intact.
= 0.7.4 = = 0.7.4 =
* WordPress.org submission cleanup. Removed the self-hosted Gitea updater (`inc/updater.php`) and the `Update URI` header from `radio.php`. WordPress.org explicitly disallows both for hosted plugins (Plugin Check `plugin_updater_detected`), so updates now flow through WordPress.org as the canonical channel. Added a top-level `LICENSE` file with the full GPL v2 text and explicit GPL header blocks to `assets/css/radio.css` and `assets/js/radio.js` so the licensing of every shipped file is unambiguous. The small `Updates` panel that used to sit at the bottom of Radio → Settings is gone; player behaviour is unchanged. * WordPress.org submission cleanup. Removed the self-hosted Gitea updater (`inc/updater.php`) and the `Update URI` header from `radio.php`. WordPress.org explicitly disallows both for hosted plugins (Plugin Check `plugin_updater_detected`), so updates now flow through WordPress.org as the canonical channel. Added a top-level `LICENSE` file with the full GPL v2 text and explicit GPL header blocks to `assets/css/radio.css` and `assets/js/radio.js` so the licensing of every shipped file is unambiguous. The small `Updates` panel that used to sit at the bottom of Radio → Settings is gone; player behaviour is unchanged.
@@ -130,6 +133,9 @@ SomaFM's track-info endpoint (`somafm.com/songs/{station}.json`) is fetched best
== Upgrade Notice == == Upgrade Notice ==
= 0.7.5 =
WordPress.org slug renamed `a-radio` → `rangerhq-radio` (lines up with display name "RangerHQ Radio" and the family pattern). Text Domain matches. No player behaviour change. Existing user state (station / volume / history / favourites) survives intact.
= 0.7.4 = = 0.7.4 =
WordPress.org submission cleanup — removes the disallowed self-hosted updater + `Update URI` header. Adds LICENSE file + per-asset GPL headers. The `Updates` panel in Settings is gone (WordPress.org handles updates now). No player behaviour changes. WordPress.org submission cleanup — removes the disallowed self-hosted updater + `Update URI` header. Adds LICENSE file + per-asset GPL headers. The `Updates` panel in Settings is gone (WordPress.org handles updates now). No player behaviour changes.