Completed
Push — v2/videopress ( 34ff07...55aa3d )
by George
63:23 queued 51:38
created

VideoPress_Player::html5_dynamic()   F

Complexity

Conditions 42
Paths > 20000

Size

Total Lines 212
Code Lines 137

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 212
rs 2
cc 42
eloc 137
nc 1080721
nop 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
 * VideoPress playback module markup generator.
4
 *
5
 * @since 1.3
6
 */
7
class VideoPress_Player {
8
	/**
9
	 * Video data for the requested guid and maximum width
10
	 *
11
	 * @since 1.3
12
	 * @var VideoPress_Video
13
	 */
14
	protected $video;
15
16
	/**
17
	 * DOM identifier of the video container
18
	 *
19
	 * @var string
20
	 * @since 1.3
21
	 */
22
	protected $video_container_id;
23
24
	/**
25
	 * DOM identifier of the video element (video, object, embed)
26
	 *
27
	 * @var string
28
	 * @since 1.3
29
	 */
30
	protected $video_id;
31
32
	/**
33
	 * Array of playback options: force_flash or freedom
34
	 *
35
	 * @var array
36
	 * @since 1.3
37
	 */
38
	protected $options;
39
40
	/**
41
	 * Array of video GUIDs shown and their counts,
42
	 * moved from the old VideoPress class.
43
	 */
44
	public static $shown = array();
45
46
	/**
47
	 * Initiate a player object based on shortcode values and possible blog-level option overrides
48
	 *
49
	 * @since 1.3
50
	 * @var string $guid VideoPress unique identifier
51
	 * @var int $maxwidth maximum desired width of the video player if specified
52
	 * @var array $options player customizations
53
	 */
54
	public function __construct( $guid, $maxwidth = 0, $options = array() ) {
55
		if ( empty( self::$shown[ $guid ] ) ) {
56
			self::$shown[ $guid ] = 0;
57
		}
58
59
		self::$shown[ $guid ]++;
60
61
		$this->video_container_id = 'v-' . $guid . '-' . self::$shown[ $guid ];
62
		$this->video_id = $this->video_container_id . '-video';
63
64
		if ( is_array( $options ) ) {
65
			$this->options = $options;
66
		} else {
67
			$this->options = array();
68
		}
69
70
		// set up the video
71
		$cache_key = null;
72
73
		// disable cache in debug mode
74
		if ( defined('WP_DEBUG') && WP_DEBUG === true ) {
75
			$cached_video = null;
76
		} else {
77
			$cache_key_pieces = array( 'video' );
78
79
			if ( is_multisite() && is_subdomain_install() ) {
80
				$cache_key_pieces[] = get_current_blog_id();
81
			}
82
83
			$cache_key_pieces[] = $guid;
84
			if ( $maxwidth > 0 ) {
85
				$cache_key_pieces[] = $maxwidth;
86
			}
87
			if ( is_ssl() ) {
88
				$cache_key_pieces[] = 'ssl';
89
			}
90
			$cache_key = implode( '-', $cache_key_pieces );
91
			$cached_video = wp_cache_get( $cache_key, 'video' );
92
		}
93
94
		if ( empty( $cached_video ) ) {
95
			$video = new VideoPress_Video( $guid, $maxwidth );
96
			if ( empty( $video ) ) {
97
				return;
98
			} elseif ( isset( $video->error ) ) {
99
				$this->video = $video->error;
0 ignored issues
show
Bug introduced by
The property error does not seem to exist in VideoPress_Video.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
100
				return;
101
			} elseif ( is_wp_error( $video ) ) {
102
				$this->video = $video;
103
				return;
104
			}
105
106
			$this->video = $video;
107
108
			if ( ! defined( 'WP_DEBUG' ) || WP_DEBUG !== true ) {
109
				$expire = 3600;
110
				if ( isset( $video->expires ) && is_int( $video->expires ) ) {
111
					$expires_diff = time() - $video->expires;
112
					if ( $expires_diff > 0 && $expires_diff < 86400 ) { // allowed range: 1 second to 1 day
113
						$expire = $expires_diff;
114
					}
115
				}
116
117
				wp_cache_set( $cache_key, serialize( $this->video ), 'video', $expire );
118
			}
119
		} else {
120
			$this->video = unserialize( $cached_video );
121
		}
122
	}
123
124
	/**
125
	 * Wrap output in a VideoPress player container
126
	 *
127
	 * @since 1.3
128
	 * @var string $content HTML string
129
	 * @return string HTML string or blank string if nothing to wrap
130
	 */
131
	private function html_wrapper( $content ) {
132
		if ( empty( $content ) ) {
133
			return '';
134
		} else {
135
			return '<div id="' . esc_attr( $this->video_container_id ) . '" class="video-player">' . $content . '</div>';
136
		}
137
	}
138
139
	/**
140
	 * Output content suitable for a feed reader displaying RSS or Atom feeds
141
	 * We do not display error messages in the feed view due to caching concerns.
142
	 * Flash content presented using <embed> markup for feed reader compatibility.
143
	 *
144
	 * @since 1.3
145
	 * @return string HTML string or empty string if error
146
	 */
147
	public function asXML() {
148
		if ( empty( $this->video ) || is_wp_error( $this->video ) ) {
149
			return '';
150
		}
151
152
		if ( isset( $this->options['freedom'] ) && $this->options['freedom'] === true ) {
153
			$content = $this->html5_static();
154
		} else {
155
			$content = $this->flash_embed();
156
		}
157
158
		return $this->html_wrapper( $content );
159
	}
160
161
	/**
162
	 * Video player markup for best matching the current request and publisher options
163
	 * @since 1.3
164
	 * @return string HTML markup string or empty string if no video property found
165
	 */
166
	public function asHTML() {
167
		if ( empty( $this->video ) ) {
168
			$content = '';
169
		} elseif ( is_wp_error( $this->video ) ) {
170
			$content = $this->error_message( $this->video );
171
		} elseif ( isset( $this->options['force_flash'] ) && $this->options['force_flash'] === true ) {
172
			$content = $this->flash_object();
173
		} elseif ( isset( $this->video->restricted_embed ) && $this->video->restricted_embed === true ) {
174
			if ( $this->options['forcestatic'] ) {
175
				$content = $this->flash_object();
176
			} else {
177
				$content = $this->html5_dynamic();
178
			}
179
		} elseif ( isset( $this->options['freedom'] ) && $this->options['freedom'] === true ) {
180
			$content = $this->html5_static();
181
		} else {
182
			$content = $this->html5_dynamic();
183
		}
184
185
		return $this->html_wrapper( $content );
186
	}
187
188
	/**
189
	 * Display an error message to users capable of doing something about the error
190
	 *
191
	 * @since 1.3
192
	 * @uses current_user_can() to test if current user has edit_posts capability
193
	 * @var WP_Error $error WordPress error
194
	 * @return string HTML string
195
	 */
196
	private function error_message( $error ) {
197
		if ( ! current_user_can( 'edit_posts' ) || empty( $error ) ) {
198
			return '';
199
		}
200
201
		$html = '<div class="videopress-error" style="background-color:rgb(255,0,0);color:rgb(255,255,255);font-family:font-family:\'Helvetica Neue\',Arial,Helvetica,\'Nimbus Sans L\',sans-serif;font-size:140%;min-height:10em;padding-top:1.5em;padding-bottom:1.5em">';
202
		$html .= '<h1 style="font-size:180%;font-style:bold;line-height:130%;text-decoration:underline">' . esc_html( sprintf( __( '%s Error', 'jetpack' ), 'VideoPress' ) ) . '</h1>';
203
		foreach ( $error->get_error_messages() as $message ) {
204
			$html .= $message;
205
		}
206
		$html .= '</div>';
207
		return $html;
208
	}
209
210
	/**
211
	 * Rating agencies and industry associations require a potential viewer verify his or her age before a video or its poster frame are displayed.
212
	 * Content rated for audiences 17 years of age or older requires such verification across multiple rating agencies and industry associations
213
	 *
214
	 * @since 1.3
215
	 * @return bool true if video requires the viewer verify he or she is 17 years of age or older
216
	 */
217
	private function age_gate_required() {
218
		if ( isset( $this->video->age_rating ) && $this->video->age_rating >= 17 ) {
219
			return true;
220
		} else {
221
			return false;
222
		}
223
	}
224
225
	/**
226
	 * Select a date of birth using HTML form elements.
227
	 *
228
	 * @since 1.5
229
	 * @return string HTML markup
230
	 */
231
	private function html_age_gate() {
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
232
		global $wp_locale;
233
		$text_align = 'left';
234
		if ( $this->video->text_direction === 'rtl' ) {
235
			$text_align = 'right';
236
		}
237
238
		$html = '<div class="videopress-age-gate" style="margin:0 60px">';
239
		$html .= '<p class="instructions" style="color:rgb(255, 255, 255);font-size:21px;padding-top:60px;padding-bottom:20px;text-align:' . $text_align . '">' . esc_html( __( 'This video is intended for mature audiences.', 'jetpack' ) ) . '<br />' . esc_html( __( 'Please verify your birthday.', 'jetpack' ) ) . '</p>';
240
		$html .= '<fieldset id="birthday" style="border:0 none;text-align:' . $text_align . ';padding:0;">';
241
		$inputs_style = 'border:1px solid #444;margin-';
242
		if ( $this->video->text_direction === 'rtl' ) {
243
			$inputs_style .= 'left';
244
		} else {
245
			$inputs_style .= 'right';
246
		}
247
		$inputs_style .= ':10px;background-color:rgb(0, 0, 0);font-size:14px;color:rgb(255,255,255);padding:4px 6px;line-height: 2em;vertical-align: middle';
248
249
		/**
250
		 * Display a list of months in the Gregorian calendar.
251
		 * Set values to 0-based to match JavaScript Date.
252
		 * @link https://developer.mozilla.org/en/JavaScript/Reference/global_objects/date Mozilla JavaScript Reference: Date
253
		 */
254
		$html .= '<select name="month" style="' . $inputs_style . '">';
255
256
		for ( $i = 0; $i < 12; $i++ ) {
257
			$html .= '<option value="' . esc_attr( $i ) . '">' . esc_html( $wp_locale->get_month( $i + 1 ) )  . '</option>';
258
		}
259
		$html .= '</select>';
260
261
		/**
262
		 * todo: numdays variance by month
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
263
		 */
264
		$html .= '<select name="day" style="' . $inputs_style . '">';
265
		for ( $i = 1; $i < 32; $i++ ) {
266
			$html .= '<option>' . $i . '</option>';
267
		}
268
		$html .= '</select>';
269
270
		/**
271
		 * Current record for human life is 122. Go back 130 years and no one is left out.
272
		 * Don't ask infants younger than 2 for their birthday
273
		 * Default to 13
274
		 */
275
		$html .= '<select name="year" style="' . $inputs_style . '">';
276
		$start_year = date('Y') - 2;
277
		$default_year = $start_year - 11;
278
		$end_year = $start_year - 128;
279
		for ( $year = $start_year; $year > $end_year; $year-- ) {
280
			$html .= '<option';
281
			if ( $year === $default_year ) {
282
				$html .= ' selected="selected"';
283
			}
284
			$html .= '>' . $year . '</option>';
285
		}
286
287
		$html .= '</select>';
288
289
		$html .= '<input type="submit" value="' . __( 'Submit', 'jetpack' ) . '" style="cursor:pointer;border-radius: 1em;border:1px solid #333;background-color:#333;background:-webkit-gradient( linear, left top, left bottom, color-stop(0.0, #444), color-stop(1, #111) );background:-moz-linear-gradient(center top, #444 0%, #111 100%);font-size:13px;padding:4px 10px 5px;line-height:1em;vertical-align:top;color:white;text-decoration:none;margin:0" />';
290
291
		$html .= '</fieldset>';
292
		$html .= '<p style="padding-top:20px;padding-bottom:60px;text-align:' . $text_align . ';"><a rel="nofollow" href="http://videopress.com/" style="color:rgb(128,128,128);text-decoration:underline;font-size:15px">' . __( 'More information', 'jetpack' ) . '</a></p>';
293
294
		$html .= '</div>';
295
		return $html;
296
	}
297
298
	/**
299
	 * Return HTML5 video static markup for the given video parameters.
300
	 * Use default browser player controls.
301
	 * No Flash fallback.
302
	 *
303
	 * @since 1.2
304
	 * @link http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html HTML5 video
305
	 * @return string HTML5 video element and children
306
	 */
307
	private function html5_static() {
308
		wp_enqueue_script( 'videopress' );
309
		$thumbnail = esc_url( $this->video->poster_frame_uri );
310
		$html = "<video id=\"{$this->video_id}\" width=\"{$this->video->calculated_width}\" height=\"{$this->video->calculated_height}\" poster=\"$thumbnail\" controls=\"true\"";
311
312
		if ( isset( $this->options['autoplay'] ) && $this->options['autoplay'] === true ) {
313
			$html .= ' autoplay="true"';
314
		} else {
315
			$html .= ' preload="metadata"';
316
		}
317
318
		if ( isset( $this->video->text_direction ) ) {
319
			$html .= ' dir="' . esc_attr( $this->video->text_direction ) . '"';
320
		}
321
		if ( isset( $this->video->language ) ) {
322
			$html .= ' lang="' . esc_attr( $this->video->language ) . '"';
323
		}
324
		$html .= '>';
325
		if ( ! isset( $this->options['freedom'] ) || $this->options['freedom'] === false ) {
326
			$mp4 = $this->video->videos->mp4->url;
327
			if ( ! empty( $mp4 ) ) {
328
				$html .= '<source src="' . esc_url( $mp4 ) . '" type="video/mp4; codecs=&quot;' . esc_attr( $this->video->videos->mp4->codecs ) . '&quot;" />';
329
			}
330
		}
331
332
		$ogg = $this->video->videos->ogv->url;
333
		if ( ! empty( $ogg ) ) {
334
			$html .= '<source src="' . esc_url( $ogg ) . '" type="video/ogg; codecs=&quot;' . esc_attr( $this->video->videos->ogv->codecs ) . '&quot;" />';
335
		}
336
337
		$html .= '<div><img alt="';
338
		if ( isset( $this->video->title ) ) {
339
			$html .= esc_attr( $this->video->title );
340
		}
341
		$html .= '" src="' . $thumbnail . '" width="' . $this->video->calculated_width . '" height="' . $this->video->calculated_height . '" /></div>';
342
		if ( isset( $this->options['freedom'] ) && $this->options['freedom'] === true ) {
343
			$html .= '<p class="robots-nocontent">' . sprintf( __( 'You do not have sufficient <a rel="nofollow" href="%s">freedom levels</a> to view this video. Support free software and upgrade.', 'jetpack' ), 'http://www.gnu.org/philosophy/free-sw.html' ) . '</p>';
344
		} elseif ( isset( $this->video->title ) ) {
345
			$html .= '<p>' . esc_html( $this->video->title ) . '</p>';
346
		}
347
		$html .= '</video>';
348
		return $html;
349
	}
350
351
	/**
352
	 * Click to play dynamic HTML5-capable player.
353
	 * The player displays a video preview section including poster frame,
354
	 * video title, play button and watermark on the original page load
355
	 * and calculates the playback capabilities of the browser. The video player
356
	 * is loaded when the visitor clicks on the video preview area.
357
	 * If Flash Player 10 or above is available the browser will display
358
	 * the Flash version of the video. If HTML5 video appears to be supported
359
	 * and the browser may be capable of MP4 (H.264, AAC) or OGV (Theora, Vorbis)
360
	 * playback the browser will display its native HTML5 player.
361
	 *
362
	 * @since 1.5
363
	 * @return string HTML markup
364
	 */
365
	private function html5_dynamic() {
366
367
		/**
368
		 * Filter the VideoPress legacy player feature
369
		 *
370
		 * This filter allows you to control whether the legacy VideoPress player should be used
371
		 * instead of the improved one.
372
		 *
373
		 * @module videopress
374
		 *
375
		 * @since 3.7.0
376
		 *
377
		 * @param boolean $videopress_use_legacy_player
378
		 */
379
		if ( ! apply_filters( 'jetpack_videopress_use_legacy_player', false ) ) {
380
			return $this->html5_dynamic_next();
381
		}
382
383
		wp_enqueue_script( 'videopress' );
384
		$video_placeholder_id = $this->video_container_id . '-placeholder';
385
		$age_gate_required = $this->age_gate_required();
386
		$width = absint( $this->video->calculated_width );
387
		$height = absint( $this->video->calculated_height );
388
389
		$html = '<div id="' . $video_placeholder_id . '" class="videopress-placeholder" style="';
390
		if ( $age_gate_required ) {
391
			$html .= "min-width:{$width}px;min-height:{$height}px";
392
		} else {
393
			$html .= "width:{$width}px;height:{$height}px";
394
		}
395
		$html .= ';display:none;cursor:pointer !important;position:relative;';
396
		if ( isset( $this->video->skin ) && isset( $this->video->skin->background_color ) ) {
397
			$html .= 'background-color:' . esc_attr( $this->video->skin->background_color ) . ';';
398
		}
399
		$html .= 'font-family: \'Helvetica Neue\',Arial,Helvetica,\'Nimbus Sans L\',sans-serif;font-weight:bold;font-size:18px">' . PHP_EOL;
400
401
		/**
402
		 * Do not display a poster frame, title, or any other content hints for mature content.
403
		 */
404
		if ( ! $age_gate_required ) {
405
			if ( ! empty( $this->video->title ) ) {
406
				$html .= '<div class="videopress-title" style="display:inline;position:absolute;margin:20px 20px 0 20px;padding:4px 8px;vertical-align:top;text-align:';
407
				if ( $this->video->text_direction === 'rtl' ) {
408
					$html .= 'right" dir="rtl"';
409
				} else {
410
					$html .= 'left" dir="ltr"';
411
				}
412
				if ( isset( $this->video->language ) ) {
413
					$html .= ' lang="' . esc_attr( $this->video->language ) . '"';
414
				}
415
				$html .= '><span style="padding:3px 0;line-height:1.5em;';
416
				if ( isset( $this->video->skin ) && isset( $this->video->skin->background_color ) ) {
417
					$html .= 'background-color:';
418
					if ( $this->video->skin->background_color === 'rgb(0,0,0)' ) {
419
						$html .= 'rgba(0,0,0,0.8)';
420
					} else {
421
						$html .= esc_attr( $this->video->skin->background_color );
422
					}
423
					$html .= ';';
424
				}
425
				$html .= 'color:rgb(255,255,255)">' . esc_html( $this->video->title ) . '</span></div>';
426
			}
427
			$html .= '<img class="videopress-poster" alt="';
428
			if ( ! empty( $this->video->title ) ) {
429
				$html .= esc_attr( $this->video->title ) . '" title="' . esc_attr( sprintf( _x( 'Watch: %s', 'watch a video title', 'jetpack' ), $this->video->title ) );
430
			}
431
			$html .= '" src="' . esc_url( $this->video->poster_frame_uri, array( 'http', 'https' ) ) . '" width="' . $width . '" height="' . $height . '" />' . PHP_EOL;
432
433
			//style a play button hovered over the poster frame
434
			$html .= '<div class="play-button"><span style="z-index:2;display:block;position:absolute;top:50%;left:50%;text-align:center;vertical-align:middle;color:rgb(255,255,255);opacity:0.9;margin:0 0 0 -0.45em;padding:0;line-height:0;font-size:500%;text-shadow:0 0 40px rgba(0,0,0,0.5)">&#9654;</span></div>' . PHP_EOL;
435
436
			// watermark
437
			if ( isset( $this->video->skin ) && isset( $this->video->skin->watermark ) ) {
438
				$html .= '<div style="position:relative;margin-top:-40px;height:25px;margin-bottom:35px;';
439
				if ( $this->video->text_direction === 'rtl' ) {
440
					$html .= 'margin-left:20px;text-align:left;';
441
				} else {
442
					$html .= 'margin-right:20px;text-align:right;';
443
				}
444
				$html .= 'vertical-align:bottom;z-index:3">';
445
				$html .= '<img alt="" src="' . esc_url( $this->video->skin->watermark, array( 'http', 'https' ) ) . '" width="90" height="13" style="background-color:transparent;background-image:none;background-repeat:no-repeat;border:none;margin:0;padding:0"/>';
446
				$html .= '</div>' . PHP_EOL;
447
			}
448
		}
449
450
		$data = array(
451
			'blog' => absint( $this->video->blog_id ),
452
			'post' => absint( $this->video->post_id ),
453
			'duration'=> absint( $this->video->duration ),
454
			'poster' => esc_url_raw( $this->video->poster_frame_uri, array( 'http', 'https' ) ),
455
			'hd' => (bool) $this->options['hd']
456
		);
457
		if ( isset( $this->video->videos ) ) {
458
			if ( isset( $this->video->videos->mp4 ) && isset( $this->video->videos->mp4->url ) ) {
459
				$data['mp4'] = array(
460
					'size' => $this->video->videos->mp4->format,
461
					'uri'  => esc_url_raw( $this->video->videos->mp4->url, array( 'http', 'https' ) )
462
				);
463
			}
464
			if ( isset( $this->video->videos->ogv ) && isset( $this->video->videos->ogv->url ) ) {
465
				$data['ogv'] = array(
466
					'size' => 'std',
467
					'uri'  => esc_url_raw( $this->video->videos->ogv->url, array( 'http', 'https' ) )
468
				);
469
			}
470
		}
471
		$locale = array( 'dir' => $this->video->text_direction );
472
		if ( isset( $this->video->language ) )
473
			$locale['lang'] = $this->video->language;
474
		$data['locale'] = $locale;
475
476
		$guid = $this->video->guid;
477
		$guid_js = json_encode( $guid );
478
		$html .= '<script type="text/javascript">' . PHP_EOL;
479
		$html .= 'jQuery(document).ready(function() {';
480
481
		$html .= 'if ( !jQuery.VideoPress.data[' . json_encode($guid) . '] ) { jQuery.VideoPress.data[' . json_encode($guid) . '] = new Array(); }' . PHP_EOL;
482
		$html .= 'jQuery.VideoPress.data[' . json_encode( $guid ) . '][' . self::$shown[ $guid ] . ']=' . json_encode($data) . ';' . PHP_EOL;
483
484
		$jq_container = json_encode( '#' . $this->video_container_id );
485
		$jq_placeholder = json_encode( '#' . $video_placeholder_id );
486
		$player_config = "{width:{$width},height:{$height},";
487
		if ( isset( $this->options['freedom'] ) && $this->options['freedom'] === true ) {
488
			$player_config .= 'freedom:"true",';
489
		}
490
		$player_config .= 'container:jQuery(' . $jq_container . ')}';
491
492
		$html .= "jQuery({$jq_placeholder}).show(0,function(){jQuery.VideoPress.analytics.impression({$guid_js})});" . PHP_EOL;
493
494
		if ( $age_gate_required ) {
495
			$html .= 'if ( jQuery.VideoPress.support.flash() ) {' . PHP_EOL;
496
			/**
497
			 * @link http://code.google.com/p/swfobject/wiki/api#swfobject.embedSWF(swfUrlStr,_replaceElemIdStr,_widthStr,_height
498
			 */
499
			$html .= 'swfobject.embedSWF(' . implode( ',', array(
500
				'jQuery.VideoPress.video.flash.player_uri',
501
				json_encode( $this->video_container_id ),
502
				json_encode( $width ),
503
				json_encode( $height ),
504
				'jQuery.VideoPress.video.flash.min_version',
505
				'jQuery.VideoPress.video.flash.expressinstall', // attempt to upgrade the Flash player if less than min_version. requires a 310x137 container or larger but we will always try to include
506
				'{guid:' . $guid_js . '}', // FlashVars
507
				'jQuery.VideoPress.video.flash.params',
508
				'null', // no attributes
509
				'jQuery.VideoPress.video.flash.embedCallback' // error fallback
510
			) ) . ');';
511
			$html .= '} else {' . PHP_EOL;
512
			$html .= "if ( jQuery.VideoPress.video.prepare({$guid_js},{$player_config}," . self::$shown[ $guid ] . ') ) {' . PHP_EOL;
513
			$html .= 'if ( jQuery(' . $jq_container . ').data( "player" ) === "flash" ){jQuery.VideoPress.video.play(jQuery(' . json_encode('#' . $this->video_container_id) . '));}else{';
514
			$html .= 'jQuery(' . $jq_placeholder . ').html(' . json_encode( $this->html_age_date() ) . ');' . PHP_EOL;
0 ignored issues
show
Bug introduced by
The method html_age_date() does not exist on VideoPress_Player. Did you maybe mean html_age_gate()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
515
			$html .= 'jQuery(' . json_encode( '#' . $video_placeholder_id . ' input[type=submit]' ) . ').one("click", function(event){jQuery.VideoPress.requirements.isSufficientAge(jQuery(' . $jq_container . '),' . absint( $this->video->age_rating ) . ')});' . PHP_EOL;
516
			$html .= '}}}' . PHP_EOL;
517
		} else {
518
			$html .= "if ( jQuery.VideoPress.video.prepare({$guid_js}, {$player_config}," . self::$shown[ $guid ] . ') ) {' . PHP_EOL;
519
			if ( isset( $this->options['autoplay'] ) && $this->options['autoplay'] === true ) {
520
				$html .= "jQuery.VideoPress.video.play(jQuery({$jq_container}));";
521
			} else {
522
				$html .= 'jQuery(' . $jq_placeholder . ').one("click",function(){jQuery.VideoPress.video.play(jQuery(' . $jq_container . '))});';
523
			}
524
			$html .= '}';
525
526
			// close the jQuery(document).ready() function
527
			$html .= '});';
528
		}
529
		$html .= '</script>' . PHP_EOL;
530
		$html .= '</div>' . PHP_EOL;
531
532
		/*
533
		 * JavaScript required
534
		 */
535
		$noun = __( 'this video', 'jetpack' );
536
		if ( ! $age_gate_required ) {
537
			$vid_type = '';
538
			if ( ( isset( $this->options['freedom'] ) && $this->options['freedom'] === true ) && ( isset( $this->video->videos->ogv ) && isset( $this->video->videos->ogv->url ) ) ) {
539
				$vid_type = 'ogv';
540
			} elseif ( isset( $this->video->videos->mp4 ) && isset( $this->video->videos->mp4->url ) ) {
541
				$vid_type = 'mp4';
542
			} elseif ( isset( $this->video->videos->ogv ) && isset( $this->video->videos->ogv->url ) ) {
543
				$vid_type = 'ogv';
544
			}
545
546
			if ( $vid_type !== '' ) {
547
				$noun = '<a ';
548
				if ( isset( $this->video->language ) ) {
549
					$noun .= 'hreflang="' . esc_attr( $this->video->language ) . '" ';
550
				}
551
				if ( $vid_type === 'mp4' ) {
552
					$noun .= 'type="video/mp4" href="' . esc_url( $this->video->videos->mp4->url, array(
553
							'http',
554
							'https'
555
						) );
556
				} elseif ( $vid_type === 'ogv' ) {
557
					$noun .= 'type="video/ogv" href="' . esc_url( $this->video->videos->ogv->url, array(
558
							'http',
559
							'https'
560
						) );
561
				}
562
				$noun .= '">';
563
				if ( isset( $this->video->title ) ) {
564
					$noun .= esc_html( $this->video->title );
565
				} else {
566
					$noun .= __( 'this video', 'jetpack' );
567
				}
568
				$noun .= '</a>';
569
			} elseif ( ! empty( $this->title ) ) {
0 ignored issues
show
Bug introduced by
The property title does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
570
				$noun = esc_html( $this->title );
571
			}
572
		}
573
		$html .= '<noscript><p>' . sprintf( _x( 'JavaScript required to play %s.', 'Play as in playback or view a movie', 'jetpack' ), $noun ) . '</p></noscript>';
574
575
		return $html;
576
	}
577
578
	function html5_dynamic_next() {
579
		$video_container_id = 'v-' . $this->video->guid;
580
581
		// Must not use iframes for IE11 due to a fullscreen bug
582
		if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && stristr( $_SERVER['HTTP_USER_AGENT'], 'Trident/7.0; rv:11.0' ) ) {
583
			$iframe_embed = false;
584
		} else {
585
586
			/**
587
			 * Filter the VideoPress iframe embed
588
			 *
589
			 * This filter allows you to control whether the videos will be embedded using an iframe.
590
			 * Set this to false in order to use an in-page embed rather than an iframe.
591
			 *
592
			 * @module videopress
593
			 *
594
			 * @since 3.7.0
595
			 *
596
			 * @param boolean $videopress_player_use_iframe
597
			 */
598
			$iframe_embed = apply_filters( 'jetpack_videopress_player_use_iframe', true );
599
		}
600
601
		if ( ! array_key_exists( 'hd', $this->options ) ) {
602
			$this->options['hd'] = (bool) get_option( 'video_player_high_quality', false );
603
		}
604
605
		$videopress_options = array(
606
			'width' => absint( $this->video->calculated_width ),
607
			'height' => absint( $this->video->calculated_height ),
608
		);
609
		foreach ( $this->options as $option => $value ) {
610
			switch ( $option ) {
611
				case 'at':
612
					if ( intval( $value ) ) {
613
						$videopress_options[ $option ] = intval( $value );
614
					}
615
					break;
616
				case 'autoplay':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
617
					$option = 'autoPlay';
618
				case 'hd':
619
				case 'loop':
620
				case 'permalink':
621
					if ( in_array( $value, array( 1, 'true' ) ) ) {
622
						$videopress_options[ $option ] = true;
623
					} elseif ( in_array( $value, array( 0, 'false' ) ) ) {
624
						$videopress_options[ $option ] = false;
625
					}
626
					break;
627
				case 'defaultlangcode':
628
					$option = 'defaultLangCode';
629
					if ( $value ) {
630
						$videopress_options[ $option ] = $value;
631
					}
632
					break;
633
			}
634
		}
635
636
		if ( $iframe_embed ) {
637
			$iframe_url = "https://videopress.com/embed/{$this->video->guid}";
638
639
			foreach ( $videopress_options as $option => $value ) {
640
				if ( ! in_array( $option, array( 'width', 'height' ) ) ) {
641
642
					// add_query_arg ignores false as a value, so replacing it with 0
643
					$iframe_url = add_query_arg( $option, ( false === $value ) ? 0 : $value, $iframe_url );
644
				}
645
			}
646
647
			$js_url = 'https://s0.wp.com/wp-content/plugins/video/assets/js/next/videopress-iframe.js';
648
			$js_url = add_query_arg( 'jetpack_version', JETPACK__VERSION, $js_url );
649
650
			return "<iframe width='" . esc_attr( $videopress_options['width'] )
651
				. "' height='" . esc_attr( $videopress_options['height'] )
652
				. "' src='" . esc_attr( $iframe_url )
653
				. "' frameborder='0' allowfullscreen></iframe>"
654
				. "<script src='" . esc_attr( $js_url ) . "'></script>";
655
656
		} else {
657
			$videopress_options = json_encode( $videopress_options );
658
			$js_url = 'https://s0.wp.com/wp-content/plugins/video/assets/js/next/videopress.js';
659
			$js_url = add_query_arg( 'jetpack_version', JETPACK__VERSION, $js_url );
660
661
			return "<div id='{$video_container_id}'></div>
662
				<script src='{$js_url}'></script>
663
				<script>
664
					videopress('{$this->video->guid}', document.querySelector('#{$video_container_id}'), {$videopress_options});
665
				</script>";
666
		}
667
	}
668
669
	/**
670
	 * Only allow legitimate Flash parameters and their values
671
	 *
672
	 * @since 1.2
673
	 * @link http://kb2.adobe.com/cps/127/tn_12701.html Flash object and embed attributes
674
	 * @link http://kb2.adobe.com/cps/133/tn_13331.html devicefont
675
	 * @link http://kb2.adobe.com/cps/164/tn_16494.html allowscriptaccess
676
	 * @link http://www.adobe.com/devnet/flashplayer/articles/full_screen_mode.html full screen mode
677
	 * @link http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001079.html allownetworking
678
	 * @param array $flash_params Flash parameters expressed in key-value form
679
	 * @return array validated Flash parameters
680
	 */
681
	public static function esc_flash_params( $flash_params ) {
682
		$allowed_params = array(
683
			'swliveconnect' => array('true', 'false'),
684
			'play' => array('true', 'false'),
685
			'loop' => array('true', 'false'),
686
			'menu' => array('true', 'false'),
687
			'quality' => array('low', 'autolow', 'autohigh', 'medium', 'high', 'best'),
688
			'scale' => array('default', 'noborder', 'exactfit', 'noscale'),
689
			'align' => array('l', 'r', 't'),
690
			'salign' => array('l', 'r', 't', 'tl', 'tr', 'bl', 'br'),
691
			'wmode' => array('window', 'opaque', 'transparent','direct','gpu'),
692
			'devicefont' => array('_sans', '_serif', '_typewriter'),
693
			'allowscriptaccess' => array('always', 'samedomain', 'never'),
694
			'allownetworking' => array('all','internal', 'none'),
695
			'seamlesstabbing' => array('true', 'false'),
696
			'allowfullscreen' => array('true', 'false'),
697
			'fullScreenAspectRatio' => array('portrait', 'landscape'),
698
			'base',
699
			'bgcolor',
700
			'flashvars'
701
		);
702
703
		$allowed_params_keys = array_keys( $allowed_params );
704
705
		$filtered_params = array();
706
		foreach( $flash_params as $param => $value ) {
707
			if ( empty( $param ) || empty( $value ) )
708
				continue;
709
			$param = strtolower( $param );
710
			if ( in_array( $param, $allowed_params_keys ) ) {
711
				if ( isset( $allowed_params[ $param ] ) && is_array( $allowed_params[ $param ] ) ) {
712
					$value = strtolower($value);
713
					if ( in_array( $value, $allowed_params[ $param ] ) ) {
714
						$filtered_params[ $param ] = $value;
715
					}
716
				} else {
717
					$filtered_params[ $param ] = $value;
718
				}
719
			}
720
		}
721
722
		/**
723
		 * Flash specifies sameDomain, not samedomain. change from lowercase value for preciseness
724
		 */
725
		if ( isset( $filtered_params['allowscriptaccess'] ) && $filtered_params['allowscriptaccess'] === 'samedomain' ) {
726
			$filtered_params['allowscriptaccess'] = 'sameDomain';
727
		}
728
729
		return $filtered_params;
730
	}
731
732
	/**
733
	 * Filter Flash variables from the response, taking into consideration player options.
734
	 *
735
	 * @since 1.3
736
	 * @return array Flash variable key value pairs
737
	 */
738
	private function get_flash_variables() {
739
		if ( ! isset( $this->video->players->swf->vars ) ) {
740
			return array();
741
		}
742
743
		$flashvars = (array) $this->video->players->swf->vars;
744
		if ( isset( $this->options['autoplay'] ) && $this->options['autoplay'] === true ) {
745
			$flashvars['autoPlay'] = 'true';
746
		}
747
		return $flashvars;
748
	}
749
750
	/**
751
	 * Validate and filter Flash parameters
752
	 *
753
	 * @since 1.3
754
	 * @return array Flash parameters passed through key and value validation
755
	 */
756
	private function get_flash_parameters() {
757
		if ( ! isset( $this->video->players->swf->params ) ) {
758
			return array();
759
		} else {
760
			return self::esc_flash_params(
761
				/**
762
				 * Filters the Flash parameters of the VideoPress player.
763
				 *
764
				 * @module videopress
765
				 *
766
				 * @since 1.2.0
767
				 *
768
				 * @param array $this ->video->players->swf->params Array of swf parameters for the VideoPress flash player.
769
				 */
770
				apply_filters( 'video_flash_params', (array) $this->video->players->swf->params, 10, 1 )
771
			);
772
		}
773
	}
774
775
	/**
776
	 * Flash player markup in a HTML embed element.
777
	 *
778
	 * @since 1.1
779
	 * @link http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#the-embed-element embed element
780
	 * @link http://www.google.com/support/reader/bin/answer.py?answer=70664 Google Reader markup support
781
	 * @return string HTML markup. Embed element with no children
782
	 */
783
	private function flash_embed() {
784
		wp_enqueue_script( 'videopress' );
785
		if ( ! isset( $this->video->players->swf ) || ! isset( $this->video->players->swf->url ) ) {
786
			return '';
787
		}
788
789
		$embed = array(
790
			'id' => $this->video_id,
791
			'src' => esc_url_raw( $this->video->players->swf->url . '&' . http_build_query( $this->get_flash_variables(), null, '&' ) , array( 'http', 'https' ) ),
792
			'type' => 'application/x-shockwave-flash',
793
			'width' => $this->video->calculated_width,
794
			'height' => $this->video->calculated_height
795
		);
796
		if ( isset( $this->video->title ) ) {
797
			$embed['title'] = $this->video->title;
798
		}
799
		$embed = array_merge( $embed, $this->get_flash_parameters() );
800
801
		$html = '<embed';
802
		foreach ( $embed as $attribute => $value ) {
803
			$html .= ' ' . esc_html( $attribute ) . '="' . esc_attr( $value ) . '"';
804
		}
805
		$html .= '></embed>';
806
		return $html;
807
	}
808
809
	/**
810
	 * Double-baked Flash object markup for Internet Explorer and more standards-friendly consuming agents.
811
	 *
812
	 * @since 1.1
813
	 * @return HTML markup. Object and children.
814
	 */
815
	private function flash_object() {
816
		wp_enqueue_script( 'videopress' );
817
		if ( ! isset( $this->video->players->swf ) || ! isset( $this->video->players->swf->url ) ) {
818
			return '';
819
		}
820
821
		$thumbnail_html = '<img alt="';
822
		if ( isset( $this->video->title ) ) {
823
			$thumbnail_html .= esc_attr( $this->video->title );
824
		}
825
		$thumbnail_html .= '" src="' . esc_url( $this->video->poster_frame_uri, array( 'http', 'https' ) ) . '" width="' . $this->video->calculated_width . '" height="' . $this->video->calculated_height . '" />';
826
		$flash_vars = esc_attr( http_build_query( $this->get_flash_variables(), null, '&' ) );
827
		$flash_params = '';
828
		foreach ( $this->get_flash_parameters() as $attribute => $value ) {
829
			$flash_params .= '<param name="' . esc_attr( $attribute ) . '" value="' . esc_attr( $value ) . '" />';
830
		}
831
		$flash_help = sprintf( __( 'This video requires <a rel="nofollow" href="%s">Adobe Flash</a> for playback.', 'jetpack' ), 'http://www.adobe.com/go/getflashplayer');
832
		$flash_player_url = esc_url( $this->video->players->swf->url, array( 'http', 'https' ) );
833
		$description = '';
834
		if ( isset( $this->video->title ) ) {
835
			$standby = $this->video->title;
836
			$description = '<p><strong>' . esc_html( $this->video->title ) . '</strong></p>';
837
		} else {
838
			$standby = __( 'Loading video...', 'jetpack' );
839
		}
840
		$standby = ' standby="' . esc_attr( $standby ) . '"';
841
		return <<<OBJECT
842
<script type="text/javascript">if(typeof swfobject!=="undefined"){swfobject.registerObject("{$this->video_id}", "{$this->video->players->swf->version}");}</script>
843
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="{$this->video->calculated_width}" height="{$this->video->calculated_height}" id="{$this->video_id}"{$standby}>
844
	<param name="movie" value="{$flash_player_url}" />
845
	{$flash_params}
846
	<param name="flashvars" value="{$flash_vars}" />
847
	<!--[if !IE]>-->
848
	<object type="application/x-shockwave-flash" data="{$flash_player_url}" width="{$this->video->calculated_width}" height="{$this->video->calculated_height}"{$standby}>
849
		{$flash_params}
850
		<param name="flashvars" value="{$flash_vars}" />
851
	<!--<![endif]-->
852
	{$thumbnail_html}{$description}<p class="robots-nocontent">{$flash_help}</p>
853
	<!--[if !IE]>-->
854
	</object>
855
	<!--<![endif]-->
856
</object>
857
OBJECT;
858
	}
859
}
860