Completed
Push — fix/manager_api_version ( cc83d0...890261 )
by
unknown
07:11
created

vimeo.php ➔ jetpack_shortcode_get_vimeo_dimensions()   F

Complexity

Conditions 16
Paths 324

Size

Total Lines 106

Duplication

Lines 23
Ratio 21.7 %

Importance

Changes 0
Metric Value
cc 16
nc 324
nop 2
dl 23
loc 106
rs 2.5466
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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 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 View Code Duplication
	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 View Code Duplication
	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 );
0 ignored issues
show
Bug introduced by
It seems like $args can also be of type null; however, jetpack_shortcode_get_vimeo_dimensions() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
195
196
	$url = esc_url( 'https://player.vimeo.com/video/' . $attr['id'] );
197
198
	// Handle autoplay and loop arguments.
199 View Code Duplication
	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 View Code Duplication
	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
	return vimeo_shortcode( array( $url ) );
262
}
263
264
/**
265
 * For bare URLs on their own line of the form
266
 * http://vimeo.com/12345
267
 *
268
 * @since 3.9
269
 *
270
 * @uses wpcom_vimeo_embed_url
271
 */
272
function wpcom_vimeo_embed_url_init() {
273
	wp_embed_register_handler( 'wpcom_vimeo_embed_url', '#https?://(.+\.)?vimeo\.com/#i', 'wpcom_vimeo_embed_url' );
274
}
275
276
/*
277
 * Register handler to modify Vimeo embeds using Jetpack's shortcode output.
278
 * This does not happen on WordPress.com, since embeds are handled by core there.
279
 */
280
if ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) {
281
	add_action( 'init', 'wpcom_vimeo_embed_url_init' );
282
}
283
284
/**
285
 * Transform a Vimeo embed iFrame into a Vimeo shortcode.
286
 *
287
 * @param string $content Post content.
288
 */
289
function vimeo_embed_to_shortcode( $content ) {
290
	if ( ! is_string( $content ) || false === stripos( $content, 'player.vimeo.com/video/' ) ) {
291
		return $content;
292
	}
293
294
	$regexp     = '!<iframe\s+src=[\'"](https?:)?//player\.vimeo\.com/video/(\d+)[\w=&;?]*[\'"]((?:\s+\w+=[\'"][^\'"]*[\'"])*)((?:[\s\w]*))></iframe>!i';
295
	$regexp_ent = str_replace( '&amp;#0*58;', '&amp;#0*58;|&#0*58;', htmlspecialchars( $regexp, ENT_NOQUOTES ) );
296
297
	foreach ( compact( 'regexp', 'regexp_ent' ) as $reg => $regexp ) {
298
		if ( ! preg_match_all( $regexp, $content, $matches, PREG_SET_ORDER ) ) {
299
			continue;
300
		}
301
302
		foreach ( $matches as $match ) {
303
			$id = (int) $match[2];
304
305
			$params = $match[3];
306
307
			if ( 'regexp_ent' === $reg ) {
308
				$params = html_entity_decode( $params );
309
			}
310
311
			$params = wp_kses_hair( $params, array( 'http' ) );
312
313
			$width  = isset( $params['width'] ) ? (int) $params['width']['value'] : 0;
314
			$height = isset( $params['height'] ) ? (int) $params['height']['value'] : 0;
315
316
			$wh = '';
317
			if ( $width && $height ) {
318
				$wh = ' w=' . $width . ' h=' . $height;
319
			}
320
321
			$shortcode = '[vimeo ' . $id . $wh . ']';
322
			$content   = str_replace( $match[0], $shortcode, $content );
323
		}
324
	}
325
326
	return $content;
327
}
328
add_filter( 'pre_kses', 'vimeo_embed_to_shortcode' );
329
330
/**
331
 * Replaces shortcodes and plain-text URLs to Vimeo videos with Vimeo embeds.
332
 * Covers shortcode usage [vimeo 1234] | [vimeo https://vimeo.com/1234] | [vimeo http://vimeo.com/1234]
333
 * Or plain text URLs https://vimeo.com/1234 | vimeo.com/1234 | //vimeo.com/1234
334
 * Links are left intact.
335
 *
336
 * @since 3.7.0
337
 * @since 3.9.5 One regular expression matches shortcodes and plain URLs.
338
 *
339
 * @param string $content HTML content.
340
 *
341
 * @return string The content with embeds instead of URLs
342
 */
343
function vimeo_link( $content ) {
344
	/**
345
	 *  [vimeo 12345]
346
	 *  [vimeo http://vimeo.com/12345]
347
	 */
348
	$shortcode = '(?:\[vimeo\s+[^0-9]*)([0-9]+)(?:\])';
349
350
	/**
351
	 * Regex to look for a Vimeo link.
352
	 *
353
	 * - http://vimeo.com/12345
354
	 * - https://vimeo.com/12345
355
	 * - //vimeo.com/12345
356
	 * - vimeo.com/some/descender/12345
357
	 *
358
	 *  Should not capture inside HTML attributes
359
	 *  [Not] <a href="vimeo.com/12345">Cool Video</a>
360
	 *  [Not] <a href="https://vimeo.com/12345">vimeo.com/12345</a>
361
	 *
362
	 *  Could erroneously capture:
363
	 *  <a href="some.link/maybe/even/vimeo">This video (vimeo.com/12345) is teh cat's meow!</a>
364
	 */
365
	$plain_url = "(?:[^'\">]?\/?(?:https?:\/\/)?vimeo\.com[^0-9]+)([0-9]+)(?:[^'\"0-9<]|$)";
366
367
	return jetpack_preg_replace_callback_outside_tags(
368
		sprintf( '#%s|%s#i', $shortcode, $plain_url ),
369
		'vimeo_link_callback',
370
		$content,
371
		'vimeo'
372
	);
373
}
374
375
/**
376
 * Callback function for the regex that replaces Vimeo URLs with Vimeo embeds.
377
 *
378
 * @since 3.7.0
379
 *
380
 * @param array $matches An array containing a Vimeo URL.
381
 * @return string The Vimeo HTML embed code.
382
 */
383
function vimeo_link_callback( $matches ) {
384
	$id = isset( $matches[2] ) ? $matches[2] : $matches[1];
385
	if ( isset( $id ) && ctype_digit( $id ) ) {
386
		return "\n" . vimeo_shortcode( array( 'id' => $id ) ) . "\n";
387
	}
388
	return $matches[0];
389
}
390
391
if (
392
	! is_admin()
393
	/** This filter is documented in modules/shortcodes/youtube.php */
394
	&& apply_filters( 'jetpack_comments_allow_oembed', true )
395
	// No need for this on WordPress.com, this is done for multiple shortcodes at a time there.
396
	&& ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM )
397
) {
398
	/*
399
	 * We attach wp_kses_post to comment_text in default-filters.php with priority of 10 anyway,
400
	 * so the iframe gets filtered out.
401
	 * Higher priority because we need it before auto-link and autop get to it
402
	 */
403
	add_filter( 'comment_text', 'vimeo_link', 1 );
404
}
405