Making a better audio shortcode for WordPress


If you use WordPress, you can get a fairly basic embedded audio player by using the audio shortcode:

[audio mp3="/path/to/file.mp3"]

I didn't particularly like how it was styled so - because WordPress is so hackable - I changed it!

Now my embedded audio looks like this:

🔊 Location Based QR Codes - Introducing http://xmts.mobi/
🎤 edent

It gets a nice border, a title, displays any attached image, and uses the native HTML5 audio element.

Here's the code to do it. Stick it in your functions.php and add suitable CSS. Shout if you spot any weird bugs.

add_filter('wp_audio_shortcode_override', 'edent_audio_shortcode_override', 10, 2);
function edent_audio_shortcode_override( $html, $attr ) {
    $audio_url = "";

    //  The shortcode will have an attribute with the URl to the file:
    //  e.g. [ audio mp3="https://example.com/path/to/file.mp3" ]
    if ( isset( $attr['wav']  ) ) { $audio_url = $attr['wav'];  }
    if ( isset( $attr['mp3']  ) ) { $audio_url = $attr['mp3'];  }
    if ( isset( $attr['m4a']  ) ) { $audio_url = $attr['m4a'];  }
    if ( isset( $attr['ogg']  ) ) { $audio_url = $attr['ogg'];  }
    if ( isset( $attr['opus'] ) ) { $audio_url = $attr['opus']; };
    if ( isset( $attr['src']  ) ) { $audio_url = $attr['src'];  }; //   For raw links without a shortcode

    //  Defaults
    $audio_meta = null;
    $audio_thumb = false;

    //  Get the attachment ID from the media library
    $audio_id = attachment_url_to_postid( $audio_url );
    if ($audio_id > 0) {
        $audio_meta  = wp_get_attachment_metadata($audio_id);
        $audio_thumb = get_the_post_thumbnail_url( $audio_id );
    } else {
        //  Is this on our server?
        $upload_dir = wp_upload_dir(); // Get the upload directory info
        $upload_baseurl = $upload_dir['baseurl'];

        // Check if the provided URL belongs to the site
        if (strpos($audio_url, $upload_baseurl) !== false) {
            // URL belongs to the site, get the file path
            $file_path = str_replace($upload_baseurl, $upload_dir['basedir'], $audio_url);
            // Check if the file exists on disk
            if (file_exists($file_path)) {
                require_once ABSPATH . 'wp-admin/includes/media.php';
                $audio_meta  = wp_read_audio_metadata( $file_path );
                $audio_thumb = false;
            }
        }
    }

    //  Get the title of the audio - or use a default
    if ( isset( $audio_meta["title"] ) ) {
        $audio_title = "🔊 " . htmlspecialchars( $audio_meta["title"], ENT_NOQUOTES | ENT_HTML5 | ENT_SUBSTITUTE, 'UTF-8', /*double_encode*/false );
    } else {
        $audio_title = "🔊";
    }

    //  Get the artist of the audio - or use a default
    if ( isset( $audio_meta["artist"] ) ) {
        $audio_artist = "<br>🎤 " . htmlspecialchars( $audio_meta["artist"], ENT_NOQUOTES | ENT_HTML5 | ENT_SUBSTITUTE, 'UTF-8', /*double_encode*/false );
    } else {
        $audio_artist = "";
    }

    //  Set the HTML for the thumbnail
    if ( $audio_thumb ) {
        $audio_thumb_html = "<img src=\"{$audio_thumb}\" class=\"audio-thumb\" alt=\"\">";
    } else {
        $audio_thumb_html = "";
    }

    $audio_html = <<<EOT
<figure class="audio">
    <figcaption class="audio">{$audio_title}{$audio_artist}</figcaption>
    {$audio_thumb_html}
    <audio class="audio-player" controls src="{$audio_url}">
        <a href="{$audio_url}">Download audio</a>
    </audio>
</figure>
EOT
;
    return $audio_html;
}

How it works

I'm indebted to this answer on WordPress StackExchange and this one onStackOverflow.

There's a whole bunch of metadata available in the audio files.

But to start with, you need to take the URl of the audio source and find its ID in the media library.

attachment_url_to_postid( "https://example.com/path/to/file.mp3" );

That should give you an ID. And here's how to get all the metadata from that attachment ID: wp_get_attachment_metadata( 1234 )

Which spits out:

array(25) {
  ["dataformat"]=>  string(3) "mp3"
  ["channels"]=>  int(1)
  ["sample_rate"]=>  int(44100)
  ["bitrate"]=>  float(63731.43187641008)
  ["channelmode"]=>  string(4) "mono"
  ["bitrate_mode"]=>  string(3) "vbr"
  ["codec"]=>  string(4) "LAME"
  ["encoder"]=>  string(8) "LAME3.97"
  ["lossless"]=>  bool(false)
  ["encoder_options"]=>  string(41) "--preset fast medium -b64 --lowpass 17500"
  ["compression_ratio"]=>  float(0.09032232408788277)
  ["fileformat"]=>  string(3) "mp3"
  ["filesize"]=>  int(5714048)
  ["mime_type"]=>  string(10) "audio/mpeg"
  ["length"]=>  int(683)
  ["length_formatted"]=>  string(5) "11:23"
  ["title"]=>  string(55) "Location Based QR Codes - Introducing http://xmts.mobi/"
  ["artist"]=>  string(5) "edent"
  ["copyright_message"]=>  string(5) "edent"
  ["time"]=>  string(4) "0549"
  ["date"]=>  string(4) "0310"
  ["year"]=>  string(4) "2010"
  ["encoded_by"]=>  string(18) "http://audioboo.fm"
  ["image"]=>  array(3) {
    ["mime"]=>    string(9) "image/png"
    ["width"]=>    int(826)
    ["height"]=>    int(1169)
  }
  ["album"]=>  string(0) ""
}

You'll notice that it doesn't actually have the image data inside. If WordPress noticed there was an embedded image in the audio on upload, it will be attached to it as a featured image. You can get it using: get_the_post_thumbnail( 1234 );

Alternative, you can get the binary data for the image using the path to the file: wp_read_audio_metadata("wp-content/uploads/2010/11/1234.mp3");

This gives:

array(24) {
  ["dataformat"]=>  string(3) "mp3"
  ["channels"]=>  int(1)
  ["sample_rate"]=>  int(44100)
  ["bitrate"]=>  float(63731.43187641008)
  ["channelmode"]=>  string(4) "mono"
  ["bitrate_mode"]=>  string(3) "vbr"
  ["codec"]=>  string(4) "LAME"
  ["encoder"]=>  string(8) "LAME3.97"
  ["lossless"]=>  bool(false)
  ["encoder_options"]=>  string(41) "--preset fast medium -b64 --lowpass 17500"
  ["compression_ratio"]=>  float(0.09032232408788277)
  ["fileformat"]=>  string(3) "mp3"
  ["filesize"]=>  int(5714048)
  ["mime_type"]=>  string(10) "audio/mpeg"
  ["length"]=>  int(683)
  ["length_formatted"]=>  string(5) "11:23"
  ["title"]=>  string(55) "Location Based QR Codes - Introducing http://xmts.mobi/"
  ["artist"]=>  string(5) "edent"
  ["copyright_message"]=>  string(5) "edent"
  ["time"]=>  string(4) "0549"
  ["date"]=>  string(4) "0310"
  ["year"]=>  string(4) "2010"
  ["encoded_by"]=>  string(18) "http://audioboo.fm"
  ["image"]=>  array(4) {
    ["data"]=>    BINARY DATA
    ["mime"]=>    string(9) "image/png"
    ["width"]=>    int(826)
    ["height"]=>    int(1169)
  }
}

See wp_read_audio_metadata() for more details. Note, it only works on local files - no reading from remote files.


Share this post on…

One thought on “Making a better audio shortcode for WordPress”

What are your reckons?

All comments are moderated and may not be published immediately. Your email address will not be published.Allowed HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <p> <pre> <br> <img src="" alt="" title="" srcset="">