PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.9.5
Jetpack – WP Security, Backup, Speed, & Growth v12.9.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 3 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
580 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 $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 $url Youtube URL.
143 */
144 function youtube_sanitize_url( $url ) {
145 $url = trim( $url, ' "' );
146 $url = trim( $url );
147 $url = str_replace( array( 'youtu.be/', '/v/', '#!v=', '&amp;', '&#038;', 'playlist' ), array( 'youtu.be/?v=', '/?v=', '?v=', '&', '&', 'videoseries' ), $url );
148
149 // 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.
150 $query_string_start = strpos( $url, '?' );
151
152 if ( false !== $query_string_start ) {
153 $url = substr( $url, 0, $query_string_start + 1 ) . str_replace( '?', '&', substr( $url, $query_string_start + 1 ) );
154 }
155
156 return $url;
157 }
158 endif;
159
160 /**
161 * Converts a YouTube URL into an embedded YouTube video.
162 *
163 * URL can be:
164 * http://www.youtube.com/embed/videoseries?list=PL94269DA08231042B&amp;hl=en_US
165 * http://www.youtube.com/watch#!v=H2Ncxw1xfck
166 * http://www.youtube.com/watch?v=H2Ncxw1xfck
167 * http://www.youtube.com/watch?v=H2Ncxw1xfck&w=320&h=240&fmt=1&rel=0&showsearch=1&hd=0
168 * http://www.youtube.com/v/jF-kELmmvgA
169 * http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US
170 * http://youtu.be/Rrohlqeir5E
171 * https://www.youtube.com/watch?v=GJNxoe-iSb4&list=PLAVZ4NFtZX0fE54mDSqNKym-o_rz-8xmk
172 *
173 * @param string $url Youtube URL.
174 */
175 function youtube_id( $url ) {
176 $id = jetpack_get_youtube_id( $url );
177
178 if ( ! $id ) {
179 return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: bad URL entered', 'jetpack' ) );
180 }
181
182 $url = youtube_sanitize_url( $url );
183 $url = wp_parse_url( $url );
184
185 $thumbnail = "https://i.ytimg.com/vi/$id/hqdefault.jpg";
186 $video_url = add_query_arg( 'v', $id, 'https://www.youtube.com/watch' );
187
188 $args = jetpack_shortcode_youtube_args( $url );
189 if ( empty( $args ) ) {
190 return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: empty URL args', 'jetpack' ) );
191 }
192
193 // Account for URL having both v and list, where jetpack_get_youtube_id() only accounts for one or the other.
194 if ( isset( $args['list'] ) && $args['list'] === $id ) {
195 $id = null;
196 }
197 if ( isset( $args['v'] ) ) {
198 $id = $args['v'];
199 }
200 if ( ! $id && empty( $args['list'] ) ) {
201 return sprintf( '<!--%s-->', esc_html__( 'YouTube Error: missing id and/or list', 'jetpack' ) );
202 }
203
204 list( $w, $h ) = jetpack_shortcode_youtube_dimensions( $args );
205
206 $params = array(
207 'rel' => ( isset( $args['rel'] ) && '0' === $args['rel'] ) ? 0 : 1,
208 'showsearch' => ( isset( $args['showsearch'] ) && '1' === $args['showsearch'] ) ? 1 : 0, // Now deprecated. See https://developers.google.com/youtube/player_parameters#march-29,-2012.
209 'showinfo' => ( isset( $args['showinfo'] ) && '0' === $args['showinfo'] ) ? 0 : 1, // Now obsolete. See https://developers.google.com/youtube/player_parameters#showinfo.
210 'iv_load_policy' => ( isset( $args['iv_load_policy'] ) && '3' === $args['iv_load_policy'] ) ? 3 : 1,
211 'fs' => 1,
212 'hl' => str_replace( '_', '-', get_locale() ),
213 );
214 if ( isset( $args['fmt'] ) && (int) $args['fmt'] ) {
215 $params['fmt'] = (int) $args['fmt']; // Apparently an obsolete parameter. Not referenced on https://developers.google.com/youtube/player_parameters.
216 }
217
218 // The autohide parameter has been deprecated since 2015. See https://developers.google.com/youtube/player_parameters#august-19,-2015.
219 if ( ! isset( $args['autohide'] ) || ( $args['autohide'] < 0 || 2 < $args['autohide'] ) ) {
220 $params['autohide'] = 2;
221 } else {
222 $params['autohide'] = (int) $args['autohide'];
223 }
224
225 $start = 0;
226 if ( isset( $args['start'] ) ) {
227 $start = (int) $args['start'];
228 } elseif ( isset( $args['t'] ) ) {
229 if ( is_numeric( $args['t'] ) ) {
230 $start = (int) $args['t'];
231 } else {
232 $time_pieces = preg_split( '/(?<=\D)(?=\d+)/', $args['t'] );
233
234 foreach ( $time_pieces as $time_piece ) {
235 $int = (int) $time_piece;
236 switch ( substr( $time_piece, - 1 ) ) {
237 case 'h':
238 $start += $int * 3600;
239 break;
240 case 'm':
241 $start += $int * 60;
242 break;
243 case 's':
244 $start += $int;
245 break;
246 }
247 }
248 }
249 }
250 if ( $start ) {
251 $params['start'] = (int) $start;
252 }
253
254 if ( isset( $args['end'] ) && (int) $args['end'] ) {
255 $params['end'] = (int) $args['end'];
256 }
257 if ( isset( $args['hd'] ) && (int) $args['hd'] ) {
258 $params['hd'] = (int) $args['hd']; // Now obsolete per https://developers.google.com/youtube/player_parameters#march-29,-2012.
259 }
260 if ( isset( $args['vq'] ) && in_array( $args['vq'], array( 'hd720', 'hd1080' ), true ) ) {
261 $params['vq'] = $args['vq']; // Note, this appears to be obsolete. Not referenced on https://developers.google.com/youtube/player_parameters.
262 }
263 if ( isset( $args['cc_load_policy'] ) ) {
264 $params['cc_load_policy'] = 1;
265 }
266 if ( isset( $args['cc_lang_pref'] ) ) {
267 $params['cc_lang_pref'] = preg_replace( '/[^_a-z0-9-]/i', '', $args['cc_lang_pref'] );
268 }
269
270 // The wmode parameter appears to be obsolete. Not referenced on https://developers.google.com/youtube/player_parameters.
271 if ( isset( $args['wmode'] ) && in_array( strtolower( $args['wmode'] ), array( 'opaque', 'window', 'transparent' ), true ) ) {
272 $params['wmode'] = $args['wmode'];
273 } else {
274 $params['wmode'] = 'transparent';
275 }
276
277 // The theme parameter is obsolete per https://developers.google.com/youtube/player_parameters#august-19,-2015.
278 if ( isset( $args['theme'] ) && in_array( strtolower( $args['theme'] ), array( 'dark', 'light' ), true ) ) {
279 $params['theme'] = $args['theme'];
280 }
281
282 if ( isset( $args['list'] ) ) {
283 $params['listType'] = 'playlist';
284 $params['list'] = preg_replace( '|[^_a-z0-9-]|i', '', $args['list'] );
285 }
286
287 /**
288 * Allow YouTube videos to start playing automatically.
289 *
290 * @module shortcodes
291 *
292 * @since 2.2.2
293 *
294 * @param bool false Enable autoplay for YouTube videos.
295 */
296 if ( apply_filters( 'jetpack_youtube_allow_autoplay', false ) && isset( $args['autoplay'] ) ) {
297 $params['autoplay'] = (int) $args['autoplay'];
298 }
299
300 $is_amp = class_exists( 'Jetpack_AMP_Support' ) && Jetpack_AMP_Support::is_amp_request();
301
302 if ( $is_amp && $id ) {
303 // Note that <amp-youtube> currently is not well suited for playlists that don't have an individual video selected, hence the $id check above.
304 $placeholder = sprintf(
305 '<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>',
306 esc_url( $video_url ),
307 esc_url( $thumbnail ),
308 esc_attr__( 'YouTube Poster', 'jetpack' ) // Would be preferable to provide YouTube video title, but not available in this non-oEmbed context.
309 );
310
311 $html_attributes = array();
312 foreach ( $params as $param_name => $param_value ) {
313 $html_attributes[] = sprintf(
314 'data-param-%s="%s"',
315 sanitize_key( $param_name ),
316 esc_attr( $param_value )
317 );
318 }
319
320 $html = sprintf(
321 '<amp-youtube data-videoid="%s" %s width="%d" height="%d" layout="responsive">%s</amp-youtube>',
322 esc_attr( $id ),
323 implode( ' ', $html_attributes ), // Note: Escaping done above.
324 esc_attr( $w ),
325 esc_attr( $h ),
326 $placeholder
327 );
328 } else {
329 // In AMP, the AMP_Iframe_Sanitizer will convert into <amp-iframe> as required.
330 $src = 'https://www.youtube.com/embed';
331 if ( $id ) {
332 $src .= "/$id";
333 }
334 $src = add_query_arg(
335 array_merge(
336 array( 'version' => 3 ),
337 $params
338 ),
339 $src
340 );
341
342 $layout = $is_amp ? 'layout="responsive" ' : '';
343
344 $html = sprintf(
345 '<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>',
346 esc_attr( $w ),
347 esc_attr( $h ),
348 $layout,
349 esc_url( $src )
350 );
351 }
352
353 // Let's do some alignment wonder in a span, unless we're producing a feed.
354 if ( ! is_feed() ) {
355 $alignmentcss = 'text-align:center;';
356 if ( isset( $args['align'] ) ) {
357 switch ( $args['align'] ) {
358 case 'left':
359 $alignmentcss = "float:left; width:{$w}px; height:{$h}px; margin-right:10px; margin-bottom: 10px;";
360 break;
361 case 'right':
362 $alignmentcss = "float:right; width:{$w}px; height:{$h}px; margin-left:10px; margin-bottom: 10px;";
363 break;
364 }
365 }
366
367 $html = sprintf(
368 '<span class="embed-youtube" style="%s display: block;">%s</span>',
369 esc_attr( $alignmentcss ),
370 $html
371 );
372
373 }
374
375 /**
376 * Format output for Calypso Reader/Notifications/Comments
377 */
378 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
379 require_once WP_CONTENT_DIR . '/lib/display-context.php';
380 $context = A8C\Display_Context\get_current_context();
381 if ( A8C\Display_Context\NOTIFICATIONS === $context ) {
382 return sprintf(
383 '<a href="%1$s" target="_blank" rel="noopener noreferrer"><img src="%2$s" alt="%3$s" /></a>',
384 esc_url( $video_url ),
385 esc_url( $thumbnail ),
386 esc_html__( 'YouTube video', 'jetpack' )
387 );
388 }
389 }
390
391 /**
392 * Filter the YouTube video HTML output.
393 *
394 * @module shortcodes
395 *
396 * @since 1.2.3
397 *
398 * @param string $html YouTube video HTML output.
399 */
400 $html = apply_filters( 'video_embed_html', $html );
401
402 return $html;
403 }
404
405 /**
406 * Gets the args present in the YouTube shortcode URL.
407 *
408 * @since 8.0.0
409 *
410 * @param array $url The parsed URL of the shortcode.
411 *
412 * @return array|false The query args of the URL, or false.
413 */
414 function jetpack_shortcode_youtube_args( $url ) {
415 $qargs = array();
416 if ( ! empty( $url['query'] ) ) {
417 wp_parse_str( $url['query'], $qargs );
418 } else {
419 return false;
420 }
421
422 $fargs = array();
423 if ( ! empty( $url['fragment'] ) ) {
424 wp_parse_str( $url['fragment'], $fargs );
425 }
426
427 return array_merge( $fargs, $qargs );
428 }
429
430 /**
431 * Display the Youtube shortcode.
432 *
433 * @param array $atts Shortcode attributes.
434 *
435 * @return string The rendered shortcode.
436 */
437 function youtube_shortcode( $atts ) {
438 $url = ( isset( $atts[0] ) ) ? ltrim( $atts[0], '=' ) : shortcode_new_to_old_params( $atts );
439 return youtube_id( $url );
440 }
441 add_shortcode( 'youtube', 'youtube_shortcode' );
442
443 /**
444 * Gets the dimensions of the [youtube] shortcode.
445 *
446 * Calculates the width and height, taking $content_width into consideration.
447 *
448 * @since 8.0.0
449 *
450 * @param array $query_args The query args of the URL.
451 *
452 * @return array The width and height of the shortcode.
453 */
454 function jetpack_shortcode_youtube_dimensions( $query_args ) {
455 $h = null;
456 global $content_width;
457
458 $input_w = ( isset( $query_args['w'] ) && (int) $query_args['w'] ) ? (int) $query_args['w'] : 0;
459 $input_h = ( isset( $query_args['h'] ) && (int) $query_args['h'] ) ? (int) $query_args['h'] : 0;
460
461 // If we have $content_width, use it.
462 if ( ! empty( $content_width ) ) {
463 $default_width = $content_width;
464 } else {
465 // Otherwise get default width from the old, now deprecated embed_size_w option.
466 $default_width = get_option( 'embed_size_w' );
467 }
468
469 // If we don't know those 2 values use a hardcoded width.
470 if ( empty( $default_width ) ) {
471 $default_width = 640;
472 }
473
474 if ( $input_w > 0 && $input_h > 0 ) {
475 $w = $input_w;
476 $h = $input_h;
477 } elseif ( 0 === $input_w && 0 === $input_h ) {
478 if ( isset( $query_args['fmt'] ) && (int) $query_args['fmt'] ) {
479 $w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 );
480 } else {
481 $w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width );
482 $h = ceil( ( $w / 16 ) * 9 );
483 }
484 } elseif ( $input_w > 0 ) {
485 $w = $input_w;
486 $h = ceil( ( $w / 16 ) * 9 );
487 } elseif ( isset( $query_args['fmt'] ) && (int) $query_args['fmt'] ) {
488 $w = ( ! empty( $content_width ) ? min( $content_width, 480 ) : 480 );
489 } else {
490 $w = ( ! empty( $content_width ) ? min( $content_width, $default_width ) : $default_width );
491 $h = $input_h;
492 }
493
494 /**
495 * Filter the YouTube player width.
496 *
497 * @module shortcodes
498 *
499 * @since 1.1.0
500 *
501 * @param int $w Width of the YouTube player in pixels.
502 */
503 $w = (int) apply_filters( 'youtube_width', $w );
504
505 /**
506 * Filter the YouTube player height.
507 *
508 * @module shortcodes
509 *
510 * @since 1.1.0
511 *
512 * @param int $h Height of the YouTube player in pixels.
513 */
514 $h = (int) apply_filters( 'youtube_height', $h );
515
516 return array( $w, $h );
517 }
518
519 /**
520 * For bare URLs on their own line of the form
521 * http://www.youtube.com/v/9FhMMmqzbD8?fs=1&hl=en_US
522 *
523 * @param array $matches Regex partial matches against the URL passed.
524 * @param array $attr Attributes received in embed response.
525 * @param array $url Requested URL to be embedded.
526 */
527 function wpcom_youtube_embed_crazy_url( $matches, $attr, $url ) {
528 return youtube_id( $url );
529 }
530
531 /**
532 * Add a new handler to automatically transform custom Youtube URLs (like playlists) into embeds.
533 */
534 function wpcom_youtube_embed_crazy_url_init() {
535 wp_embed_register_handler( 'wpcom_youtube_embed_crazy_url', '#https?://(?:www\.)?(?:youtube.com/(?:v/|playlist|watch[/\#?])|youtu\.be/).*#i', 'wpcom_youtube_embed_crazy_url' );
536 }
537 add_action( 'init', 'wpcom_youtube_embed_crazy_url_init' );
538
539 if (
540 ! is_admin()
541 /**
542 * Allow oEmbeds in Jetpack's Comment form.
543 *
544 * @module shortcodes
545 *
546 * @since 2.8.0
547 *
548 * @param int $allow_oembed Option to automatically embed all plain text URLs.
549 */
550 && apply_filters( 'jetpack_comments_allow_oembed', true )
551 // No need for this on WordPress.com, this is done for multiple shortcodes at a time there.
552 && ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM )
553 ) {
554 /*
555 * We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway,
556 * so the iframe gets filtered out.
557 * Higher priority because we need it before auto-link and autop get to it.
558 */
559 add_filter( 'comment_text', 'youtube_link', 1 );
560 }
561
562 /**
563 * Core changes to do_shortcode (https://core.trac.wordpress.org/changeset/34747) broke "improper" shortcodes
564 * with the format [shortcode=http://url.com].
565 *
566 * This removes the "=" from the shortcode so it can be parsed.
567 *
568 * @see https://github.com/Automattic/jetpack/issues/3121
569 *
570 * @param string $content HTML content.
571 */
572 function jetpack_fix_youtube_shortcode_display_filter( $content ) {
573 if ( strpos( $content, '[youtube=' ) !== false ) {
574 $content = preg_replace( '@\[youtube=(.*?)\]@', '[youtube $1]', $content );
575 }
576
577 return $content;
578 }
579 add_filter( 'the_content', 'jetpack_fix_youtube_shortcode_display_filter', 7 );
580