DESIGNED TO PLAY STREAMING AUDIO
KCR is a community radio station. This website is designed to allow an audio stream to play continuously, even as the user navigates around the site from page to page.
The streaming audio player is installed in the footer of the “Home-Frame” page. This master page has a header, a footer and a central div that is targeted by iFrames that contain the content pages. The “Home-Frame” page has headers and footers defined in the Divi Theme Builder, which are unique to this page.
The image below shows the structure. There are two header sections, one each for desktop and mobile – more about the mobile menu below. There is the footer containing the streaming audio player code.
The middle frame is iFrame content and its associated JavaScript file. By default, it loads the home page content when the user navigates to https://kcr.org.au.

MENU SYSTEM
On menu click, the main menu system is intercepted by the iFrame jQuery code. This stops the default action and the event propagation.
The jQuery code extracts the content page name from the menu item URL, filtered by a CSS class of “menu-item”. The jQuery code uses this to load that content page into the iFrame dynamically.
This mirrors the actions of a single-page application and so, does not refresh the “Home-Frame” host page. As the footer is not reloaded the player can continue to play, even though the content has been changed. A normal page post or refresh would reload the player, stopping and then restarting the stream.
WHY A SEPARATE MOBILE MENU
In practice, the jQuery intercepted the normal menu click when in Desktop mode, but not in the default WordPress mobile mode. I could not find out why. The hack was to create a separate header for mobile with a manually defined menu with its own CSS classes.
The structure of the mobile menu is a straightforward li with id=<page-name> and a CSS class of “menu-item”. Submenu uls need a sub-menu class to make them work.
If pages are added, you need to update the menu code below with the new menu items and then update the header menu – mobile text. It should then just work.
<div class="dsMobileMenu">
<div class="dsMobileLogo" onclick="openMobileMenu"><img src="wp-content/uploads/2022/04/kcr-logo.webp" alt="" />
</div>
<div id="dsMenuIcon" class="dsMobileIcon">
<p><img src="wp-content/uploads/2022/04/menu-icon.png" alt="" /></p>
<p> </p>
<div class="dsMenu">
<div class="dsMenuContainer">
<ul class="dsList">
<li id="home-content" class="menu-item">Home</li>
<li id="programs" class="menu-item">Programs</li>
<li id="podcasts" class="menu-item">Podcasts</li>
<li id="local-news" class="menu-item">Local News</li>
<li id="our-people" class="menu-item">Our People</li>
<li id="about-us" class="sub-menu">About Us<br /><br />
<ul class="dsList dsSubmenu">
<li id="memberships" class=" menu-item">Membership</li>
<li id="our-sponsors" class=" menu-item">Our Sponsors</li>
<li id="help-us" class="dsSubmenu menu-item">Help Us</li>
</ul>
</li>
<li id="contact" class="menu-item">Contact</li>
</ul>
</div>
</div>
</div>
</div>
ABOUT THE IFRAME PAGES
There is some dynamic communication between the Home-Frame and the content pages to get the height of the content in the iFrame. This updates the containing divs CSS height using JavaScript. In this way the content is correctly sized in the page. This height is refreshed every half-second, so if the page is resized, the content frame gets dynamically scaled accordingly.
The content pages and posts also have their header and footer defined in the Divi Theme Builder. They are defined to have no header or footer and therefore only display the page content. This works even if the post or page is actually built using the native Guttenberg page builder.
The content pages and posts can be constructed as usual, with no need for extra code or special structures. This should make maintenance by non-technical users as simple as possible.
HIDING AND DISPLAYING RESPONSIVE CONTENT
Where Divi’s native responsive mode display was unsatisfactory from a design pov, duplicate sections were created for desktop and responsive views.

The Divi visibility property hides and shows the correct section on the page load.
THE STREAMING AUDIO PLAYER
The streaming audio for KCR is encoded in the studio into MP3 and AAC streams via a dedicated NUC computer running software from TRITON Digital in the US. This is a supplier chosen by the Community Broadcasting Association of Australia (CBAA), where we are members and we get a member’s discount. These streams are sent to the US where a customised Shoutcast streaming server, rebroadcasts the streams to our listeners.
AUDIO STREAM URLS (.aac and .mp3):
https://playerservices.streamtheworld.com/api/livestream-redirect/KIAMACRAAC.aac and https://playerservices.streamtheworld.com/api/livestream-redirect/KIAMACR.mp3
The player itself is a simple HTML5 audio player using <audio> tags. This has been heavily customised using CSS and jQuery. This code is located in the <ROOT>/AudioPlayer directory
Playing Now Information
The KCR studio automation software is a freeware product called RadioDJ. It has a function that allows an external PHP script to interrogate the RadioDJ application for information about the current track playing. What information is available is configurable within RadioDJ.
We have a PHP script running in the <ROOT>/rdj folder called “dsPlayingInfo.php”. It creates and regularly updates a text file called “playing.txt”.
There is a jQuery script located in the footer player area that polls this text file and displays the updated track information.
ADDITIONAL BESPOKE FUNCTIONALITY (NOT PLUGINS)
Additional PHP development is located in the root rather than the plugin directory. The following functionality is involved:
- Audio player CSS and Javascript
- Podcasts – this is the most complex subsystem
- Schedule (soon to be bypassed with an external Zoho Calendar)
- RadioDJ database backup files – these are backups of the studio automation database that are automatically uploaded weekly by the studio server
- The rdj folder is the intermediate data store for the currently playing track. The audioPlayer script in the home page footer accesses this to load the “playing.txt” file created by the “dsPlayingInfo.php” file.
- The current track is loaded into the front end via a jQuery script that polls the text file every so often (5 seconds right now)
UPDATING THE PODCASTS
The podcast system dynamically loads our podcasts from KCR’s BuzzSprout account.
- The page is generated by a PHP script and inserted as an iFrame within a Divi page, and that Divi page is inserted into the main host iFrame. Unusual, but it works
- The podcast page uses an Ajax call to get a JSON data feed. The jQuery parses this to create the individual podcast information and formats it for display
- The image names come from the JSON but are actually sourced from a locally stored images folder
- If a new podcast is uploaded, the system notes that there is no corresponding image in the local image folder and downloads the full 2 Mb image from BuzzSprout
- This is resized by a PHP script and stored in the local image folder with the same name but at a vastly smaller file size
- Data attributes on each podcast container element drive the categorisation side menu. It takes care of itself and will automatically add any new categories created at the BuzzSprout level
- The search functionality uses a jQuery function to display only elements that contain the search keyword
- When the podcast element is clicked, it opens a player element that accesses the BuzzSprout audio feed to play the track
- This audio player element is within the podcast iFrame. To get it to the centre of the webpage, we do some inter-page/inter-iFrame communication to pass the podcast player up to the page header/footer level.
- This is so the audio player can be given a z-index with reference to the page’s main container and also can be centred with reference to this container.
- This whole system is working fine; you just need to be aware that it is there and that both code and HTML elements make this happen
- If the web audio streamer is playing and the user opens a podcast, playing the podcast triggers a jQuery function that mutes the web player and un-mutes it when the podcast element is closed
- Again, most of this is contained in the podcast directory and the Divi podcast script element on the Home container page. It is all pretty stable and should give you no problems.
UPDATING NEWS CONTENT
News and other local event material is uploaded using posts and displayed using WordPress blog grids. It is vital that the correct categories are applied to each post, as well the date and author information.
The posts are displayed in descending date order on the home page and the news page. The formatting can easily be changed if this is required.
The posts are created in the standard WordPress Guttenberg editor, which is quick and powerful enough for such posts.
MEMBERSHIP
We currently use the WordPress Paymatic Pro payment module to take membership payments via our Stripe account https://paymattic.com/. It is simple and reliable enough.
Reports can be run within the plugin’s admin interface. They also appear in a Dashboard widget.
MOBILE APPS USES WEBSITE PAGES FOR CONTENT
- The website feeds the mobile apps with content:
- On the app home screen, the weather comes from the “weather-app” page
- The news and whats-on were fed by “app-news” and “app-whats-on”
- The current schedule and program information comes from “app-schedule” and “app-programs”
- The app is still looking for the news and wats-on pages, so I have set up a redirect to load the schedule and program pages to the apps. This will not be necessary once the apps have been updated and everyone has updated their mobile apps
- The news and whats-on use posts that are made in Guttenberg (not Divi – which is too slow to create this kind of simple page)
- The news and whats-on display sections have been hidden, so they are effectively inactive. They were displayed in various places:
- Home page
- Local news
- App-news
- App-whats-on
- Call me if these local event pages are ever to be re-activated, and I’ll take you through the categorisation and display methodology. It is simple enough. (0472686181)
OTHER NOTES
- Most of the CSS for the site is contained in the /wp-content/themes/DsDivi folder, but CSS for the audio player, podcast player and the current program schedule system are in their own directories in the relevant root directories
- I use the LESS pre-processor to access its functions and nesting to automate and organise the CSS. I compile the LESS using Visual Studio code. However, using the existing final CSS file as a starting point also works
- In Divi, CSS snippets can also be stored in a Custom CSS area in the Divi/Theme Options/ page. When I am doing style fixups, I’ll paste the classes there and move them over to the proper CSS later once the changes prove to be worthwhile
- I also may have some global CSS in the Appearance/Customise/Additional CSS WordPress area.
- I will try to get time to clean all this up, but I may not be able to do so – so if there is something you cannot find, these are the places to look
- Sometimes global JavaScript is stored in the Divi/Integration/Code Integration page
- Page-specific JavaScript is either in Divi code modules which should be clearly labelled when you look at the page in wireframe mode; or it is in the individual external modules at the root directory level in their js directories