Builds the Playlist shortcode output.
Description
This implements the functionality of the playlist shortcode for displaying a collection of WordPress audio or video files in a post.
Parameters
$attrarrayrequired- Array of default playlist attributes.
typestringType of playlist to display. Accepts'audio'or'video'. Default'audio'.orderstringDesignates ascending or descending order of items in the playlist.
Accepts'ASC','DESC'. Default'ASC'.orderbystringAny column, or columns, to sort the playlist. If $ids are passed, this defaults to the order of the $ids array ('post__in').
Otherwise default is ‘menu_order ID’.idintIf an explicit $ids array is not present, this parameter will determine which attachments are used for the playlist.
Default is the current post ID.idsarrayCreate a playlist out of these explicit attachment IDs. If empty, a playlist will be created from all $type attachments of $id.
Default empty.excludearrayList of specific attachment IDs to exclude from the playlist. Default empty.stylestringPlaylist style to use. Accepts'light'or'dark'. Default'light'.tracklistboolWhether to show or hide the playlist. Default true.tracknumbersboolWhether to show or hide the numbers next to entries in the playlist. Default true.imagesboolShow or hide the video or audio thumbnail (Featured Image/post thumbnail). Default true.artistsboolWhether to show or hide artist name in the playlist. Default true.
Source
function wp_playlist_shortcode( $attr ) {
global $content_width;
$post = get_post();
static $instance = 0;
++$instance;
static $is_loaded = false;
if ( ! empty( $attr['ids'] ) ) {
// 'ids' is explicitly ordered, unless you specify otherwise.
if ( empty( $attr['orderby'] ) ) {
$attr['orderby'] = 'post__in';
}
$attr['include'] = $attr['ids'];
}
/**
* Filters the playlist output.
*
* Returning a non-empty value from the filter will short-circuit generation
* of the default playlist output, returning the passed value instead.
*
* @since 3.9.0
* @since 4.2.0 The `$instance` parameter was added.
*
* @param string $output Playlist output. Default empty.
* @param array $attr An array of shortcode attributes.
* @param int $instance Unique numeric ID of this playlist shortcode instance.
*/
$output = apply_filters( 'post_playlist', '', $attr, $instance );
if ( ! empty( $output ) ) {
return $output;
}
$atts = shortcode_atts(
array(
'type' => 'audio',
'order' => 'ASC',
'orderby' => 'menu_order ID',
'id' => $post ? $post->ID : 0,
'include' => '',
'exclude' => '',
'style' => 'light',
'tracklist' => true,
'tracknumbers' => true,
'images' => true,
'artists' => true,
),
$attr,
'playlist'
);
$id = (int) $atts['id'];
if ( 'audio' !== $atts['type'] ) {
$atts['type'] = 'video';
}
$args = array(
'post_status' => 'inherit',
'post_type' => 'attachment',
'post_mime_type' => $atts['type'],
'order' => $atts['order'],
'orderby' => $atts['orderby'],
);
if ( ! empty( $atts['include'] ) ) {
$args['include'] = $atts['include'];
$_attachments = get_posts( $args );
$attachments = array();
foreach ( $_attachments as $key => $val ) {
$attachments[ $val->ID ] = $_attachments[ $key ];
}
} elseif ( ! empty( $atts['exclude'] ) ) {
$args['post_parent'] = $id;
$args['exclude'] = $atts['exclude'];
$attachments = get_children( $args );
} else {
$args['post_parent'] = $id;
$attachments = get_children( $args );
}
if ( ! empty( $args['post_parent'] ) ) {
$post_parent = get_post( $id );
// Terminate the shortcode execution if the user cannot read the post or it is password-protected.
if ( ! current_user_can( 'read_post', $post_parent->ID ) || post_password_required( $post_parent ) ) {
return '';
}
}
if ( empty( $attachments ) ) {
return '';
}
if ( is_feed() ) {
$output = "\n";
foreach ( $attachments as $att_id => $attachment ) {
$output .= wp_get_attachment_link( $att_id ) . "\n";
}
return $output;
}
$outer = 22; // Default padding and border of wrapper.
$default_width = 640;
$default_height = 360;
$theme_width = empty( $content_width ) ? $default_width : ( $content_width - $outer );
$theme_height = empty( $content_width ) ? $default_height : round( ( $default_height * $theme_width ) / $default_width );
$data = array(
'type' => $atts['type'],
// Don't pass strings to JSON, will be truthy in JS.
'tracklist' => wp_validate_boolean( $atts['tracklist'] ),
'tracknumbers' => wp_validate_boolean( $atts['tracknumbers'] ),
'images' => wp_validate_boolean( $atts['images'] ),
'artists' => wp_validate_boolean( $atts['artists'] ),
);
$tracks = array();
foreach ( $attachments as $attachment ) {
$url = wp_get_attachment_url( $attachment->ID );
$ftype = wp_check_filetype( $url, wp_get_mime_types() );
$track = array(
'src' => $url,
'type' => $ftype['type'],
'title' => $attachment->post_title,
'caption' => $attachment->post_excerpt,
'description' => $attachment->post_content,
);
$track['meta'] = array();
$meta = wp_get_attachment_metadata( $attachment->ID );
if ( ! empty( $meta ) ) {
foreach ( wp_get_attachment_id3_keys( $attachment ) as $key => $label ) {
if ( ! empty( $meta[ $key ] ) ) {
$track['meta'][ $key ] = $meta[ $key ];
}
}
if ( 'video' === $atts['type'] ) {
if ( ! empty( $meta['width'] ) && ! empty( $meta['height'] ) ) {
$width = $meta['width'];
$height = $meta['height'];
$theme_height = round( ( $height * $theme_width ) / $width );
} else {
$width = $default_width;
$height = $default_height;
}
$track['dimensions'] = array(
'original' => compact( 'width', 'height' ),
'resized' => array(
'width' => $theme_width,
'height' => $theme_height,
),
);
}
}
if ( $atts['images'] ) {
$thumb_id = get_post_thumbnail_id( $attachment->ID );
if ( ! empty( $thumb_id ) ) {
list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'full' );
$track['image'] = compact( 'src', 'width', 'height' );
list( $src, $width, $height ) = wp_get_attachment_image_src( $thumb_id, 'thumbnail' );
$track['thumb'] = compact( 'src', 'width', 'height' );
} else {
$src = wp_mime_type_icon( $attachment->ID, '.svg' );
$width = 48;
$height = 64;
$track['image'] = compact( 'src', 'width', 'height' );
$track['thumb'] = compact( 'src', 'width', 'height' );
}
}
$tracks[] = $track;
}
$data['tracks'] = $tracks;
$safe_type = esc_attr( $atts['type'] );
$safe_style = esc_attr( $atts['style'] );
ob_start();
if ( ! $is_loaded ) {
/**
* Prints and enqueues playlist scripts, styles, and JavaScript templates.
*
* @since 3.9.0
*
* @param string $type Type of playlist. Possible values are 'audio' or 'video'.
* @param string $style The 'theme' for the playlist. Core provides 'light' and 'dark'.
*/
do_action( 'wp_playlist_scripts', $atts['type'], $atts['style'] );
$is_loaded = true;
}
?>
<div class="wp-playlist wp-<?php echo $safe_type; ?>-playlist wp-playlist-<?php echo $safe_style; ?>">
<?php if ( 'audio' === $atts['type'] ) : ?>
<div class="wp-playlist-current-item"></div>
<?php endif; ?>
<<?php echo $safe_type; ?> controls="controls" preload="none" width="<?php echo (int) $theme_width; ?>"
<?php
if ( 'video' === $safe_type ) {
echo ' height="', (int) $theme_height, '"';
}
?>
></<?php echo $safe_type; ?>>
<div class="wp-playlist-next"></div>
<div class="wp-playlist-prev"></div>
<noscript>
<ol>
<?php
foreach ( $attachments as $att_id => $attachment ) {
printf( '<li>%s</li>', wp_get_attachment_link( $att_id ) );
}
?>
</ol>
</noscript>
<script type="application/json" class="wp-playlist-script"><?php echo wp_json_encode( $data, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ); ?></script>
</div>
<?php
return ob_get_clean();
}
Hooks
- apply_filters( ‘post_playlist’,
string $output ,array $attr ,int $instance ) Filters the playlist output.
- do_action( ‘wp_playlist_scripts’,
string $type ,string $style ) Prints and enqueues playlist scripts, styles, and JavaScript templates.
Changelog
| Version | Description |
|---|---|
| 3.9.0 | Introduced. |
FEEDBACK: This (and other) code references would be quite a bit more useful if they could include SCREEN SHOTS of what the resulting page looks like, where applicable.
In this case, four screenshots of PLAYLIST results would be appropriate:
– type=”audio” style=”light” (default)
– type=”audio” style=”dark”
– type=”video” (style=”light” – default)
– type=”video” style=”dark”
and other screenshots as needed to illustrate the results of various parameters.
NOTE: These would also be extremely useful on corresponding SHORTCODE pages of the codex.