Make WordPress Core


Ignore:
Timestamp:
02/24/2014 06:07:51 PM (11 years ago)
Author:
wonderboymusic
Message:

Add core support for Playlists and Video Playlists.

  • Playlists operate like galleries in the admin.
  • Provide default UI and JS support in themes using MediaElement and Backbone.
  • The shortcodes are clickable, editable, and configurable using the media modal.
  • Playlists support images for each item, whether or not the current theme supports images for attachment:audio and attachment:video
  • Playlists respond to $content_width and resize videos accordingly.
  • All playlist data is included inline, using a script tag with type="application/json", allowing anyone to unenqueue the WP playlist JS and roll their own.
  • Playlist styles are minimal and work out of the box in the last 5 default themes. They inherit and adapt to the current theme's font styles, and their rules are easily overrideable.

See #26631.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/media.php

    r27209 r27239  
    933933    return $output;
    934934}
     935
     936/**
     937 * The Playlist shortcode.
     938 *
     939 * This implements the functionality of the Playlist Shortcode for displaying
     940 * a collection of WordPress audio or video files in a post.
     941 *
     942 * @since 3.9.0
     943 *
     944 * @param array $attr Attributes of the shortcode.
     945 * @return string $type Type of playlist. Defaults to audio, video is also supported
     946 */
     947function wp_get_playlist( $attr, $type ) {
     948    global $content_width;
     949    $post = get_post();
     950
     951    if ( ! in_array( $type, array( 'audio', 'video' ) ) ) {
     952        return '';
     953    }
     954
     955    static $instance = 0;
     956    $instance++;
     957
     958    if ( ! empty( $attr['ids'] ) ) {
     959        // 'ids' is explicitly ordered, unless you specify otherwise.
     960        if ( empty( $attr['orderby'] ) ) {
     961            $attr['orderby'] = 'post__in';
     962        }
     963        $attr['include'] = $attr['ids'];
     964    }
     965
     966    // Allow plugins/themes to override the default gallery template.
     967    $output = apply_filters( 'post_playlist', '', $attr, $type );
     968    if ( $output != '' ) {
     969        return $output;
     970    }
     971
     972    // We're trusting author input, so let's at least make sure it looks like a valid orderby statement
     973    if ( isset( $attr['orderby'] ) ) {
     974        $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
     975        if ( ! $attr['orderby'] )
     976            unset( $attr['orderby'] );
     977    }
     978
     979    extract( shortcode_atts( array(
     980        'order'     => 'ASC',
     981        'orderby'   => 'menu_order ID',
     982        'id'        => $post ? $post->ID : 0,
     983        'include'   => '',
     984        'exclude'   => '',
     985        'style'     => 'light',
     986        'tracklist' => 'audio' === $type,
     987        'tracknumbers' => 'audio' === $type,
     988        'images'    => true,
     989        'artists'   => true
     990    ), $attr, 'playlist' ) );
     991
     992    $id = intval( $id );
     993    if ( 'RAND' == $order ) {
     994        $orderby = 'none';
     995    }
     996
     997    $args = array(
     998        'post_status' => 'inherit',
     999        'post_type' => 'attachment',
     1000        'post_mime_type' => $type,
     1001        'order' => $order,
     1002        'orderby' => $orderby
     1003    );
     1004
     1005    if ( ! empty( $include ) ) {
     1006        $args['include'] = $include;
     1007        $_attachments = get_posts( $args );
     1008
     1009        $attachments = array();
     1010        foreach ( $_attachments as $key => $val ) {
     1011            $attachments[$val->ID] = $_attachments[$key];
     1012        }
     1013    } elseif ( ! empty( $exclude ) ) {
     1014        $args['post_parent'] = $id;
     1015        $args['exclude'] = $exclude;
     1016        $attachments = get_children( $args );
     1017    } else {
     1018        $args['post_parent'] = $id;
     1019        $attachments = get_children( $args );
     1020    }
     1021
     1022    if ( empty( $attachments ) ) {
     1023        return '';
     1024    }
     1025
     1026    if ( is_feed() ) {
     1027        $output = "\n";
     1028        foreach ( $attachments as $att_id => $attachment ) {
     1029            $output .= wp_get_attachment_link( $att_id ) . "\n";
     1030        }
     1031        return $output;
     1032    }
     1033
     1034    $supports_thumbs = ( current_theme_supports( 'post-thumbnails', "attachment:$type" ) && post_type_supports( "attachment:$type", 'thumbnail' ) )
     1035        || $images;
     1036
     1037    $outer = 22; // default padding and border of wrapper
     1038    $theme_width = $content_width - $outer;
     1039    $data = compact( 'type', 'style' );
     1040
     1041    // don't pass strings to JSON, will be truthy in JS
     1042    foreach ( array( 'tracklist', 'tracknumbers', 'images', 'artists' ) as $key ) {
     1043        $data[$key] = filter_var( $$key, FILTER_VALIDATE_BOOLEAN );
     1044    }
     1045
     1046    $tracks = array();
     1047    foreach ( $attachments as $attachment ) {
     1048        $url = wp_get_attachment_url( $attachment->ID );
     1049        $ftype = wp_check_filetype( $url, wp_get_mime_types() );
     1050        $track = array(
     1051            'type' => $type,
     1052            'src' => $url,
     1053            'type' => $ftype['ext'],
     1054            'title' => get_the_title( $attachment->ID ),
     1055            'caption' => wptexturize( $attachment->post_excerpt ),
     1056            'description' => wptexturize( $attachment->post_content )
     1057        );
     1058
     1059        $meta = wp_get_attachment_metadata( $attachment->ID );
     1060        if ( ! empty( $meta ) ) {
     1061            $track['meta'] = array();
     1062
     1063            $keys = array( 'title', 'artist', 'band', 'album', 'genre', 'year', 'length', 'length_formatted' );
     1064            foreach ( $keys as $key ) {
     1065                if ( ! empty( $meta[ $key ] ) ) {
     1066                    $track['meta'][ $key ] = $meta[ $key ];
     1067                }
     1068            }
     1069
     1070            if ( 'video' === $type ) {
     1071                $width = empty( $meta['width'] ) ? 640 : $meta['width'];
     1072                $height = empty( $meta['height'] ) ? 360 : $meta['height'];
     1073                $theme_height = round( ( $height * $theme_width ) / $width );
     1074                $track['dimensions'] = array(
     1075                    'original' => compact( 'width', 'height' ),
     1076                    'resized' => array(
     1077                        'width' => $theme_width,
     1078                        'height' => $theme_height
     1079                    )
     1080                );
     1081            }
     1082        }
     1083
     1084        if ( $supports_thumbs ) {
     1085            $id = get_post_thumbnail_id( $attachment->ID );
     1086            if ( ! empty( $id ) ) {
     1087                list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'full' );
     1088                $track['image'] = compact( 'src', 'width', 'height' );
     1089                list( $src, $width, $height ) = wp_get_attachment_image_src( $id, 'thumb' );
     1090                $track['thumb'] = compact( 'src', 'width', 'height' );
     1091            }
     1092        }
     1093
     1094        $tracks[] = $track;
     1095    }
     1096    $data['tracks'] = $tracks;
     1097
     1098    ob_start();
     1099
     1100    if ( 1 === $instance ):
     1101        wp_enqueue_style( 'wp-mediaelement' );
     1102        wp_enqueue_script( 'wp-playlist' );
     1103?>
     1104<!--[if lt IE 9]><script>document.createElement('<?php echo $type ?>');</script><![endif]-->
     1105<script type="text/html" id="tmpl-wp-playlist-current-item">
     1106    <# if ( data.image ) { #>
     1107    <img src="{{{ data.thumb.src }}}"/>
     1108    <# } #>
     1109    <# if ( data.meta.title ) { #>
     1110    <div class="wp-playlist-caption">
     1111        <span class="wp-caption-meta wp-caption-title">&#8220;{{{ data.meta.title }}}&#8221;</span>
     1112        <span class="wp-caption-meta wp-caption-album">{{{ data.meta.album }}}</span>
     1113        <span class="wp-caption-meta wp-caption-artist">{{{ data.meta.artist }}}</span>
     1114    </div>
     1115    <# } else { #>
     1116    <div class="wp-playlist-caption">{{{ data.caption }}}</div>
     1117    <# } #>
     1118</script>
     1119<script type="text/html" id="tmpl-wp-playlist-item">
     1120    <div class="wp-playlist-item">
     1121        <# if ( ( data.title || data.meta.title ) && ( ! data.artists || data.meta.artist ) ) { #>
     1122        <div class="wp-playlist-caption">
     1123            {{{ data.index ? ( data.index + '.&nbsp;' ) : '' }}}
     1124            <span class="wp-caption-title">&#8220;{{{ data.title ? data.title : data.meta.title }}}&#8221;</span>
     1125            <# if ( data.artists ) { #>
     1126            <span class="wp-caption-by"><?php _e( 'by' ) ?></span>
     1127            <span class="wp-caption-artist">{{{ data.meta.artist }}}</span>
     1128            <# } #>
     1129        </div>
     1130        <# } else { #>
     1131        <div class="wp-playlist-caption">{{{ data.index ? ( data.index + '.' ) : '' }}} {{{ data.caption ? data.caption : data.title }}}</div>
     1132        <# } #>
     1133        <# if ( data.meta.length_formatted ) { #>
     1134        <div class="wp-playlist-item-length">{{{ data.meta.length_formatted }}}</div>
     1135        <# } #>
     1136    </div>
     1137</script>
     1138    <?php endif ?>
     1139<div class="wp-playlist wp-<?php echo $type ?>-playlist wp-playlist-<?php echo $style ?>">
     1140    <?php if ( 'audio' === $type ): ?>
     1141    <div class="wp-playlist-current-item"></div>
     1142    <?php endif ?>
     1143    <<?php echo $type ?> controls="controls" preload="metadata" width="<?php echo $content_width - $outer ?>"></<?php echo $type ?>>
     1144    <div class="wp-playlist-next"></div>
     1145    <div class="wp-playlist-prev"></div>
     1146    <noscript>
     1147    <?php
     1148    $output = "\n";
     1149    foreach ( $attachments as $att_id => $attachment ) {
     1150        $output .= wp_get_attachment_link( $att_id ) . "\n";
     1151    }
     1152
     1153    echo $output;
     1154    ?>
     1155    </noscript>
     1156    <script type="application/json"><?php echo json_encode( $data ) ?></script>
     1157</div>
     1158    <?php
     1159    return ob_get_clean();
     1160}
     1161
     1162/**
     1163 * Playlist shortcode handler
     1164 *
     1165 * @since 3.9.0
     1166 *
     1167 * @param array $attr Parsed shortcode attributes.
     1168 * @return string The resolved playlist shortcode markup.
     1169 */
     1170function wp_playlist_shortcode( $attr ) {
     1171    return wp_get_playlist( $attr, 'audio' );
     1172}
     1173add_shortcode( 'playlist', 'wp_playlist_shortcode' );
     1174
     1175/**
     1176 * Video playlist shortcode handler
     1177 *
     1178 * @since 3.9.0
     1179 *
     1180 * @param array $attr Parsed shortcode attributes.
     1181 * @return string The resolved video playlist shortcode markup.
     1182 */
     1183function wp_video_playlist_shortcode( $attr ) {
     1184    return wp_get_playlist( $attr, 'video' );
     1185}
     1186add_shortcode( 'video-playlist', 'wp_video_playlist_shortcode' );
    9351187
    9361188/**
     
    20452297        'insertMediaTitle'   => __( 'Insert Media' ),
    20462298        'createNewGallery'   => __( 'Create a new gallery' ),
     2299        'createNewPlaylist'   => __( 'Create a new playlist' ),
     2300        'createNewVideoPlaylist'   => __( 'Create a new video playlist' ),
    20472301        'returnToLibrary'    => __( '&#8592; Return to library' ),
    20482302        'allMediaItems'      => __( 'All media items' ),
     
    20722326        'imageDetailsTitle'     => __( 'Image Details' ),
    20732327        'imageReplaceTitle'     => __( 'Replace Image' ),
    2074         'imageDetailsCancel'     => __( 'Cancel Edit' )
     2328        'imageDetailsCancel'    => __( 'Cancel Edit' ),
     2329
     2330        // Playlist
     2331        'playlistDragInfo'    => __( 'Drag and drop to reorder tracks.' ),
     2332        'createPlaylistTitle' => __( 'Create Playlist' ),
     2333        'editPlaylistTitle'   => __( 'Edit Playlist' ),
     2334        'cancelPlaylistTitle' => __( '&#8592; Cancel Playlist' ),
     2335        'insertPlaylist'      => __( 'Insert playlist' ),
     2336        'updatePlaylist'      => __( 'Update playlist' ),
     2337        'addToPlaylist'       => __( 'Add to playlist' ),
     2338        'addToPlaylistTitle'  => __( 'Add to Playlist' ),
     2339
     2340        // Video Playlist
     2341        'videoPlaylistDragInfo'    => __( 'Drag and drop to reorder videos.' ),
     2342        'createVideoPlaylistTitle' => __( 'Create Video Playlist' ),
     2343        'editVideoPlaylistTitle'   => __( 'Edit Video Playlist' ),
     2344        'cancelVideoPlaylistTitle' => __( '&#8592; Cancel Video Playlist' ),
     2345        'insertVideoPlaylist'      => __( 'Insert video playlist' ),
     2346        'updateVideoPlaylist'      => __( 'Update video playlist' ),
     2347        'addToVideoPlaylist'       => __( 'Add to video playlist' ),
     2348        'addToVideoPlaylistTitle'  => __( 'Add to Video Playlist' ),
    20752349    );
    20762350
Note: See TracChangeset for help on using the changeset viewer.