diff options
Diffstat (limited to 'plugins/jetpack/modules/shortcodes/youtube.php')
-rw-r--r-- | plugins/jetpack/modules/shortcodes/youtube.php | 267 |
1 files changed, 171 insertions, 96 deletions
diff --git a/plugins/jetpack/modules/shortcodes/youtube.php b/plugins/jetpack/modules/shortcodes/youtube.php index f3e37faf..693eb71e 100644 --- a/plugins/jetpack/modules/shortcodes/youtube.php +++ b/plugins/jetpack/modules/shortcodes/youtube.php @@ -11,7 +11,7 @@ * http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US * https://www.youtube.com/playlist?list=PLP7HaNDU4Cifov7C2fQM8Ij6Ew_uPHEXW * - * @package Jetpack + * @package automattic/jetpack */ /** @@ -27,8 +27,8 @@ * 12-2010: * <object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/3H8bnKdf654?fs=1&hl=en_GB"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/3H8bnKdf654?fs=1&hl=en_GB" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object> * 01-2011: - * <iframe title="YouTube video player" class="youtube-player" type="text/html" width="640" height="390" src="http://www.youtube.com/embed/Qq9El3ki0_g" frameborder="0" allowFullScreen></iframe> - * <iframe class="youtube-player" type="text/html" width="640" height="385" src="http://www.youtube.com/embed/VIDEO_ID" frameborder="0"></iframe> + * <iframe title="YouTube video player" class="youtube-player" width="640" height="390" src="http://www.youtube.com/embed/Qq9El3ki0_g" frameborder="0" allowFullScreen></iframe> + * <iframe class="youtube-player" width="640" height="385" src="http://www.youtube.com/embed/VIDEO_ID" frameborder="0"></iframe> * * @param string $content HTML content. * @return string The content with YouTube embeds replaced with YouTube shortcodes. @@ -168,6 +168,7 @@ endif; * http://www.youtube.com/v/jF-kELmmvgA * http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US * http://youtu.be/Rrohlqeir5E + * https://www.youtube.com/watch?v=GJNxoe-iSb4&list=PLAVZ4NFtZX0fE54mDSqNKym-o_rz-8xmk * * @param string $url Youtube URL. */ @@ -181,61 +182,108 @@ function youtube_id( $url ) { $url = youtube_sanitize_url( $url ); $url = wp_parse_url( $url ); + $thumbnail = "https://i.ytimg.com/vi/$id/hqdefault.jpg"; + $video_url = add_query_arg( 'v', $id, 'https://www.youtube.com/watch' ); + $args = jetpack_shortcode_youtube_args( $url ); if ( empty( $args ) ) { return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: empty URL args', 'jetpack' ) ); } + // Account for URL having both v and list, where jetpack_get_youtube_id() only accounts for one or the other. + if ( isset( $args['list'] ) && $args['list'] === $id ) { + $id = null; + } + if ( isset( $args['v'] ) ) { + $id = $args['v']; + } + if ( ! $id && empty( $args['list'] ) ) { + return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: missing id and/or list', 'jetpack' ) ); + } + list( $w, $h ) = jetpack_shortcode_youtube_dimensions( $args ); - $rel = ( isset( $args['rel'] ) && '0' === $args['rel'] ) ? 0 : 1; - $search = ( isset( $args['showsearch'] ) && '1' === $args['showsearch'] ) ? 1 : 0; - $info = ( isset( $args['showinfo'] ) && '0' === $args['showinfo'] ) ? 0 : 1; - $iv = ( isset( $args['iv_load_policy'] ) && '3' === $args['iv_load_policy'] ) ? 3 : 1; - $fmt = ( isset( $args['fmt'] ) && intval( $args['fmt'] ) ) ? '&fmt=' . (int) $args['fmt'] : ''; + $params = array( + 'rel' => ( isset( $args['rel'] ) && '0' === $args['rel'] ) ? 0 : 1, + 'showsearch' => ( isset( $args['showsearch'] ) && '1' === $args['showsearch'] ) ? 1 : 0, // Now deprecated. See https://developers.google.com/youtube/player_parameters#march-29,-2012. + 'showinfo' => ( isset( $args['showinfo'] ) && '0' === $args['showinfo'] ) ? 0 : 1, // Now obsolete. See https://developers.google.com/youtube/player_parameters#showinfo. + 'iv_load_policy' => ( isset( $args['iv_load_policy'] ) && '3' === $args['iv_load_policy'] ) ? 3 : 1, + 'fs' => 1, + 'hl' => str_replace( '_', '-', get_locale() ), + ); + if ( isset( $args['fmt'] ) && (int) $args['fmt'] ) { + $params['fmt'] = (int) $args['fmt']; // Apparently an obsolete parameter. Not referenced on https://developers.google.com/youtube/player_parameters. + } + // The autohide parameter has been deprecated since 2015. See https://developers.google.com/youtube/player_parameters#august-19,-2015. if ( ! isset( $args['autohide'] ) || ( $args['autohide'] < 0 || 2 < $args['autohide'] ) ) { - $autohide = '&autohide=2'; + $params['autohide'] = 2; } else { - $autohide = '&autohide=' . absint( $args['autohide'] ); + $params['autohide'] = (int) $args['autohide']; } $start = 0; if ( isset( $args['start'] ) ) { - $start = intval( $args['start'] ); + $start = (int) $args['start']; } elseif ( isset( $args['t'] ) ) { - $time_pieces = preg_split( '/(?<=\D)(?=\d+)/', $args['t'] ); - - foreach ( $time_pieces as $time_piece ) { - $int = (int) $time_piece; - switch ( substr( $time_piece, -1 ) ) { - case 'h': - $start += $int * 3600; - break; - case 'm': - $start += $int * 60; - break; - case 's': - $start += $int; - break; + if ( is_numeric( $args['t'] ) ) { + $start = (int) $args['t']; + } else { + $time_pieces = preg_split( '/(?<=\D)(?=\d+)/', $args['t'] ); + + foreach ( $time_pieces as $time_piece ) { + $int = (int) $time_piece; + switch ( substr( $time_piece, - 1 ) ) { + case 'h': + $start += $int * 3600; + break; + case 'm': + $start += $int * 60; + break; + case 's': + $start += $int; + break; + } } } } + if ( $start ) { + $params['start'] = (int) $start; + } - $start = $start ? '&start=' . $start : ''; - $end = ( isset( $args['end'] ) && intval( $args['end'] ) ) ? '&end=' . (int) $args['end'] : ''; - $hd = ( isset( $args['hd'] ) && intval( $args['hd'] ) ) ? '&hd=' . (int) $args['hd'] : ''; - - $vq = ( isset( $args['vq'] ) && in_array( $args['vq'], array( 'hd720', 'hd1080' ), true ) ) ? '&vq=' . $args['vq'] : ''; + if ( isset( $args['end'] ) && (int) $args['end'] ) { + $params['end'] = (int) $args['end']; + } + if ( isset( $args['hd'] ) && (int) $args['hd'] ) { + $params['hd'] = (int) $args['hd']; // Now obsolete per https://developers.google.com/youtube/player_parameters#march-29,-2012. + } + if ( isset( $args['vq'] ) && in_array( $args['vq'], array( 'hd720', 'hd1080' ), true ) ) { + $params['vq'] = $args['vq']; // Note, this appears to be obsolete. Not referenced on https://developers.google.com/youtube/player_parameters. + } + if ( isset( $args['cc_load_policy'] ) ) { + $params['cc_load_policy'] = 1; + } + if ( isset( $args['cc_lang_pref'] ) ) { + $params['cc_lang_pref'] = preg_replace( '/[^_a-z0-9-]/i', '', $args['cc_lang_pref'] ); + } - $cc = ( isset( $args['cc_load_policy'] ) ) ? '&cc_load_policy=1' : ''; - $cc_lang = ( isset( $args['cc_lang_pref'] ) ) ? '&cc_lang_pref=' . preg_replace( '/[^_a-z0-9-]/i', '', $args['cc_lang_pref'] ) : ''; + // The wmode parameter appears to be obsolete. Not referenced on https://developers.google.com/youtube/player_parameters. + if ( isset( $args['wmode'] ) && in_array( strtolower( $args['wmode'] ), array( 'opaque', 'window', 'transparent' ), true ) ) { + $params['wmode'] = $args['wmode']; + } else { + $params['wmode'] = 'transparent'; + } - $wmode = ( isset( $args['wmode'] ) && in_array( strtolower( $args['wmode'] ), array( 'opaque', 'window', 'transparent' ), true ) ) ? $args['wmode'] : 'transparent'; + // The theme parameter is obsolete per https://developers.google.com/youtube/player_parameters#august-19,-2015. + if ( isset( $args['theme'] ) && in_array( strtolower( $args['theme'] ), array( 'dark', 'light' ), true ) ) { + $params['theme'] = $args['theme']; + } - $theme = ( isset( $args['theme'] ) && in_array( strtolower( $args['theme'] ), array( 'dark', 'light' ), true ) ) ? '&theme=' . $args['theme'] : ''; + if ( isset( $args['list'] ) ) { + $params['listType'] = 'playlist'; + $params['list'] = preg_replace( '|[^_a-z0-9-]|i', '', $args['list'] ); + } - $autoplay = ''; /** * Allow YouTube videos to start playing automatically. * @@ -246,16 +294,60 @@ function youtube_id( $url ) { * @param bool false Enable autoplay for YouTube videos. */ if ( apply_filters( 'jetpack_youtube_allow_autoplay', false ) && isset( $args['autoplay'] ) ) { - $autoplay = '&autoplay=' . (int) $args['autoplay']; + $params['autoplay'] = (int) $args['autoplay']; } - if ( - ( isset( $url['path'] ) && '/videoseries' === $url['path'] ) - || isset( $args['list'] ) - ) { - $html = "<iframe class='youtube-player' type='text/html' width='$w' height='$h' src='" . esc_url( "https://www.youtube.com/embed/videoseries?list=$id&hl=en_US" ) . "' allowfullscreen='true' style='border:0;'></iframe>"; + $is_amp = class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request(); + + if ( $is_amp && $id ) { + // Note that <amp-youtube> currently is not well suited for playlists that don't have an individual video selected, hence the $id check above. + $placeholder = sprintf( + '<a href="%1$s" placeholder><amp-img src="%2$s" alt="%3$s" layout="fill" object-fit="cover"><noscript><img src="%2$s" loading="lazy" decoding="async" alt="%3$s"></noscript></amp-img></a>', + esc_url( $video_url ), + esc_url( $thumbnail ), + esc_attr__( 'YouTube Poster', 'jetpack' ) // Would be preferable to provide YouTube video title, but not available in this non-oEmbed context. + ); + + $html_attributes = array(); + foreach ( $params as $param_name => $param_value ) { + $html_attributes[] = sprintf( + 'data-param-%s="%s"', + sanitize_key( $param_name ), + esc_attr( $param_value ) + ); + } + + $html = sprintf( + '<amp-youtube data-videoid="%s" %s width="%d" height="%d" layout="responsive">%s</amp-youtube>', + esc_attr( $id ), + implode( ' ', $html_attributes ), // Note: Escaping done above. + esc_attr( $w ), + esc_attr( $h ), + $placeholder + ); } else { - $html = "<iframe class='youtube-player' type='text/html' width='$w' height='$h' src='" . esc_url( "https://www.youtube.com/embed/$id?version=3&rel=$rel&fs=1$fmt$autohide&showsearch=$search&showinfo=$info&iv_load_policy=$iv$start$end$hd&wmode=$wmode$theme$autoplay$vq{$cc}{$cc_lang}" ) . "' allowfullscreen='true' style='border:0;'></iframe>"; + // In AMP, the AMP_Iframe_Sanitizer will convert into <amp-iframe> as required. + $src = 'https://www.youtube.com/embed'; + if ( $id ) { + $src .= "/$id"; + } + $src = add_query_arg( + array_merge( + array( 'version' => 3 ), + $params + ), + $src + ); + + $layout = $is_amp ? 'layout="responsive" ' : ''; + + $html = sprintf( + '<iframe class="youtube-player" width="%s" height="%s" %ssrc="%s" allowfullscreen="true" style="border:0;" sandbox="allow-scripts allow-same-origin allow-popups allow-presentation"></iframe>', + esc_attr( $w ), + esc_attr( $h ), + $layout, + esc_url( $src ) + ); } // Let's do some alignment wonder in a span, unless we're producing a feed. @@ -281,6 +373,22 @@ function youtube_id( $url ) { } /** + * Format output for Calypso Reader/Notifications/Comments + */ + if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { + require_once WP_CONTENT_DIR . '/lib/display-context.php'; + $context = A8C\Display_Context\get_current_context(); + if ( A8C\Display_Context\NOTIFICATIONS === $context ) { + return sprintf( + '<a href="%1$s" target="_blank" rel="noopener noreferrer"><img src="%2$s" alt="%3$s" /></a>', + esc_url( $video_url ), + esc_url( $thumbnail ), + esc_html__( 'YouTube video', 'jetpack' ) + ); + } + } + + /** * Filter the YouTube video HTML output. * * @module shortcodes @@ -299,7 +407,7 @@ function youtube_id( $url ) { * * @since 8.0.0 * - * @param string $url The URL of the shortcode. + * @param array $url The parsed URL of the shortcode. * * @return array|false The query args of the URL, or false. */ @@ -328,49 +436,11 @@ function jetpack_shortcode_youtube_args( $url ) { */ function youtube_shortcode( $atts ) { $url = ( isset( $atts[0] ) ) ? ltrim( $atts[0], '=' ) : shortcode_new_to_old_params( $atts ); - - if ( - class_exists( 'Jetpack_AMP_Support' ) - && Jetpack_AMP_Support::is_amp_request() - ) { - return jetpack_amp_youtube_shortcode( $url ); - } else { - return youtube_id( $url ); - } + return youtube_id( $url ); } add_shortcode( 'youtube', 'youtube_shortcode' ); /** - * Renders the [youtube] shortcode as an AMP component. - * - * @since 8.0.0 - * - * @param string $url The YouTube URL. - * - * @return string The AMP-compatible rendered shortcode. - */ -function jetpack_amp_youtube_shortcode( $url ) { - $video_id = jetpack_get_youtube_id( $url ); - if ( empty( $video_id ) ) { - return sprintf( - '<a href="%1$s" class="amp-wp-embed-fallback">%1$s</a>', - esc_url( $url ) - ); - } - - $sanitized_url = youtube_sanitize_url( $url ); - $parsed_url = wp_parse_url( $sanitized_url ); - $args = jetpack_shortcode_youtube_args( $parsed_url ); - list( $width, $height ) = jetpack_shortcode_youtube_dimensions( $args ); - return sprintf( - '<amp-youtube data-videoid="%s" layout="responsive" width="%d" height="%d"></amp-youtube>', - esc_attr( $video_id ), - absint( $width ), - absint( $height ) - ); -} - -/** * Gets the dimensions of the [youtube] shortcode. * * Calculates the width and height, taking $content_width into consideration. @@ -384,8 +454,8 @@ function jetpack_amp_youtube_shortcode( $url ) { function jetpack_shortcode_youtube_dimensions( $query_args ) { global $content_width; - $input_w = ( isset( $query_args['w'] ) && intval( $query_args['w'] ) ) ? intval( $query_args['w'] ) : 0; - $input_h = ( isset( $query_args['h'] ) && intval( $query_args['h'] ) ) ? intval( $query_args['h'] ) : 0; + $input_w = ( isset( $query_args['w'] ) && (int) $query_args['w'] ) ? (int) $query_args['w'] : 0; + $input_h = ( isset( $query_args['h'] ) && (int) $query_args['h'] ) ? (int) $query_args['h'] : 0; // If we have $content_width, use it. if ( ! empty( $content_width ) ) { @@ -404,7 +474,7 @@ function jetpack_shortcode_youtube_dimensions( $query_args ) { $w = $input_w; $h = $input_h; } elseif ( 0 === $input_w && 0 === $input_h ) { - if ( isset( $query_args['fmt'] ) && intval( $query_args['fmt'] ) ) { + if ( isset( $query_args['fmt'] ) && (int) $query_args['fmt'] ) { $w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 ); } else { $w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width ); @@ -414,7 +484,7 @@ function jetpack_shortcode_youtube_dimensions( $query_args ) { $w = $input_w; $h = ceil( ( $w / 16 ) * 9 ); } else { - if ( isset( $query_args['fmt'] ) && intval( $query_args['fmt'] ) ) { + if ( isset( $query_args['fmt'] ) && (int) $query_args['fmt'] ) { $w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 ); } else { $w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width ); @@ -467,16 +537,21 @@ function wpcom_youtube_embed_crazy_url_init() { } add_action( 'init', 'wpcom_youtube_embed_crazy_url_init' ); -/** - * Allow oEmbeds in Jetpack's Comment form. - * - * @module shortcodes - * - * @since 2.8.0 - * - * @param int get_option('embed_autourls') Option to automatically embed all plain text URLs. - */ -if ( ! is_admin() && apply_filters( 'jetpack_comments_allow_oembed', true ) ) { +if ( + ! is_admin() + /** + * Allow oEmbeds in Jetpack's Comment form. + * + * @module shortcodes + * + * @since 2.8.0 + * + * @param int $allow_oembed Option to automatically embed all plain text URLs. + */ + && apply_filters( 'jetpack_comments_allow_oembed', true ) + // No need for this on WordPress.com, this is done for multiple shortcodes at a time there. + && ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) +) { /* * We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway, * so the iframe gets filtered out. |