VITREOUS

YOUR MUSIC DESERVES BETTER THAN A BASIC EMBED

Want to know more about Vitreous or learn about its use, use these 2 below to navigate to the areas you need:

About vitreous

Find out about Vitreous Music Player and its Library, Track and Artist management functions. Learn why this could be beneficial.

Knowledgebase

Get help in regards to the use of all functions of this plugin; its backend, its addition to pages and frontend use.

Find out how development of Vitreous is going:

 2026 BUILD COUNTS
JANUARYTemplate builds from v0.1.0 to v2.4.6
FEBRUARYWordPress plugin build from v3.0.0 to v4.0.12
MARCH64 builds from v4.0.13 to v4.3.10
APRIL46 builds from v4.4.0 to v6.5.3
MAY95 builds from v6.5.4 to v11.1.8

MAY 2026 BUILDS

TUESDAY THE 26TH OF MAY

  • Removed: Dead CSS from vitreous-player.css. Six dead blocks removed: orphaned property declarations with no selector (remnant of a deleted rule); #vamp-color-palette-section and #vamp-color-palette-light-section rules targeting elements that no longer exist in the player template; #vamp-embed-code-input rule for a removed embed code panel; #fullscreen-artist-profile rule targeting a non-existent ID (element uses fullscreen-artist-profile-extras); .fullscreen-meta-section rule for a class not present in the template or JS; #vamp-crossfade hide rules targeting removed UI controls. 52 lines removed, zero functional change.

  • Text: Full en-GB visible text pass across all frontend and admin files (excluding changelog). All em dashes in user-facing strings replaced with hyphens: format badge notices, import mode descriptions, download source hint, orphan purge notice, DO sidebar title, artist/library meta separator.
  • Text: American English corrected in the main player frontend: “color” changed to “colour” in Disco Mode warning; “Audio Normalization (Auto-Leveling)” changed to “Audio Normalisation (Auto-Levelling)”; “Audio Visualizer” changed to “Audio Visualiser” in label and aria-label; Version placeholder em dash changed to hyphen.
  • Removed: migrations/migrate-to-v4.php – migration class never referenced anywhere in the plugin. Dead file.
  • Removed: admin/admin-page.php – old modal and GUI editor page, never included or rendered anywhere. All IDs it defined were unhandled. Dead file.
  • Removed: ajax_delete_library() handler and its wp_ajax registration – library deletion is handled via a nonce-protected GET link in libraries-list.php. Never called from JS.
  • Removed: handle_import_tracks() handler and its admin_post registration – import was converted to AJAX at v11.1.2. The old form POST route was never reachable.
  • Removed: ajax_link_track_artist() handler and its wp_ajax registration – replaced by vitreous_link_unlinked_track. Never called from anywhere.
  • Removed: player_scale from set_default_options() and from settings-page.php POST save and read – the setting was saved but never read or applied anywhere in the plugin or JS.
  • Removed: vtReloadTracks dead call from import handler in admin.js – function never defined anywhere.
  • Removed: Misplaced Theme toggle comment from top of admin.js – sat above format indicator code, not theme toggle code.
  • Removed: Duplicate separator comment line in admin.js.
  • Removed: getAnimationSpeedLabel() from vitreous-player.js – defined but never called anywhere.
  • Removed: Empty else {} block in vitreous-player.js at the vitreousSettings check – did nothing.

MONDAY THE 25TH OF MAY

  • New: Track edit area – tracks with no audio file now show a red warning badge: “No audio file – this track will not be displayed on the frontend.” Matches the style of the existing audio format support notices. Badge updates dynamically when the audio URL field is cleared.
  • Fixed: Frontend player – tracks with an empty src field are now excluded from the track list rendered to the frontend. They are never passed to the player JS.
  • Fixed: Metrics — all ranking and count queries now exclude tracks with an empty src: Most Played, Most Liked, Artist Rankings, Genre/Mood/Tempo rankings, and per-library track counts in the metrics chart. Site Stats Card total track count, most played and most liked featured panels also exclude audio-less tracks.
  • Fixed: Import Tracks – file input and radio buttons now match Vitreous admin theme. Native file input hidden and replaced with a styled label trigger showing a folder icon and selected filename. Radio buttons use custom appearance: none styling with gold border and filled state on selection. Filename display resets to “No file chosen” after a successful import.
  • Fixed: Import button was unresponsive. Root cause: the import IIFE was placed inside the Display Options sidebar IIFE which guards all its code behind if (!doSidebar) return. On the library-edit page where #vt-do-sidebar does not exist, the entire block was skipped before the import handler ran. Fixed by wrapping the DO code in if (doSidebar) { ... } instead of using early return, allowing the import IIFE to execute unconditionally on all admin pages.
  • New: Import Tracks – three import modes added: Add New Only (previous behaviour), Overwrite Matching (replaces all fields on exact title match), Merge Matching (fills only empty fields on exact title match). Title matching is case-insensitive using LOWER() on both sides.
  • New: Import Tracks – close match review step. When an incoming track title is similar but not identical to an existing track (≥80% Levenshtein similarity), the import pauses and presents a per-track decision panel showing the incoming title alongside the matched existing title and similarity percentage. User chooses per track: Add as New, Overwrite Existing, Merge into Existing, or Skip. Exact matches and new tracks are processed automatically per the selected mode. Only close matches require user input.
  • Changed: Import is now AJAX-based rather than a full page POST/redirect. Results are shown inline without a page reload.

WEDNESDAY THE 20TH OF MAY

  • Fixed: Colour options removed from Display Options typography areas for accent-driven elements. astat_name and astat_track_likes on Artist Stats Card, and sstat_feat_count and sstat_feat_badge on Site Stats Card all use var(--accent) — their colour is controlled by the panel-level Accent picker only. Colour picker rows removed from their typography accordions in the DO sidebar, colour property skipped during frontend inline style generation, and colour column keys removed from $allowed_keys so they are never saved.
  • Fixed: Artist Stats Card — missing Display Options controls added: Stat Icons (Play & Heart) icon size slider; Most Liked Track Badge full typography area (font family, size, colour, weight, letter spacing). Both apply correctly to the rendered widget via inline styles.
  • Fixed: Site Stats Card — missing Display Options controls added: Count Icons size slider; Featured Count Badge full typography area; Featured Panel Label full typography area. All apply correctly to the rendered widget via inline styles.
  • New: DB migration adds missing columns to vitreous_display_options: astat_stat_icon_font_size, astat_track_likes_* (9 cols), sstat_count_icon_font_size, sstat_feat_count_* (9 cols), sstat_feat_badge_* (9 cols). All new keys added to $allowed_keys in ajax_save_display_options.
  • Fixed: Display Options accent and theme not persisting for Artist Stats, Track Player, and Site Stats tabs. Three state management breaks identified and corrected: (1) trigger button in libraries-list.php was missing data-astat-*, data-tplayer-*, data-sstat-* attributes — accent and theme were never read from the DB at page load; (2) vtDoPopulateFromTrigger in admin.js only populated list, card, alist — new sections never populated on sidebar open; (3) save handler write-back only updated list, card, alist data attributes — new section values lost on next open without a page reload.
  • Fixed: Display Options not persisting for Artist Stats, Track Player, and Site Stats tabs. All astat_*, tplayer_*, and sstat_* column keys were missing from the $allowed_keys whitelist in ajax_save_display_options. POST data for these fields was being silently stripped before the database write. All 106 new keys added to the whitelist.
  • Fixed: Track Player card now has a fixed width via --vtp-max-width: 480px CSS variable and centres within its container using display: flex; justify-content: center on the root — mirroring the main player pattern.
  • Fixed: Track Player volume slider now slides in and out with 10-second auto-hide. Player bar wrapped in .vt-list-item-player so vtListInit in vitreous-list.js discovers and wires up all controls via the existing standalone item path.
  • Fixed: Track Player responsive breakpoint added — at max-width: 520px the card width falls back to 100% to fill narrow screens gracefully.
  • Fixed: Track Player shortcode was reading file_source_url (the download source) as the audio element src. Corrected to read the src column, which holds the direct audio URL used by all other player contexts.
  • Major: Three new frontend widgets added — Artist Stats Card, Single Track Minified Player, and Site-Wide Stats Card. All available as Elementor widgets, Gutenberg blocks, and shortcodes. All support Display Options styling. DB migration adds 106 new columns to vitreous_display_options (astat_*, tplayer_*, sstat_*).
  • New: Display Options sidebar updated to two-row tab layout (six tabs, three per row) to accommodate the three new widget tabs. Tabs: Track List, Artist Card, Artist List, Artist Stats, Track Player, Site Stats.
  • New: Metrics page — Most Played Artists and Most Liked Artists ranking panels added. Top Genres, Top Moods, Top Tempos attribute ranking sections added. Per-library bar chart now shows average plays per track. Artist filter dropdown added to the time-series chart for per-artist play overlay.
  • New: Library Edit — unlinked track count badge in the Tracks header. Artist Profiles — Unlinked Tracks section in Column C with inline Link button.
  • Summary of patch versions leading to this release: v10.1.7 (artist chart line), v10.1.8 (DB migration), v10.1.9 (DO tab layout + new panels), v10.1.10 (admin.js extension), v10.1.11 (Artist Stats widget), v10.1.12 (Track Player widget), v10.1.13 (Site Stats widget).
  • New: Site-Wide Stats Card widget — displays aggregate totals (total plays, likes, tracks, artists, libraries) in a count grid, plus three featured panels: Most Played Track, Most Liked Track, and Most Active Library — each with album art, gradient overlay, title, artist/meta, and count badge. Available as Elementor widget, Gutenberg block, and shortcode [ vitreous_site_stats ]. Supports Display Options via sstat_* columns.
  • New: Single Track Minified Player widget — displays a single track with album art thumbnail, title, and artist in a meta row above a horizontal minified player (play button, progress bar, volume control). Track selected from all available tracks across all libraries. Available as Elementor widget, Gutenberg block, and shortcode [ vitreous_track_player id="#" ]. Reuses .vt-list-* player classes so the existing vitreous-list.js handles all audio controls automatically. Supports Display Options via tplayer_* columns.
  • New: Artist Stats Card widget — displays artist image, name, social icons, total plays, total likes (aggregated from all linked tracks), and most liked track with album art, gradient overlay, and like count badge. Available as Elementor widget, Gutenberg block, and shortcode [ vitreous_artist_stats id="#" ]. Styled to match Artist Card. Supports Display Options via astat_* columns.
  • New: admin.jspreviews object extended with astat, tplayer, sstat preview panel references.
  • New: vtDoUpdatePreviewpreviewMap extended with typography element mappings for all three new sections. Social icon size preview extended to include astat.
  • New: vtDoLoadFirstTrack — populates all new preview element text nodes with first track data on sidebar open.
  • New: vtDoLoadTypography — skip list extended to ignore astat_*, tplayer_*, sstat_* accent and theme keys during load.
  • New: Display Options sidebar tab bar updated to two-row layout — flex-wrap: wrap with flex: 0 0 33.333%, three tabs per row. Font size reduced to 11px to accommodate longer labels. Three new tabs added: Artist Stats, Track Player, Site Stats.
  • New: Three new live preview panels added to the DO sidebar: Artist Stats preview (image, name, social icon, stat blocks, most liked track), Track Player preview (meta row with art/title/artist, horizontal player bar), Site Stats preview (count blocks, featured track panel).
  • New: Three new DO section panels added (astat, tplayer, sstat) — full typography, colour, glass mode controls. Artist Stats includes social icon size control.
  • DB: Migration added to maybe_upgrade_schema for v11.0.0 widget Display Options columns — astat_* (Artist Stats Card: 48 columns), tplayer_* (Track Player: 20 columns), sstat_* (Site Stats Card: 38 columns). All added via ALTER TABLE with existence check. No frontend changes.
  • New: Metrics chart — third line added showing artist plays over time in purple (rgba(167,139,250,0.85)), rendered as a dashed line to distinguish from the solid Plays and Likes lines. Only appears when an artist is selected.
  • New: Artist filter dropdown added to the chart legend. Selecting an artist re-fetches the chart and overlays their play activity. Defaults to “All Artists” (no third line). Only appears when at least one artist has play data.
  • New: Chart tooltip gains a third “Artist” row showing artist plays for the hovered bucket. Hidden when no artist is selected.
  • Fixed: Metrics page critical error — PHP parse error: unexpected endif on line 880. The <?php if ($play_log_exists): ?> wrapper around the chart script block was lost when the new ranking sections were inserted. The orphaned endif caused a fatal parse error before any page output. Wrapper restored.
  • Debug: Temporary error reporting added to metrics-page.php to surface the exact PHP fault in the browser. To be removed once fault is identified.
  • Fixed: Metrics page critical error. $wpdb->prepare() was being called with a partial SQL fragment inside string concatenation passed to get_results(). Replaced with safe intval() interpolation — $filter_library is already sanitised with intval() at input, making direct interpolation safe.
  • Fixed: Metrics page critical error. Artist ranking queries were constructing invalid SQL by appending AND t.library_id = %d directly after a JOIN clause with no preceding WHERE keyword. Added WHERE 1=1 before the conditional filter clause in both Most Played Artists and Most Liked Artists queries. Library filter variable extracted to $lib_where_artists to avoid calling $wpdb->prepare() inside string concatenation twice.
  • Fixed: Metrics page critical error. HAVING total_plays > 0 and HAVING total_likes > 0 in the Most Played Artists and Most Liked Artists queries used column aliases in the HAVING clause, which is not supported by MariaDB. Replaced with full aggregate expressions: HAVING SUM(t.global_play_count) > 0 and HAVING SUM(t.global_favourite_count) > 0.
  • Fixed: Metrics page critical error on load. MySQL reserved word at was used as a table alias in the Most Played Artists, Most Liked Artists, Unlinked Tracks (AJAX), and Library Edit unlinked count queries. All new query aliases renamed to vat.
  • New: Metrics — Most Played Artists and Most Liked Artists ranking panels added below the existing track rankings. Both follow the same panel pattern as Most Played and Most Liked tracks. Requires tracks to be linked to artist profiles to populate.
  • New: Metrics — Track Attribute Rankings section added: Top Genres, Top Moods, and Top Tempos, each showing a ranked scrollable list with inline bar chart and play count. All filtered by the existing library filter.
  • New: Metrics — Per-Library bar chart now shows average plays per track alongside total plays and likes.
  • New: Library Edit — Unlinked track count badge added to the Tracks section header. Only appears when one or more tracks in the library have no linked artist profile. Shown in red to distinguish from informational badges.
  • New: Artist Profiles — Unlinked Tracks section added to Column C. When an artist is selected, all tracks across all libraries with no artist link are listed below the Linked Tracks panel. Each unlinked track has an inline Link button to assign it to the selected artist immediately without leaving the page.

TUESDAY THE 19TH OF MAY

  • Fixed: Display Options sidebar button was non-functional — clicking it produced no response. Root cause: vtDoUpdatePreview, vtDoLoadFirstTrack, vtDoSetText, and vtDoLoadTypography function definitions were missing from admin.js. A ReferenceError on vtDoUpdatePreview halted execution inside vtDoPopulateFromTrigger before vtDoOpen was ever reached. All four functions restored from v8.3.1.
  • Fixed: Editor overlay added to .glass-player via CSS ::after pseudo-element, scoped to body.elementor-editor-active. Displays “Ready for Live Page” in gold over the glassmorphic card when a library is selected in the Elementor editor. No effect on the frontend.
  • Removed: Alignment controls removed from Elementor widget and Gutenberg block. Queued for future work.
  • Fixed: Player width setting now works correctly. .glass-player was hardcoded to 400px inside @media (min-width: 521px), overriding --player-max-width entirely. Replaced with var(--player-max-width, 420px). All width defaults (CSS, JS, PHP, template) corrected from 400px/500px to 420px to match the settings slider minimum.
  • Fixed: .player-wrapper no longer uses min-height: 100vh or align-items: center in standard page view — the player now sits naturally in the page flow rather than being vertically centred in the viewport. Fullscreen mode retains full centring via explicit rules on :fullscreen and .fullscreen-override.
  • New: Player alignment control added. Shortcode supports align="left|center|right" (default: center). Elementor widget has a new alignment picker (left/centre/right) in the widget panel. Gutenberg block has a new alignment select in the inspector sidebar. All three apply a vt-align-* class to .player-wrapper. Users can use widget/block padding and margin to fine-tune placement.

SUNDAY THE 17TH OF MAY

  • Fixed: Animation Speed dropdown showed no selected option on load. The reset path was setting animationSpeed: 1.0 (float) while the select option has value="1" (string). Changed to animationSpeed: 1 throughout. Change handler updated to store the value as a string rather than parsing it back to a float via parseFloat, eliminating the type mismatch.
  • Fixed — Rope, Pulse Rings, DNA/Helix: All three styles were using a full-spectrum frequency average which produced low values on bass-heavy and DnB tracks, causing minimal reactivity. All three now sample the first 20 frequency bins (sub-bass and kick range, ~20–200Hz) instead. Rope amplitude, Pulse Rings spawn threshold, and DNA/Helix strand amplitude all now respond correctly to bass-driven and low-BPM tracks.
  • Fixed — Pulse Rings: Spawn threshold raised from 0.15 to 0.30 to reduce excess ring density. Spawn guard gap increased from r>12 to r>30 to space rings further apart. Alpha decay slowed from 0.93 to 0.97 so rings remain visible across more of the canvas width. Growth rate increased from 2.5 to 3.5 so rings reach the far edge before fading completely.
  • Fixed — Pulse Rings: Spawn threshold lowered from 0.55 to 0.15 so rings appear at normal playing volumes. Starting radius changed from 2 to 0 so rings are visible immediately at the left edge.
  • Fixed — Particle Drift: Upward float fixed — velocity now decays toward zero at low signal using a damping factor rather than drifting constantly. Spawn position uses full canvas height (random y between 2 and h-2) instead of always spawning at centre. Blur added to each dot. Each particle has a randomly assigned fade target between 60%–100% of canvas width so particles disappear at varied positions.
  • New: Waveform container edge fade added via CSS mask-image — 12px soft fade on left and right edges, 4px on top and bottom. Affects all canvas layers simultaneously including the static waveform, live visualiser, progress overlay, and playhead.
  • New: Five additional live visualiser styles — Circles (repeating portrait-mirrored circles across canvas width), Rope (sine wave driven by audio amplitude), Pulse Rings (concentric arcs expanding from left edge on transients), Particle Drift (dots drifting right with vertical oscillation, fading to transparent), DNA / Helix (two offset sine waves with scrolling rungs). All selectable from the Visualiser Style dropdown in Visual settings.
  • Renamed: “Circular” visualiser style renamed to “Circles”.
  • Improved: Oscilloscope line spacing increased — samples every 8th point instead of every point, giving the waveform more breathing room.
  • Fixed: Static waveform seed changed from a fixed value of 42 to the track DB ID. Each track now generates a unique stable decorative waveform that is consistent across page loads.
  • New: Three additional live visualiser styles added — Oscilloscope (raw time-domain signal as a continuous line), Filled Wave (frequency data as a filled gradient area), and Circular (frequency bars radiating from a centre point). Selectable via a new Visualiser Style dropdown in the player Visual settings tab. Style persists to localStorage.
  • Fixed: Keyboard Shortcuts button and sidebar are now hidden on touch-primary mobile and tablet devices on init, using the existing vtIsMobileDevice() check. Keyboard shortcuts are not applicable on touch devices.
  • Fixed: Landscape fullscreen overlay was incorrectly firing on desktop browsers in widescreen because window.innerWidth > window.innerHeight is always true on a landscape monitor. Added vtIsMobileDevice() check — navigator.maxTouchPoints > 0 combined with (pointer: coarse) media query — so the overlay only activates on touch-primary mobile devices. Desktop browsers are unaffected.
  • Fixed: Artist Profiles three-column layout now uses 1fr 1fr 1fr — equal thirds — instead of a fixed-width approach that left Column A dominating. All three columns share the available width equally.
  • Improved: Linked Tracks items in Column C now have left and right padding (14px) giving the art thumbnail and library pill breathing room.
  • Fixed: Three-column layout on Artist Profiles was still collapsing because the .vt-track-editor-layout--three-col modifier rule was declared before the base .vt-track-editor-layout rule in the stylesheet, causing the base two-column grid-template-columns to win the cascade. Modifier moved to after the base rule so it correctly overrides it.
  • Fixed: Three-column layout on Artist Profiles was still collapsing because calc(100% - 700px) for Column A produced a near-zero or negative value when the WordPress admin container width was reduced by the sidebar. Replaced with minmax(160px, 1fr) so Column A flexes within available space without going negative, while Columns B (400px) and C (300px) remain fixed.
  • Fixed: Artist Profiles three-column layout was collapsing Column C into a full-width row below Columns A and B at desktop widths due to an uninstructed 1100px breakpoint. Removed. Three columns now remain side by side at all desktop widths. Mobile stack at 700px is retained.
  • Improved: Artist Profiles page now uses a three-column layout. Linked Tracks moves from the bottom of Column B (editor form) into a dedicated Column C (300px fixed, scrollable) sitting alongside the artist list and editor. A loading indicator shows while tracks are fetched.
  • Responsive: At 1100px and below, Column C drops to a full-width row below Columns A and B (max-height 300px). At 700px and below all three columns stack vertically.
  • New DB table: vitreous_artist_tracks — stores direct artist-to-track links (artist_id, track_id). Replaces fragile text-matching between the track Artist field and the artist profile Name field. Migration guard added to maybe_upgrade_schema() for existing installs.
  • Backend — Track Edit: Artist field replaced with a searchable combo input backed by a datalist of all existing artist profiles. Selecting a profile sets a hidden linked_artist_id field. A “New” button reveals an inline create form (Name, Year Started, Bio, Image) that saves via the existing vitreous_save_artist handler, then automatically selects the newly created profile. A clear button removes the link.
  • Backend — Artist Profiles: Column B now shows a “Linked Tracks” section listing all tracks linked to the selected artist, with art thumbnail, title, and library name.
  • Backend — Save flow: ajax_save_track() accepts linked_artist_id. If set, the linked profile name is synced into the cached artist column automatically. The artist-track link is written to vitreous_artist_tracks. ajax_load_track() JOINs the linkage table and returns linkedArtistId so the combo shows the correct profile on load.
  • Frontend — Player: Artist profile matching in the fullscreen sidebar now uses linkedArtistId (ID lookup) as the primary method, falling back to text match for tracks without a link. This eliminates case-sensitivity and whitespace fragility.
  • New AJAX handlers: vitreous_link_track_artist (write/clear a link), vitreous_get_artist_tracks (fetch all tracks linked to an artist).
  • Fixed: Added 16px spacing between the copyright line and the Ko-fi button in the About sidebar.
  • New: Ko-fi support button added to the About sidebar of the main player, below the copyright line. Gold coloured (#c4a75d) to match the plugin aesthetic.
  • Fixed: Metrics page layout corrected — time-series chart and per-library breakdown now appear above the Full Rankings, under an “Activity Over Time” section label. Rankings appear below under “Full Rankings”.
  • Fixed: Most Played and Most Liked ranking lists are now scrollable fixed-height panels (max-height: 520px; overflow-y: auto) so they do not flood the page with large track libraries. Custom scrollbar styled to match the plugin gold palette.
  • Improved: Bar chart replaced with a smooth curved line chart. Two lines (plays gold, likes red) drawn using cubic bezier curves. Subtle filled area beneath each line. Data point circles on each bucket. Y-axis gridlines and X-axis labels retained.
  • New: Hover tooltip added — HTML div absolutely positioned over the chart container (z-index: 100), showing the bucket label, play count, and like count on mouseenter of invisible hit-area rects. Edge-aware positioning: right-edge overflow anchors tooltip to the left of the point; left-edge check ensures tooltip never clips at the left boundary.
  • New: Dedicated Metrics admin page (vitreous-metrics) added to the WordPress sidebar. Contains the full extended Most Played and Most Liked rankings (no cap, all tracks with at least one play or like), filterable by library via a dropdown. Each panel shows a track count badge in the header. Time-series chart (Hourly/Daily/Monthly/Custom) and per-library breakdown sit below the rankings.
  • Fixed: Metrics chart and library breakdown removed from the Overview page where they did not belong. Overview now contains only the stats bar, quick actions, top 10 Most Played, top 10 Most Liked, and the Ko-fi support panel.
  • New: Metrics quick action card added to the Overview page linking to the new Metrics page.
  • New DB tables: vitreous_play_log and vitreous_like_log added. Each play event inserts a row into vitreous_play_log (track_id, library_id, played_at). Each like or unlike event inserts a row into vitreous_like_log (track_id, library_id, action, liked_at). Existing running totals and last_played_at behaviour are completely unchanged.
  • New AJAX handler: ajax_get_metrics() — admin-only, nonce-protected. Accepts range (hourly/daily/monthly/custom) and optional date_from/date_to. Returns grouped play and like totals as JSON plus per-library running totals. Custom ranges over 90 days auto-switch to monthly grouping. Max range capped at 365 days server-side.
  • Overview page — Metrics section: Four-tab chart panel (Hourly 24h, Daily 30d, Monthly 12m, Custom) with SVG bar chart showing plays (gold) and likes (red) per time bucket. Custom tab shows native date inputs with 365-day max validation. Per-library horizontal bar breakdown below the chart, drawn from all-time running totals. Historical data note displayed — time-series data records from v9.0.0 onwards only.
  • Fixed: Scenario B-2 — when a user pressed the fullscreen button in landscape, rotated to portrait, and the overlay dismissed, the player showed with the accent gradient but not in true fullscreen (website chrome visible around it). Native fullscreen was never entered in Scenario B. A vtScenarioBPending flag now tracks this state. When the resize listener detects a portrait rotation while the flag is set, it calls requestFullscreen() to properly enter native fullscreen, then clears the flag. The flag is also cleared on Exit Fullscreen button press (Scenario B-1).
  • New: Landscape fullscreen overlay added. When the player is in fullscreen and the device rotates to landscape, a blocking overlay appears with a rotate-back prompt and an Exit Fullscreen button. Rotating back to portrait automatically dismisses the overlay. When the fullscreen button is pressed while already in landscape, the overlay appears instead of entering fullscreen. The native fullscreen state is only exited if the user explicitly presses Exit Fullscreen.
  • New: BPM sort filter now has two directions — BPM ↑ (slow to fast) and BPM ↓ (fast to slow). Group order in the playlist panel reverses accordingly. Both directions are reflected in play order via buildPlayOrder().
  • New: BPM badge colours now use a continuous rainbow gradient derived from the actual BPM value. 70 BPM and under renders blue (hue 220). 71–200 BPM interpolates across the full rainbow (blue → cyan → green → yellow → orange → red). Over 200 BPM renders purple (hue 270). Colour is applied inline via applyBpmBadgeStyle() — the three static CSS classes (bpm-slow, bpm-medium, bpm-fast) are removed.
  • Fixed: Track play order (Next/Prev buttons, swipe, keyboard arrows, auto-advance on end) previously followed DB insertion order regardless of the active sort filter. A playOrder array is now maintained — an ordered list of track indices matching the active sort mode — rebuilt on init and whenever the sort filter changes. Next and Prev navigate through playOrder, so play order always matches what the user sees in the track list.
  • Fixed: Shuffle now picks randomly from playOrder rather than the raw track count, correctly acting as an override to the sort order rather than ignoring it.

FRIDAY THE 15TH OF MAY

  • Fixed: Audio visualiser bars had a hardcoded cyan/teal bottom gradient stop (rgba(0,210,255,0.3)) regardless of the track accent colour. The bottom stop now derives from currentThemeHex — parsed to RGB, reduced to 25% brightness, at 0.4 opacity — giving a dark shade of the accent colour instead.
  • Fixed: Browse Libraries and Artist Profiles quick-action cards on the Overview page were showing empty icon boxes. fa-list-music and fa-user-music are Font Awesome Pro icons not available in the free CDN. Replaced with fa-layer-group and fa-user respectively.
  • New: Overview page now shows Most Played and Most Liked track rankings — top 10 each, side by side. Each entry shows position number, album art thumbnail, track title, artist, library name (as a pill label), and the play or like count. Tracks with zero plays or likes are excluded. Empty state shown if no data exists yet.
  • CSS: New ranking panel styles added to admin.css. Rankings collapse to a single column below 900px.
  • New: Overview page added as the Vitreous plugin landing page. Shows live counts for libraries, tracks, and artist profiles. Quick-action cards link directly to Add a Library, Browse Libraries, Artist Profiles, Settings, and Changelog. Includes a Ko-fi support button at the bottom.
  • Structure: Top-level Vitreous menu item now opens the Overview page. Libraries list moved to its own submenu entry (vitreous-library-list). All internal back-links and delete redirects updated accordingly. No DB changes.

THURSDAY THE 14TH OF MAY

  • Fixed: After saving a track, the sidebar item in Column A did not update its art thumbnail, artist meta line, or duration — requiring a full page refresh to see the correct data. Both wp_send_json_success calls in ajax_save_track() now return art, artist, and total_time alongside track_id and title, matching what the JS sidebar update handler expects.
  • Rebuild: Library Edit and Artist Profiles backend layout rebuilt to match the Standalone Tracklist Builder. Column A (track/artist list) now fills the majority of the screen width; Column B (edit form) is a fixed 400px panel on the right. Grid changed from 240px 1fr to calc(100% - 400px) 400px in admin.css.
  • Rebuild: Track sidebar items in Column A now display a number badge, art thumbnail, title, artist meta line, and duration. DB query in library-edit.php updated to include artist, art, and total_time. New CSS classes added: .vt-track-sidebar-num, .vt-track-sidebar-art, .vt-track-sidebar-info, .vt-track-sidebar-meta, .vt-track-sidebar-duration.
  • Rebuild: Artist sidebar items in Column A now display the artist image thumbnail and name. DB query in artist-profile-page.php updated to include image_url.
  • Rebuild: Track edit form in Column B (track-row.php) converted from form-table two-column layout to single-column builder form with labelled sections and paired field rows. All field name attributes, data-index values, and JS hook classes preserved unchanged.
  • Rebuild: Artist edit form in Column B (artist-profile-page.php) converted to builder form sections — Artist Image, Artist Details, Social Media. All element IDs preserved unchanged.
  • Fix: Dynamic track and artist item creation in admin.js updated to match new enriched sidebar HTML. vtSortSidebar now renumbers .vt-track-sidebar-num badges after every sort and delete.
  • Fix: Two .closest('.vt-track-fields') calls in the WP Media Library audio picker updated to .closest('.vt-tab-panel') to remain functional after removal of .vt-track-fields wrapper.
  • CSS: Responsive collapse breakpoint for .vt-track-editor-layout moved from 900px to 700px to preserve the two-panel layout at typical admin widths.

WEDNESDAY THE 13TH OF MAY

  • Redesign: All backend page headers (.vitreous-page-head) redesigned to match the Tracklist Builder top bar — sticky, dark glass background with gold gradient, backdrop blur, border and shadow. Applied across all admin pages via admin.css.
  • Redesign: Changelog page header updated to match the new page header style.
  • Redesign: Vitreous logo updated to white SVG (vitreous-logo-white.svg) across all admin pages — correct for dark header backgrounds.
  • Redesign: Library name in library-edit.php restyled as a prominent inline editable heading — large uppercase text with underline input replacing the standard form row.
  • Layout: Audio File URL and Album Art URL fields moved to a full-width section above the two-column track edit grid in track-row.php.
  • Fixed: Sidebar bleeding on mobile — `.vamp-sidebar`, `.vamp-sidebar-right` and `#dna-recon-sidebar` width and hidden position constraints now applied at 768px covering all phones and tablets, including the Honor 90 on Vivaldi and Opera GX.
  • Fixed: Fullscreen track/artist sidebar (`#fullscreen-metadata-sidebar .vamp-sidebar-content`) could not be scrolled by touch on mobile. Touch scrolling restored within the 768px breakpoint.

TUESDAY THE 12TH OF MAY

  • Layout: Desktop and mobile player layouts are now fully separated via @media — no shared sizing rules between the two.
  • Desktop (min-width: 521px): transform: scale() removed. All internal elements sized to 80% of previous coded values matching the previous scale(0.8) visual. Player width 400px. Player Scale setting removed from backend.
  • Mobile (max-width: 520px): Player fills viewport width. All internal elements use clamp() for fluid sizing. Both sidebars constrained to calc(100vw - 40px). Player wrapper padding reduced to 8px.
  • Fixed: vtUpdateFormatIndicator exposed globally via window.vtUpdateFormatIndicator so it is accessible from the WordPress Media Library integration block outside the main IIFE.
  • Fixed: Auto-fill of track title and duration when selecting audio from WP Media Library. JS was traversing to .track-row which does not exist — corrected to .vt-track-fields. Removed reference to non-existent .track-title-display class.
  • Fixed: Duration fallback path now correctly handles tracks over 60 minutes, outputting H:MM:SS format instead of MMM:SS.
  • Fixed: Main player current time counter now shows H:MM:SS for tracks over 60 minutes. Shared vtFormatTime() function used across all three time display points.
  • Fixed: Minified player (Track List, Artist Card, Artist List) current time counter now shows H:MM:SS for tracks over 60 minutes via updated vtListFormatTime().
  • New: Duration field in track edit now has a ? help button opening a modal listing accepted duration formats (M:SS, MM:SS, H:MM:SS, HH:MM:SS).

SATURDAY THE 9TH OF MAY

  • Fixed: Artist List search and pagination typography not applying on frontend. Both elements moved inside .vt-artist-list-root so they are children of the ID-scoped root element, matching the existing typography scoping pattern used by all other Artist List elements.
  • DB: 18 new columns on vitreous_display_optionsalist_search_* and alist_pagination_* (9 typography properties each). Added safely via SHOW COLUMNS guard in maybe_upgrade_schema().
  • New: Artist List Display Options now includes Search Input and Pagination typography areas, matching the Track List accordion.
  • Fixed: Track List and Artist List search and pagination now consistently themed. CSS variables and data-theme moved from the inner root element to the outer wrapper in both shortcodes, so search and pagination correctly inherit glassmorphic styling and accent colours from Display Options.
  • Fixed: Artist List search and pagination now correctly inherit theme CSS variables. data-theme and inline CSS vars moved from .vt-artist-list-root to .vt-artist-list-wrapper so all child elements including search and pagination receive them.
  • Fixed: Artist List search and pagination CSS rewritten to mirror the Track List accordion pattern exactly — same sizing, same variable usage, same hover/active states.

TUESDAY THE 5TH OF MAY

  • New: Artist List — fuzzy search input filters artists by name in real time. Pagination at 10 artists per page with Previous/Next and page number controls.
  • Fixed: Elementor Artist List widget — Show All toggle now correctly reveals a multi-select artist picker when toggled off. Selected artist IDs are passed to the shortcode as id="1,2,3".
  • Fixed: Gutenberg Artist List block — Show All toggle now reveals per-artist toggle controls. Selected artists stored as artistIds attribute and passed to the shortcode. vitreousArtists now localised to the artist list block script.
  • Fixed: Last Modified column now displays the raw stored date and time (DD/MM/YYYY HH:MM) with no time-ago calculation. Removes timezone offset issues that varied by server and user location.
  • Fixed: Last Modified time-ago was offset by the server timezone. Now uses WordPress’s configured GMT offset for date display and current_time('timestamp') for time-ago comparison — correct for any server location worldwide.
  • Fixed: Last Modified on the library list was showing the creation date instead of the actual modification date. The updated_at column on vitreous_libraries was missing ON UPDATE CURRENT_TIMESTAMP on existing installs due to a dbDelta limitation. Fixed via a SHOW COLUMNS guard in maybe_upgrade_schema() that runs a targeted ALTER TABLE MODIFY COLUMN on affected installs only.
  • Fixed: Library list query filter removed — phantom entries can no longer be created since the pre-insert was removed in v8.1.4. Any existing phantom entries are visible and deleteable via the standard Delete button.
  • Fixed: Add New Library — blank page after saving. wp_redirect was failing silently as headers were already sent. Replaced with JavaScript redirect.
  • Fixed: Library list now hides phantom (empty-titled) libraries from the list query.
  • Fixed: Last Modified column now shows UK date/time (DD/MM/YYYY HH:MM) with time-ago below in muted text.
  • Fixed: Vitreous Artist List Gutenberg block error — SelectControl was missing from component destructuring.
  • Fixed: About sidebar version was hardcoded at v4.4.0. Now reads dynamically from vitreousSettings.pluginVersion.

SUNDAY THE 3RD OF MAY

  • Fixed: Year sort now sorts by full release date, not just year. Tracks within the same year are ordered by their complete parsed date, then A-Z by title as a tiebreaker.
  • New: vtParseReleaseDate() — full date parser supporting ISO, DD/MM/YYYY, DD-MM-YYYY, ordinal long form (30th April 2026), plain long form (30 April 2026), named month US order (April 30, 2026), month and year only (April 2026), and year only. US numeric MM/DD/YYYY is intentionally excluded. UK regional DD/MM assumed for ambiguous numeric formats.
  • New: Release Date field in track edit now has a help button () that opens a modal listing all accepted date formats. Modal closes via X button, Close button, overlay click, or Escape key.
  • Fixed: Recently Played tab was inheriting admin backend styles, showing a gold border and gold text instead of matching the player frontend theme. Tab now uses var(--player-accent) — identical to the TRACKS tab — so it responds to per-track colour changes and global player colour settings. Inactive tab renders at 0.4 opacity; active tab at full opacity.

SATURDAY THE 2ND OF MAY

  • New: Recently Played tab added to the Media Recon sidebar to the right of TRACKS. Shows the 10 most recently played unique tracks for the current library, ordered by most recent play time. Deduplicated via GROUP BY id — each track appears once at its most recent play time.
  • New: Clicking a Recently Played track row selects it in the main player.
  • New: 300-second auto-refresh poll fires while the Recently Played tab is open. Poll is cleared when switching back to TRACKS or closing the Media Recon sidebar.
  • New: vitreous_get_recently_played AJAX endpoint — accepts library_id, returns 10 deduplicated recently played tracks.
  • DB: Two new columns on vitreous_display_optionscard_social_icon_font_size and alist_social_icon_font_size. Added safely via SHOW COLUMNS guard in maybe_upgrade_schema().
  • New: Social Media Icons accordion area added to the end of the Typography section in Artist Card and Artist List Display Options panels. Contains a single icon size slider (8–48px) with a synced text input.
  • New: Live preview shows a sample Instagram icon in the Artist Card and Artist List preview sections. Icon size updates in real time as the slider is adjusted.
  • New: Saved icon size applied to all social link elements on the frontend via inline style.
  • Fixed: Media Recon like count spacing not applying on mobile — .track-favorite-btn now uses display: flex; align-items: center so the margin-left on the count span works correctly in both desktop and mobile contexts.
  • Fixed: Media Recon like count spacing — margin-left increased from 3px to 8px to give clear separation between the heart icon and the count number.
  • Fixed: Tracklist utility row — global like count moved to between the heart button and the download icon. Order is now: heart | like count | download | play count.
  • Fixed: Artist Card and Artist List random track players were not incrementing global play counts. The track DB id was selected in the query but never rendered onto the .vt-list-item-player div as data-track-id, so the play count AJAX call had no track ID to send. Attribute added.
  • Fixed: Heart icon state not syncing between main player and tracklist widget on toggle. Added shared window.vtUpdateAllHeartState(trackDbId, trackIdx, isFavourited) function updating Media Recon heart button, fullscreen heart button, and tracklist heart button simultaneously. Added data-track-index to Media Recon heart button so it can be found by the shared function.
  • Fixed: Like count not syncing between main player and tracklist widget on toggle. A shared window.vtUpdateAllLikeCounts(trackDbId, trackIdx, count) function is now defined by the main player and called by both the main player and tracklist widget on every toggle and poll response — updating Media Recon, fullscreen sidebar, and tracklist utility row simultaneously. Fallback handles tracklist-only pages where the main player is absent.
  • Fixed: Main player regression — tracks was used instead of the correct trackData variable in both the toggleFavorite handler and the 60-second poll, causing a ReferenceError that prevented the player from initialising.
  • Fixed: Media Recon and fullscreen sidebar like count not updating on toggle — the tracks array was not updated before updatePlaylistUI rebuilt the DOM, causing the AJAX response to target a replaced element. Count now updates the tracks array first so subsequent UI rebuilds render the correct value.
  • Fixed: Redundant heart icon removed from the tracklist utility row global likes span — the like button already has its own heart icon.
  • New: vitreous_get_track_counts AJAX endpoint returning global like and play counts for multiple track IDs in a single request.
  • New: 60-second poll in both the main player and tracklist widget refreshing global like counts from the server. All visible count displays update in sync.
  • DB: New global_favourite_count column on vitreous_tracks. 18 new typography columns on vitreous_display_options for Global Likes and Global Plays text areas. Both added safely via SHOW COLUMNS guards in maybe_upgrade_schema().
  • New: Global like count — clicking the heart/favourite toggle increments or decrements the global like count via AJAX. Decrement floors at 0. Count updates immediately on the page without reload.
  • New: Media Recon — global like count displayed to the right of the heart icon per track row.
  • New: Fullscreen sidebar — global like count displayed below the Favourite button label.
  • New: Accordion track list utility row — global like count (heart icon + number) shown to the left of the global play count. Updates immediately on toggle.
  • New: Display Options — Global Likes and Global Plays are now separate typography areas in the Track List section.
  • Fixed: Artist Card and Artist List Elementor widgets now have a Display Options Library dropdown. The selected library ID is passed to the shortcode so Display Options are correctly applied on the frontend.
  • Fixed: Artist Card and Artist List Gutenberg blocks now have a Display Options Library selector in the block inspector. The selected library ID is stored as a block attribute, passed to the render callback, and included in the shortcode call. vitreousLibraries now localised to both artist block scripts.
  • Fixed: Live preview now updates in real time on every control change — colour pickers, hex inputs, sliders, text inputs, selects, and glass mode toggle all call the preview update immediately. Select elements now correctly use the change event. This was missing from the initial build.
  • Updated: Font Size control replaced with a slider (8–72px) synced with a text input. Dragging the slider updates the text input. Typing in the text input updates the slider. Value saved and applied as px.
  • Fixed: All admin CSS and JS enqueue version strings updated to match the plugin version — previously left at old values causing WordPress to serve cached files and preventing updated styles from loading.
  • New: Font Family control replaced with searchable font picker matching Stratum’s implementation — fuzzy search across System Fonts and Google Fonts, selected font rendered in its own typeface, Google Fonts injected dynamically on selection.
  • Fixed: Display Options sidebar inputs and selects were unstyled due to WordPress core overriding plugin CSS. Scoped !important overrides added to #vt-do-sidebar matching Stratum’s pattern, correctly theming all text inputs, selects, and colour pickers.
  • Fixed: Display Options sidebar moved to the correct location — Libraries list page, one trigger button per library row in the actions column alongside Edit and Delete. Sidebar shell rendered once after the page wrap, hidden by default. Follows the Stratum pattern exactly: trigger button carries saved accent/theme values as data attributes, sidebar is populated immediately from those on click, typography loaded via AJAX, saved values written back to trigger button data attributes on save so reopening the same row shows correct values without a fresh fetch.
  • Fixed: Display Options button and sidebar completely removed from library edit page.

FRIDAY THE 1ST OF MAY

  • DB: New vitreous_display_options table — one row per library, library_id as unique key. 180 scalar columns covering accent colour, glass mode toggle, and 9 typography properties for 19 named text areas across Track List, Artist Card, and Artist List widgets.
  • New: Display Options button on the library edit page opens a right sidebar with Live Preview, tabbed sections for Track List, Artist Card, and Artist List, each with Colours and Typography sub-sections.
  • New: Live Preview shows the first real track from the library. Updating any control updates the preview immediately.
  • New: Accent colour picker and hex input synced per section. Glass Mode toggle switches between Light and Dark glassmorphic backgrounds.
  • New: Typography controls per named text area — font family, size, colour, weight, style, text transform, text decoration, letter spacing, line height. No alignment.
  • New: All three shortcodes read saved Display Options for the library and apply data-theme, inline CSS variable overrides, and scoped typography styles on the root element.
  • New: Dark glass mode added to all three widget CSS files — rgba(0,0,0,0.X) values matching light mode opacity.
  • Fixed: Minified players in the accordion track list, artist card, and artist list tracklists were not incrementing the global play count when a track was played. Global play count is now incremented via vitreous_increment_play AJAX on each play press — matching the main player pattern. vitreousListSettings localised to provide ajaxUrl to the list script.
  • Fixed: Page load performance — audio context and compressor chain now created only on first play press, never on page init. Removed vtListApplyNormalisation which was fetching every audio file on page load.
  • Updated: Minified player compressor chain now matches main player values — threshold -24dB, knee 30, ratio 12, attack 3ms, release 250ms. Single shared vtListAudioCtx context reused across all minified players. All chain variables prefixed vtList to avoid conflicts with the main player.
  • Updated: Default volume on all minified players set to 60%.
  • New: Fuzzy search input above the accordion track list — filters by title and artist in real time. Resets to page 1 on each keystroke.
  • New: Pagination below the accordion track list — fixed 10 tracks per page. Open rows close and playing audio stops on page change. Pagination updates against the filtered set when search is active.

APRIL 2026 BUILDS

TUESDAY THE 28TH OF APRIL

  • Fixed: Accordion track list now orders all tracks A-Z by title on the frontend. Previously tracks were ordered by the backend drag order, meaning newly added tracks always appeared at the bottom. Backend drag order in the library editor is unaffected.

MONDAY THE 27TH OF APRIL

  • Fixed: Favourite heart icon now switches between outline (far fa-heart) and solid filled (fas fa-heart) when toggled. Solid state is also restored correctly on page load for previously favourited tracks.
  • Fixed: Accordion track list utility row — download icon now renders correctly using the full source type map mirroring FILE_SOURCES from the player. Font Awesome icons render as <i> elements, favicon-based services render as <img> via Google’s favicon service — matching the Media Recon and fullscreen sidebar behaviour exactly.
  • Updated: Accordion track list — Download link removed from the track detail area.
  • New: Accordion track list — new row added below the track details showing a Favourite heart button and the global play count for that track.
  • New: Favourite state is saved to browser local storage and restored on page load.

SUNDAY THE 26TH OF APRIL

  • Fixed: Artist Card right column — added min-width: 0, overflow: hidden, and box-sizing: border-box so content respects the grid column boundary at all viewport sizes. Bio text now uses overflow-wrap: break-word to prevent long words overflowing.
  • Fixed: Artist Accordion List body content — added min-width: 0 and overflow: hidden to the body content flex column so it respects the grid track boundary. Bio word-wrap fixed. Responsive breakpoint widened from 600px to 700px so the two-column grid switches to single column earlier on tablet widths where the fixed 200px image column was causing overflow.
  •  
  • Fixed: Volume slider in artist card and artist list tracklists reverted to inline flex behaviour — removed absolute positioning overrides. The track item enforces the row boundary via overflow: hidden. The slider expands inline pushing the track title right, which compresses and clips with ellipsis at the boundary. No other container elements are affected.
  • Fixed: Volume slider in artist card and artist list tracklists was causing overflow — pushing track titles, duration text, and artist images outside the container boundary. Replaced the max-width transition with opacity and visibility transitions on the absolutely positioned slider overlay. The slider now fades in and out at a fixed width anchored to the right edge of the row without affecting any other layout elements.
  • Fixed: Artist tracklist was showing the first 5 alphabetical tracks rather than a random selection. Query now picks 5 random unique titles then sorts them alphabetically for display. Duplicate tracks across libraries are deduplicated by title via GROUP BY.
  • Fixed: Volume slider in artist card and artist list tracklists was expanding inline and pushing track titles, duration, and parent container elements out of bounds. The volume slider wrap is now position: absolute anchored to the right edge of the track row. The row uses position: relative; overflow: hidden to contain the slider within the row boundary. Track title clips with ellipsis when the slider is visible.
  • Fixed: Artist tracklist was showing duplicate tracks when the same track exists in multiple libraries. Added GROUP BY title to deduplicate before selecting.
  • Fixed: Artist tracklist was showing the first 5 alphabetical tracks rather than a random selection. Now selects 5 random unique tracks then sorts them A-Z for display. Each page load shows a different set.
  • New: Artist tracklist added to both Artist Card and Artist Accordion List. Shows up to 5 tracks alphabetically matching the artist name, each with the full minified player (play/pause, progress bar, volume slide-in). Suppressed if no matching tracks found. Play button and progress fill use the correct accent colour from the parent root context via scoped CSS — no !important.
  • Updated: Play count display format changed to “You: X plays” and “Global: Y plays” in both Media Recon sidebar and Fullscreen Track Details sidebar.
  • Updated: Fullscreen Track Details sidebar now shows both local and global play counts using dedicated fullscreen-scoped CSS — does not inherit Media Recon styling.

SATURDAY THE 25TH OF APRIL

  • New: Artist Accordion List — new  [ vitreous_artist_list ] shortcode, Gutenberg block, and Elementor widget. Lists all artist profiles as a glassmorphic accordion. Each collapsed row shows the artist name and social link icons. Expanding a row reveals the 16:9 artist image, bio, year started, and members. Social icons are the only interactive elements and stop accordion toggle propagation. Multi-open — multiple rows can be expanded simultaneously.
  • New: Artist Card — new [ vitreous_artist_card id="1" ] shortcode, Gutenberg block, and Elementor widget. Renders a two-column glassmorphic card for any artist profile. Left column shows the artist image at 16:9 ratio, artist name, and social link icons. Right column shows bio and year started. Social icons are the only interactive elements — each opens in a new tab. Cards with no data for a field suppress that element entirely.
  • Fixed: Replaced !important on accordion track list image fill rules with .vt-list-root-scoped selectors (.vt-list-root .vt-list-art img and .vt-list-root .vt-list-body-art img). The increased specificity overrides WordPress and theme global image styles without requiring !important.
  • Fixed: Album art images in both the collapsed row thumbnail and expanded body not filling their square containers. WordPress and theme stylesheets apply max-width: 100% and height: auto globally to images which was overriding the fill rules. Added !important to all critical image fill properties on both .vt-list-art img and .vt-list-body-art img to enforce correct fill behaviour regardless of external stylesheet interference.
  • Fixed: Removed loading="lazy" from both album art image elements in the accordion track list. Lazy loading deferred image dimension establishment causing images to not fill their containers correctly and contributing to page load issues on WordPress. All Vitreous image output is eager-loaded.
  • Fixed: Collapsed row album art thumbnail was flush to the top of its container and not filling the square. The fixed height: 48px on .vt-list-art was being overridden by the flex parent causing the container to collapse, leaving the absolutely positioned image anchored to top: 0 with no height to fill. Replaced with aspect-ratio: 1 / 1 matching the main player pattern — the square is now enforced independently of the flex context.
  • Fixed: Album art in both the collapsed row thumbnail and the expanded body was not correctly filling its 1:1 square container for landscape or portrait source images. Both containers now use position: relative with the image set to position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; object-position: center — matching the main Vitreous player pattern exactly. The expanded body art additionally uses aspect-ratio: 1 / 1 with align-self: start replacing the previous fixed height, eliminating the empty space below the image when the field grid is taller than the art container.
  • Fixed: Volume slider in the accordion track list replaced the popup pattern with an inline slide-in on the same row as the player controls. The slider slides in horizontally from beside the volume icon using a CSS max-width transition. Hovering the volume icon or clicking it reveals the slider for 10 seconds. Any adjustment to the slider resets the timer to 5 seconds from the last interaction. The slider auto-hides after the timer expires. Hovering or clicking the icon again re-shows it for another 10 seconds.
  • Fixed: Volume slider popup in the accordion track list was clipped at the top edge of the row. Root cause was overflow: hidden on .vt-list-item which prevented the absolutely positioned slider from escaping the item boundary. Removed overflow: hidden from the item and redistributed border-radius clipping to the row (full radius when collapsed, top corners only when open) and the expanded body (bottom corners only), preserving the glassmorphic corner rounding without clipping the volume popup.
  • New: Accordion Track List — new [ vitreous_list id="1" ] shortcode, Gutenberg block, and Elementor widget. Renders a glassmorphic accordion list for any library. Each collapsed row shows the 1:1 album art thumbnail, track title, artist name, and a minified player. Multi-open — multiple rows can be expanded simultaneously.
  • New: Minified player — each row has its own independent audio element with a progress bar (seekable), play/pause button, and volume control. Volume icon acts as mute/unmute on click and reveals a slider on hover. Playback is restricted to one track at a time across all rows — pressing play on a new row stops the current one.
  • New: Volume normalisation — each minified player applies a Web Audio API gain/compressor chain to normalise playback level. If the audio source is on an external CDN without CORS headers, the normalisation falls back gracefully and the track plays without adjustment.
  • New: Expanded accordion body — all non-empty track fields are displayed in a responsive grid alongside a larger 1:1 album art image. Empty fields and the internal colour value are suppressed. Inspiration and Credits render full-width. Download link rendered if a file source URL is present.
  • DB: Two new columns added to vitreous_tracks via maybe_upgrade_schema() with SHOW COLUMNS existence checks — global_play_count INT(11) DEFAULT 0 and last_played_at DATETIME DEFAULT NULL. Both are added safely on first admin load for existing installs. Fresh installs receive the columns via the existing CREATE TABLE definition.
  • New: Global play count — every time a track is played on the frontend, a fire-and-forget fetch POST increments global_play_count and sets last_played_at server-side. The handler is registered as both wp_ajax_* and wp_ajax_nopriv_* to support all visitors regardless of login state. No nonce required — mirrors the existing localStorage play count behaviour exactly.
  • New: Media Recon play count display updated to show two lines per track — “X plays (you)” from localStorage and “Y plays (all)” from the server-side global count. The in-memory globalPlayCount value is updated immediately on each play so the Media Recon reflects the increment without a page reload.
  • Note: last_played_at is stored but not yet displayed. It will be used for a “Recently Played” tab in a future build.
  • Fixed: Audio format warning moved from save callback to a real-time indicator displayed directly below the Audio File URL field and media library button. The indicator updates immediately as the URL is typed or pasted, and when a file is selected via the media library picker. A green badge confirms good browser support (MP3, etc.), an amber badge warns of reduced support (OGG, OPUS, FLAC, WAV, M4A, AAC), and a red badge flags poor support (AIFF). Existing tracks display the correct badge on page load.
  • Fixed: Removed format warning from the track save response — it was in the wrong place and never displayed correctly.

FRIDAY THE 24TH OF APRIL

  • New: Track Import — replaces the disabled CSV import placeholder. Accepts a Vitreous .json export file containing an array of track objects. The title field is required; all others are optional. Tracks are appended to the library without removing existing ones. A result notice confirms how many tracks were imported and how many entries were skipped. Uses the WordPress admin-post.php form pattern for reliable file upload handling.
  • New: Track Export — exports all tracks in the current library as a .json file. The exported file uses the same field names as the import schema and round-trips cleanly into any Vitreous library. Uses the WordPress admin-post.php form pattern for reliable file download handling — no JavaScript required.
  • New: Format warning on track save. If the Audio File URL uses a format with reduced browser support (OGG, OPUS, FLAC, WAV, M4A, AAC, AIFF), a warning is displayed in the save status bar alongside the confirmation, persisting for six seconds.
  • New: Format warning on JSON import. If any imported track’s src URL uses a reduced-support format, the import result notice includes a format notice listing the affected formats.
  • Fixed: Copy button in the Share sidebar was non-functional. The copyToClipboard() function was called but never defined, causing a silent ReferenceError on every click attempt. The function is now implemented using navigator.clipboard.writeText() on HTTPS contexts, with a document.execCommand('copy') fallback for non-secure or older browser environments. On success, a “Link copied!” confirmation fades in below the input for two seconds. On failure, an instruction to use Ctrl+C is shown instead.
  • Fixed: Right-click context menu did not offer a copy option when manually highlighting the share link. Clicking the share link input field now automatically selects all text, ensuring both right-click copy and Ctrl+C work without requiring manual drag-selection.
  • Fixed: Share link now encodes the track’s stable database ID (track.id) rather than its current array index. Previously, ?track= used the sorted array position which could change as tracks were added or reordered, causing shared links to land on the wrong track. The parameter now always resolves to the correct track regardless of library changes.
  • Fixed: Share links are now consumed on page load. A new deep-link handler reads the ?track= URL parameter, finds the matching track by database ID, and sets it as the initial track before the player loads. If a &t= timestamp parameter is also present, the player seeks to that position once the audio is ready. Deep-link resolution takes priority over the Remember Track setting.
  • Fixed: Frontend play order — each track in trackData is now stamped with its pre-sort injection index (_injectionIdx) before the year-descending sort is applied. This ensures positional operations (track selection, navigation) and identity operations (play counts, favourites, share ID) remain consistent regardless of how many tracks are added to the library or in what order.

SUNDAY THE 19TH OF APRIL

  • Versioning correction: This release corrects a versioning error introduced at v4.6.0. Under ARV, any DB change (new table, new column, migration, or rebuild) constitutes a Major version bump as all DB changes carry plugin-breaking potential. The Artist Profiles feature shipped at v4.6.0 introduced a new vitreous_artists DB table and migrated existing data — this was always a Major change and should have been v5.0.0 at the time. Versions v4.6.0 through v4.6.10 are therefore misnumbered. This was an AI assistant classification error, not an ARV rule change. All versioning from v5.0.0 forward follows the correct rule strictly.
  • Fixed: Animation Speed dropdown showed a blank selection on load. The Normal option had value="1.0" but JavaScript sets .value = 1 (float-to-string converts 1.0 to "1"), so no option matched and the dropdown appeared empty. Option value corrected to "1". JS default corrected to match. Normal option relabelled Normal (Default) for clarity.
  • Fixed: Animation Speed control replaced. The range slider visually rendered at the leftmost (Slow) position regardless of the actual value due to layout constraints inside the settings sidebar. Replaced with a three-option dropdown — Slow (0.5), Normal (1.0), Fast (2.0) — matching the three bands already used by getAnimationSpeedLabel(). Default remains Normal (1.0). Event listener updated from input to change.
  • Fixed: Changelog card gap not rendering. Cards sit directly inside #vt-cl-entries — the .vitreous-changelog-list wrapper class and its gap rule were never applied. Fixed by applying display:flex; flex-direction:column; gap:32px; margin-top:24px directly to #vt-cl-entries.
  • Fixed: Admin background colour corrected from #1a1a2e to #0f172a across all Vitreous admin pages, matching Criterium and Stratum. Both --vt-bg and --vt-admin-bg tokens updated. --vt-surface updated from rgba(20,24,48,0.95) to rgba(20,30,50,0.95) to match.
  • Updated: Changelog page redesigned to match Criterium layout. Outer wrapper changed to WordPress standard wrap class for full-width rendering — the previous max-width:860px constraint has been removed. Page head replaced with logo + title pattern matching Criterium. All changelog card heads now include a version-row with a colour-coded type badge (Patch/Minor/Major) and a date aligned to the right, matching Criterium exactly. New CSS rules added for .vitreous-changelog-wrap, .vitreous-changelog-head, .vitreous-changelog-logo, .vitreous-changelog-title, .vitreous-changelog-version-row, .vitreous-changelog-type, and .vitreous-changelog-date.
  • Fixed: Frontend player regression persisting from v4.6.5 and v4.6.6. The none waveform handler was inserted with three closing braces before it (}}}) instead of two (}}), closing drawWave() prematurely and leaving the else if(none) block outside the function entirely. Corrected to }}else if(style==='none'){...}} — the minimal for-loop and if-block close with two braces, the none handler follows inside the function, then one final brace closes drawWave().
  • Fixed: Frontend player regression introduced in v4.6.5. The none waveform handler was inserted after drawWave()‘s closing brace rather than inside it, producing a syntax error that broke the entire player JS. The extra closing brace has been removed and the none handler correctly placed as the final else if branch inside drawWave().
  • Added: Waveform Style now includes a None option across all three surfaces — the in-player Settings dropdown, the global Waveform Style setting in the admin, and the per-track override in the track editor. When None is selected, drawWave() clears both waveform-canvas-bg and waveform-canvas-fg without drawing anything. The visualiser layer (waveform-canvas-vis) and progress mask continue to operate normally.
  • Fixed: Waveform style options (Bars, Line Wave, Mirrored Bars, Minimal) now update in real time when selected from the in-player Settings sidebar, including during playback. The guard in drawWave() that prevented it from running while the visualiser was active has been removed. That guard existed to prevent both functions drawing to the same canvas — since drawVisualizer() now draws to the dedicated waveform-canvas-vis layer (v4.6.3), the conflict no longer exists and drawWave() can always run freely.
  • Fixed: Waveform layer system restored to correct four-layer architecture. A dedicated waveform-canvas-vis canvas (z-index 2) has been added between waveform-canvas-bg (z-index 1) and waveform-canvas-fg (z-index 3). drawVisualizer() now draws to vis instead of fg, meaning the live frequency visualiser and the static waveform are fully independent layers. Both vis and fg are revealed by the playhead clip-path on timeupdate and reset to fully hidden on track load. vis is cleared on stop/pause. waveform-canvas-fg z-index corrected from 2 to 3. Global accent colour applies to vis, fg, and wave-progress-mask. bg remains fixed transparent light grey.

SATURDAY THE 18TH OF APRIL

  • Fixed: Play counts now keyed by database track ID instead of array index position. Previously, adding or reordering tracks caused index positions to shift, assigning existing play counts to different tracks. New tracks inherited counts from whichever track previously occupied their index. Play counts are now stored as {trackDbId: count} in localStorage — the DB ID is stable regardless of sort order, additions, or deletions. Existing localStorage data keyed by index becomes orphaned and ignored; counts start fresh from zero for all tracks after this update.
  • Fixed: Mobile layout and Player Max Width restored. The outer player-wrapper div was incorrectly removed from player-template.php in v4.3.5 under the assumption it was a duplicate. It was not — the JS uses getElementById('dynamic-bg') to target the outer wrapper specifically for background, border-radius, and viewport-width context. Without it, mobile layout was broken and all CSS variable-based settings (scale, max-width) failed to cascade correctly. Reinstated exactly as it existed in v4.3.4.
  • Major: Artist Profile (singular) replaced with Artist Profiles — supports any number of artist profiles. New dedicated database table vitreous_artists with individual columns for all profile fields and 15 social platform URLs.
  • Added: Artist Profiles admin page — two-panel layout identical to Library Edit. Left panel: scrollable alphabetical artist list. Right panel: full artist editing form (image, name, members, bio, year started, 15 social URLs). Save, load, and delete all via AJAX. Auto-alphabetises on save. Unsaved changes protection with Save Now / Discard modal.
  • Added: AJAX handlers — vitreous_save_artist, vitreous_load_artist, vitreous_delete_artist.
  • Migration: On first load after update, any existing single artist profile stored as WordPress options is automatically migrated to the new vitreous_artists table. Legacy options are deleted after migration. No data is lost.
  • Updated: Frontend player — vitreousSettings.artistProfile (single object) replaced with vitreousSettings.artistProfiles (array). Profile matching logic updated to find the correct profile from the array by exact artist name match. Multiple tracks by different artists on the same page each show their own profile.

WEDNESDAY THE 15TH OF APRIL

  • Fixed: Save Track button moved out of the scrolling editor area into a persistent full-width footer bar that spans the full width of both the track list and track edit panels. The button is now always visible without needing to scroll. The footer appears when a track is loaded or a new track is created, and hides when the editor resets to the placeholder state.
  • Fixed: Library Details — title input and Save Title button now sit on one row. The containing element was constrained to 240px by the vitreous-field--sm class, causing the button to wrap below.
  • Fixed: Track sidebar and track editor area now use calc(100vh - 320px) instead of a fixed 640px height, scaling responsively to the actual viewport.
  • Added: Gold scrollbars on the track sidebar and track editor area via ::-webkit-scrollbar. Firefox receives partial theming via scrollbar-color. Scrollbar thumb is gold at 35% opacity, brightening on hover.
  • Reordered: Track Info fields reorganised by likely input priority. Left column: Title, Artist, Album, Mix Version, Genre, Tempo, Production Method, Theme Colour. Right column: Audio File URL, Album Art URL, File Source, Duration, Release Date, Copyright Year, License, Key Signature, Mood, Inspiration, Credits.
  • Rebuilt: Library Edit page — replaced the accordion track row layout with a two-panel architecture. Left panel: scrollable alphabetical track list. Right panel: single track editing area loaded on demand. Only one set of form fields exists in the DOM at any time, resolving performance degradation with 10+ track libraries.
  • Added: Per-track AJAX save — each track saves individually to the database via AJAX. The previous bulk delete-then-reinsert approach is retired. New tracks are inserted on first save; existing tracks update in place using their database ID.
  • Added: AJAX handlers — vitreous_save_track, vitreous_load_track, vitreous_delete_track — covering insert, update, load for editing, and hard delete.
  • Added: Auto-alphabetisation — the track sidebar list sorts A-Z automatically whenever a track is saved or its title is updated. No manual ordering needed.
  • Added: Unsaved changes protection — dirty flag system matching the Criterium pattern. If a track has unsaved changes when the user clicks away to another track, a modal fires with Save Now or Discard options.
  • Disabled: CSV Import — panel is present but marked unavailable. The import schema does not cover all 26 track fields and will be reworked before re-enabling.

SUNDAY THE 12TH OF APRIL

  • Fixed: Icon size mismatch on Artist Profile social media list and Settings share platform tiles. FontAwesome icons were inheriting small font sizes from their parent containers (10px and 11px respectively) while the Bluesky SimpleIcons image was rendering at its explicit pixel size. Fixed by adding explicit font-size:16px to FA icons on the Artist Profile page and font-size:20px on the Settings tile icons, matching the Bluesky image dimensions in both locations.
  • Fixed: Preview audio button in the track editor was still rendering green. Should have been changed to gold ghost style alongside all other track row buttons in v4.4.2.
  • Fixed: Bluesky icon definitively resolved for Artist Profile and Settings share platforms. Replaced fa-brands fa-bluesky (FontAwesome dependency) with a SimpleIcons CDN image (cdn.simpleicons.org/bluesky/c4a75d) — an SVG served directly as an <img> tag, gold-coloured to match the admin theme. No FontAwesome required. A new simpleicon icon type has been added to both admin pages’ icon rendering logic, mirroring the existing favicon pattern.
  • Fixed: Bluesky icon still missing from admin pages (Artist Profile, Settings share platforms) after v4.4.2. Root cause: elementor-font-awesome is registered by Elementor on all admin pages but not on frontend pages — which is why the frontend player showed Bluesky correctly while the admin did not. This handle was in the skip list, causing the CDN fallback to never fire in the admin. Removed from the skip list. Only four genuine FA Free handles remain: font-awesome, font-awesome-5-all, font-awesome-official, fontawesome.
  • Fixed: Bluesky icon missing from Artist Profile socials and Settings share platforms. Root cause: three Elementor icon handles were incorrectly added to the FontAwesome skip list during the v4.4.0 rebuild. Because Elementor registers those handles on every admin page, Vitreous was bailing out before loading its own FA 6.6.0 from CDN. The skip list has been restored to the original five handles from v4.3.4.
  • Fixed: Track row media buttons (Select audio, Select image, Select from Media Library, Copy Audio URL, Add Track Below) were rendering with WordPress default white styling. All now use the admin gold ghost button style matching the rest of the backend.
  • Fixed: About section in Changelog page was showing version 4.3.10 — updated to current.
  • Removed: Dead .vt-cl-btn and .vt-cl-page-label CSS from the Changelog page inline style block — these classes were replaced in v4.4.0 and the rules were never removed.
  • Added: Light/dark theme toggle — crescent moon button (☾) in the page header on all admin pages except Changelog. Defaults to dark. Preference persisted to localStorage as vitreous-admin-theme, matching the Criterium pattern exactly.
  • Added: Light theme CSS — body.vitreous-admin-page.vitreous-light token block overrides all surface, background, text, input, and danger tokens for the light variant. Light-mode overrides added for changelog item text, diagnostics result text colours, modal background, and track card backgrounds.
  • Removed: Admin Appearance settings section — background colour picker, custom colour picker, and glass intensity selector all removed from Settings. The admin background is now fixed to #1a1a2e (dark) or #f0f0f0 (light) controlled by the toggle. Glass intensity hardcoded to bold defaults in admin.css :root.
  • Removed: inject_admin_appearance_css() PHP method and its admin_head hook — no longer needed now that all CSS variables are static in admin.css.
  • Removed: vitreous_admin_bg_preset, vitreous_admin_bg_custom, and vitreous_admin_glass_intensity WordPress options — save and load logic both removed from settings-page.php.
  • Major: Full admin backend rebuild — architecture brought in line with Criterium plugin. All admin pages now use custom vitreous-* component classes instead of WordPress native classes (.wp-list-table, .button, .notice, .form-table etc.), eliminating all CSS specificity conflicts with WordPress core styles.
  • Added: admin_body_class filter — injects body.vitreous-admin-page on all Vitreous admin screens. Background override CSS now scoped to this class (Criterium/Stratum pattern), preventing any bleed to other admin pages.
  • Added: Full custom component set — vitreous-btn (primary, ghost, danger, sm), vitreous-table, vitreous-notice (success, error, warning), vitreous-label, vitreous-field, vitreous-field-hint, vitreous-panel, vitreous-section, vitreous-page-head, vitreous-toolbar, vitreous-actions, vitreous-empty, vitreous-tabs, vitreous-modal, vitreous-diag-result variants, vitreous-changelog-card.
  • Fixed: Font rendering — every component class now carries an explicit font-family: var(--vt-font-head) or var(--vt-font-body) declaration. Font inheritance no longer relies on the cascade, so WordPress core styles cannot override it.
  • Updated: Admin accent colour changed from cyan #00d2ff to gold #c4a75d throughout the admin backend, matching Criterium and Stratum design language. Player frontend accent remains cyan.
  • Updated: Admin CSS rebuilt from 682 lines to 1,078 lines — matching Criterium’s full component coverage.
  • Updated: Font tokens renamed to --vt-font-head (Geologica 600) and --vt-font-body (Asap) — consistent with planned Criterium/Stratum font migration.
  • Updated: inject_admin_appearance_css now outputs only dynamic CSS variables (background, glass intensity). Background scoping moved to admin.css under body.vitreous-admin-page.
  • Restored: wp_enqueue_style('vitreous-admin-fonts') with correct null version parameter — Elementor loads Asap and Geologica globally in this installation, so the fonts are available.
  • Fixed: Glassmorphic confirm dialogs — all window.confirm() calls replaced with the vitreous-confirm-delete modal system (matching Criterium). Library delete links and orphan purge button both use the new modal.
  • Fixed: CSV import messages updated from notice notice-* WP classes to vitreous-notice classes.
  • Fixed: Track number badges no longer display a # prefix — numbers only, matching the gold badge design.
  • Rebuilt: libraries-list.php, library-edit.php, settings-page.php, artist-profile-page.php, database-viewer.php, changelog-page.php — all HTML updated to use new component classes throughout.