Audio Player

code 1code 2code 3


Audio Player is a custom WordPress block that allows you to embed and play audio directly on your website.

It uses Advanced Custom Fields (ACF) to manage audio files and titles, and JavaScript to handle playback, progress tracking, and interactions.

What this block does

  • Plays audio with custom play / pause controls

  • Displays current time and total duration

  • Allows click & drag seeking via a progress bar

  • Ensures only one audio plays at a time

  • Fully reusable — multiple players per page supported


HTML / PHP Block Template

Purpose: Outputs the audio markup and pulls data from ACF.

Required ACF Fields

  • audio_file (File or URL) – required

  • audio_title (Text) – optional

HTML Copied!
                                                        <?php

/**
 * Block Template.
 *
 * @param   array $block The block settings and attributes.
 * @param   string $content The block inner HTML (empty).
 * @param   bool $is_preview True during AJAX preview.
 * @param   (int|string) $post_id The post ID this block is saved to.
 */

$classes = 'wp-block-audio-player';
$audio = get_field('audio_file'); // URL of the audio
$title = get_field('audio_title'); // optional
if(!$audio) return; ?>
<section class="<?php echo esc_attr( nucleo_block_classes( $classes, $block ) ); ?>">
	<div class="acf-audio-player has-black-background-color has-white-color">
		<div class="acf-audio-player_inner">
			<?php if(!empty($audio)): ?>
				<audio class="audio-element" src="<?php echo esc_url($audio); ?>"></audio>
			<?php endif; ?>
			<button class="audio-toggle">
				<span class="play-icon">
					<svg xmlns="http://www.w3.org/2000/svg" width="30px" height="30px" viewBox="0 0 24 24"><path fill="#fff" d="M8 19V5l11 7z"/></svg>
				</span>
				<span class="pause-icon" style="display:none;">
					<svg xmlns="http://www.w3.org/2000/svg" width="30px" height="30px" viewBox="0 0 24 24"><path fill="#fff" d="M14 19V5h4v14zm-8 0V5h4v14z"/></svg>
				</span>
			</button>
			<?php if(!empty($title)): ?>
				<p class="has-white-text-color mb-0"><?php echo esc_html($title); ?></p>
			<?php endif; ?>
			<span class="audio-current">0:00</span> / <span class="audio-duration">0:00</span>
		</div>	
		<div class="audio-progress">
			<div class="audio-progress-bar"></div>
		</div>
	</div>
</section>
                                                    

Javascript

Purpose: Controls playback, timing, progress bar updates, and interaction logic.

Features handled by JS

  • Play / pause toggle
  • Auto-pause other players
  • Time formatting
  • Click & drag seek support
JS Copied!
                                                        	document.addEventListener('DOMContentLoaded', () => {
		const players = document.querySelectorAll('.acf-audio-player');
		players.forEach(player => {
			const audio = player.querySelector('.audio-element');
			const toggleBtn = player.querySelector('.audio-toggle');
			const playIcon = toggleBtn.querySelector('.play-icon');
			const pauseIcon = toggleBtn.querySelector('.pause-icon');
			const currentTimeEl = player.querySelector('.audio-current');
			const durationEl = player.querySelector('.audio-duration');
			const progressContainer = player.querySelector('.audio-progress');
			const progressBar = player.querySelector('.audio-progress-bar');
			// Pause other audios when playing
			audio.addEventListener('play', () => {
				players.forEach(p => {
					const a = p.querySelector('.audio-element');
					if (a !== audio) a.pause();
				});
				playIcon.style.display = 'none';
				pauseIcon.style.display = 'inline';
			});
			audio.addEventListener('pause', () => {
				playIcon.style.display = 'inline';
				pauseIcon.style.display = 'none';
			});
			// Toggle button
			toggleBtn.addEventListener('click', () => {
				if(audio.paused) audio.play();
				else audio.pause();
			});
			// Show duration
			audio.addEventListener('loadedmetadata', () => {
				durationEl.textContent = formatTime(audio.duration);
			});
			// Update time and progress bar
			audio.addEventListener('timeupdate', () => {
				currentTimeEl.textContent = formatTime(audio.currentTime);
				progressBar.style.width = (audio.currentTime / audio.duration) * 100 + '%';
			});
			// Seek on click or drag
			let isDragging = false;
			const seek = e => {
				const rect = progressContainer.getBoundingClientRect();
				let x = e.clientX - rect.left;
				x = Math.max(0, Math.min(x, rect.width)); // clamp
				audio.currentTime = (x / rect.width) * audio.duration;
			};
			// Click to seek
			progressContainer.addEventListener('click', seek);
			// Drag to seek
			progressContainer.addEventListener('mousedown', e => { isDragging = true; seek(e); });
			window.addEventListener('mousemove', e => { if(isDragging) seek(e); });
			window.addEventListener('mouseup', () => { isDragging = false; });
			function formatTime(time) {
				const minutes = Math.floor(time / 60);
				const seconds = Math.floor(time % 60);
				return minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
			}
		});
	});
                                                    

Styles (SCSS / CSS)

Purpose: Controls layout, colors, progress bar visuals, and interaction layers.

CSS Copied!
                                                        .wp-block-audio-player{
	.acf-audio-player {
		width: 100%;
		position: relative;
		background: #7F7F7F;
		overflow: hidden;
        &_inner{
            z-index: 9;
            width: max-content; /* shrink exactly to its content */
            display: flex;
            justify-content: flex-start;
            align-items: center;
            position: relative;
            text-transform: uppercase;
            pointer-events: none;
            left: 0; /* align to left */
            > * {
                pointer-events: auto; /* inner buttons/text are still clickable */
            }
            p{
                margin: 0 1rem;
            }
        }
	}
	.audio-toggle {
		width: 50px;
		height: 50px;
		display: flex;
		align-items: center;
		justify-content: center;
		cursor: pointer;
		background: #74a300;
		color: #fff;
		border: none;
		flex-shrink: 0; /* prevent shrinking */
        .pause-icon {
            display: none;
        }
	}
	.audio-progress {
		width: 100%;
		height: 100%;
		background: #9b9b9bff;
		position: absolute;
		top: 0;
		left: 0;
		cursor: pointer;
		border-radius: 0;
        &-bar {
            height: 100%;
            width: 0;
            background: #2E2F2F;
            border-radius: 0;
            margin-left: 50px;
            border-left:1px solid #fff;
        }    
	}
}
                                                    

🚧 Under Construction

We're working on something awesome. Check back soon.