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 | |
| JANUARY | Template builds from v0.1.0 to v2.4.6 |
| FEBRUARY | WordPress plugin build from v3.0.0 to v4.0.12 |
| MARCH | 64 builds from v4.0.13 to v4.3.10 |
| APRIL | 46 builds from v4.4.0 to v6.5.3 |
| MAY | 109 builds from v6.5.4 to v11.2.12 |
| JUNE | 31 builds from v11.2.13 to v12.1.2 |
JUNE 2026 BUILDS
THURSDAY THE 4TH OF JUNE
- Database Debug — full v12 rewrite: Page rebuilt to reflect the canonical track architecture throughout. Removed the legacy “All Tracks” panel that read
library_idandtrack_orderfromvitreous_tracksdirectly. Removed legacy library-scoped duplicate detection and orphan query. - Playlists Table: Track counts now sourced from
vitreous_library_tracksjunction table. - All Tracks: Lists all canonical tracks with playlist membership shown via junction join. Duplicate detection is now title-only across the global track table.
- Orphaned Track Maintenance: Orphan definition updated — a track is orphaned if it has no row in
vitreous_library_tracks(not if itslibrary_idcolumn references a missing library). Purge query updated to match. - Featured Artists Integrity: New panel checks
vitreous_featured_artistsfor stale rows where the referenced track or artist no longer exists. - Terminology: “Back to Libraries” updated to “Back to Playlists”. “Libraries Table” renamed to “Playlists Table”. Junction table panel renamed to “Playlist-Track Junction Table”.
- Fixed: Artist Profiles — featured artists were not showing linked tracks and were incorrectly appearing in the Unlinked Tracks panel.
ajax_get_artist_tracks()now joins bothvitreous_artist_tracks(primary) andvitreous_featured_artists(featured), returning tracks where the artist holds either role.ajax_get_unlinked_tracks()now checks both tables — a track is only unlinked if it has no row in either. Unlinked count badge on the Tracks page updated to match.
- Featured Artists — tracks can now have multiple additional artist profiles linked (collaborators, remixers, featured vocalists), stored in the new
vitreous_featured_artiststable. Separate from the primary artist link. - Admin: Featured Artists checkbox section in the Track Editor (Track Info tab) — select from existing artist profiles, pre-checked on load, saves on every track save.
- Main Player — Fullscreen Sidebar: New “Featured Artists” accordion between Bio & Details and Track Details. Hidden when no featured artists exist. Shows 36×36px square artist image and name per artist. Collapses on track change.
- Track List Widget: Featured artist chips appear in a horizontal row below the expanded track data fields, separated by a top border. Each chip shows a 32×32px square artist image and name in accent colour, with glassmorphic background following the widget’s Glass Mode Display Option.
- Display Options: New “Featured Artist Name” typography area in Track List Display Options — font family, size, weight, style, transform, decoration, letter spacing, line height. Colour not configurable — accent colour is always used.
- Fixed: Display Options typography values for Featured Artist Name not persisting. Root cause: the 8 new
list_featured_artist_name_*column names were missing from$allowed_keysinajax_save_display_options()— POST values were silently discarded. All 8 keys added (no colour). - Fixed: Migration intermediate stamp corrected from
12.0.8to12.0.2to correctly reflect the migration sequence. - Fixed:
colourremoved from$fa_col_typesmigration array — 8 columns not 9. Featured artist name uses the accent colour by CSS default; colour override is not permitted. - Fixed: Colour field suppressed in the Display Options UI for the Featured Artist Name typography area — replaced with an informational note. Colour is also excluded from the inline typography injection in
list-shortcode.php. - Styling: Featured artist chips now use
var(--vl-glass)background andvar(--vl-border)border, automatically following the widget’s light/dark Glass Mode Display Option setting.
- Fixed: Featured artist chips were stacking vertically because they were inside
.vt-list-body-inner— a two-column grid — causing them to flow into column 1 of the next row. Moved outside.vt-list-body-innerentirely, sitting between body-inner and the track actions row. Now a proper horizontal flex row withflex-wrap: wrapfor narrow screens, separated from the fields above by a top border. - Display Options: New Featured Artist Name typography area added to the Track List Display Options panel — all 9 typography properties. 9 new columns added to
vitreous_display_optionsviaSHOW COLUMNS-guarded migration. - Responsive: Chips row works correctly at all widths — on mobile (
max-width: 600px) the body-inner switches to single column but the chips row remains full-width below it, wrapping chips to additional rows if needed.
- Track List Widget — Featured Artists: Featured artist chips now appear in the expanded accordion body below the fields grid, only when a track has featured artists. Each chip shows a 32×32px square artist image (or user icon fallback) and the artist name. Full
!importantimage fill pattern applied matching the track list album art fix. - Data:
list-shortcode.phpjoinsvitreous_featured_artistsin a single query for all tracks and indexes by track ID — no per-row queries. - Step 3 of 3 — all featured artist steps complete.
- V12.0.4 – Fixed: Featured artist images in the fullscreen sidebar not filling the 1:1 container — portrait and landscape images were letterboxing. Added
object-fit: cover,object-position: center, anddisplay: blockto.fullscreen-featured-artist-img img, matching the track list album art pattern. - V12.0.5 – Fixed: Featured artist images still not filling the 1:1 container. Root cause: the container uses
display: flexfor icon fallback centering — as a flex container,width/height: 100%on the child image resolves against flex context rather than filling absolutely. Fixed by addingposition: relativeto the container andposition: absolute; top: 0; left: 0to the image, ensuring it always fills the container regardless of flex layout. - V12.0.6 – Fixed: Featured artist images still not filling 1:1 container. Applied the exact combination established for the track list album art squares:
aspect-ratio: 1 / 1on the container (replacing fixed height), andposition: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; max-width: noneon the image. Themax-width: noneis critical — WordPress global stylesheets applymax-width: 100%to all images which was overriding the fill behaviour.
V12.0.7 – Fixed: Featured artist images still not filling container. Added!importantto all critical fill properties on.fullscreen-featured-artist-img img—position,top,left,width,height,object-fit,object-position,display,max-width. WordPress theme global image styles (max-width: 100%; height: auto) apply with high specificity via element selectors and were overriding the fill rules despiteposition: absoluteandmax-width: nonebeing present. Matches the definitive fix applied to the track list album art squares.
- Player — Featured Artists accordion: Main player fullscreen right sidebar gains a “Featured Artists” accordion between Bio & Details and Track Details. Hidden when the track has no featured artists. On open shows each artist as a small 36×36px square image (or user icon fallback) and their name. Collapses on every track change.
- Data:
render_player_shortcode()now joinsvitreous_featured_artistsin a single query and attaches afeaturedArtistsarray to each track’s JSON object —id,name,imageUrl. - Step 2 of 3 — Track list widget in Step 3.
- DB: New
vitreous_featured_artiststable —track_id,artist_idwith unique key on the pair. Stores additional artist links per track (collaborators, remixers, featured vocalists). Separate from the primaryvitreous_artist_trackstable which is untouched. - Admin — Track Editor: New Featured Artists section in the Track Info tab, below the primary Artist Profile field. Shows all existing artist profiles as checkboxes. Pre-checked on load for any already linked. Checked items are highlighted in gold. Saves and replaces on every track save.
- Step 1 of 3 — DB and admin only. Frontend display in Steps 2 and 3.
- Fixed: Site-wide stats widget (
[ vitreous_site_stats ]) still showed “Libraries”, “Top Library”, “Most Active Library”, and “No library data yet”. All four updated to “Playlists”, “Top Playlist”, “Most Active Playlist”, and “No playlist data yet”.
TUESDAY THE 2ND OF JUNE
- Canonical Track Architecture: Tracks are now a primary entity, existing once in
vitreous_tracksindependent of any playlist. Libraries are now Playlists — organisational containers that reference tracks via thevitreous_library_tracksjunction table. A track can belong to multiple playlists without duplication of its record, play counts, or like counts. - New table:
vitreous_library_tracks—id,library_id,track_id,sort_order. Populated on migration from existinglibrary_idandtrack_ordervalues.library_idandtrack_orderremain onvitreous_tracksfor reversion safety and are not dropped. - Admin restructure: New Tracks page — canonical track editor, import, and export. Playlists page — renamed from Libraries, with a new two-panel composition UI (A-Z sorted, add/remove tracks, searchable picker). Add New sidebar entry with Track / Artist / Playlist child items. Overview Quick Actions updated.
- Query migration: All 27 query locations migrated from
WHERE t.library_id = Xto junction joins acrossvitreous-player.php, all shortcodes, and all admin pages. - Reversion: Reversion to v11.2.25 via FTP is fully safe —
library_idandtrack_orderremain onvitreous_tracksuntouched. Thevitreous_library_trackstable is ignored by v11.2.25 code.
- Removed: Drag-to-reorder from the Playlist composer. Both panels now sort A-Z by title consistently. Frontend players use their own sort methods; manual sort order in the admin was unnecessary.
- Changed: Playlist left panel and right panel picker both order by
t.title ASC.ajax_get_playlist_tracks()updated to match.ajax_reorder_playlist()handler and AJAX registration removed. Drag handles, save order button, reorder notice, andenableDrag()all removed fromadmin.jsandlibrary-edit.php..vt-playlist-drag-handleCSS rule removed.
- Fixed: Playlist composer columns now scroll correctly. Applied
max-height: calc(100vh - 340px)andoverflow-y: autodirectly on.vt-playlist-track-listand.vt-playlist-picker-list, matching the established metrics page scrollable panel pattern. Gold webkit scrollbar styling added to match the rest of the admin.
- Fixed: Playlist composer columns were not scrolling despite the layout having a
max-height. Root cause:.vt-playlist-currentand.vt-playlist-pickerhad noheight: 100%oroverflow: hidden, so the flex children had no fixed height to scroll within. Both properties added — columns now fill the grid height and the track lists scroll independently.
- UI: Playlist composer layout now constrained to viewport height —
max-height: calc(100vh - 280px)on.vt-playlist-composer-layoutprevents the panel growing beyond the visible area. Both the current playlist and track picker columns scroll independently within the fixed panel height. Column headers remain pinned.
- Critical fix: Missing
})();closing bracket on the import IIFE inadmin.js. This caused a JavaScript syntax error that prevented the entireadmin.jsfrom parsing and executing on any admin page — breaking the track editor, Add Track button, and all other admin JS interactions across the plugin. Root cause: the playlist composer IIFE was appended directly after the import function body without first closing the import IIFE.
- Fixed: Track editor JS not initialising on the Tracks page. Root cause: database queries in
tracks-page.phpwere placed at the top of the file before any HTML output, breaking page render on managed hosting. Queries moved inside thevitreous-paneldiv, matching the exact pattern from v11.2.13library-edit.php.
- Debug:
vtLoadTrack()error feedback made visible — failures now display the server error message in the save status bar and reveal the footer bar. A.fail()handler added to surface AJAX-level errors (network, server 500, etc). Previously all failures were silent.
- Fixed:
ajax_save_track()— removedlibrary_id < 1guard. Track saves on the Tracks page (no playlist context) now succeed. New tracks created withlibrary_id = 0insert a canonical record only; junction row is written only when a valid playlist ID is present. - Fixed:
ajax_analyse_import()andajax_process_import()— allowlibrary_id = 0. Imports on the Tracks page insert canonical track records with no junction rows. Duplicate detection onlibrary_id = 0checks against all tracks globally. - Fixed:
handle_export_tracks()— allowlibrary_id = 0. Export with no library context exports all canonical tracks ordered by title. Filename becomesvitreous-all-tracks-{date}.json. - Added: Export All Tracks panel on the Tracks page.
- Fixed: Add Playlist Quick Actions icon replaced —
fa-list-music(Font Awesome Pro, unavailable) replaced withfa-list(Free). - Fixed: Track / Artist / Playlist submenu items under Add New now display with visual indentation and reduced opacity to distinguish them as child actions rather than top-level pages.
- Admin restructure: New Tracks submenu page — standalone canonical track editor listing all tracks system-wide. Track creation, editing, deletion, import, and export now live here, independent of any playlist context.
- Playlist composer: Library edit page (
library-edit.php) repurposed as a Playlist composer. Track editor, import, and export panels removed. New two-panel composition layout: left side shows current playlist tracks in sort order with remove buttons and drag-to-reorder; right side shows a searchable picker of all canonical tracks with add buttons. - Terminology: All user-facing “Library/Libraries” labels updated to “Playlist/Playlists” across
libraries-list.php,library-edit.php, andoverview-page.php. - Menu: Sidebar restructured — “Libraries” renamed to “Playlists”, “Add New Library” removed, new “Tracks” page added, new “Add New” parent item pointing to Overview Quick Actions, with Track / Artist / Playlist child items beneath it.
- Quick Actions: Overview Quick Actions updated — Add Track, Add Artist, Add Playlist, Browse Tracks, Browse Playlists, Artist Profiles, Shortcodes, Metrics, Settings, Changelog. Stats bar “Libraries” label updated to “Playlists”.
- AJAX: Five new handlers registered —
ajax_get_all_tracks,ajax_get_playlist_tracks,ajax_add_track_to_playlist,ajax_remove_track_from_playlist,ajax_reorder_playlist. - Delete confirmation: Library delete now confirms “delete this playlist” with no mention of track deletion, correctly reflecting that tracks are preserved.
- Query migration: All 27 query locations across
vitreous-player.php,list-shortcode.php,site-stats-shortcode.php,library-edit.php,libraries-list.php,metrics-page.php, andoverview-page.phpmigrated fromWHERE t.library_id = XtoINNER JOIN vitreous_library_tracks lt ON lt.track_id = t.id WHERE lt.library_id = X. - Save track:
library_idremoved from$dataarray written tovitreous_tracks. New tracks now insert a canonical track record first, then write a junction row tovitreous_library_trackswith the correctsort_order. - Delete track: Junction rows in
vitreous_library_tracksare now deleted before the track record is removed, clearing the track from all playlists it belonged to. - Delete library: Library deletion now removes junction rows from
vitreous_library_tracksrather than deleting tracks fromvitreous_tracks. Tracks themselves are preserved. - Play/like logging:
ajax_increment_play()andajax_toggle_favourite()now source library membership fromvitreous_library_tracksand log against all libraries a track belongs to. - Import/export: All import and export paths updated to use junction joins. New tracks imported now insert a junction row. Overwrite and merge operations update the canonical track record only.
- Artist tracks / unlinked tracks:
library_titlenow sourced via junction join usingGROUP_CONCAT— tracks in multiple libraries show all library names. - Safety: Reversion to v11.2.15 via FTP is fully safe —
library_idandtrack_orderremain onvitreous_tracksuntouched.
- Fixed: Migration version stamp in
maybe_upgrade_schema()was conditional on a row count match after populatingvitreous_library_tracks. On any install where the count check failed, the stamp was never written and the full migration chain would re-run on every subsequent page load. Stamp now writes unconditionally once the table exists, regardless of whether population ran.INSERT IGNOREensures safe re-runs with no duplicate risk.
- DB: New
vitreous_library_tracksjunction table added —id,library_id,track_id,sort_orderwith a unique key on(library_id, track_id). This is the foundation for the canonical track architecture where tracks exist once and libraries reference them via this table. Purely additive —library_idandtrack_orderonvitreous_tracksare untouched. - Migration:
maybe_upgrade_schema()createsvitreous_library_trackson existing installs and populates it from the currentlibrary_idandtrack_ordervalues onvitreous_tracksviaINSERT IGNORE ... SELECT. A row count verification runs before the version stamp is written — if counts do not match, the stamp is withheld and the migration retries on next page load. - Debug: Database Debug page gains a new Library-Track Junction Table panel at the top. Shows whether
vitreous_library_tracksexists, a pass/warn row count check againstvitreous_tracks, and the full junction table contents grouped by library with Junction ID, Library ID, Track ID, Sort Order, and Track Title columns. - Safety: Reversion to v11.2.13 via FTP is fully safe — no existing columns are modified or removed. The
vitreous_library_trackstable is ignored by v11.2.13 code.
- Fixed:
maybe_upgrade_schema()now has a version gate at the top – readsvitreous_db_versionfrom WordPress options and returns immediately if already at11.2.13or above. On a normal page load after a successful migration, zero database queries are fired by the migration system. The version is stamped at the end of a successful migration run. - Fixed: Recursive
create_tables()call removed from the v7.0.0 Display Options migration block insidemaybe_upgrade_schema(). Replaced with a direct$wpdb->query()inlineCREATE TABLE IF NOT EXISTScall – consistent with every other table creation insidemaybe_upgrade_schema(). - Fixed:
$libraries_tableand$do_tablevariables now declared at the top ofmaybe_upgrade_schema()– previously$libraries_tablewas undeclared when the method ran via theinithook causing a PHP notice on the v8.2.0 migration block.
MAY 2026 BUILDS
SATURDAY THE 30TH OF MAY
- Fixed: Overview quick actions – Shortcodes card was missing. Added between Artist Profiles and Metrics, consistent with the admin menu order.
- Fixed: Fullscreen track sidebar Credits and Inspiration fields – multiline text was colliding with the label. Fixed by scoping
align-items: flex-startandmax-width: 60%to#fullscreen-row-creditsand#fullscreen-row-inspirationonly via ID-scoped CSS. All other single-line meta rows are unaffected.
FRIDAY THE 29TH OF MAY
- Fixed: Fullscreen artist/track sidebar no longer showing. Root cause: v11.2.9 renamed
fullscreen-artist-rowtofullscreen-row-artistin the HTML but missed an existing JS reference to the old ID in the artist profile matching logic. Updated JS reference to match the new ID.
- Fixed: Fullscreen sidebar track accordion – empty meta fields now hide their entire row (label and value) rather than showing a dash. Affected fields: Artist, Album, Genre, Tempo, Key, Method, Mix Version, Mood, Inspiration, Credits, Release Date. BPM stat row also hidden when no valid tempo value is present. Rows restore visibility when navigating to a track that has the field populated.
WEDNESDAY THE 27TH OF MAY
- Fixed: Player regression – library data not loading. Root cause:
var glassPlayerdeclared inside the iOS detection block conflicted with an existingconst glassPlayerat line 112 in the same function scope. Variable hoisting caused a runtime error that broke the entire player init chain before track data could load. Renamed toiosGlassPlayerto resolve the conflict.
- Fixed: Main player squished on iOS Safari and Brave on iPhone (confirmed iPhone SE2, iPhone 16, iPhone 17). Fix is scoped exclusively to iOS via the existing
vtIsIOSUA detection – avt-iosclass is added to.glass-playeron iOS devices only. Android and desktop are completely unaffected. Three iOS Safari specific issues addressed: (1)aspect-ratio: 1/1inside nestedoverflow: hiddenelements causes iOS Safari to miscalculate the outer container height – replaced with padding-top percentage trick scoped to.glass-player.vt-ios .album-cover-containeronly; (2)overflow: hiddencombined withborder-radiuson a flex item forces a GPU compositing layer that clips to stale pre-layout height on iOS – fixed with-webkit-transform: translateZ(0); (3)-webkit-backdrop-filtercombined with the above two properties creates three simultaneous compositing triggers on iOS – resolved withwill-change: transform. Opera on iOS was unaffected as its rendering wrapper handles these conditions differently. Pending iOS device screenshot confirmation.
Big thanks to Champie, Steve (unofficial), Alanwino, ecrollie and Ruth for their iOS screenshots of the Main Player that allowed me to figure out that this was an iOS Webkit related issue.
- Fixed: Main player squished on iOS Safari (confirmed iPhone 17). Root cause:
all: initialon.player-wrapperis handled inconsistently by iOS Safari – it was resettingwidth,box-sizing, and-webkit-text-size-adjustin a way that caused the player to render at a narrower width than the viewport before subsequent rules re-established the correct layout. Replacedall: initialwith explicit property resets covering only the properties needed to isolate the player from WordPress theme interference. Added explicit-webkit-text-size-adjust: 100%to suppress iOS font inflation. Android was unaffected as Chrome handlesall: initialmore predictably. Pending second set of screenshots to confirm fix.
- Accessibility: Full ARIA pass across all 7 frontend elements. Main Player – added
role="region"to player wrapper;role="dialog"andaria-modalto all five sidebars;role="tablist"androle="tab"to Media Recon and Settings tab groups;role="tabpanel"to all tab content panels;aria-hidden="true"to all waveform canvases, album art effect canvas, and status dot;aria-labelto main audio element;aria-pressedto play/pause, shuffle, repeat, and all utility toggle buttons updated dynamically;aria-expandedto detail toggle button updated dynamically; bare<label>elements in shortcuts sidebar replaced with<span class="vamp-shortcut-section-label">; landscape overlay givenrole="alertdialog". - Accessibility: Track List –
role="list"on track container;aria-valuemin/max/nowon seek slider;aria-labelon inline audio elements; fallbackaria-labelon download links; pagination container changed to<nav>withrole="navigation". - Accessibility: Artist Card, Artist Stats Card, Track Player –
aria-hidden="true"on placeholder SVG logos;role="region"with descriptivearia-labelon each widget root. - Accessibility: Artist List –
aria-hidden="true"on placeholder SVG;role="button",aria-expanded, andtabindex="0"on accordion row headers; keyboard Enter/Space support added for accordion toggle; pagination changed to<nav>. - Accessibility: Site Stats Card –
role="region"on root; meaningfulalttext on featured track images (was empty);role="img"with compositearia-labelon each stat count item;aria-hidden="true"on decorative stat icons.
- Fixed: Stale dropdown fix – all seven Elementor widgets now use
SELECT2searchable controls with DB queries run at widget registration time. A newelementor/editor/after_enqueue_scriptshook registers library, artist, and track data for Elementor editor use. - Fixed: All seven Gutenberg blocks now use
ComboboxControl(searchable single-select, type to filter) replacing the previousSelectControl. The track player block no longer uses a plain text input for Track ID – it now has a searchable combobox populated fromwindow.vitreousTracksmatching all other blocks. - Fixed: Track player Gutenberg block editor preview now shows the track title rather than the raw ID.
- Fixed: Library list – added spacing between ID badge and library name.
- Fixed: Artist Profiles sidebar – ID badge now sits at the far right of the name row using
margin-left: auto.
- Fixed: Shortcodes page – incorrect wrapper class and missing admin header corrected. Page now uses
vitreous-wrapand the standard Vitreous page head with logo and theme toggle. Inline styles moved toadmin.css. - Fixed: Library ID badge repositioned to the left of the library name in the Libraries list.
- Fixed: Track ID badge repositioned to the right of the track duration in the library editor track sidebar. Removed from inside the track info block where it was disrupting the layout.
- Fixed: Track editor – removed ID bar from inside the editor form which was breaking tab and padding layout. Track ID is now shown in the Tracks section header as “Viewing Track ID: X” in the same row as the unlinked notice. Hidden when adding a new track.
- Fixed: Artist ID badge repositioned inline to the right of the artist name in the Artist Profiles sidebar.
- Fixed: Stray floating CSS fragment removed from
admin.css. Deadvt-track-editor-id-barrule removed.
- New: Shortcodes reference page added under Vitreous – Shortcodes. Documents all seven shortcodes with full parameter tables, required/optional badges, default Azure theme note for the six newer widgets, and copy-ready examples for every variation.
- New: Library ID badges added to the Libraries list page – visible next to each library name for quick reference when writing shortcodes or configuring widgets.
- New: Artist ID badges added to the Artist Profiles sidebar – visible next to each artist name.
- New: Track ID badges added to the track sidebar in the library editor, and shown in the track editor form header when an existing track is loaded. Hidden for new unsaved tracks.
- Fixed: Stale dropdown issue in all Elementor widgets and the Gutenberg Track Player block. All SELECT and SELECT2 controls that queried the database at widget registration time have been replaced with NUMBER or TEXT inputs. Elementor bakes options arrays at registration, meaning newly added libraries, artists, or tracks would not appear in dropdowns until the editor page was fully reloaded. All six Elementor widgets (Track List, Artist Card, Artist List, Artist Stats Card, Site Stats Card, Track Player) and the Gutenberg Track Player block now use direct ID inputs with descriptions directing the user to find IDs in the Vitreous admin. No DB queries run at registration time.
- Changed: Artist List Elementor widget – the Select Artists multi-select (SELECT2) replaced with a plain text field accepting comma-separated Artist IDs (e.g. 1,3,5).
TUESDAY THE 26TH OF MAY
- Fixed: Volume bar is now hidden on iOS devices. Apple enforces a strict OS-level restriction on all iOS browsers (including third-party browsers, which are required to use WebKit) where
HTMLMediaElement.volumeis read-only and locked to the hardware volume buttons. The volume slider, mute button, and percentage display were silently non-functional on all iOS devices. On player load, the OS is checked vianavigator.userAgentand if iOS is detected the entire.volume-barrow is hidden. Volume-related keyboard shortcuts (Shift+Up, Shift+Down, Shift+M) are also suppressed on iOS. This build has not yet been confirmed on a live iOS device.
- 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-sectionand#vamp-color-palette-light-sectionrules targeting elements that no longer exist in the player template;#vamp-embed-code-inputrule for a removed embed code panel;#fullscreen-artist-profilerule targeting a non-existent ID (element usesfullscreen-artist-profile-extras);.fullscreen-meta-sectionrule for a class not present in the template or JS;#vamp-crossfadehide 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 itswp_ajaxregistration – library deletion is handled via a nonce-protected GET link inlibraries-list.php. Never called from JS. - Removed:
handle_import_tracks()handler and itsadmin_postregistration – import was converted to AJAX at v11.1.2. The old form POST route was never reachable. - Removed:
ajax_link_track_artist()handler and itswp_ajaxregistration – replaced byvitreous_link_unlinked_track. Never called from anywhere. - Removed:
player_scalefromset_default_options()and fromsettings-page.phpPOST save and read – the setting was saved but never read or applied anywhere in the plugin or JS. - Removed:
vtReloadTracksdead call from import handler inadmin.js– function never defined anywhere. - Removed: Misplaced
Theme togglecomment from top ofadmin.js– sat above format indicator code, not theme toggle code. - Removed: Duplicate separator comment line in
admin.js. - Removed:
getAnimationSpeedLabel()fromvitreous-player.js– defined but never called anywhere. - Removed: Empty
else {}block invitreous-player.jsat thevitreousSettingscheck – 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
srcfield 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: nonestyling 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-sidebardoes not exist, the entire block was skipped before the import handler ran. Fixed by wrapping the DO code inif (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_nameandastat_track_likeson Artist Stats Card, andsstat_feat_countandsstat_feat_badgeon Site Stats Card all usevar(--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_keysso 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_keysinajax_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.phpwas missingdata-astat-*,data-tplayer-*,data-sstat-*attributes — accent and theme were never read from the DB at page load; (2)vtDoPopulateFromTriggerinadmin.jsonly populatedlist,card,alist— new sections never populated on sidebar open; (3) save handler write-back only updatedlist,card,alistdata 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_*, andsstat_*column keys were missing from the$allowed_keyswhitelist inajax_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: 480pxCSS variable and centres within its container usingdisplay: flex; justify-content: centeron 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-playersovtListInitinvitreous-list.jsdiscovers and wires up all controls via the existing standalone item path. - Fixed: Track Player responsive breakpoint added — at
max-width: 520pxthe card width falls back to100%to fill narrow screens gracefully.
- Fixed: Track Player shortcode was reading
file_source_url(the download source) as the audio elementsrc. Corrected to read thesrccolumn, 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 viasstat_*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 existingvitreous-list.jshandles all audio controls automatically. Supports Display Options viatplayer_*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 viaastat_*columns.
- New:
admin.js—previewsobject extended withastat,tplayer,sstatpreview panel references. - New:
vtDoUpdatePreview—previewMapextended with typography element mappings for all three new sections. Social icon size preview extended to includeastat. - New:
vtDoLoadFirstTrack— populates all new preview element text nodes with first track data on sidebar open. - New:
vtDoLoadTypography— skip list extended to ignoreastat_*,tplayer_*,sstat_*accent and theme keys during load.
- New: Display Options sidebar tab bar updated to two-row layout —
flex-wrap: wrapwithflex: 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_schemafor 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 viaALTER TABLEwith 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
endifon line 880. The<?php if ($play_log_exists): ?>wrapper around the chart script block was lost when the new ranking sections were inserted. The orphanedendifcaused 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 toget_results(). Replaced with safeintval()interpolation —$filter_libraryis already sanitised withintval()at input, making direct interpolation safe.
- Fixed: Metrics page critical error. Artist ranking queries were constructing invalid SQL by appending
AND t.library_id = %ddirectly after aJOINclause with no precedingWHEREkeyword. AddedWHERE 1=1before the conditional filter clause in both Most Played Artists and Most Liked Artists queries. Library filter variable extracted to$lib_where_artiststo avoid calling$wpdb->prepare()inside string concatenation twice.
- Fixed: Metrics page critical error.
HAVING total_plays > 0andHAVING total_likes > 0in the Most Played Artists and Most Liked Artists queries used column aliases in theHAVINGclause, which is not supported by MariaDB. Replaced with full aggregate expressions:HAVING SUM(t.global_play_count) > 0andHAVING SUM(t.global_favourite_count) > 0.
- Fixed: Metrics page critical error on load. MySQL reserved word
atwas 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 tovat.
- 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, andvtDoLoadTypographyfunction definitions were missing fromadmin.js. AReferenceErroronvtDoUpdatePreviewhalted execution insidevtDoPopulateFromTriggerbeforevtDoOpenwas ever reached. All four functions restored from v8.3.1.
- Fixed: Editor overlay added to
.glass-playervia CSS::afterpseudo-element, scoped tobody.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-playerwas hardcoded to400pxinside@media (min-width: 521px), overriding--player-max-widthentirely. Replaced withvar(--player-max-width, 420px). All width defaults (CSS, JS, PHP, template) corrected from400px/500pxto420pxto match the settings slider minimum. - Fixed:
.player-wrapperno longer usesmin-height: 100vhoralign-items: centerin 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:fullscreenand.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 avt-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 hasvalue="1"(string). Changed toanimationSpeed: 1throughout. Change handler updated to store the value as a string rather than parsing it back to a float viaparseFloat, 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
42to 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.innerHeightis always true on a landscape monitor. AddedvtIsMobileDevice()check —navigator.maxTouchPoints > 0combined 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-colmodifier rule was declared before the base.vt-track-editor-layoutrule in the stylesheet, causing the base two-columngrid-template-columnsto 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 withminmax(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 tomaybe_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_idfield. A “New” button reveals an inline create form (Name, Year Started, Bio, Image) that saves via the existingvitreous_save_artisthandler, 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()acceptslinked_artist_id. If set, the linked profile name is synced into the cachedartistcolumn automatically. The artist-track link is written tovitreous_artist_tracks.ajax_load_track()JOINs the linkage table and returnslinkedArtistIdso 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
divabsolutely positioned over the chart container (z-index: 100), showing the bucket label, play count, and like count onmouseenterof 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_logandvitreous_like_logadded. Each play event inserts a row intovitreous_play_log(track_id, library_id, played_at). Each like or unlike event inserts a row intovitreous_like_log(track_id, library_id, action, liked_at). Existing running totals andlast_played_atbehaviour 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
vtScenarioBPendingflag now tracks this state. When the resize listener detects a portrait rotation while the flag is set, it callsrequestFullscreen()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
playOrderarray 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 throughplayOrder, so play order always matches what the user sees in the track list. - Fixed: Shuffle now picks randomly from
playOrderrather 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 fromcurrentThemeHex— 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-musicandfa-user-musicare Font Awesome Pro icons not available in the free CDN. Replaced withfa-layer-groupandfa-userrespectively.
- 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_successcalls inajax_save_track()now returnart,artist, andtotal_timealongsidetrack_idandtitle, 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 1frtocalc(100% - 400px) 400pxinadmin.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.phpupdated to includeartist,art, andtotal_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.phpupdated to includeimage_url. - Rebuild: Track edit form in Column B (
track-row.php) converted fromform-tabletwo-column layout to single-column builder form with labelled sections and paired field rows. All fieldnameattributes,data-indexvalues, 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.jsupdated to match new enriched sidebar HTML.vtSortSidebarnow renumbers.vt-track-sidebar-numbadges 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-fieldswrapper. - CSS: Responsive collapse breakpoint for
.vt-track-editor-layoutmoved 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 viaadmin.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.phprestyled 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 width400px. Player Scale setting removed from backend. - Mobile (
max-width: 520px): Player fills viewport width. All internal elements useclamp()for fluid sizing. Both sidebars constrained tocalc(100vw - 40px). Player wrapper padding reduced to8px.
- Fixed:
vtUpdateFormatIndicatorexposed globally viawindow.vtUpdateFormatIndicatorso 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-rowwhich does not exist — corrected to.vt-track-fields. Removed reference to non-existent.track-title-displayclass. - Fixed: Duration fallback path now correctly handles tracks over 60 minutes, outputting
H:MM:SSformat instead ofMMM:SS. - Fixed: Main player current time counter now shows
H:MM:SSfor tracks over 60 minutes. SharedvtFormatTime()function used across all three time display points. - Fixed: Minified player (Track List, Artist Card, Artist List) current time counter now shows
H:MM:SSfor tracks over 60 minutes via updatedvtListFormatTime(). - 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-rootso 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_options—alist_search_*andalist_pagination_*(9 typography properties each). Added safely viaSHOW COLUMNSguard inmaybe_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-thememoved 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-themeand inline CSS vars moved from.vt-artist-list-rootto.vt-artist-list-wrapperso 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
artistIdsattribute and passed to the shortcode.vitreousArtistsnow 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_atcolumn onvitreous_librarieswas missingON UPDATE CURRENT_TIMESTAMPon existing installs due to a dbDelta limitation. Fixed via aSHOW COLUMNSguard inmaybe_upgrade_schema()that runs a targetedALTER TABLE MODIFY COLUMNon 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_redirectwas 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 —
SelectControlwas 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_playedAJAX endpoint — acceptslibrary_id, returns 10 deduplicated recently played tracks.
- DB: Two new columns on
vitreous_display_options—card_social_icon_font_sizeandalist_social_icon_font_size. Added safely viaSHOW COLUMNSguard inmaybe_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-btnnow usesdisplay: flex; align-items: centerso themargin-lefton the count span works correctly in both desktop and mobile contexts.
- Fixed: Media Recon like count spacing —
margin-leftincreased 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
idwas selected in the query but never rendered onto the.vt-list-item-playerdiv asdata-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. Addeddata-track-indexto 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 —
trackswas used instead of the correcttrackDatavariable in both thetoggleFavoritehandler and the 60-second poll, causing aReferenceErrorthat prevented the player from initialising.
- Fixed: Media Recon and fullscreen sidebar like count not updating on toggle — the
tracksarray was not updated beforeupdatePlaylistUIrebuilt the DOM, causing the AJAX response to target a replaced element. Count now updates thetracksarray 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_countsAJAX 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_countcolumn onvitreous_tracks. 18 new typography columns onvitreous_display_optionsfor Global Likes and Global Plays text areas. Both added safely viaSHOW COLUMNSguards inmaybe_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.
vitreousLibrariesnow 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
changeevent. 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
!importantoverrides added to#vt-do-sidebarmatching 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_optionstable — one row per library,library_idas 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_playAJAX on each play press — matching the main player pattern.vitreousListSettingslocalised to provideajaxUrlto the list script.
- Fixed: Page load performance — audio context and compressor chain now created only on first play press, never on page init. Removed
vtListApplyNormalisationwhich 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
vtListAudioCtxcontext reused across all minified players. All chain variables prefixedvtListto 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_SOURCESfrom 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, andbox-sizing: border-boxso content respects the grid column boundary at all viewport sizes. Bio text now usesoverflow-wrap: break-wordto prevent long words overflowing. - Fixed: Artist Accordion List body content — added
min-width: 0andoverflow: hiddento the body content flex column so it respects the grid track boundary. Bio word-wrap fixed. Responsive breakpoint widened from600pxto700pxso 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-widthtransition withopacityandvisibilitytransitions 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: absoluteanchored to the right edge of the track row. The row usesposition: relative; overflow: hiddento 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 titleto 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
!importanton accordion track list image fill rules with.vt-list-root-scoped selectors (.vt-list-root .vt-list-art imgand.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%andheight: autoglobally to images which was overriding the fill rules. Added!importantto all critical image fill properties on both.vt-list-art imgand.vt-list-body-art imgto 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: 48pxon.vt-list-artwas being overridden by the flex parent causing the container to collapse, leaving the absolutely positioned image anchored totop: 0with no height to fill. Replaced withaspect-ratio: 1 / 1matching 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: relativewith the image set toposition: 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 usesaspect-ratio: 1 / 1withalign-self: startreplacing 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-widthtransition. 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: hiddenon.vt-list-itemwhich prevented the absolutely positioned slider from escaping the item boundary. Removedoverflow: hiddenfrom 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_tracksviamaybe_upgrade_schema()withSHOW COLUMNSexistence checks —global_play_count INT(11) DEFAULT 0andlast_played_at DATETIME DEFAULT NULL. Both are added safely on first admin load for existing installs. Fresh installs receive the columns via the existingCREATE TABLEdefinition. - New: Global play count — every time a track is played on the frontend, a fire-and-forget
fetchPOST incrementsglobal_play_countand setslast_played_atserver-side. The handler is registered as bothwp_ajax_*andwp_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
globalPlayCountvalue is updated immediately on each play so the Media Recon reflects the increment without a page reload. - Note:
last_played_atis 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
.jsonexport file containing an array of track objects. Thetitlefield 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 WordPressadmin-post.phpform pattern for reliable file upload handling. - New: Track Export — exports all tracks in the current library as a
.jsonfile. The exported file uses the same field names as the import schema and round-trips cleanly into any Vitreous library. Uses the WordPressadmin-post.phpform 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
srcURL 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 usingnavigator.clipboard.writeText()on HTTPS contexts, with adocument.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
trackDatais 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_artistsDB 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 converts1.0to"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 frominputtochange.
- Fixed: Changelog card gap not rendering. Cards sit directly inside
#vt-cl-entries— the.vitreous-changelog-listwrapper class and itsgaprule were never applied. Fixed by applyingdisplay:flex; flex-direction:column; gap:32px; margin-top:24pxdirectly to#vt-cl-entries.
- Fixed: Admin background colour corrected from
#1a1a2eto#0f172aacross all Vitreous admin pages, matching Criterium and Stratum. Both--vt-bgand--vt-admin-bgtokens updated.--vt-surfaceupdated fromrgba(20,24,48,0.95)torgba(20,30,50,0.95)to match. - Updated: Changelog page redesigned to match Criterium layout. Outer wrapper changed to WordPress standard
wrapclass for full-width rendering — the previousmax-width:860pxconstraint 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
nonewaveform handler was inserted with three closing braces before it (}}}) instead of two (}}), closingdrawWave()prematurely and leaving theelse 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 closesdrawWave().
- Fixed: Frontend player regression introduced in v4.6.5. The
nonewaveform handler was inserted afterdrawWave()‘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 thenonehandler correctly placed as the finalelse ifbranch insidedrawWave().
- 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 bothwaveform-canvas-bgandwaveform-canvas-fgwithout 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 — sincedrawVisualizer()now draws to the dedicatedwaveform-canvas-vislayer (v4.6.3), the conflict no longer exists anddrawWave()can always run freely.
- Fixed: Waveform layer system restored to correct four-layer architecture. A dedicated
waveform-canvas-viscanvas (z-index 2) has been added betweenwaveform-canvas-bg(z-index 1) andwaveform-canvas-fg(z-index 3).drawVisualizer()now draws tovisinstead offg, meaning the live frequency visualiser and the static waveform are fully independent layers. Bothvisandfgare revealed by the playhead clip-path ontimeupdateand reset to fully hidden on track load.visis cleared on stop/pause.waveform-canvas-fgz-index corrected from 2 to 3. Global accent colour applies tovis,fg, andwave-progress-mask.bgremains 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-wrapperdiv was incorrectly removed fromplayer-template.phpin v4.3.5 under the assumption it was a duplicate. It was not — the JS usesgetElementById('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_artistswith 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_artiststable. Legacy options are deleted after migration. No data is lost. - Updated: Frontend player —
vitreousSettings.artistProfile(single object) replaced withvitreousSettings.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--smclass, 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 viascrollbar-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:16pxto FA icons on the Artist Profile page andfont-size:20pxon 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 newsimpleiconicon type has been added to both admin pages’ icon rendering logic, mirroring the existingfaviconpattern.
- Fixed: Bluesky icon still missing from admin pages (Artist Profile, Settings share platforms) after v4.4.2. Root cause:
elementor-font-awesomeis 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-btnand.vt-cl-page-labelCSS 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
localStorageasvitreous-admin-theme, matching the Criterium pattern exactly. - Added: Light theme CSS —
body.vitreous-admin-page.vitreous-lighttoken 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 inadmin.css :root. - Removed:
inject_admin_appearance_css()PHP method and itsadmin_headhook — no longer needed now that all CSS variables are static inadmin.css. - Removed:
vitreous_admin_bg_preset,vitreous_admin_bg_custom, andvitreous_admin_glass_intensityWordPress options — save and load logic both removed fromsettings-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-tableetc.), eliminating all CSS specificity conflicts with WordPress core styles. - Added:
admin_body_classfilter — injectsbody.vitreous-admin-pageon 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-resultvariants,vitreous-changelog-card. - Fixed: Font rendering — every component class now carries an explicit
font-family: var(--vt-font-head)orvar(--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
#00d2ffto gold#c4a75dthroughout 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_cssnow outputs only dynamic CSS variables (background, glass intensity). Background scoping moved toadmin.cssunderbody.vitreous-admin-page. - Restored:
wp_enqueue_style('vitreous-admin-fonts')with correctnullversion 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 thevitreous-confirm-deletemodal 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 tovitreous-noticeclasses. - 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.
Share it, so others know...
- Share on Bluesky (Opens in new window) Bluesky
- Share on Mastodon (Opens in new window) Mastodon
- Email a link to a friend (Opens in new window) Email
- Print (Opens in new window) Print
- More
- Share on X (Opens in new window) X
- Share on WhatsApp (Opens in new window) WhatsApp
- Share on Reddit (Opens in new window) Reddit
- Share on Pinterest (Opens in new window) Pinterest
- Share on Threads (Opens in new window) Threads
- Share on Tumblr (Opens in new window) Tumblr
- Share on Facebook (Opens in new window) Facebook
- Share on Telegram (Opens in new window) Telegram
- Share on Nextdoor (Opens in new window) Nextdoor
- Share on LinkedIn (Opens in new window) LinkedIn
- Share on X (Opens in new window) X
