PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 12.9.3
Jetpack – WP Security, Backup, Speed, & Growth v12.9.3
16.2-beta 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 All 501 releases
jetpack / modules / shortcodes / vimeo.php
vimeo.php
417 lines 11.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Vimeo Shortcode.
4 *
5 * Examples:
6 * [vimeo 141358]
7 * [vimeo http://vimeo.com/141358]
8 * [vimeo 141358 h=500&w=350]
9 * [vimeo 141358 h=500 w=350]
10 * [vimeo id=141358 width=350 height=500]
11 *
12 * <iframe src="http://player.vimeo.com/video/18427511" width="400" height="225" frameborder="0"></iframe><p><a href="http://vimeo.com/18427511">Eskmo 'We Got More' (Official Video)</a> from <a href="http://vimeo.com/ninjatune">Ninja Tune</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
13 *
14 * @package automattic/jetpack
15 */
16
17 /**
18 * Extract Vimeo ID from shortcode.
19 *
20 * @param array $atts Shortcode attributes.
21 */
22 function jetpack_shortcode_get_vimeo_id( $atts ) {
23 if ( isset( $atts[0] ) ) {
24 $atts[0] = trim( $atts[0], '=' );
25 $id = false;
26 if ( is_numeric( $atts[0] ) ) {
27 $id = (int) $atts[0];
28 } elseif ( preg_match( '|vimeo\.com/(\d+)/?$|i', $atts[0], $match ) ) {
29 $id = (int) $match[1];
30 } elseif ( preg_match( '|player\.vimeo\.com/video/(\d+)/?$|i', $atts[0], $match ) ) {
31 $id = (int) $match[1];
32 }
33
34 return $id;
35 }
36
37 return 0;
38 }
39
40 /**
41 * Get video dimensions.
42 *
43 * @since 8.0.0
44 *
45 * @param array $attr The attributes of the shortcode.
46 * @param array $old_attr Optional array of attributes from the old shortcode format.
47 *
48 * @return array Width and height.
49 */
50 function jetpack_shortcode_get_vimeo_dimensions( $attr, $old_attr = array() ) {
51 global $content_width;
52
53 $default_width = 600;
54 $default_height = 338;
55 $aspect_ratio = $default_height / $default_width;
56
57 /*
58 * For width and height, we want to support both formats
59 * that can be provided in the new shortcode format:
60 * - for width: width or w
61 * - for height: height or h
62 *
63 * For each variation, the full word takes priority.
64 *
65 * If no variation is set, we default to the default width and height values set above.
66 */
67 if ( ! empty( $attr['width'] ) ) {
68 $width = absint( $attr['width'] );
69 } elseif ( ! empty( $attr['w'] ) ) {
70 $width = absint( $attr['w'] );
71 } else {
72 $width = $default_width;
73 }
74
75 if ( ! empty( $attr['height'] ) ) {
76 $height = absint( $attr['height'] );
77 } elseif ( ! empty( $attr['h'] ) ) {
78 $height = absint( $attr['h'] );
79 } else {
80 $height = $default_height;
81 }
82
83 /*
84 * Support w and h argument as fallbacks in old shortcode format.
85 */
86 if (
87 $default_width === $width
88 && ! empty( $old_attr['w'] )
89 ) {
90 $width = absint( $old_attr['w'] );
91
92 if (
93 $default_width === $width
94 && empty( $old_attr['h'] )
95 ) {
96 $height = round( $width * $aspect_ratio );
97 }
98 }
99
100 if (
101 $default_height === $height
102 && ! empty( $old_attr['h'] )
103 ) {
104 $height = absint( $old_attr['h'] );
105
106 if ( empty( $old_attr['w'] ) ) {
107 $width = round( $height * $aspect_ratio );
108 }
109 }
110
111 /*
112 * If we have a content width defined, let it be the new default.
113 */
114 if (
115 $default_width === $width
116 && ! empty( $content_width )
117 ) {
118 $width = absint( $content_width );
119 }
120
121 /*
122 * If we have a custom width, we need a custom height as well
123 * to maintain aspect ratio.
124 */
125 if (
126 $default_width !== $width
127 && $default_height === $height
128 ) {
129 $height = round( ( $width / 640 ) * 360 );
130 }
131
132 /**
133 * Filter the Vimeo player width.
134 *
135 * @module shortcodes
136 *
137 * @since 3.4.0
138 *
139 * @param int $width Width of the Vimeo player in pixels.
140 */
141 $width = (int) apply_filters( 'vimeo_width', $width );
142
143 /**
144 * Filter the Vimeo player height.
145 *
146 * @module shortcodes
147 *
148 * @since 3.4.0
149 *
150 * @param int $height Height of the Vimeo player in pixels.
151 */
152 $height = (int) apply_filters( 'vimeo_height', $height );
153
154 return array( $width, $height );
155 }
156
157 /**
158 * Convert a Vimeo shortcode into an embed code.
159 *
160 * @param array $atts An array of shortcode attributes.
161 *
162 * @return string The embed code for the Vimeo video.
163 */
164 function vimeo_shortcode( $atts ) {
165 $attr = array_map(
166 'intval',
167 shortcode_atts(
168 array(
169 'id' => 0,
170 'width' => 0,
171 'height' => 0,
172 'autoplay' => 0,
173 'loop' => 0,
174 'w' => 0,
175 'h' => 0,
176 ),
177 $atts
178 )
179 );
180
181 if ( isset( $atts[0] ) ) {
182 $attr['id'] = jetpack_shortcode_get_vimeo_id( $atts );
183 }
184
185 if ( ! $attr['id'] ) {
186 return '<!-- vimeo error: not a vimeo video -->';
187 }
188
189 // Handle old shortcode params such as h=500&w=350.
190 $params = shortcode_new_to_old_params( $atts );
191 $params = str_replace( array( '&amp;', '&#038;' ), '&', $params );
192 parse_str( $params, $args );
193
194 list( $width, $height ) = jetpack_shortcode_get_vimeo_dimensions( $attr, $args );
195
196 $url = esc_url( 'https://player.vimeo.com/video/' . $attr['id'] );
197
198 // Handle autoplay and loop arguments.
199 if (
200 isset( $args['autoplay'] ) && '1' === $args['autoplay'] // Parsed from the embedded URL.
201 || $attr['autoplay'] // Parsed from shortcode arguments.
202 || in_array( 'autoplay', $atts, true ) // Catch the argument passed without a value.
203 ) {
204 $url = add_query_arg( 'autoplay', 1, $url );
205 }
206
207 if (
208 isset( $args['loop'] ) && '1' === $args['loop'] // Parsed from the embedded URL.
209 || $attr['loop'] // Parsed from shortcode arguments.
210 || in_array( 'loop', $atts, true ) // Catch the argument passed without a value.
211 ) {
212 $url = add_query_arg( 'loop', 1, $url );
213 }
214
215 if (
216 class_exists( 'Jetpack_AMP_Support' )
217 && Jetpack_AMP_Support::is_amp_request()
218 ) {
219 $html = sprintf(
220 '<amp-vimeo data-videoid="%1$s" layout="responsive" width="%2$d" height="%3$d"></amp-vimeo>',
221 esc_attr( $attr['id'] ),
222 absint( $width ),
223 absint( $height )
224 );
225 } else {
226 $html = sprintf(
227 '<div class="embed-vimeo" style="text-align: center;"><iframe src="%1$s" width="%2$u" height="%3$u" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></div>',
228 esc_url( $url ),
229 esc_attr( $width ),
230 esc_attr( $height )
231 );
232 }
233
234 /**
235 * Filter the Vimeo player HTML.
236 *
237 * @module shortcodes
238 *
239 * @since 1.2.3
240 *
241 * @param string $html Embedded Vimeo player HTML.
242 */
243 $html = apply_filters( 'video_embed_html', $html );
244
245 return $html;
246 }
247 add_shortcode( 'vimeo', 'vimeo_shortcode' );
248
249 /**
250 * Callback to modify output of embedded Vimeo video using Jetpack's shortcode.
251 *
252 * @since 3.9
253 *
254 * @param array $matches Regex partial matches against the URL passed.
255 * @param array $attr Attributes received in embed response.
256 * @param array $url Requested URL to be embedded.
257 *
258 * @return string Return output of Vimeo shortcode with the proper markup.
259 */
260 function wpcom_vimeo_embed_url( $matches, $attr, $url ) {
261 $vimeo_info = array( $url );
262
263 // If we are able to extract a video ID, use it in the shortcode instead of the full URL.
264 if ( ! empty( $matches['video_id'] ) ) {
265 $vimeo_info = array( 'id' => $matches['video_id'] );
266 }
267
268 return vimeo_shortcode( $vimeo_info );
269 }
270
271 /**
272 * For bare URLs on their own line of the form.
273 *
274 * Accepted formats:
275 * https://vimeo.com/289091934/cd1f466bcc
276 * https://vimeo.com/album/2838732/video/6342264
277 * https://vimeo.com/6342264
278 * http://player.vimeo.com/video/18427511
279 *
280 * @since 3.9
281 *
282 * @uses wpcom_vimeo_embed_url
283 */
284 function wpcom_vimeo_embed_url_init() {
285 wp_embed_register_handler( 'wpcom_vimeo_embed_url', '#https?://(?:[^/]+\.)?vimeo\.com/(?:album/(?<album_id>\d+)/)?(?:video/)?(?<video_id>\d+)(?:/.*)?$#i', 'wpcom_vimeo_embed_url' );
286 }
287
288 /*
289 * Register handler to modify Vimeo embeds using Jetpack's shortcode output.
290 * This does not happen on WordPress.com, since embeds are handled by core there.
291 */
292 if ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) {
293 add_action( 'init', 'wpcom_vimeo_embed_url_init' );
294 }
295
296 /**
297 * Transform a Vimeo embed iFrame into a Vimeo shortcode.
298 *
299 * @param string $content Post content.
300 */
301 function vimeo_embed_to_shortcode( $content ) {
302 if ( ! is_string( $content ) || false === stripos( $content, 'player.vimeo.com/video/' ) ) {
303 return $content;
304 }
305
306 $regexp = '!<iframe\s+src=[\'"](https?:)?//player\.vimeo\.com/video/(\d+)[\w=&;?]*[\'"]((?:\s+\w+=[\'"][^\'"]*[\'"])*)((?:[\s\w]*))></iframe>!i';
307 $regexp_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );
308
309 foreach ( compact( 'regexp', 'regexp_ent' ) as $reg => $regexp ) {
310 if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
311 continue;
312 }
313
314 foreach ( $matches as $match ) {
315 $id = (int) $match[2];
316
317 $params = $match[3];
318
319 if ( 'regexp_ent' === $reg ) {
320 $params = html_entity_decode( $params, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
321 }
322
323 $params = wp_kses_hair( $params, array( 'http' ) );
324
325 $width = isset( $params['width'] ) ? (int) $params['width']['value'] : 0;
326 $height = isset( $params['height'] ) ? (int) $params['height']['value'] : 0;
327
328 $wh = '';
329 if ( $width && $height ) {
330 $wh = ' w=' . $width . ' h=' . $height;
331 }
332
333 $shortcode = '[vimeo ' . $id . $wh . ']';
334 $content = str_replace( $match[0], $shortcode, $content );
335 }
336 }
337
338 return $content;
339 }
340 add_filter( 'pre_kses', 'vimeo_embed_to_shortcode' );
341
342 /**
343 * Replaces shortcodes and plain-text URLs to Vimeo videos with Vimeo embeds.
344 * Covers shortcode usage [vimeo 1234] | [vimeo https://vimeo.com/1234] | [vimeo http://vimeo.com/1234]
345 * Or plain text URLs https://vimeo.com/1234 | vimeo.com/1234 | //vimeo.com/1234
346 * Links are left intact.
347 *
348 * @since 3.7.0
349 * @since 3.9.5 One regular expression matches shortcodes and plain URLs.
350 *
351 * @param string $content HTML content.
352 *
353 * @return string The content with embeds instead of URLs
354 */
355 function vimeo_link( $content ) {
356 /**
357 * [vimeo 12345]
358 * [vimeo http://vimeo.com/12345]
359 */
360 $shortcode = '(?:\[vimeo\s+[^0-9]*)([0-9]+)(?:\])';
361
362 /**
363 * Regex to look for a Vimeo link.
364 *
365 * - http://vimeo.com/12345
366 * - https://vimeo.com/12345
367 * - //vimeo.com/12345
368 * - vimeo.com/some/descender/12345
369 *
370 * Should not capture inside HTML attributes
371 * [Not] <a href="vimeo.com/12345">Cool Video</a>
372 * [Not] <a href="https://vimeo.com/12345">vimeo.com/12345</a>
373 *
374 * Could erroneously capture:
375 * <a href="some.link/maybe/even/vimeo">This video (vimeo.com/12345) is teh cat's meow!</a>
376 */
377 $plain_url = "(?:[^'\">]?\/?(?:https?:\/\/)?vimeo\.com[^0-9]+)([0-9]+)(?:[^'\"0-9<]|$)";
378
379 return jetpack_preg_replace_callback_outside_tags(
380 sprintf( '#%s|%s#i', $shortcode, $plain_url ),
381 'vimeo_link_callback',
382 $content,
383 'vimeo'
384 );
385 }
386
387 /**
388 * Callback function for the regex that replaces Vimeo URLs with Vimeo embeds.
389 *
390 * @since 3.7.0
391 *
392 * @param array $matches An array containing a Vimeo URL.
393 * @return string The Vimeo HTML embed code.
394 */
395 function vimeo_link_callback( $matches ) {
396 $id = isset( $matches[2] ) ? $matches[2] : $matches[1];
397 if ( isset( $id ) && ctype_digit( $id ) ) {
398 return "\n" . vimeo_shortcode( array( 'id' => $id ) ) . "\n";
399 }
400 return $matches[0];
401 }
402
403 if (
404 ! is_admin()
405 /** This filter is documented in modules/shortcodes/youtube.php */
406 && apply_filters( 'jetpack_comments_allow_oembed', true )
407 // No need for this on WordPress.com, this is done for multiple shortcodes at a time there.
408 && ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM )
409 ) {
410 /*
411 * We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway,
412 * so the iframe gets filtered out.
413 * Higher priority because we need it before auto-link and autop get to it
414 */
415 add_filter( 'comment_text', 'vimeo_link', 1 );
416 }
417