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>
This commit is contained in:
2026-05-30 00:03:21 +01:00
parent 2bd501d610
commit 0dc3a220d9
7 changed files with 226 additions and 3 deletions
+4
View File
@@ -51,6 +51,10 @@ function radio_render_dashboard_widget() {
<span data-radio-play-label><?php esc_html_e( 'Play', 'radio' ); ?></span>
</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', 'radio' ); ?>">
<span aria-hidden="true">↗</span> <?php esc_html_e( 'Pop out', 'radio' ); ?>
</button>
<div class="radio-player__volume">
<button type="button" class="radio-player__mute" data-radio-mute aria-label="<?php esc_attr_e( 'Mute', 'radio' ); ?>">
<span class="dashicons dashicons-controls-volumeon" aria-hidden="true"></span>