PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 13.1.5
Jetpack – WP Security, Backup, Speed, & Growth v13.1.5
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / shortcodes / youtube.php
jetpack / modules / shortcodes Last commit date
css 2 years ago images 12 years ago img 13 years ago js 4 years ago archiveorg-book.php 5 years ago archiveorg.php 5 years ago archives.php 5 years ago bandcamp.php 3 years ago brightcove.php 5 years ago cartodb.php 5 years ago class.filter-embedded-html-objects.php 2 years ago codepen.php 5 years ago crowdsignal.php 2 years ago dailymotion.php 3 years ago descript.php 4 years ago facebook.php 2 years ago flatio.php 5 years ago flickr.php 2 years ago getty.php 2 years ago gist.php 3 years ago googleapps.php 2 years ago googlemaps.php 2 years ago googleplus.php 5 years ago gravatar.php 2 years ago houzz.php 5 years ago inline-pdfs.php 4 years ago instagram.php 3 years ago kickstarter.php 3 years ago mailchimp.php 3 years ago medium.php 3 years ago mixcloud.php 2 years ago others.php 2 years ago pinterest.php 2 years ago presentations.php 2 years ago quiz.php 4 years ago recipe.php 2 years ago scribd.php 5 years ago sitemap.php 5 years ago slideshare.php 5 years ago slideshow.php 3 years ago smartframe.php 3 years ago soundcloud.php 3 years ago spotify.php 2 years ago ted.php 5 years ago tweet.php 2 years ago twitchtv.php 5 years ago twitter-timeline.php 5 years ago unavailable.php 3 years ago untappd-menu.php 3 years ago upcoming-events.php 3 years ago ustream.php 5 years ago videopress.php 4 years ago vimeo.php 3 years ago vine.php 5 years ago vr.php 3 years ago wordads.php 5 years ago wufoo.php 3 years ago youtube.php 2 years ago
youtube.php
584 lines
1 <?php
2 /**
3 * Youtube shortcode
4 *
5 * Contains shortcode + some improvements over the Core Embeds syntax (see http://codex.wordpress.org/Embeds )
6 *
7 * Examples:
8 * [youtube https://www.youtube.com/watch?v=WVbQ-oro7FQ]
9 * [youtube=http://www.youtube.com/watch?v=wq0rXGLs0YM&fs=1&hl=bg_BG&autohide=1&rel=0]
10 * http://www.youtube.com/watch?v=H2Ncxw1xfck&w=320&h=240&fmt=1&rel=0&showsearch=1&hd=0
11 * http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US
12 * https://www.youtube.com/playlist?list=PLP7HaNDU4Cifov7C2fQM8Ij6Ew_uPHEXW
13 *
14 * @package automattic/jetpack
15 */
16
17 /**
18 * Replaces YouTube embeds with YouTube shortcodes.
19 *
20 * Covers the following formats:
21 * 2008-07-15:
22 * <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/bZBHZT3a-FA&hl=en&fs=1"></param><param name="allowFullScreen" value="true"></param><embed src="http://www.youtube.com/v/bZBHZT3a-FA&hl=en&fs=1" type="application/x-shockwave-flash" allowfullscreen="true" width="425" height="344"></embed></object>
23 * around 2008-06-06 youtube changed their old embed code to this:
24 * <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/M1D30gS7Z8U&hl=en"></param><embed src="http://www.youtube.com/v/M1D30gS7Z8U&hl=en" type="application/x-shockwave-flash" width="425" height="344"></embed></object>
25 * old style was:
26 * <object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/dGY28Qbj76A&rel=0"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/dGY28Qbj76A&rel=0" type="application/x-shockwave-flash" wmode="transparent" width="425" height="344"></embed></object>
27 * 12-2010:
28 * <object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/3H8bnKdf654?fs=1&amp;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&amp;hl=en_GB" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object>
29 * 01-2011:
30 * <iframe title="YouTube video player" class="youtube-player" width="640" height="390" src="http://www.youtube.com/embed/Qq9El3ki0_g" frameborder="0" allowFullScreen></iframe>
31 * <iframe class="youtube-player" width="640" height="385" src="http://www.youtube.com/embed/VIDEO_ID" frameborder="0"></iframe>
32 *
33 * @param string $content HTML content.
34 * @return string The content with YouTube embeds replaced with YouTube shortcodes.
35 */
36 function youtube_embed_to_short_code( $content ) {
37 if ( ! is_string( $content ) || ! str_contains( $content, 'youtube.com' ) ) {
38 return $content;
39 }
40
41 // older codes.
42 $regexp = '!<object(.*?)>.*?<param\s+name=[\'"]movie[\'"]\s+value=[\'"](https?:)?//www\.youtube\.com/v/([^\'"]+)[\'"].*?>.*?</object>!i';
43 $regexp_ent = htmlspecialchars( $regexp, ENT_NOQUOTES );
44 $old_regexp = '!<embed(?:\s+\w+="[^"]*")*\s+src="https?(?:\:|&#0*58;)//www\.youtube\.com/v/([^"]+)"(?:\s+\w+="[^"]*")*\s*(?:/>|>\s*</embed>)!';
45 $old_regexp_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $old_regexp, ENT_NOQUOTES ) );
46
47 // new code.
48 $ifr_regexp = '!<iframe((?:\s+\w+="[^"]*")*?)\s+src="(https?:)?//(?:www\.)*youtube.com/embed/([^"]+)".*?</iframe>!i';
49 $ifr_regexp_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $ifr_regexp, ENT_NOQUOTES ) );
50
51 foreach ( compact( 'regexp', 'regexp_ent', 'old_regexp', 'old_regexp_ent', 'ifr_regexp', 'ifr_regexp_ent' ) as $reg => $regexp ) {
52 if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
53 continue;
54 }
55
56 foreach ( $matches as $match ) {
57 /*
58 * Hack, but '?' should only ever appear once, and
59 * it should be for the 1st field-value pair in query string,
60 * if it is present
61 * YouTube changed their embed code.
62 * Example of how it is now:
63 * <object width="640" height="385"><param name="movie" value="http://www.youtube.com/v/aP9AaD4tgBY?fs=1&amp;hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/aP9AaD4tgBY?fs=1&amp;hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="385"></embed></object>
64 * As shown at the start of function, previous YouTube didn't '?'
65 * the 1st field-value pair.
66 */
67 if ( in_array( $reg, array( 'ifr_regexp', 'ifr_regexp_ent', 'regexp', 'regexp_ent' ), true ) ) {
68 $params = $match[1];
69
70 if ( in_array( $reg, array( 'ifr_regexp_ent', 'regexp_ent' ), true ) ) {
71 $params = html_entity_decode( $params, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
72 }
73
74 $params = wp_kses_hair( $params, array( 'http' ) );
75
76 $width = isset( $params['width'] ) ? (int) $params['width']['value'] : 0;
77 $height = isset( $params['height'] ) ? (int) $params['height']['value'] : 0;
78 $wh = '';
79
80 if ( $width && $height ) {
81 $wh = "&w=$width&h=$height";
82 }
83
84 $url = esc_url_raw( "https://www.youtube.com/watch?v={$match[3]}{$wh}" );
85 } else {
86 $match[1] = str_replace( '?', '&', $match[1] );
87
88 $url = esc_url_raw( 'https://www.youtube.com/watch?v=' . html_entity_decode( $match[1], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ) );
89 }
90
91 $content = str_replace( $match[0], "[youtube $url]", $content );
92
93 /**
94 * Fires before the YouTube embed is transformed into a shortcode.
95 *
96 * @module shortcodes
97 *
98 * @since 1.2.0
99 *
100 * @param string youtube Shortcode name.
101 * @param string $url YouTube video URL.
102 */
103 do_action( 'jetpack_embed_to_shortcode', 'youtube', $url );
104 }
105 }
106
107 return $content;
108 }
109 add_filter( 'pre_kses', 'youtube_embed_to_short_code' );
110
111 /**
112 * Replaces plain-text links to YouTube videos with YouTube embeds.
113 *
114 * @param string $content HTML content.
115 *
116 * @return string The content with embeds instead of URLs
117 */
118 function youtube_link( $content ) {
119 return jetpack_preg_replace_callback_outside_tags( '!(?:\n|\A)https?://(?:www\.)?(?:youtube.com/(?:v/|playlist|watch[/\#?])|youtu\.be/)[^\s]+?(?:\n|\Z)!i', 'youtube_link_callback', $content, 'youtube.com/' );
120 }
121
122 /**
123 * Callback function for the regex that replaces YouTube URLs with
124 * YouTube embeds.
125 *
126 * @param array $matches An array containing a YouTube URL.
127 */
128 function youtube_link_callback( $matches ) {
129 return "\n" . youtube_id( $matches[0] ) . "\n";
130 }
131
132 /**
133 * Normalizes a YouTube URL to include a v= parameter and a query string free of encoded ampersands.
134 *
135 * @param string|array $url Youtube URL.
136 * @return string The normalized URL
137 */
138 if ( ! function_exists( 'youtube_sanitize_url' ) ) :
139 /**
140 * Clean up Youtube URL to match a single format.
141 *
142 * @param string|array $url Youtube URL.
143 */
144 function youtube_sanitize_url( $url ) {
145 if ( is_array( $url ) && isset( $url['url'] ) ) {
146 $url = $url['url'];
147 }
148
149 $url = trim( $url, ' "' );
150 $url = trim( $url );
151 $url = str_replace( array( 'youtu.be/', '/v/', '#!v=', '&amp;', '&#038;', 'playlist' ), array( 'youtu.be/?v=', '/?v=', '?v=', '&', '&', 'videoseries' ), $url );
152
153 // Replace any extra question marks with ampersands - the result of a URL like "http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US" being passed in.
154 $query_string_start = strpos( $url, '?' );
155
156 if ( false !== $query_string_start ) {
157 $url = substr( $url, 0, $query_string_start + 1 ) . str_replace( '?', '&', substr( $url, $query_string_start + 1 ) );
158 }
159
160 return $url;
161 }
162 endif;
163
164 /**
165 * Converts a YouTube URL into an embedded YouTube video.
166 *
167 * URL can be:
168 * http://www.youtube.com/embed/videoseries?list=PL94269DA08231042B&amp;hl=en_US
169 * http://www.youtube.com/watch#!v=H2Ncxw1xfck
170 * http://www.youtube.com/watch?v=H2Ncxw1xfck
171 * http://www.youtube.com/watch?v=H2Ncxw1xfck&w=320&h=240&fmt=1&rel=0&showsearch=1&hd=0
172 * http://www.youtube.com/v/jF-kELmmvgA
173 * http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US
174 * http://youtu.be/Rrohlqeir5E
175 * https://www.youtube.com/watch?v=GJNxoe-iSb4&list=PLAVZ4NFtZX0fE54mDSqNKym-o_rz-8xmk
176 *
177 * @param string $url Youtube URL.
178 */
179 function youtube_id( $url ) {
180 $id = jetpack_get_youtube_id( $url );
181
182 if ( ! $id ) {
183 return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: bad URL entered', 'jetpack' ) );
184 }
185
186 $url = youtube_sanitize_url( $url );
187 $url = wp_parse_url( $url );
188
189 $thumbnail = "https://i.ytimg.com/vi/$id/hqdefault.jpg";
190 $video_url = add_query_arg( 'v', $id, 'https://www.youtube.com/watch' );
191
192 $args = jetpack_shortcode_youtube_args( $url );
193 if ( empty( $args ) ) {
194 return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: empty URL args', 'jetpack' ) );
195 }
196
197 // Account for URL having both v and list, where jetpack_get_youtube_id() only accounts for one or the other.
198 if ( isset( $args['list'] ) && $args['list'] === $id ) {
199 $id = null;
200 }
201 if ( isset( $args['v'] ) ) {
202 $id = $args['v'];
203 }
204 if ( ! $id && empty( $args['list'] ) ) {
205 return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: missing id and/or list', 'jetpack' ) );
206 }
207
208 list( $w, $h ) = jetpack_shortcode_youtube_dimensions( $args );
209
210 $params = array(
211 'rel' => ( isset( $args['rel'] ) && '0' === $args['rel'] ) ? 0 : 1,
212 'showsearch' => ( isset( $args['showsearch'] ) && '1' === $args['showsearch'] ) ? 1 : 0, // Now deprecated. See https://developers.google.com/youtube/player_parameters#march-29,-2012.
213 'showinfo' => ( isset( $args['showinfo'] ) && '0' === $args['showinfo'] ) ? 0 : 1, // Now obsolete. See https://developers.google.com/youtube/player_parameters#showinfo.
214 'iv_load_policy' => ( isset( $args['iv_load_policy'] ) && '3' === $args['iv_load_policy'] ) ? 3 : 1,
215 'fs' => 1,
216 'hl' => str_replace( '_', '-', get_locale() ),
217 );
218 if ( isset( $args['fmt'] ) && (int) $args['fmt'] ) {
219 $params['fmt'] = (int) $args['fmt']; // Apparently an obsolete parameter. Not referenced on https://developers.google.com/youtube/player_parameters.
220 }
221
222 // The autohide parameter has been deprecated since 2015. See https://developers.google.com/youtube/player_parameters#august-19,-2015.
223 if ( ! isset( $args['autohide'] ) || ( $args['autohide'] < 0 || 2 < $args['autohide'] ) ) {
224 $params['autohide'] = 2;
225 } else {
226 $params['autohide'] = (int) $args['autohide'];
227 }
228
229 $start = 0;
230 if ( isset( $args['start'] ) ) {
231 $start = (int) $args['start'];
232 } elseif ( isset( $args['t'] ) ) {
233 if ( is_numeric( $args['t'] ) ) {
234 $start = (int) $args['t'];
235 } else {
236 $time_pieces = preg_split( '/(?<=\D)(?=\d+)/', $args['t'] );
237
238 foreach ( $time_pieces as $time_piece ) {
239 $int = (int) $time_piece;
240 switch ( substr( $time_piece, - 1 ) ) {
241 case 'h':
242 $start += $int * 3600;
243 break;
244 case 'm':
245 $start += $int * 60;
246 break;
247 case 's':
248 $start += $int;
249 break;
250 }
251 }
252 }
253 }
254 if ( $start ) {
255 $params['start'] = (int) $start;
256 }
257
258 if ( isset( $args['end'] ) && (int) $args['end'] ) {
259 $params['end'] = (int) $args['end'];
260 }
261 if ( isset( $args['hd'] ) && (int) $args['hd'] ) {
262 $params['hd'] = (int) $args['hd']; // Now obsolete per https://developers.google.com/youtube/player_parameters#march-29,-2012.
263 }
264 if ( isset( $args['vq'] ) && in_array( $args['vq'], array( 'hd720', 'hd1080' ), true ) ) {
265 $params['vq'] = $args['vq']; // Note, this appears to be obsolete. Not referenced on https://developers.google.com/youtube/player_parameters.
266 }
267 if ( isset( $args['cc_load_policy'] ) ) {
268 $params['cc_load_policy'] = 1;
269 }
270 if ( isset( $args['cc_lang_pref'] ) ) {
271 $params['cc_lang_pref'] = preg_replace( '/[^_a-z0-9-]/i', '', $args['cc_lang_pref'] );
272 }
273
274 // The wmode parameter appears to be obsolete. Not referenced on https://developers.google.com/youtube/player_parameters.
275 if ( isset( $args['wmode'] ) && in_array( strtolower( $args['wmode'] ), array( 'opaque', 'window', 'transparent' ), true ) ) {
276 $params['wmode'] = $args['wmode'];
277 } else {
278 $params['wmode'] = 'transparent';
279 }
280
281 // The theme parameter is obsolete per https://developers.google.com/youtube/player_parameters#august-19,-2015.
282 if ( isset( $args['theme'] ) && in_array( strtolower( $args['theme'] ), array( 'dark', 'light' ), true ) ) {
283 $params['theme'] = $args['theme'];
284 }
285
286 if ( isset( $args['list'] ) ) {
287 $params['listType'] = 'playlist';
288 $params['list'] = preg_replace( '|[^_a-z0-9-]|i', '', $args['list'] );
289 }
290
291 /**
292 * Allow YouTube videos to start playing automatically.
293 *
294 * @module shortcodes
295 *
296 * @since 2.2.2
297 *
298 * @param bool false Enable autoplay for YouTube videos.
299 */
300 if ( apply_filters( 'jetpack_youtube_allow_autoplay', false ) && isset( $args['autoplay'] ) ) {
301 $params['autoplay'] = (int) $args['autoplay'];
302 }
303
304 $is_amp = class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request();
305
306 if ( $is_amp && $id ) {
307 // Note that <amp-youtube> currently is not well suited for playlists that don't have an individual video selected, hence the $id check above.
308 $placeholder = sprintf(
309 '<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>',
310 esc_url( $video_url ),
311 esc_url( $thumbnail ),
312 esc_attr__( 'YouTube Poster', 'jetpack' ) // Would be preferable to provide YouTube video title, but not available in this non-oEmbed context.
313 );
314
315 $html_attributes = array();
316 foreach ( $params as $param_name => $param_value ) {
317 $html_attributes[] = sprintf(
318 'data-param-%s="%s"',
319 sanitize_key( $param_name ),
320 esc_attr( $param_value )
321 );
322 }
323
324 $html = sprintf(
325 '<amp-youtube data-videoid="%s" %s width="%d" height="%d" layout="responsive">%s</amp-youtube>',
326 esc_attr( $id ),
327 implode( ' ', $html_attributes ), // Note: Escaping done above.
328 esc_attr( $w ),
329 esc_attr( $h ),
330 $placeholder
331 );
332 } else {
333 // In AMP, the AMP_Iframe_Sanitizer will convert into <amp-iframe> as required.
334 $src = 'https://www.youtube.com/embed';
335 if ( $id ) {
336 $src .= "/$id";
337 }
338 $src = add_query_arg(
339 array_merge(
340 array( 'version' => 3 ),
341 $params
342 ),
343 $src
344 );
345
346 $layout = $is_amp ? 'layout="responsive" ' : '';
347
348 $html = sprintf(
349 '<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 allow-popups-to-escape-sandbox"></iframe>',
350 esc_attr( $w ),
351 esc_attr( $h ),
352 $layout,
353 esc_url( $src )
354 );
355 }
356
357 // Let's do some alignment wonder in a span, unless we're producing a feed.
358 if ( ! is_feed() ) {
359 $alignmentcss = 'text-align:center;';
360 if ( isset( $args['align'] ) ) {
361 switch ( $args['align'] ) {
362 case 'left':
363 $alignmentcss = "float:left; width:{$w}px; height:{$h}px; margin-right:10px; margin-bottom: 10px;";
364 break;
365 case 'right':
366 $alignmentcss = "float:right; width:{$w}px; height:{$h}px; margin-left:10px; margin-bottom: 10px;";
367 break;
368 }
369 }
370
371 $html = sprintf(
372 '<span class="embed-youtube" style="%s display: block;">%s</span>',
373 esc_attr( $alignmentcss ),
374 $html
375 );
376
377 }
378
379 /**
380 * Format output for Calypso Reader/Notifications/Comments
381 */
382 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
383 require_once WP_CONTENT_DIR . '/lib/display-context.php';
384 $context = A8C\Display_Context\get_current_context();
385 if ( A8C\Display_Context\NOTIFICATIONS === $context ) {
386 return sprintf(
387 '<a href="%1$s" target="_blank" rel="noopener noreferrer"><img src="%2$s" alt="%3$s" /></a>',
388 esc_url( $video_url ),
389 esc_url( $thumbnail ),
390 esc_html__( 'YouTube video', 'jetpack' )
391 );
392 }
393 }
394
395 /**
396 * Filter the YouTube video HTML output.
397 *
398 * @module shortcodes
399 *
400 * @since 1.2.3
401 *
402 * @param string $html YouTube video HTML output.
403 */
404 $html = apply_filters( 'video_embed_html', $html );
405
406 return $html;
407 }
408
409 /**
410 * Gets the args present in the YouTube shortcode URL.
411 *
412 * @since 8.0.0
413 *
414 * @param array $url The parsed URL of the shortcode.
415 *
416 * @return array|false The query args of the URL, or false.
417 */
418 function jetpack_shortcode_youtube_args( $url ) {
419 $qargs = array();
420 if ( ! empty( $url['query'] ) ) {
421 wp_parse_str( $url['query'], $qargs );
422 } else {
423 return false;
424 }
425
426 $fargs = array();
427 if ( ! empty( $url['fragment'] ) ) {
428 wp_parse_str( $url['fragment'], $fargs );
429 }
430
431 return array_merge( $fargs, $qargs );
432 }
433
434 /**
435 * Display the Youtube shortcode.
436 *
437 * @param array $atts Shortcode attributes.
438 *
439 * @return string The rendered shortcode.
440 */
441 function youtube_shortcode( $atts ) {
442 $url = ( isset( $atts[0] ) ) ? ltrim( $atts[0], '=' ) : shortcode_new_to_old_params( $atts );
443 return youtube_id( $url );
444 }
445 add_shortcode( 'youtube', 'youtube_shortcode' );
446
447 /**
448 * Gets the dimensions of the [youtube] shortcode.
449 *
450 * Calculates the width and height, taking $content_width into consideration.
451 *
452 * @since 8.0.0
453 *
454 * @param array $query_args The query args of the URL.
455 *
456 * @return array The width and height of the shortcode.
457 */
458 function jetpack_shortcode_youtube_dimensions( $query_args ) {
459 $h = null;
460 global $content_width;
461
462 $input_w = ( isset( $query_args['w'] ) && (int) $query_args['w'] ) ? (int) $query_args['w'] : 0;
463 $input_h = ( isset( $query_args['h'] ) && (int) $query_args['h'] ) ? (int) $query_args['h'] : 0;
464
465 // If we have $content_width, use it.
466 if ( ! empty( $content_width ) ) {
467 $default_width = $content_width;
468 } else {
469 // Otherwise get default width from the old, now deprecated embed_size_w option.
470 $default_width = get_option( 'embed_size_w' );
471 }
472
473 // If we don't know those 2 values use a hardcoded width.
474 if ( empty( $default_width ) ) {
475 $default_width = 640;
476 }
477
478 if ( $input_w > 0 && $input_h > 0 ) {
479 $w = $input_w;
480 $h = $input_h;
481 } elseif ( 0 === $input_w && 0 === $input_h ) {
482 if ( isset( $query_args['fmt'] ) && (int) $query_args['fmt'] ) {
483 $w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 );
484 } else {
485 $w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width );
486 $h = ceil( ( $w / 16 ) * 9 );
487 }
488 } elseif ( $input_w > 0 ) {
489 $w = $input_w;
490 $h = ceil( ( $w / 16 ) * 9 );
491 } elseif ( isset( $query_args['fmt'] ) && (int) $query_args['fmt'] ) {
492 $w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 );
493 } else {
494 $w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width );
495 $h = $input_h;
496 }
497
498 /**
499 * Filter the YouTube player width.
500 *
501 * @module shortcodes
502 *
503 * @since 1.1.0
504 *
505 * @param int $w Width of the YouTube player in pixels.
506 */
507 $w = (int) apply_filters( 'youtube_width', $w );
508
509 /**
510 * Filter the YouTube player height.
511 *
512 * @module shortcodes
513 *
514 * @since 1.1.0
515 *
516 * @param int $h Height of the YouTube player in pixels.
517 */
518 $h = (int) apply_filters( 'youtube_height', $h );
519
520 return array( $w, $h );
521 }
522
523 /**
524 * For bare URLs on their own line of the form
525 * http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US
526 *
527 * @param array $matches Regex partial matches against the URL passed.
528 * @param array $attr Attributes received in embed response.
529 * @param array $url Requested URL to be embedded.
530 */
531 function wpcom_youtube_embed_crazy_url( $matches, $attr, $url ) {
532 return youtube_id( $url );
533 }
534
535 /**
536 * Add a new handler to automatically transform custom Youtube URLs (like playlists) into embeds.
537 */
538 function wpcom_youtube_embed_crazy_url_init() {
539 wp_embed_register_handler( 'wpcom_youtube_embed_crazy_url', '#https?://(?:www\.)?(?:youtube.com/(?:v/|playlist|watch[/\#?])|youtu\.be/).*#i', 'wpcom_youtube_embed_crazy_url' );
540 }
541 add_action( 'init', 'wpcom_youtube_embed_crazy_url_init' );
542
543 if (
544 ! is_admin()
545 /**
546 * Allow oEmbeds in Jetpack's Comment form.
547 *
548 * @module shortcodes
549 *
550 * @since 2.8.0
551 *
552 * @param int $allow_oembed Option to automatically embed all plain text URLs.
553 */
554 && apply_filters( 'jetpack_comments_allow_oembed', true )
555 // No need for this on WordPress.com, this is done for multiple shortcodes at a time there.
556 && ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM )
557 ) {
558 /*
559 * We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway,
560 * so the iframe gets filtered out.
561 * Higher priority because we need it before auto-link and autop get to it.
562 */
563 add_filter( 'comment_text', 'youtube_link', 1 );
564 }
565
566 /**
567 * Core changes to do_shortcode (https://core.trac.wordpress.org/changeset/34747) broke "improper" shortcodes
568 * with the format [shortcode=http://url.com].
569 *
570 * This removes the "=" from the shortcode so it can be parsed.
571 *
572 * @see https://github.com/Automattic/jetpack/issues/3121
573 *
574 * @param string $content HTML content.
575 */
576 function jetpack_fix_youtube_shortcode_display_filter( $content ) {
577 if ( strpos( $content, '[youtube=' ) !== false ) {
578 $content = preg_replace( '@\[youtube=(.*?)\]@', '[youtube $1]', $content );
579 }
580
581 return $content;
582 }
583 add_filter( 'the_content', 'jetpack_fix_youtube_shortcode_display_filter', 7 );
584