Completed
Push — fix/videopress-missing-from-se... ( 60564b )
by
unknown
22:41 queued 12:31
created

modules/videopress/class.videopress-player.php (1 issue)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
		self::$shown[ $guid ]++;
59
60
		$this->video_container_id = 'v-' . $guid . '-' . self::$shown[ $guid ];
61
		$this->video_id = $this->video_container_id . '-video';
62
63
		if ( is_array( $options ) )
64
			$this->options = $options;
65
		else
66
			$this->options = array();
67
68
		// set up the video
69
		$cache_key = null;
70
71
		// disable cache in debug mode
72
		if ( defined('WP_DEBUG') && WP_DEBUG === true ) {
73
			$cached_video = null;
74
		} else {
75
			$cache_key_pieces = array( 'video' );
76
77
			if ( is_multisite() && is_subdomain_install() )
78
				$cache_key_pieces[] = get_current_blog_id();
79
80
			$cache_key_pieces[] = $guid;
81
			if ( $maxwidth > 0 )
82
				$cache_key_pieces[] = $maxwidth;
83
			if ( is_ssl() )
84
				$cache_key_pieces[] = 'ssl';
85
			$cache_key = implode( '-', $cache_key_pieces );
86
			unset( $cache_key_pieces );
87
			$cached_video = wp_cache_get( $cache_key, 'video' );
88
		}
89
		if ( empty( $cached_video ) ) {
90
			$video = new VideoPress_Video( $guid, $maxwidth );
91
			if ( empty( $video ) ) {
92
				return;
93
			} elseif ( isset( $video->error ) ) {
94
				$this->video = $video->error;
0 ignored issues
show
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...
95
				return;
96
			} elseif ( is_wp_error( $video ) ) {
97
				$this->video = $video;
98
				return;
99
			}
100
101
			$this->video = $video;
102
			unset( $video );
103
104
			if ( ! defined( 'WP_DEBUG' ) || WP_DEBUG !== true ) {
105
				$expire = 3600;
106
				if ( isset( $video->expires ) && is_int( $video->expires ) ) {
107
					$expires_diff = time() - $video->expires;
108
					if ( $expires_diff > 0 && $expires_diff < 86400 ) // allowed range: 1 second to 1 day
109
						$expire = $expires_diff;
110
					unset( $expires_diff );
111
				}
112
113
				wp_cache_set( $cache_key, serialize( $this->video ), 'video', $expire );
114
				unset( $expire );
115
			}
116
		} else {
117
			$this->video = unserialize( $cached_video );
118
		}
119
		unset( $cache_key );
120
		unset( $cached_video );
121
	}
122
123
	/**
124
	 * Wrap output in a VideoPress player container
125
	 *
126
	 * @since 1.3
127
	 * @var string $content HTML string
128
	 * @return string HTML string or blank string if nothing to wrap
129
	 */
130
	private function html_wrapper( $content ) {
131
		if ( empty( $content ) )
132
			return '';
133
		else
134
			return '<div id="' . esc_attr( $this->video_container_id ) . '" class="video-player">' . $content . '</div>';
135
	}
136
137
	/**
138
	 * Output content suitable for a feed reader displaying RSS or Atom feeds
139
	 * We do not display error messages in the feed view due to caching concerns.
140
	 * Flash content presented using <embed> markup for feed reader compatibility.
141
	 *
142
	 * @since 1.3
143
	 * @return string HTML string or empty string if error
144
	 */
145
	public function asXML() {
146
		if ( empty( $this->video ) || is_wp_error( $this->video ) ) {
147
			return '';
148
		}
149
150
		if ( isset( $this->options['force_flash'] ) && true === $this->options['force_flash'] ) {
151
			$content = $this->flash_embed();
152
153
		} else {
154
			$content = $this->html5_static();
155
		}
156
157
		return $this->html_wrapper( $content );
158
	}
159
160
	/**
161
	 * Video player markup for best matching the current request and publisher options
162
	 * @since 1.3
163
	 * @return string HTML markup string or empty string if no video property found
164
	 */
165
	public function asHTML() {
166
		if ( empty( $this->video ) ) {
167
			$content = '';
168
169
		} elseif ( is_wp_error( $this->video ) ) {
170
			$content = $this->error_message( $this->video );
171
172
		} elseif ( isset( $this->options['force_flash'] ) && true === $this->options['force_flash'] ) {
173
			$content = $this->flash_object();
174
175
		} elseif ( isset( $this->video->restricted_embed ) && true === $this->video->restricted_embed ) {
176
177
			if ( $this->options['forcestatic'] ) {
178
				$content = $this->flash_object();
179
180
			} else {
181
				$content = $this->html5_dynamic();
182
			}
183
184
		} elseif ( isset( $this->options['freedom'] ) && true === $this->options['freedom'] ) {
185
			$content = $this->html5_static();
186
187
		} else {
188
			$content = $this->html5_dynamic();
189
		}
190
191
		return $this->html_wrapper( $content );
192
	}
193
194
	/**
195
	 * Display an error message to users capable of doing something about the error
196
	 *
197
	 * @since 1.3
198
	 * @uses current_user_can() to test if current user has edit_posts capability
199
	 * @var WP_Error $error WordPress error
200
	 * @return string HTML string
201
	 */
202
	private function error_message( $error ) {
203
		if ( ! current_user_can( 'edit_posts' ) || empty( $error ) )
204
			return '';
205
206
		$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">';
207
		$html .= '<h1 style="font-size:180%;font-style:bold;line-height:130%;text-decoration:underline">' . esc_html( sprintf( __( '%s Error', 'jetpack' ), 'VideoPress' ) ) . '</h1>';
208
		foreach( $error->get_error_messages() as $message ) {
209
			$html .= $message;
210
		}
211
		$html .= '</div>';
212
		return $html;
213
	}
214
215
	/**
216
	 * Rating agencies and industry associations require a potential viewer verify his or her age before a video or its poster frame are displayed.
217
	 * Content rated for audiences 17 years of age or older requires such verification across multiple rating agencies and industry associations
218
	 *
219
	 * @since 1.3
220
	 * @return bool true if video requires the viewer verify he or she is 17 years of age or older
221
	 */
222
	private function age_gate_required() {
223
		if ( isset( $this->video->age_rating ) && $this->video->age_rating >= 17 )
224
			return true;
225
		else
226
			return false;
227
	}
228
229
	/**
230
	 * Select a date of birth using HTML form elements.
231
	 *
232
	 * @since 1.5
233
	 * @return string HTML markup
234
	 */
235
	private function html_age_gate() {
236
		global $wp_locale;
237
		$text_align = 'left';
238
		if ( $this->video->text_direction === 'rtl' )
239
			$text_align = 'right';
240
241
		$html = '<div class="videopress-age-gate" style="margin:0 60px">';
242
		$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>';
243
		$html .= '<fieldset id="birthday" style="border:0 none;text-align:' . $text_align . ';padding:0;">';
244
		$inputs_style = 'border:1px solid #444;margin-';
245
		if ( $this->video->text_direction === 'rtl' )
246
			$inputs_style .= 'left';
247
		else
248
			$inputs_style .= 'right';
249
		$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';
250
251
		/**
252
		 * Display a list of months in the Gregorian calendar.
253
		 * Set values to 0-based to match JavaScript Date.
254
		 * @link https://developer.mozilla.org/en/JavaScript/Reference/global_objects/date Mozilla JavaScript Reference: Date
255
		 */
256
		$html .= '<select name="month" style="' . $inputs_style . '">';
257
258
		for( $i=0; $i<12; $i++ ) {
259
			$html .= '<option value="' . esc_attr( $i ) . '">' . esc_html( $wp_locale->get_month( $i + 1 ) )  . '</option>';
260
		}
261
		$html .= '</select>';
262
263
		/**
264
		 * todo: numdays variance by month
265
		 */
266
		$html .= '<select name="day" style="' . $inputs_style . '">';
267
		for ( $i=1; $i<32; $i++ ) {
268
			$html .= '<option>' . $i . '</option>';
269
		}
270
		$html .= '</select>';
271
272
		/**
273
		 * Current record for human life is 122. Go back 130 years and no one is left out.
274
		 * Don't ask infants younger than 2 for their birthday
275
		 * Default to 13
276
		 */
277
		$html .= '<select name="year" style="' . $inputs_style . '">';
278
		$start_year = date('Y') - 2;
279
		$default_year = $start_year - 11;
280
		$end_year = $start_year - 128;
281
		for ( $year=$start_year; $year>$end_year; $year-- ) {
282
			$html .= '<option';
283
			if ( $year === $default_year )
284
				$html .= ' selected="selected"';
285
			$html .= '>' . $year . '</option>';
286
		}
287
		unset( $start_year );
288
		unset( $default_year );
289
		unset( $end_year );
290
		$html .= '</select>';
291
292
		$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" />';
293
294
		$html .= '</fieldset>';
295
		$html .= '<p style="padding-top:20px;padding-bottom:60px;text-align:' . $text_align . ';"><a rel="nofollow" href="http://videopress.com/" target="_blank" style="color:rgb(128,128,128);text-decoration:underline;font-size:15px">' . __( 'More information', 'jetpack' ) . '</a></p>';
296
297
		$html .= '</div>';
298
		return $html;
299
	}
300
301
	/**
302
	 * Return HTML5 video static markup for the given video parameters.
303
	 * Use default browser player controls.
304
	 * No Flash fallback.
305
	 *
306
	 * @since 1.2
307
	 * @link http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html HTML5 video
308
	 * @return string HTML5 video element and children
309
	 */
310
	private function html5_static() {
311
		wp_enqueue_script( 'videopress' );
312
		$thumbnail = esc_url( $this->video->poster_frame_uri );
313
		$html = "<video id=\"{$this->video_id}\" width=\"{$this->video->calculated_width}\" height=\"{$this->video->calculated_height}\" poster=\"$thumbnail\" controls=\"true\"";
314 View Code Duplication
		if ( isset( $this->options['autoplay'] ) && $this->options['autoplay'] === true )
315
			$html .= ' autoplay="true"';
316
		else
317
			$html .= ' preload="metadata"';
318
		if ( isset( $this->video->text_direction ) )
319
			$html .= ' dir="' . esc_attr( $this->video->text_direction ) . '"';
320 View Code Duplication
		if ( isset( $this->video->language ) )
321
			$html .= ' lang="' . esc_attr( $this->video->language ) . '"';
322
		$html .= '>';
323
		if ( ! isset( $this->options['freedom'] ) || $this->options['freedom'] === false ) {
324
			$mp4 = $this->video->videos->mp4->url;
325 View Code Duplication
			if ( ! empty( $mp4 ) )
326
				$html .= '<source src="' . esc_url( $mp4 ) . '" type="video/mp4; codecs=&quot;' . esc_attr( $this->video->videos->mp4->codecs ) . '&quot;" />';
327
			unset( $mp4 );
328
		}
329
330
		if ( isset( $this->video->videos->ogv ) ) {
331
			$ogg = $this->video->videos->ogv->url;
332 View Code Duplication
			if ( ! empty( $ogg ) ) {
333
				$html .= '<source src="' . esc_url( $ogg ) . '" type="video/ogg; codecs=&quot;' . esc_attr( $this->video->videos->ogv->codecs ) . '&quot;" />';
334
			}
335
336
			unset( $ogg );
337
		}
338
339
		$html .= '<div><img alt="';
340
		if ( isset( $this->video->title ) )
341
			$html .= esc_attr( $this->video->title );
342
		$html .= '" src="' . $thumbnail . '" width="' . $this->video->calculated_width . '" height="' . $this->video->calculated_height . '" /></div>';
343
		if ( isset( $this->options['freedom'] ) && $this->options['freedom'] === true )
344
			$html .= '<p class="robots-nocontent">' . sprintf( __( 'You do not have sufficient <a rel="nofollow" href="%s" target="_blank">freedom levels</a> to view this video. Support free software and upgrade.', 'jetpack' ), 'http://www.gnu.org/philosophy/free-sw.html' ) . '</p>';
345
		elseif ( isset( $this->video->title ) )
346
			$html .= '<p>' . esc_html( $this->video->title ) . '</p>';
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
		$html .= ';display:none;cursor:pointer !important;position:relative;';
395
		if ( isset( $this->video->skin ) && isset( $this->video->skin->background_color ) )
396
			$html .= 'background-color:' . esc_attr( $this->video->skin->background_color ) . ';';
397
		$html .= 'font-family: \'Helvetica Neue\',Arial,Helvetica,\'Nimbus Sans L\',sans-serif;font-weight:bold;font-size:18px">' . PHP_EOL;
398
399
		/**
400
		 * Do not display a poster frame, title, or any other content hints for mature content.
401
		 */
402
		if ( ! $age_gate_required ) {
403
			if ( ! empty( $this->video->title ) ) {
404
				$html .= '<div class="videopress-title" style="display:inline;position:absolute;margin:20px 20px 0 20px;padding:4px 8px;vertical-align:top;text-align:';
405
				if ( $this->video->text_direction === 'rtl' )
406
					$html .= 'right" dir="rtl"';
407
				else
408
					$html .= 'left" dir="ltr"';
409 View Code Duplication
				if ( isset( $this->video->language ) )
410
					$html .= ' lang="' . esc_attr( $this->video->language ) . '"';
411
				$html .= '><span style="padding:3px 0;line-height:1.5em;';
412
				if ( isset( $this->video->skin ) && isset( $this->video->skin->background_color ) ) {
413
					$html .= 'background-color:';
414
					if ( $this->video->skin->background_color === 'rgb(0,0,0)' )
415
						$html .= 'rgba(0,0,0,0.8)';
416
					else
417
						$html .= esc_attr( $this->video->skin->background_color );
418
					$html .= ';';
419
				}
420
				$html .= 'color:rgb(255,255,255)">' . esc_html( $this->video->title ) . '</span></div>';
421
			}
422
			$html .= '<img class="videopress-poster" alt="';
423
			if ( ! empty( $this->video->title ) )
424
				$html .= esc_attr( $this->video->title ) . '" title="' . esc_attr( sprintf( _x( 'Watch: %s', 'watch a video title', 'jetpack' ), $this->video->title ) );
425
			$html .= '" src="' . esc_url( $this->video->poster_frame_uri, array( 'http', 'https' ) ) . '" width="' . $width . '" height="' . $height . '" />' . PHP_EOL;
426
427
			//style a play button hovered over the poster frame
428
			$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;
429
430
			// watermark
431
			if ( isset( $this->video->skin ) && isset( $this->video->skin->watermark ) ) {
432
				$html .= '<div style="position:relative;margin-top:-40px;height:25px;margin-bottom:35px;';
433
				if ( $this->video->text_direction === 'rtl' )
434
					$html .= 'margin-left:20px;text-align:left;';
435
				else
436
					$html .= 'margin-right:20px;text-align:right;';
437
				$html .= 'vertical-align:bottom;z-index:3">';
438
				$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"/>';
439
				$html .= '</div>' . PHP_EOL;
440
			}
441
		}
442
443
		$data = array(
444
			'blog' => absint( $this->video->blog_id ),
445
			'post' => absint( $this->video->post_id ),
446
			'duration'=> absint( $this->video->duration ),
447
			'poster' => esc_url_raw( $this->video->poster_frame_uri, array( 'http', 'https' ) ),
448
			'hd' => (bool) $this->options['hd']
449
		);
450
		if ( isset( $this->video->videos ) ) {
451
			if ( isset( $this->video->videos->mp4 ) && isset( $this->video->videos->mp4->url ) )
452
				$data['mp4'] = array( 'size' => $this->video->videos->mp4->format, 'uri' => esc_url_raw( $this->video->videos->mp4->url, array( 'http', 'https' ) ) );
453
			if ( isset( $this->video->videos->ogv ) && isset( $this->video->videos->ogv->url ) )
454
				$data['ogv'] = array( 'size' => 'std', 'uri' => esc_url_raw( $this->video->videos->ogv->url, array( 'http', 'https' ) ) );
455
		}
456
		$locale = array( 'dir' => $this->video->text_direction );
457
		if ( isset( $this->video->language ) )
458
			$locale['lang'] = $this->video->language;
459
		$data['locale'] = $locale;
460
		unset( $locale );
461
462
		$guid = $this->video->guid;
463
		$guid_js = json_encode( $guid );
464
		$html .= '<script type="text/javascript">' . PHP_EOL;
465
		$html .= 'jQuery(document).ready(function() {';
466
467
		$html .= 'if ( !jQuery.VideoPress.data[' . json_encode($guid) . '] ) { jQuery.VideoPress.data[' . json_encode($guid) . '] = new Array(); }' . PHP_EOL;
468
		$html .= 'jQuery.VideoPress.data[' . json_encode( $guid ) . '][' . self::$shown[ $guid ] . ']=' . json_encode($data) . ';' . PHP_EOL;
469
		unset( $data );
470
471
		$jq_container = json_encode( '#' . $this->video_container_id );
472
		$jq_placeholder = json_encode( '#' . $video_placeholder_id );
473
		$player_config = "{width:{$width},height:{$height},";
474
		if ( isset( $this->options['freedom'] ) && $this->options['freedom'] === true )
475
			$player_config .= 'freedom:"true",';
476
		$player_config .= 'container:jQuery(' . $jq_container . ')}';
477
478
		$html .= "jQuery({$jq_placeholder}).show(0,function(){jQuery.VideoPress.analytics.impression({$guid_js})});" . PHP_EOL;
479
480
		if ( $age_gate_required ) {
481
			$html .= 'if ( jQuery.VideoPress.support.flash() ) {' . PHP_EOL;
482
			/**
483
			 * @link http://code.google.com/p/swfobject/wiki/api#swfobject.embedSWF(swfUrlStr,_replaceElemIdStr,_widthStr,_height
484
			 */
485
			$html .= 'swfobject.embedSWF(' . implode( ',', array(
486
				'jQuery.VideoPress.video.flash.player_uri',
487
				json_encode( $this->video_container_id ),
488
				json_encode( $width ),
489
				json_encode( $height ),
490
				'jQuery.VideoPress.video.flash.min_version',
491
				'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
492
				'{guid:' . $guid_js . '}', // FlashVars
493
				'jQuery.VideoPress.video.flash.params',
494
				'null', // no attributes
495
				'jQuery.VideoPress.video.flash.embedCallback' // error fallback
496
			) ) . ');';
497
			$html .= '} else {' . PHP_EOL;
498
			$html .= "if ( jQuery.VideoPress.video.prepare({$guid_js},{$player_config}," . self::$shown[ $guid ] . ') ) {' . PHP_EOL;
499
			$html .= 'if ( jQuery(' . $jq_container . ').data( "player" ) === "flash" ){jQuery.VideoPress.video.play(jQuery(' . json_encode('#' . $this->video_container_id) . '));}else{';
500
			$html .= 'jQuery(' . $jq_placeholder . ').html(' . json_encode( $this->html_age_date() ) . ');' . PHP_EOL;
501
			$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;
502
			$html .= '}}}' . PHP_EOL;
503
		} else {
504
			$html .= "if ( jQuery.VideoPress.video.prepare({$guid_js}, {$player_config}," . self::$shown[ $guid ] . ') ) {' . PHP_EOL;
505
			if ( isset( $this->options['autoplay'] ) && $this->options['autoplay'] === true )
506
				$html .= "jQuery.VideoPress.video.play(jQuery({$jq_container}));";
507
			else
508
				$html .= 'jQuery(' . $jq_placeholder .  ').one("click",function(){jQuery.VideoPress.video.play(jQuery(' . $jq_container . '))});';
509
			$html .= '}';
510
511
			// close the jQuery(document).ready() function
512
			$html .= '});';
513
		}
514
		$html .= '</script>' . PHP_EOL;
515
		$html .= '</div>' . PHP_EOL;
516
517
		/*
518
		 * JavaScript required
519
		 */
520
		$noun = __( 'this video', 'jetpack' );
521
		if ( ! $age_gate_required ) {
522
			$vid_type = '';
523
			if ( ( isset( $this->options['freedom'] ) && $this->options['freedom'] === true ) && ( isset( $this->video->videos->ogv ) && isset( $this->video->videos->ogv->url ) ) )
524
				$vid_type = 'ogv';
525 View Code Duplication
			elseif ( isset( $this->video->videos->mp4 ) && isset( $this->video->videos->mp4->url ) )
526
				$vid_type = 'mp4';
527 View Code Duplication
			elseif ( isset( $this->video->videos->ogv ) && isset( $this->video->videos->ogv->url ) )
528
				$vid_type = 'ogv';
529
530
			if ( $vid_type !== '' ) {
531
				$noun = '<a ';
532 View Code Duplication
				if ( isset( $this->video->language ) )
533
					$noun .= 'hreflang="' . esc_attr( $this->video->language ) . '" ';
534
				if ( $vid_type === 'mp4' )
535
					$noun .= 'type="video/mp4" href="' . esc_url( $this->video->videos->mp4->url, array( 'http', 'https' ) );
536
				elseif ( $vid_type === 'ogv' )
537
					$noun .= 'type="video/ogv" href="' . esc_url( $this->video->videos->ogv->url, array( 'http', 'https' ) );
538
				$noun .= '">';
539
				if ( isset( $this->video->title ) )
540
					$noun .= esc_html( $this->video->title );
541
				else
542
					$noun .= __( 'this video', 'jetpack' );
543
				$noun .= '</a>';
544
			} elseif ( ! empty( $this->title ) ) {
545
				$noun = esc_html( $this->title );
546
			}
547
			unset( $vid_type );
548
		}
549
		$html .= '<noscript><p>' . sprintf( _x( 'JavaScript required to play %s.', 'Play as in playback or view a movie', 'jetpack' ), $noun ) . '</p></noscript>';
550
551
		return $html;
552
	}
553
554
	function html5_dynamic_next() {
555
		$video_container_id = 'v-' . $this->video->guid;
556
557
		// Must not use iframes for IE11 due to a fullscreen bug
558
		if ( isset( $_SERVER['HTTP_USER_AGENT'] ) && stristr( $_SERVER['HTTP_USER_AGENT'], 'Trident/7.0; rv:11.0' ) ) {
559
			$iframe_embed = false;
560
		} else {
561
562
			/**
563
			 * Filter the VideoPress iframe embed
564
			 *
565
			 * This filter allows you to control whether the videos will be embedded using an iframe.
566
			 * Set this to false in order to use an in-page embed rather than an iframe.
567
			 *
568
			 * @module videopress
569
			 *
570
			 * @since 3.7.0
571
			 *
572
			 * @param boolean $videopress_player_use_iframe
573
			 */
574
			$iframe_embed = apply_filters( 'jetpack_videopress_player_use_iframe', true );
575
		}
576
577
		if ( ! array_key_exists( 'hd', $this->options ) ) {
578
			$this->options['hd'] = (bool) get_option( 'video_player_high_quality', false );
579
		}
580
581
		$videopress_options = array(
582
			'width' => absint( $this->video->calculated_width ),
583
			'height' => absint( $this->video->calculated_height ),
584
		);
585
		foreach ( $this->options as $option => $value ) {
586
			switch ( $option ) {
587
				case 'at':
588
					if ( intval( $value ) ) {
589
						$videopress_options[ $option ] = intval( $value );
590
					}
591
					break;
592
				case 'autoplay':
593
					$option = 'autoPlay';
594
				case 'hd':
595
				case 'loop':
596
				case 'permalink':
597
					if ( in_array( $value, array( 1, 'true' ) ) ) {
598
						$videopress_options[ $option ] = true;
599
					} elseif ( in_array( $value, array( 0, 'false' ) ) ) {
600
						$videopress_options[ $option ] = false;
601
					}
602
					break;
603
				case 'defaultlangcode':
604
					$option = 'defaultLangCode';
605
					if ( $value ) {
606
						$videopress_options[ $option ] = $value;
607
					}
608
					break;
609
			}
610
		}
611
612
		if ( $iframe_embed ) {
613
			$iframe_url = "https://videopress.com/embed/{$this->video->guid}";
614
615
			foreach ( $videopress_options as $option => $value ) {
616
				if ( ! in_array( $option, array( 'width', 'height' ) ) ) {
617
618
					// add_query_arg ignores false as a value, so replacing it with 0
619
					$iframe_url = add_query_arg( $option, ( false === $value ) ? 0 : $value, $iframe_url );
620
				}
621
			}
622
623
			$js_url = 'https://s0.wp.com/wp-content/plugins/video/assets/js/next/videopress-iframe.js';
624
			$js_url = add_query_arg( 'jetpack_version', JETPACK__VERSION, $js_url );
625
626
			return "<iframe width='" . esc_attr( $videopress_options['width'] )
627
				. "' height='" . esc_attr( $videopress_options['height'] )
628
				. "' src='" . esc_attr( $iframe_url )
629
				. "' frameborder='0' allowfullscreen></iframe>"
630
				. "<script src='" . esc_attr( $js_url ) . "'></script>";
631
632
		} else {
633
			$videopress_options = json_encode( $videopress_options );
634
			$js_url = 'https://s0.wp.com/wp-content/plugins/video/assets/js/next/videopress.js';
635
			$js_url = add_query_arg( 'jetpack_version', JETPACK__VERSION, $js_url );
636
637
			return "<div id='{$video_container_id}'></div>
638
				<script src='{$js_url}'></script>
639
				<script>
640
					videopress('{$this->video->guid}', document.querySelector('#{$video_container_id}'), {$videopress_options});
641
				</script>";
642
		}
643
	}
644
645
	/**
646
	 * Only allow legitimate Flash parameters and their values
647
	 *
648
	 * @since 1.2
649
	 * @link http://kb2.adobe.com/cps/127/tn_12701.html Flash object and embed attributes
650
	 * @link http://kb2.adobe.com/cps/133/tn_13331.html devicefont
651
	 * @link http://kb2.adobe.com/cps/164/tn_16494.html allowscriptaccess
652
	 * @link http://www.adobe.com/devnet/flashplayer/articles/full_screen_mode.html full screen mode
653
	 * @link http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00001079.html allownetworking
654
	 * @param array $flash_params Flash parameters expressed in key-value form
655
	 * @return array validated Flash parameters
656
	 */
657
	public static function esc_flash_params( $flash_params ) {
658
		$allowed_params = array(
659
			'swliveconnect' => array('true', 'false'),
660
			'play' => array('true', 'false'),
661
			'loop' => array('true', 'false'),
662
			'menu' => array('true', 'false'),
663
			'quality' => array('low', 'autolow', 'autohigh', 'medium', 'high', 'best'),
664
			'scale' => array('default', 'noborder', 'exactfit', 'noscale'),
665
			'align' => array('l', 'r', 't'),
666
			'salign' => array('l', 'r', 't', 'tl', 'tr', 'bl', 'br'),
667
			'wmode' => array('window', 'opaque', 'transparent','direct','gpu'),
668
			'devicefont' => array('_sans', '_serif', '_typewriter'),
669
			'allowscriptaccess' => array('always', 'samedomain', 'never'),
670
			'allownetworking' => array('all','internal', 'none'),
671
			'seamlesstabbing' => array('true', 'false'),
672
			'allowfullscreen' => array('true', 'false'),
673
			'fullScreenAspectRatio' => array('portrait', 'landscape'),
674
			'base',
675
			'bgcolor',
676
			'flashvars'
677
		);
678
679
		$allowed_params_keys = array_keys( $allowed_params );
680
681
		$filtered_params = array();
682
		foreach( $flash_params as $param=>$value ) {
683
			if ( empty($param) || empty($value) )
684
				continue;
685
			$param = strtolower($param);
686
			if ( in_array($param, $allowed_params_keys) ) {
687
				if ( isset( $allowed_params[$param] ) && is_array( $allowed_params[$param] ) ) {
688
					$value = strtolower($value);
689
					if ( in_array( $value, $allowed_params[$param] ) )
690
						$filtered_params[$param] = $value;
691
				} else {
692
					$filtered_params[$param] = $value;
693
				}
694
			}
695
		}
696
		unset( $allowed_params_keys );
697
698
		/**
699
		 * Flash specifies sameDomain, not samedomain. change from lowercase value for preciseness
700
		 */
701
		if ( isset( $filtered_params['allowscriptaccess'] ) && $filtered_params['allowscriptaccess'] === 'samedomain' )
702
			$filtered_params['allowscriptaccess'] = 'sameDomain';
703
704
		return $filtered_params;
705
	}
706
707
	/**
708
	 * Filter Flash variables from the response, taking into consideration player options.
709
	 *
710
	 * @since 1.3
711
	 * @return array Flash variable key value pairs
712
	 */
713
	private function get_flash_variables() {
714
		if ( ! isset( $this->video->players->swf->vars ) )
715
			return array();
716
717
		$flashvars = (array) $this->video->players->swf->vars;
718 View Code Duplication
		if ( isset( $this->options['autoplay'] ) && $this->options['autoplay'] === true )
719
			$flashvars['autoPlay'] = 'true';
720
		return $flashvars;
721
	}
722
723
	/**
724
	 * Validate and filter Flash parameters
725
	 *
726
	 * @since 1.3
727
	 * @return array Flash parameters passed through key and value validation
728
	 */
729
	private function get_flash_parameters() {
730
		if ( ! isset( $this->video->players->swf->params ) )
731
			return array();
732
		else
733
			return self::esc_flash_params(
734
				/**
735
				 * Filters the Flash parameters of the VideoPress player.
736
				 *
737
				 * @module videopress
738
				 *
739
				 * @since 1.2.0
740
				 *
741
				 * @param array $this->video->players->swf->params Array of swf parameters for the VideoPress flash player.
742
				 */
743
				apply_filters( 'video_flash_params', (array) $this->video->players->swf->params, 10, 1 )
744
			);
745
	}
746
747
	/**
748
	 * Flash player markup in a HTML embed element.
749
	 *
750
	 * @since 1.1
751
	 * @link http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#the-embed-element embed element
752
	 * @link http://www.google.com/support/reader/bin/answer.py?answer=70664 Google Reader markup support
753
	 * @return string HTML markup. Embed element with no children
754
	 */
755
	private function flash_embed() {
756
		wp_enqueue_script( 'videopress' );
757 View Code Duplication
		if ( ! isset( $this->video->players->swf ) || ! isset( $this->video->players->swf->url ) )
758
			return '';
759
760
		$embed = array(
761
			'id' => $this->video_id,
762
			'src' => esc_url_raw( $this->video->players->swf->url . '&' . http_build_query( $this->get_flash_variables(), null, '&' ) , array( 'http', 'https' ) ),
763
			'type' => 'application/x-shockwave-flash',
764
			'width' => $this->video->calculated_width,
765
			'height' => $this->video->calculated_height
766
		);
767
		if ( isset( $this->video->title ) )
768
			$embed['title'] = $this->video->title;
769
		$embed = array_merge( $embed, $this->get_flash_parameters() );
770
771
		$html = '<embed';
772
		foreach ( $embed as $attribute => $value ) {
773
			$html .= ' ' . esc_html( $attribute ) . '="' . esc_attr( $value ) . '"';
774
		}
775
		unset( $embed );
776
		$html .= '></embed>';
777
		return $html;
778
	}
779
780
	/**
781
	 * Double-baked Flash object markup for Internet Explorer and more standards-friendly consuming agents.
782
	 *
783
	 * @since 1.1
784
	 * @return HTML markup. Object and children.
785
	 */
786
	private function flash_object() {
787
		wp_enqueue_script( 'videopress' );
788 View Code Duplication
		if ( ! isset( $this->video->players->swf ) || ! isset( $this->video->players->swf->url ) )
789
			return '';
790
791
		$thumbnail_html = '<img alt="';
792
		if ( isset( $this->video->title ) )
793
			$thumbnail_html .= esc_attr( $this->video->title );
794
		$thumbnail_html .= '" src="' . esc_url( $this->video->poster_frame_uri, array( 'http', 'https' ) ) . '" width="' . $this->video->calculated_width . '" height="' . $this->video->calculated_height . '" />';
795
		$flash_vars = esc_attr( http_build_query( $this->get_flash_variables(), null, '&' ) );
796
		$flash_params = '';
797
		foreach ( $this->get_flash_parameters() as $attribute => $value ) {
798
			$flash_params .= '<param name="' . esc_attr( $attribute ) . '" value="' . esc_attr( $value ) . '" />';
799
		}
800
		$flash_help = sprintf( __( 'This video requires <a rel="nofollow" href="%s" target="_blank">Adobe Flash</a> for playback.', 'jetpack' ), 'http://www.adobe.com/go/getflashplayer');
801
		$flash_player_url = esc_url( $this->video->players->swf->url, array( 'http', 'https' ) );
802
		$description = '';
803
		if ( isset( $this->video->title ) ) {
804
			$standby = $this->video->title;
805
			$description = '<p><strong>' . esc_html( $this->video->title ) . '</strong></p>';
806
		} else {
807
			$standby = __( 'Loading video...', 'jetpack' );
808
		}
809
		$standby = ' standby="' . esc_attr( $standby ) . '"';
810
		return <<<OBJECT
811
<script type="text/javascript">if(typeof swfobject!=="undefined"){swfobject.registerObject("{$this->video_id}", "{$this->video->players->swf->version}");}</script>
812
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="{$this->video->calculated_width}" height="{$this->video->calculated_height}" id="{$this->video_id}"{$standby}>
813
	<param name="movie" value="{$flash_player_url}" />
814
	{$flash_params}
815
	<param name="flashvars" value="{$flash_vars}" />
816
	<!--[if !IE]>-->
817
	<object type="application/x-shockwave-flash" data="{$flash_player_url}" width="{$this->video->calculated_width}" height="{$this->video->calculated_height}"{$standby}>
818
		{$flash_params}
819
		<param name="flashvars" value="{$flash_vars}" />
820
	<!--<![endif]-->
821
	{$thumbnail_html}{$description}<p class="robots-nocontent">{$flash_help}</p>
822
	<!--[if !IE]>-->
823
	</object>
824
	<!--<![endif]-->
825
</object>
826
OBJECT;
827
	}
828
}
829