$post ? $post->ID : '',
'playlist' => 'show',
),
$atts,
'albatross_audio'
);
if (empty($atts['id'])) {
return 'Error: No ID provided.';
}
// Validate and sanitize the playlist attribute
$playlist_visibility = strtolower(trim($atts['playlist']));
if (!in_array($playlist_visibility, array('hide', 'show'))) {
$playlist_visibility = 'show';
}
$id = intval($atts['id']);
$audio_songs = get_post_meta($id, 'albatross_audio_songs', true);
$output = '';
if (!empty($audio_songs)) {
$playlist = '';
$unique_id = uniqid('jp_');
$song_count = count($audio_songs);
$total_duration = $this->albaau_albatross_audio_duration($audio_songs);
// Variables to hold the first valid song's artist and thumbnail
$initial_song_artist = '';
$initial_song_thumb = '';
foreach ($audio_songs as $song) {
$song_title = esc_js($song['song_title']);
$song_file = esc_url($song['song_file']);
$song_artist = esc_attr($song['song_artist']);
$song_thumb = !empty($song['song_thumb']) ? esc_url($song['song_thumb']) : $this->albaau_albatross_audio_get_song_thum_fallback($id);
// Only process valid songs
if (!$song['song_file'] || !$this->albaau_albatross_is_valid_url($song_file) || !$this->albaau_albatross_audio_is_playable_url($song_file)) {
continue;
}
// Capture the first valid song's artist and thumbnail (only once)
if (empty($initial_song_artist) && empty($initial_song_thumb)) {
$initial_song_artist = $song_artist;
$initial_song_thumb = $song_thumb;
}
// Add the artist property to the playlist item
$playlist .= '{title:"' . $song_title . '",mp3:"' . $song_file . '",oga:"' . $song_file . '",thumb:"' . $song_thumb . '",artist:"' . $song_artist . '"},';
}
// Fallback values if no valid song was found
if (empty($initial_song_artist)) {
$initial_song_artist = '';
}
if (empty($initial_song_thumb)) {
$initial_song_thumb = $this->albaau_albatross_audio_get_song_thum_fallback($id);
}
$this_title = get_the_title($id) ? get_the_title($id) : 'untitled';
$output .= '
';
// The following script initializes jPlayer and sets up the playlist toggle behavior.
// It uses the new "playlist" attribute to determine the initial visibility.
$inline_script = "
jQuery(document).ready(function (\$) {
var player = new jPlayerPlaylist({
jPlayer: '#jquery_jplayer_" . esc_js($unique_id) . "',
cssSelectorAncestor: '#jp_container_" . esc_js($unique_id) . "'
}, [{$playlist}], {
swfPath: '../js',
supplied: 'mp3, oga',
useStateClassSkin: true,
autoBlur: false,
smoothPlayBar: false,
keyEnabled: true,
audioFullScreen: true
});
// Update the UI (thumbnail and artist) with fade transitions
function updateUI() {
var currentIndex = player.current;
if (player.playlist[currentIndex]) {
var newThumbnail = player.playlist[currentIndex].thumb;
var newArtist = player.playlist[currentIndex].artist || '';
var thumbnail = \$('#albatross-player-thumb-" . esc_js($unique_id) . "');
var artistElement = \$('#jp_container_" . esc_js($unique_id) . " .albatross-player-song-artist');
// Only update the thumbnail if it has changed
if (thumbnail.attr('src') !== newThumbnail) {
thumbnail.fadeOut(75, function() {
\$(this).attr('src', newThumbnail).fadeIn(75);
});
}
// Always update the artist text with a fade transition
artistElement.fadeOut(75, function() {
\$(this).text(newArtist).fadeIn(75);
});
}
}
// Update UI on song change event
\$('#jquery_jplayer_" . esc_js($unique_id) . "').bind(\$.jPlayer.event.play, function() {
setTimeout(updateUI, 75);
});
// Playlist toggle with smooth text opacity animation to avoid flicker
var hideButton = \$('#jp_container_" . esc_js($unique_id) . " .albatross-hide-playlist');
var playlist = \$('#jp_container_" . esc_js($unique_id) . " .jp-playlist');
// Set initial playlist visibility based on the 'playlist' shortcode attribute
var initialVisibility = '" . esc_js($playlist_visibility) . "';
if (initialVisibility === 'hide') {
playlist.hide();
} else {
playlist.show();
}
if (hideButton.length && playlist.length) {
// Clear any existing content and build the toggle button
hideButton.empty();
var iconSpan = \$('').addClass(initialVisibility === 'hide' ? 'icon-caret-down' : 'icon-caret-up');
var buttonText = \$('').text(initialVisibility === 'hide' ? ' Show' : ' Hide');
hideButton.append(iconSpan).append(buttonText);
hideButton.on('click', function() {
if (playlist.is(':visible')) {
playlist.fadeOut(150);
iconSpan.removeClass('icon-caret-up').addClass('icon-caret-down');
buttonText.stop(true, true).animate({ opacity: 0 }, 75, function() {
\$(this).text(' Expand').animate({ opacity: 1 }, 75);
});
} else {
playlist.fadeIn(150);
iconSpan.removeClass('icon-caret-down').addClass('icon-caret-up');
buttonText.stop(true, true).animate({ opacity: 0 }, 75, function() {
\$(this).text(' Hide').animate({ opacity: 1 }, 75);
});
}
});
}
});
";
wp_add_inline_script('albatross-audio-script', $inline_script);
}
return $output;
}
// Validate URL
/**
* Validate URL.
*
* @param string $url The URL to validate.
* @return bool True if valid, false otherwise.
*/
private function albaau_albatross_is_valid_url($url) {
return filter_var($url, FILTER_VALIDATE_URL) !== false;
}
// Check if URL is playable
private function albaau_albatross_audio_is_playable_url($url) {
$headers = get_headers($url, 1);
if ($headers === false || strpos($headers[0], '200') === false) {
return false;
}
return isset($headers['Content-Type']) && (strpos($headers['Content-Type'], 'audio/') !== false);
}
// Get the song thumbnail fallback
private function albaau_albatross_audio_get_song_thum_fallback($id) {
if (!empty(get_the_post_thumbnail_url($id))) {
return get_the_post_thumbnail_url($id);
} else {
$placeholder_image = plugins_url('img/albatross-placeholder.png', __FILE__);
return $placeholder_image;
}
}
// Get playlist song count
public function albaau_albatross_audio_song_count($songs) {
$song_count = 0;
if (!empty($songs)) {
foreach ($songs as $song) {
$song_file = $song['song_file'];
if ($song_file) {
$song_id = attachment_url_to_postid($song_file);
$song_metadata = wp_get_attachment_metadata($song_id);
if (isset($song_metadata['length_formatted'])) {
$song_count++;
}
}
}
}
return $song_count;
}
// Get playlist duration
public function albaau_albatross_audio_duration($songs) {
$play_times = array();
if (!empty($songs)) {
foreach ($songs as $song) {
$song_file = $song['song_file'];
if ($song_file) {
$song_id = attachment_url_to_postid($song_file);
$song_metadata = wp_get_attachment_metadata($song_id);
if (isset($song_metadata['length_formatted'])) {
$play_times[] = $song_metadata['length_formatted'];
}
}
}
}
return $this->albaau_albatross_audio_AddPlayTime($play_times);
}
// Add "s" if plural
public function albaau_albatross_audio_pluralistic($amount, $singular = '', $plural = 's') {
return ($amount === 1) ? $singular : $plural;
}
// Total play time
public function albaau_albatross_audio_AddPlayTime($play_times) {
$minutes = 0;
if (!empty($play_times)) {
foreach ($play_times as $time) {
list($hour, $minute) = explode(':', $time);
$minutes += $hour * 60 + $minute;
}
}
$hours = floor($minutes / 60);
$minutes -= $hours * 60;
return sprintf('%02d:%02d', $hours, $minutes);
}
}
new Albatross_Audio_Shortcode();