Make WordPress Core

Changeset 23729


Ignore:
Timestamp:
03/16/2013 05:25:44 AM (14 years ago)
Author:
markjaquith
Message:

Introduce [audio] and [video] shortcodes, and use MediaElement.js to play them.

props wonderboymusic. see #23282.

Location:
trunk
Files:
15 added
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-admin/includes/ajax-actions.php

    r23699 r23729  
    20202020                $title = ''; // We no longer insert title tags into <img> tags, as they are redundant.
    20212021                $html = get_image_send_to_editor( $id, $caption, $title, $align, $url, (bool) $rel, $size, $alt );
     2022        } elseif ( 'video' === substr( $post->post_mime_type, 0, 5 ) || 'audio' === substr( $post->post_mime_type, 0, 5 )  ) {
     2023                $html = stripslashes_deep( $_POST['html'] );
    20222024        }
    20232025
  • trunk/wp-includes/functions.php

    r23637 r23729  
    40214021</div>' ) );
    40224022}
     4023
     4024/**
     4025 * Return RegEx body to liberally match an opening HTML tag that:
     4026 * 1. Is self-closing or
     4027 * 2. Has no body but has a closing tag of the same name or
     4028 * 3. Contains a body and a closing tag of the same name
     4029 *
     4030 * Note: this RegEx does not balance inner tags and does not attempt to produce valid HTML
     4031 *
     4032 * @since 3.6.0
     4033 *
     4034 * @param string $tag An HTML tag name. Example: 'video'
     4035 * @return string
     4036 */
     4037function get_tag_regex( $tag ) {
     4038        if ( empty( $tag ) )
     4039                return;
     4040
     4041        return sprintf( '(<%1$s[^>]*(?:/?>$|>[\s\S]*?</%1$s>))', tag_escape( $tag ) );
     4042}
  • trunk/wp-includes/js/media-editor.js

    r23298 r23729  
    6767                                        captionId: 'attachment_' + attachment.id
    6868                                });
    69 
     69                        } else if ( 'video' === attachment.type || 'audio' === attachment.type ) {
     70                                _.extend( props, _.pick( attachment, 'title', 'type', 'icon', 'mime' ) );
    7071                        // Format properties for non-images.
    7172                        } else {
    … …  
    9495
    9596                        return wp.html.string( options );
     97                },
     98
     99                audio: function( props, attachment ) {
     100                        var shortcode, html;
     101
     102                        props = wp.media.string.props( props, attachment );
     103
     104                        shortcode = {};
     105
     106                        if ( props.mime ) {
     107                                switch ( props.mime ) {
     108                                case 'audio/mpeg':
     109                                        if ( props.linkUrl.indexOf( 'mp3' ) )
     110                                                shortcode.mp3 = props.linkUrl;
     111                                        else if ( props.linkUrl.indexOf( 'm4a' ) )
     112                                                shortcode.m4a = props.linkUrl;
     113                                        break;
     114                                case 'audio/mp3':
     115                                        shortcode.mp3 = props.linkUrl;
     116                                        break;
     117                                case 'audio/m4a':
     118                                        shortcode.m4a = props.linkUrl;
     119                                        break;
     120                                case 'audio/wav':
     121                                        shortcode.wav = props.linkUrl;
     122                                        break;
     123                                case 'audio/ogg':
     124                                        shortcode.ogg = props.linkUrl;
     125                                        break;
     126                                case 'audio/x-ms-wma':
     127                                case 'audio/wma':
     128                                        shortcode.wma = props.linkUrl;
     129                                        break;
     130                                }
     131                        }
     132
     133                        html = wp.shortcode.string({
     134                                tag:     'audio',
     135                                attrs:   shortcode
     136                        });
     137
     138                        return html;
     139                },
     140
     141                video: function( props, attachment ) {
     142                        var shortcode, html;
     143
     144                        props = wp.media.string.props( props, attachment );
     145
     146                        shortcode = {};
     147
     148                        if ( props.mime ) {
     149                                switch ( props.mime ) {
     150                                case 'video/mp4':
     151                                        shortcode.mp4 = props.linkUrl;
     152                                        break;
     153                                case 'video/m4v':
     154                                        shortcode.m4v = props.linkUrl;
     155                                        break;
     156                                case 'video/webm':
     157                                        shortcode.webm = props.linkUrl;
     158                                        break;
     159                                case 'video/ogg':
     160                                        shortcode.ogv = props.linkUrl;
     161                                        break;
     162                                case 'video/x-ms-wmv':
     163                                case 'video/wmv':
     164                                case 'video/asf':
     165                                        shortcode.wmv = props.linkUrl;
     166                                        break;
     167                                case 'video/flv':
     168                                case 'video/x-flv':
     169                                        shortcode.flv = props.linkUrl;
     170                                        break;
     171                                }
     172                        }
     173
     174                        html = wp.shortcode.string({
     175                                tag:     'video',
     176                                attrs:   shortcode
     177                        });
     178
     179                        return html;
    96180                },
    97181
    … …  
    576660                                                        options[ option ] = props[ prop ];
    577661                                        });
    578 
     662                                } else if ( 'video' === attachment.type ) {
     663                                        html = wp.media.string.video( props );
     664                                } else if ( 'audio' === attachment.type ) {
     665                                        html = wp.media.string.audio( props );
    579666                                } else {
    580667                                        html = wp.media.string.link( props );
  • trunk/wp-includes/media.php

    r23714 r23729  
    805805        return $output;
    806806}
     807
     808/**
     809 * Provide a No-JS Flash fallback as a last resort for audio / video
     810 *
     811 * @since 3.6.0
     812 *
     813 * @param string $url
     814 * @return string Fallback HTML
     815 */
     816function wp_mediaelement_fallback( $url ) {
     817        return apply_filters( 'wp_mediaelement_fallback', sprintf( '<a href="%1$s">%1$s</a>', esc_url( $url ) ), $url );
     818}
     819
     820/**
     821 * Return a filtered list of WP-supported audio formats
     822 *
     823 * @since 3.6.0
     824 * @return array
     825 */
     826function wp_get_audio_extensions() {
     827        return apply_filters( 'wp_audio_extensions', array( 'mp3', 'ogg', 'wma', 'm4a', 'wav' ) );
     828}
     829
     830/**
     831 * The Audio shortcode.
     832 *
     833 * This implements the functionality of the Audio Shortcode for displaying
     834 * WordPress mp3s in a post.
     835 *
     836 * @since 3.6.0
     837 *
     838 * @param array $attr Attributes of the shortcode.
     839 * @return string HTML content to display audio.
     840 */
     841function wp_audio_shortcode( $attr ) {
     842        $post_id = get_post() ? get_the_ID() : 0;
     843
     844        static $instances = 0;
     845        $instances++;
     846
     847        $audio = null;
     848
     849        $default_types = wp_get_audio_extensions();
     850        $defaults_atts = array( 'src' => '' );
     851        foreach ( $default_types as $type  )
     852                $defaults_atts[$type] = '';
     853
     854        $atts = shortcode_atts( $defaults_atts, $attr );
     855        extract( $atts );
     856
     857        $primary = false;
     858        if ( ! empty( $src ) ) {
     859                $type = wp_check_filetype( $src );
     860                if ( ! in_array( $type['ext'], $default_types ) ) {
     861                        printf( '<a class="wp-post-format-link-audio" href="%1$s">%1$s</a>', $src );
     862                        return;
     863                }
     864                $primary = true;
     865                array_unshift( $default_types, 'src' );
     866        } else {
     867                foreach ( $default_types as $ext ) {
     868                        if ( ! empty( $$ext ) ) {
     869                                $type = wp_check_filetype( $$ext );
     870                                if ( $type['ext'] === $ext )
     871                                        $primary = true;
     872                        }
     873                }
     874        }
     875
     876        if ( ! $primary ) {
     877                $audios = get_post_audio( $post_id );
     878                if ( empty( $audios ) )
     879                        return;
     880
     881                $audio = reset( $audios );
     882                $src = wp_get_attachment_url( $audio->ID );
     883                if ( empty( $src ) )
     884                        return;
     885
     886                array_unshift( $default_types, 'src' );
     887        }
     888
     889        $library = apply_filters( 'wp_audio_shortcode_library', 'mediaelement' );
     890        if ( 'mediaelement' === $library ) {
     891                wp_enqueue_style( 'wp-mediaelement' );
     892                wp_enqueue_script( 'wp-mediaelement' );
     893        }
     894
     895        $atts = array(
     896                sprintf( 'class="%s"', apply_filters( 'wp_audio_shortcode_class', 'wp-audio-shortcode' ) ),
     897                sprintf( 'id="audio-%d-%d"', $post_id, $instances ),
     898        );
     899
     900        $html = sprintf( '<audio %s controls="controls" preload="none">', join( ' ', $atts ) );
     901
     902        $fileurl = '';
     903        $source = '<source type="%s" src="%s" />';
     904        foreach ( $default_types as $fallback ) {
     905                if ( ! empty( $$fallback ) ) {
     906                        if ( empty( $fileurl ) )
     907                                $fileurl = $$fallback;
     908                        $type = wp_check_filetype( $$fallback );
     909                        $html .= sprintf( $source, $type['type'], $$fallback );
     910                }
     911        }
     912
     913        if ( 'mediaelement' === $library )
     914                $html .= wp_mediaelement_fallback( $fileurl );
     915        $html .= '</audio>';
     916
     917        return apply_filters( 'wp_audio_shortcode', $html, $atts, $audio, $post_id );
     918}
     919add_shortcode( 'audio', apply_filters( 'wp_audio_shortcode_handler', 'wp_audio_shortcode' ) );
     920
     921/**
     922 * Return a filtered list of WP-supported video formats
     923 *
     924 * @since 3.6.0
     925 * @return array
     926 */
     927function wp_get_video_extensions() {
     928        return apply_filters( 'wp_video_extensions', array( 'mp4', 'm4v', 'webm', 'ogv', 'wmv', 'flv' ) );
     929}
     930
     931/**
     932 * The Video shortcode.
     933 *
     934 * This implements the functionality of the Video Shortcode for displaying
     935 * WordPress mp4s in a post.
     936 *
     937 * @since 3.6.0
     938 *
     939 * @param array $attr Attributes of the shortcode.
     940 * @return string HTML content to display video.
     941 */
     942function wp_video_shortcode( $attr ) {
     943        global $content_width;
     944        $post_id = get_post() ? get_the_ID() : 0;
     945
     946        static $instances = 0;
     947        $instances++;
     948
     949        $video = null;
     950
     951        $default_types = wp_get_video_extensions();
     952        $defaults_atts = array(
     953                'src' => '',
     954                'poster' => '',
     955                'height' => 360,
     956                'width' => empty( $content_width ) ? 640 : $content_width,
     957        );
     958        foreach ( $default_types as $type  )
     959                $defaults_atts[$type] = '';
     960
     961        $atts = shortcode_atts( $defaults_atts, $attr );
     962        extract( $atts );
     963
     964        $primary = false;
     965        if ( ! empty( $src ) ) {
     966                $type = wp_check_filetype( $src );
     967                if ( ! in_array( $type['ext'], $default_types ) ) {
     968                        printf( '<a class="wp-post-format-link-video" href="%1$s">%1$s</a>', $src );
     969                        return;
     970                }
     971                $primary = true;
     972                array_unshift( $default_types, 'src' );
     973        } else {
     974                foreach ( $default_types as $ext ) {
     975                        if ( ! empty( $$ext ) ) {
     976                                $type = wp_check_filetype( $$ext );
     977                                if ( $type['ext'] === $ext )
     978                                        $primary = true;
     979                        }
     980                }
     981        }
     982
     983        if ( ! $primary ) {
     984                $videos = get_post_video( $post_id );
     985                if ( empty( $videos ) )
     986                        return;
     987
     988                $video = reset( $videos );
     989                $src = wp_get_attachment_url( $video->ID );
     990                if ( empty( $src ) )
     991                        return;
     992
     993                array_unshift( $default_types, 'src' );
     994        }
     995
     996        $library = apply_filters( 'wp_video_shortcode_library', 'mediaelement' );
     997        if ( 'mediaelement' === $library ) {
     998                wp_enqueue_style( 'wp-mediaelement' );
     999                wp_enqueue_script( 'wp-mediaelement' );
     1000        }
     1001
     1002        $atts = array(
     1003                sprintf( 'class="%s"', apply_filters( 'wp_video_shortcode_class', 'wp-video-shortcode' ) ),
     1004                sprintf( 'id="video-%d-%d"', $post_id, $instances ),
     1005                sprintf( 'width="%d"', $width ),
     1006                sprintf( 'height="%d"', $height ),
     1007        );
     1008
     1009        if ( ! empty( $poster ) )
     1010                $atts[] = sprintf( 'poster="%s"', esc_url( $poster ) );
     1011
     1012        $html = sprintf( '<video %s controls="controls" preload="none">', join( ' ', $atts ) );
     1013
     1014        $fileurl = '';
     1015        $source = '<source type="%s" src="%s" />';
     1016        foreach ( $default_types as $fallback ) {
     1017                if ( ! empty( $$fallback ) ) {
     1018                        if ( empty( $fileurl ) )
     1019                                $fileurl = $$fallback;
     1020                        $type = wp_check_filetype( $$fallback );
     1021                        // m4v sometimes shows up as video/mpeg which collides with mp4
     1022                        if ( 'm4v' === $type['ext'] )
     1023                                $type['type'] = 'video/m4v';
     1024                        $html .= sprintf( $source, $type['type'], $$fallback );
     1025                }
     1026        }
     1027        if ( 'mediaelement' === $library )
     1028                $html .= wp_mediaelement_fallback( $fileurl, $width, $height );
     1029        $html .= '</video>';
     1030
     1031        return apply_filters( 'wp_video_shortcode', $html, $atts, $video, $post_id );
     1032}
     1033add_shortcode( 'video', apply_filters( 'wp_video_shortcode_handler', 'wp_video_shortcode' ) );
    8071034
    8081035/**
    … …  
    15461773        do_action( 'wp_enqueue_media' );
    15471774}
     1775
     1776/**
     1777 * Retrieve audio attached to the passed post
     1778 *
     1779 * @since 3.6.0
     1780 *
     1781 * @param int $post_id  Post ID
     1782 * @return array Found audio attachments
     1783 */
     1784function get_post_audio( $post_id = 0 ) {
     1785        $post = empty( $post_id ) ? get_post() : get_post( $post_id );
     1786        if ( empty( $post ) )
     1787                return;
     1788
     1789        $children = get_children( array(
     1790                'post_parent' => $post->ID,
     1791                'post_type' => 'attachment',
     1792                'post_mime_type' => 'audio',
     1793                'posts_per_page' => -1
     1794        ) );
     1795
     1796        if ( ! empty( $children ) )
     1797                return $children;
     1798}
     1799
     1800/**
     1801 * Retrieve video attached to the passed post
     1802 *
     1803 * @since 3.6.0
     1804 *
     1805 * @param int $post_id  Post ID
     1806 * @return array Found video attachments
     1807 */
     1808function get_post_video( $post_id = 0 ) {
     1809        $post = empty( $post_id ) ? get_post() : get_post( $post_id );
     1810        if ( empty( $post ) )
     1811                return;
     1812
     1813        $children = get_children( array(
     1814                'post_parent' => $post->ID,
     1815                'post_type' => 'attachment',
     1816                'post_mime_type' => 'video',
     1817                'posts_per_page' => -1
     1818        ) );
     1819
     1820        if ( ! empty( $children ) )
     1821                return $children;
     1822}
     1823
     1824/**
     1825 * Audio embed handler callback.
     1826 *
     1827 * @param array $matches The regex matches from the provided regex when calling {@link wp_embed_register_handler()}.
     1828 * @param array $attr Embed attributes.
     1829 * @param string $url The original URL that was matched by the regex.
     1830 * @param array $rawattr The original unmodified attributes.
     1831 * @return string The embed HTML.
     1832 */
     1833function wp_audio_embed( $matches, $attr, $url, $rawattr ) {
     1834        $audio = $url;
     1835        if ( shortcode_exists( 'audio' ) )
     1836                $audio = do_shortcode( '[audio src="' . $url . '" /]' );
     1837        return apply_filters( 'wp_audio_embed', $audio, $attr, $url, $rawattr );
     1838}
     1839wp_embed_register_handler( 'wp_audio_embed', '#https?://.+?\.(' . join( '|', wp_get_audio_extensions() ) . ')#i', apply_filters( 'wp_audio_embed_handler', 'wp_audio_embed' ), 9999 );
     1840
     1841/**
     1842 * Video embed handler callback.
     1843 *
     1844 * @param array $matches The regex matches from the provided regex when calling {@link wp_embed_register_handler()}.
     1845 * @param array $attr Embed attributes.
     1846 * @param string $url The original URL that was matched by the regex.
     1847 * @param array $rawattr The original unmodified attributes.
     1848 * @return string The embed HTML.
     1849 */
     1850function wp_video_embed( $matches, $attr, $url, $rawattr ) {
     1851        $dimensions = '';
     1852        $video = $url;
     1853        if ( shortcode_exists( 'video' ) ) {
     1854                if ( ! empty( $rawattr['width'] ) && ! empty( $rawattr['height'] ) ) {
     1855                        $dimensions .= sprintf( 'width="%d" ', (int) $rawattr['width'] );
     1856                        $dimensions .= sprintf( 'height="%d" ', (int) $rawattr['height'] );
     1857                }
     1858                $video = do_shortcode( '[video ' . $dimensions . 'src="' . $url . '" /]' );
     1859        }
     1860        return apply_filters( 'wp_video_embed', $video, $attr, $url, $rawattr );
     1861}
     1862wp_embed_register_handler( 'wp_video_embed', '#https?://.+?\.(' . join( '|', wp_get_video_extensions() ) . ')#i', apply_filters( 'wp_video_embed_handler', 'wp_video_embed' ), 9999 );
  • trunk/wp-includes/post-formats.php

    r23655 r23729  
    309309        $format_output = '';
    310310        $meta = get_post_format_meta( $post->ID );
     311        // passed by ref in preg_match()
     312        $matches = array();
    311313
    312314        switch ( $format ) {
    … …  
    366368
    367369                case 'gallery':
    368                         preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches );
    369                         if ( ! empty( $matches ) && isset( $matches[2] ) ) {
    370                                 foreach ( (array) $matches[2] as $match ) {
    371                                         if ( 'gallery' === $match )
    372                                                 break 2; // foreach + case
    373                                 }
    374                         }
    375 
    376                         if ( ! empty( $meta['gallery'] ) ) {
     370                        if ( ! has_shortcode( $post->post_content, $format ) && ! empty( $meta['gallery'] ) )
    377371                                $format_output .= $meta['gallery'];
    378                         }
    379372                        break;
    380373
    381374                case 'video':
    382375                case 'audio':
    383                         $shortcode_regex = '/' . get_shortcode_regex() . '/s';
    384                         $matches = preg_match( $shortcode_regex, $content );
    385                         if ( ! $matches || $format !== $matches[2] ) {
    386                                 if ( ! empty( $meta['media'] ) ) {
    387                                         // the metadata is a shortcode or an embed code
    388                                         if ( preg_match( $shortcode_regex, $meta['media'] ) || preg_match( '#<[^>]+>#', $meta['media'] ) ) {
    389                                                 $format_output .= $meta['media'];
    390                                         } elseif ( ! stristr( $content, $meta['media'] ) ) {
    391                                                 // attempt to embed the URL
    392                                                 $format_output .= sprintf( '[embed]%s[/embed]', $meta['media'] );
    393                                         }
     376                        if ( ! has_shortcode( $post->post_content, $format ) && ! empty( $meta['media'] ) ) {
     377                                // the metadata is a shortcode or an embed code
     378                                if ( preg_match( '/' . get_shortcode_regex() . '/s', $meta['media'] ) || preg_match( '#<[^>]+>#', $meta['media'] ) ) {
     379                                        $format_output .= $meta['media'];
     380                                } elseif ( ! stristr( $content, $meta['media'] ) ) {
     381                                        // attempt to embed the URL
     382                                        $format_output .= sprintf( '[embed]%s[/embed]', $meta['media'] );
    394383                                }
    395384                        }
  • trunk/wp-includes/script-loader.php

    r23683 r23729  
    278278        $scripts->add( 'imgareaselect', "/wp-includes/js/imgareaselect/jquery.imgareaselect$suffix.js", array('jquery'), '0.9.8', 1 );
    279279
     280        $scripts->add( 'mediaelement', "/wp-includes/js/mediaelement/mediaelement-and-player$suffix.js", array('jquery'), '2.10.1', 1 );
     281        $scripts->add( 'wp-mediaelement', "/wp-includes/js/mediaelement/wp-mediaelement.js", array('mediaelement'), false, 1 );
     282
    280283        $scripts->add( 'password-strength-meter', "/wp-admin/js/password-strength-meter$suffix.js", array('jquery'), false, 1 );
    281284        did_action( 'init' ) && $scripts->localize( 'password-strength-meter', 'pwsL10n', array(
    … …  
    542545        $styles->add( 'buttons', "/wp-includes/css/buttons$suffix.css" );
    543546
     547        $styles->add( 'mediaelement', "/wp-includes/js/mediaelement/mediaelementplayer$suffix.css" );
     548        $styles->add( 'wp-mediaelement', "/wp-includes/js/mediaelement/wp-mediaelement.css", array( 'mediaelement' ) );
     549
    544550        foreach ( $rtl_styles as $rtl_style ) {
    545551                $styles->add_data( $rtl_style, 'rtl', true );
  • trunk/wp-includes/shortcodes.php

    r23626 r23729  
    126126
    127127        $shortcode_tags = array();
     128}
     129
     130/**
     131 * Whether a registered shortcode exists named $tag
     132 *
     133 * @since 3.6.0
     134 *
     135 * @global array $shortcode_tags
     136 * @param string $tag
     137 * @return boolean
     138 */
     139function shortcode_exists( $tag ) {
     140        global $shortcode_tags;
     141        return array_key_exists( $tag, $shortcode_tags );
     142}
     143
     144/**
     145 * Whether the passed content contains the specified shortcode
     146 *
     147 * @since 3.6.0
     148 *
     149 * @global array $shortcode_tags
     150 * @param string $tag
     151 * @return boolean
     152 */
     153function has_shortcode( $content, $tag ) {
     154        if ( shortcode_exists( $tag ) ) {
     155                $matches = array();
     156                preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER );
     157                if ( empty( $matches ) )
     158                        return false;
     159
     160                foreach ( $matches as $shortcode ) {
     161                        if ( $tag === $shortcode[2] )
     162                                return true;
     163                }
     164        }
     165        return false;
    128166}
    129167
Note: See TracChangeset for help on using the changeset viewer.