Completed
Push — 3.10/videopress ( e75fc6 )
by George
10:47
created

Jetpack_VideoPress::handle_editor_view_js()   B

Complexity

Conditions 3
Paths 2

Size

Total Lines 28
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 28
rs 8.8571
cc 3
eloc 22
nc 2
nop 0
1
<?php
2
/**
3
 * VideoPress in Jetpack
4
 *
5
 */
6
class Jetpack_VideoPress {
7
	public $module = 'videopress';
8
	public $option_name = 'videopress';
9
	public $version = 4;
10
11
	/**
12
	 * Singleton
13
	 */
14
	public static function init() {
15
		static $instance = false;
16
17
		if ( ! $instance )
18
			$instance = new Jetpack_VideoPress;
19
20
		return $instance;
21
	}
22
23
	function __construct() {
24
		$this->version = time(); // <s>ghost</s> cache busters!
25
		add_action( 'init', array( $this, 'on_init' ) );
26
		add_action( 'admin_notices', array( __CLASS__, 'handle_editor_view_js' ) );
27
		add_action( 'jetpack_activate_module_videopress', array( $this, 'jetpack_module_activated' ) );
28
		add_action( 'jetpack_deactivate_module_videopress', array( $this, 'jetpack_module_deactivated' ) );
29
	}
30
31
	/**
32
	 * Fires on init since is_connection_owner should wait until the user is initialized by $wp->init();
33
	 */
34
	function on_init() {
35
		$options = $this->get_options();
36
37
		// Only the connection owner can configure this module.
38
		if ( $this->is_connection_owner() ) {
39
			Jetpack::enable_module_configurable( $this->module );
40
			Jetpack::module_configuration_load( $this->module, array( $this, 'jetpack_configuration_load' ) );
41
			Jetpack::module_configuration_screen( $this->module, array( $this, 'jetpack_configuration_screen' ) );
42
		}
43
44
		// Only if the current user can manage the VideoPress library and one has been connected.
45
		if ( $this->can( 'read_videos' ) && $options['blog_id'] ) {
46
			add_action( 'wp_enqueue_media', array( $this, 'enqueue_admin_scripts' ) );
47
			add_action( 'print_media_templates', array( $this, 'print_media_templates' ) );
48
49
			// Load these at priority -1 so they're fired before Core's are.
50
			add_action( 'wp_ajax_query-attachments', array( $this, 'wp_ajax_query_attachments' ), -1 );
51
			add_action( 'wp_ajax_save-attachment', array( $this, 'wp_ajax_save_attachment' ), -1 );
52
			add_action( 'wp_ajax_save-attachment-compat', array( $this, 'wp_ajax_save_attachment' ), -1 );
53
			add_action( 'wp_ajax_delete-post', array( $this, 'wp_ajax_delete_post' ), -1 );
54
55
			add_action( 'admin_menu', array( $this, 'admin_menu' ) );
56
		}
57
58
		if ( $this->can( 'upload_videos' ) && $options['blog_id'] ) {
59
			add_action( 'wp_ajax_videopress-get-upload-token', array( $this, 'wp_ajax_videopress_get_upload_token' ) );
60
		}
61
62
		add_filter( 'videopress_shortcode_options', array( $this, 'videopress_shortcode_options' ) );
63
	}
64
65
	function wp_ajax_videopress_get_upload_token() {
66
		if ( ! $this->can( 'upload_videos' ) )
67
			return wp_send_json_error();
68
69
		$result = $this->query( 'jetpack.vpGetUploadToken' );
70
		if ( is_wp_error( $result ) )
71
			return wp_send_json_error( array( 'message' => __( 'Could not obtain a VideoPress upload token. Please try again later.', 'jetpack' ) ) );
72
73
		$response = $result;
74
		if ( empty( $response['videopress_blog_id'] ) || empty( $response['videopress_token'] ) || empty( $response[ 'videopress_action_url' ] ) )
75
			return wp_send_json_error( array( 'message' => __( 'Could not obtain a VideoPress upload token. Please try again later.', 'jetpack' ) ) );
76
77
		return wp_send_json_success( $response );
78
	}
79
80
	/**
81
	 * Get VideoPress options
82
	 */
83
	function get_options() {
84
		$defaults = array(
85
			'blogs' => array(),
86
			'blog_id' => 0,
87
			'access' => '',
88
			'allow-upload' => false,
89
			'freedom' => false,
90
			'hd' => false,
91
			'meta' => array(
92
				'max_upload_size' => 0,
93
			),
94
		);
95
96
		$options = Jetpack_Options::get_option( $this->option_name, array() );
97
98
		// If options have not been saved yet, check for older VideoPress plugin options.
99
		if ( empty( $options ) ) {
100
			$options['freedom'] = (bool) get_option( 'video_player_freedom', false );
101
			$options['hd'] = (bool) get_option( 'video_player_high_quality', false );
102
		}
103
104
		$options = array_merge( $defaults, $options );
105
		return $options;
106
	}
107
108
	/**
109
	 * Update VideoPress options
110
	 */
111
	function update_options( $options ) {
112
		Jetpack_Options::update_option( $this->option_name, $options );
113
	}
114
115
	/**
116
	 * Runs when the VideoPress module is activated.
117
	 */
118
	function jetpack_module_activated() {
119
		if ( ! $this->is_connection_owner() )
120
			return;
121
122
		$options = $this->get_options();
123
124
		// Ask WordPress.com for a list of VideoPress blogs
125
		$result = $this->query( 'jetpack.vpGetBlogs' );
126
		if ( ! is_wp_error( $result ) )
127
			$options['blogs'] = $result;
128
129
		// If there's at least one available blog, let's use it.
130
		if ( is_array( $options['blogs'] ) && count( $options['blogs'] ) > 0 )
131
			$options['blog_id'] = $options['blogs'][0]['blog_id'];
132
133
		$this->update_options( $options );
134
	}
135
136
	/**
137
	 * Runs when the VideoPress module is deactivated.
138
	 */
139
	function jetpack_module_deactivated() {
140
		Jetpack_Options::delete_option( $this->option_name );
141
	}
142
143
	/**
144
	 * Remote Query
145
	 *
146
	 * Performs a remote XML-RPC query using Jetpack's IXR Client. And also
147
	 * appends some useful stuff about this setup to the query.
148
	 *
149
	 * @return the Jetpack_IXR_Client object after querying.
150
	 */
151
	function query( $method, $args = null ) {
152
		$options = $this->get_options();
153
		Jetpack::load_xml_rpc_client();
154
		$xml = new Jetpack_IXR_Client( array(
155
			'user_id' => JETPACK_MASTER_USER, // All requests are on behalf of the connection owner.
156
		) );
157
158
		$params = array(
159
			'args' => $args,
160
			'video_blog_id' => $options['blog_id'],
161
			'caps' => array(),
162
		);
163
164
		// Let Jetpack know about our local caps.
165 View Code Duplication
		foreach ( array( 'read_videos', 'edit_videos', 'delete_videos', 'upload_videos' ) as $cap )
166
			if ( $this->can( $cap ) )
167
				$params['caps'][] = $cap;
168
169
		$xml->query( $method, $params );
170
171
		if ( $xml->isError() )
172
			return new WP_Error( 'xml_rpc_error', 'An XML-RPC error has occurred.' );
173
174
		$response = $xml->getResponse();
175
176
		// If there's any metadata with the response, save it for future use.
177
		if ( is_array( $response ) && isset( $response['meta'] ) ) {
178
			$options = $this->get_options();
179
			if ( $response['meta'] !== $options['meta'] ) {
180
				$options['meta'] = array_merge( $options['meta'], $response['meta'] );
181
				$this->update_options( $options );
182
			}
183
		}
184
185
		if ( is_array( $response ) && isset( $response['result'] ) )
186
			return $response['result'];
187
188
		return $response;
189
	}
190
191
	/**
192
	 * Runs before the VideoPress Configuration screen loads, useful
193
	 * to update options and yield errors.
194
	 */
195
	function jetpack_configuration_load() {
196
		$this->enqueue_admin_scripts();
197
198
		/**
199
		 * Save configuration
200
		 */
201
		if ( ! empty( $_POST['action'] ) && $_POST['action'] == 'videopress-save' ) {
202
			check_admin_referer( 'videopress-settings' );
203
			$options = $this->get_options();
204
205
			if ( isset( $_POST['blog_id'] ) && in_array( $_POST['blog_id'], wp_list_pluck( $options['blogs'], 'blog_id' ) ) )
206
				$options['blog_id'] = $_POST['blog_id'];
207
208
			// Allow the None setting too.
209
			if ( isset( $_POST['blog_id'] ) && $_POST['blog_id'] == 0 )
210
				$options['blog_id'] = 0;
211
212
			/**
213
			 * @see $this->can()
214
			 */
215
			if ( isset( $_POST['videopress-access'] ) && in_array( $_POST['videopress-access'], array( '', 'read', 'edit', 'delete' ) ) )
216
				$options['access'] = $_POST['videopress-access'];
217
218
			$options['freedom'] = isset( $_POST['videopress-freedom'] );
219
			$options['hd'] = isset( $_POST['videopress-hd'] );
220
221
			// Allow upload only if some level of access has been granted, and uploads were allowed.
222
			$options['allow-upload'] = false;
223
			if ( ! empty( $options['access'] ) && isset( $_POST['videopress-upload'] ) )
224
				$options['allow-upload'] = true;
225
226
			$this->update_options( $options );
227
			Jetpack::state( 'message', 'module_configured' );
228
			wp_safe_redirect( Jetpack::module_configuration_url( $this->module ) );
229
		}
230
231
		/**
232
		 * Refresh the list of available WordPress.com blogs
233
		 */
234
		if ( ! empty( $_GET['videopress'] ) && $_GET['videopress'] == 'refresh-blogs' ) {
235
			check_admin_referer( 'videopress-settings' );
236
			$options = $this->get_options();
237
238
			$result = $this->query( 'jetpack.vpGetBlogs' );
239
			if ( ! is_wp_error( $result ) ) {
240
				$options['blogs'] = $result;
241
				$this->update_options( $options );
242
			}
243
244
			wp_safe_redirect( Jetpack::module_configuration_url( $this->module ) );
245
		}
246
	}
247
248
	/**
249
	 * Renders the VideoPress Configuration screen in Jetpack.
250
	 */
251
	function jetpack_configuration_screen() {
252
		$options = $this->get_options();
253
		$refresh_url = wp_nonce_url( add_query_arg( 'videopress', 'refresh-blogs' ), 'videopress-settings' );
254
		?>
255
		<div class="narrow">
256
			<form method="post" id="videopress-settings">
257
				<input type="hidden" name="action" value="videopress-save" />
258
				<?php wp_nonce_field( 'videopress-settings' ); ?>
259
260
				<table id="menu" class="form-table">
261
					<tr>
262
						<th scope="row" colspan="2">
263
							<p><?php _e( 'Please note that the VideoPress module requires a WordPress.com account with an active <a href="http://store.wordpress.com/premium-upgrades/videopress/" target="_blank">VideoPress subscription</a>.', 'jetpack' ); ?></p>
264
						</th>
265
					</tr>
266
					<tr>
267
						<th scope="row">
268
							<label><?php _e( 'Connected WordPress.com Blog', 'jetpack' ); ?></label>
269
						</th>
270
						<td>
271
							<select name="blog_id">
272
								<option value="0" <?php selected( $options['blog_id'], 0 ); ?>> <?php esc_html_e( 'None', 'jetpack' ); ?></option>
273
								<?php foreach ( $options['blogs'] as $blog ) : ?>
0 ignored issues
show
Bug introduced by
The expression $options['blogs'] of type array|integer|string|false is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
274
								<option value="<?php echo absint( $blog['blog_id'] ); ?>" <?php selected( $options['blog_id'], $blog['blog_id'] ); ?>><?php echo esc_html( $blog['name'] ); ?> (<?php echo esc_html( $blog['domain'] ); ?>)</option>
275
								<?php endforeach; ?>
276
							</select>
277
							<p class="description"><?php _e( 'Only videos from the selected blog will be available in your media library.', 'jetpack' ); ?>
278
								<?php printf( __( '<a href="%s">Click here</a> to refresh this list.', 'jetpack' ), esc_url( $refresh_url ) ); ?>
279
							</p>
280
						</td>
281
					</tr>
282
					<tr>
283
						<th scope="row">
284
							<label><?php _e( 'Video Library Access', 'jetpack' ); ?></label>
285
						</th>
286
						<td>
287
							<label><input type="radio" name="videopress-access" value="" <?php checked( '', $options['access'] ); ?> />
288
								<?php _e( 'Do not allow other users to access my VideoPress library', 'jetpack' ); ?></label><br/>
289
							<label><input type="radio" name="videopress-access" value="read" <?php checked( 'read', $options['access'] ); ?> />
290
								<?php _e( 'Allow users to access my videos', 'jetpack' ); ?></label><br/>
291
							<label><input type="radio" name="videopress-access" value="edit" <?php checked( 'edit', $options['access'] ); ?> />
292
								<?php _e( 'Allow users to access and edit my videos', 'jetpack' ); ?></label><br/>
293
							<label><input type="radio" name="videopress-access" value="delete" <?php checked( 'delete', $options['access'] ); ?> />
294
								<?php _e( 'Allow users to access, edit, and delete my videos', 'jetpack' ); ?></label><br/><br />
295
296
							<label><input type="checkbox" name="videopress-upload" value="1" <?php checked( $options['allow-upload'] ); ?> />
297
								<?php _e( 'Allow users to upload videos', 'jetpack' ); ?></label><br />
298
						</td>
299
					</tr>
300
					<tr>
301
						<th scope="row">
302
							<label for="videopress-freedom"><?php _e( 'Free formats', 'jetpack' ); ?></label>
303
						</th>
304
						<td>
305
							<label><input type="checkbox" name="videopress-freedom" id="videopress-freedom" <?php checked( $options['freedom'] ); ?> />
306
								<?php _e( 'Only display videos in free software formats', 'jetpack' ); ?></label>
307
							<p class="description"><?php _e( 'Ogg file container with Theora video and Vorbis audio. Note that some browsers are unable to play free software video formats, including Internet Explorer and Safari.', 'jetpack' ); ?></p>
308
						</td>
309
					</tr>
310
					<tr>
311
						<th scope="row">
312
							<label for="videopress-hd"><?php _e( 'Default quality', 'jetpack' ); ?></label>
313
						</th>
314
						<td>
315
							<label><input type="checkbox" name="videopress-hd" id="videopress-hd" <?php checked( $options['hd'] ); ?> />
316
								<?php _e( 'Display higher quality video by default.', 'jetpack' ); ?></label>
317
							<p class="description"><?php _e( 'This setting may be overridden for individual videos.', 'jetpack' ); ?></p>
318
						</td>
319
					</tr>
320
				</table>
321
322
				<?php submit_button(); ?>
323
			</form>
324
		</div>
325
		<?php
326
	}
327
328
	function admin_menu() {
329
		add_media_page( __( 'VideoPress Library', 'jetpack' ), __( 'VideoPress', 'jetpack' ), 'upload_files', 'videopress-library', array( $this, 'admin_menu_library' ) );
330
	}
331
332
	function admin_menu_library() {
333
		wp_enqueue_media();
334
		$this->enqueue_admin_scripts();
335
		?>
336
		<div class="wrap" style="max-width: 600px;">
337
			<?php screen_icon(); ?>
338
	        <h2><?php _e( 'VideoPress Library', 'jetpack' ); ?></h2>
339
	        <p><?php _e( 'Use the button below to browse your VideoPress Library. Note that you can also browse your VideoPress Library while editing a post or page by using the <strong>Add Media</strong> button in the post editor.', 'jetpack' ); ?></p>
340
	        <p class="hide-if-no-js"><a href="#" id="videopress-browse" class="button"><?php _e( 'Browse Your VideoPress Library', 'jetpack' ); ?></a></p>
341
	        <p class="hide-if-js description"><?php _e( 'Please enable JavaScript support in your browser to use VideoPress.', 'jetpack' ); ?></p>
342
	    </div>
343
		<?php
344
	}
345
346
	/**
347
	 * A can of coke
348
	 *
349
	 * Similar to current_user_can, but internal to VideoPress. Returns
350
	 * true if the given VideoPress capability is allowed by the given user.
351
	 */
352
	function can( $cap, $user_id = false ) {
353
		if ( ! $user_id )
354
			$user_id = get_current_user_id();
355
356
		// Connection owners are allowed to do all the things.
357
		if ( $this->is_connection_owner( $user_id ) )
358
			return true;
359
360
		/**
361
		 * The access setting can be set by the connection owner, to allow sets
362
		 * of operations to other site users. Each access value corresponds to
363
		 * an array of things they can do.
364
		 */
365
366
		$options = $this->get_options();
367
		$map = array(
368
			'read'   => array( 'read_videos' ),
369
			'edit'   => array( 'read_videos', 'edit_videos' ),
370
			'delete' => array( 'read_videos', 'edit_videos', 'delete_videos' ),
371
		);
372
373
		if ( ! array_key_exists( $options['access'], $map ) )
374
			return false;
375
376
		if ( ! in_array( $cap, $map[ $options['access'] ] ) && 'upload_videos' != $cap )
377
			return false;
378
379
		// Additional and intrenal caps checks
380
381
		if ( ! user_can( $user_id, 'upload_files' ) )
382
			return false;
383
384
		if ( 'edit_videos' == $cap && ! user_can( $user_id, 'edit_others_posts' ) )
385
			return false;
386
387
		if ( 'delete_videos' == $cap && ! user_can( $user_id, 'delete_others_posts' ) )
388
			return false;
389
390
		if ( 'upload_videos' == $cap && ! $options['allow-upload'] )
391
			return false;
392
393
		return true;
394
	}
395
396
	/**
397
	 * Returns true if the provided user is the Jetpack connection owner.
398
	 */
399
	function is_connection_owner( $user_id = false ) {
400
		if ( ! $user_id )
401
			$user_id = get_current_user_id();
402
403
		$user_token = Jetpack_Data::get_access_token( JETPACK_MASTER_USER );
404
		return $user_token && is_object( $user_token ) && isset( $user_token->external_user_id ) && $user_id === $user_token->external_user_id;
405
	}
406
407
	/**
408
	 * Our custom AJAX callback for the query-attachments action
409
	 * used in the media modal. By-passed if not for VideoPress.
410
	 */
411
	function wp_ajax_query_attachments() {
412
413
		// Watch for VideoPress calls
414
		if ( ! isset( $_POST['query']['videopress'] ) )
415
			return;
416
417
		if ( ! $this->can( 'read_videos' ) )
418
			return wp_send_json_error( 'permission denied' );
419
420
		// Get and sanitize query arguments.
421
		$query_args = $this->sanitize_wp_query_args( $_POST['query'] );
422
423
		// Fire a remote WP_Query
424
		$result = $this->query( 'jetpack.vpQuery', $query_args );
425
426
		if ( is_wp_error( $result ) )
427
			return wp_send_json_error( 'xml rpc request error' );
428
429
		$items = $result;
430
		$shortcode_handler = Jetpack_VideoPress_Shortcode::init();
431
432
		foreach ( $items as $key => $item ) {
433
434
			// Check local permissions
435
			if ( ! $this->can( 'edit_videos' ) )
436
				unset( $item['vp_nonces']['update'] );
437
438
			if ( ! $this->can( 'delete_videos' ) )
439
				unset( $item['vp_nonces']['delete'] );
440
441
			// Add a second pair of nonces for the .org blog.
442
			$item['nonces'] = array();
443 View Code Duplication
			if ( ! empty( $item['vp_nonces']['update'] ) )
444
				$item['nonces']['update'] = wp_create_nonce( 'update-videopress-post_' . $item['id'] );
445
446 View Code Duplication
			if ( ! empty( $item['vp_nonces']['delete'] ) )
447
				$item['nonces']['delete'] = wp_create_nonce( 'delete-videopress-post_' . $item['id'] );
448
449
			$item['vp_embed'] = $shortcode_handler->shortcode_callback( array(
450
				$item['vp_guid'],
451
				'autoplay' => true,
452
				'flashonly' => true,
453
				'w' => 440,
454
			) );
455
456
			$items[ $key ] = $item;
457
		}
458
459
		wp_send_json_success( $items );
460
	}
461
462
	/**
463
	 * Sanitize user-provided WP_Query arguments
464
	 *
465
	 * These might be sent to the VideoPress server, for a remote WP_Query
466
	 * call so let's make sure they're sanitized and safe to send.
467
	 */
468
	function sanitize_wp_query_args( $args ) {
469
		$args = shortcode_atts( array(
470
			'posts_per_page' => 40,
471
			'orderby' => 'date',
472
			'order' => 'desc',
473
			'paged' => 1,
474
			's' => '',
475
		), (array) $args, 'wpvideo' );
476
477
		$args['posts_per_page'] = absint( $args['posts_per_page'] );
478
479
		$args['orderby'] = strtolower( $args['orderby'] );
480
		$args['orderby'] = ( in_array( $args['orderby'], array( 'date' ) ) ) ? $args['orderby'] : 'date';
481
482
		$args['order'] = strtolower( $args['order'] );
483
		$args['order'] = ( in_array( $args['order'], array( 'asc', 'desc' ) ) ) ? $args['order'] : 'desc';
484
485
		$args['paged'] = absint( $args['paged'] );
486
		$args['s'] = sanitize_text_field( $args['s'] );
487
		return $args;
488
	}
489
490
	/**
491
	 * Custom AJAX callback for the save-attachment action. If the request was
492
	 * not for a VideoPress object, core's fallback action will kick in.
493
	 */
494
	function wp_ajax_save_attachment() {
495
		if ( ! isset( $_POST['is_videopress'] ) )
496
			return;
497
498
		if ( ! $this->can( 'edit_videos' ) )
499
			return wp_send_json_error( 'permission denied' );
500
501
		$post_id = 0;
502 View Code Duplication
		if ( ! isset( $_POST['id'] ) || ! $post_id = absint( $_POST['id'] ) )
503
			wp_send_json_error();
504
505
		if ( ! isset( $_POST['vp_nonces']['update'] ) )
506
			wp_send_json_error();
507
508
		check_ajax_referer( 'update-videopress-post_' . $post_id, 'nonce' );
509
510
		$changes = ( ! empty( $_POST['changes'] ) ) ? (array) $_POST['changes'] : array();
511
		$changes = shortcode_atts( array(
512
			'title' => null,
513
			'caption' => null,
514
			'description' => null,
515
516
			'vp_share' => null,
517
			'vp_rating' => null,
518
		), $changes, 'wpvideo' );
519
520
		if ( ! is_null( $changes['vp_share'] ) )
521
			$changes['vp_share'] = (bool) $changes['vp_share'];
522
523
		if ( ! is_null( $changes['vp_rating'] ) )
524
			$changes['vp_rating'] = ( array_key_exists( $changes['vp_rating'], $this->get_available_ratings() ) ) ? $changes['vp_rating'] : null;
525
526
		// Remove null-values
527
		foreach ( $changes as $key => $value )
528
			if ( is_null( $value ) )
529
				unset( $changes[ $key ] );
530
531
		$result = $this->query( 'jetpack.vpSaveAttachment', array(
532
			'post_id' => $post_id,
533
			'changes' => $changes,
534
			'nonce' => $_POST['vp_nonces']['update'],
535
		) );
536
537
		if ( is_wp_error( $result ) )
538
			return wp_send_json_error( 'xml rpc request error' );
539
540
		wp_send_json_success();
541
	}
542
543
	/**
544
	 * Custom AJAX callback for the delete-post action, only for VideoPress objects.
545
	 */
546
	function wp_ajax_delete_post() {
547
		if ( ! isset( $_POST['is_videopress'] ) )
548
			return;
549
550
		if ( ! $this->can( 'delete_videos' ) )
551
			return wp_send_json_error( 'permission denied' );
552
553
		$post_id = 0;
554 View Code Duplication
		if ( ! isset( $_POST['id'] ) || ! $post_id = absint( $_POST['id'] ) )
555
			wp_send_json_error();
556
557
		if ( ! isset( $_POST['vp_nonces']['delete'] ) )
558
			wp_send_json_error();
559
560
		check_ajax_referer( 'delete-videopress-post_' . $post_id );
561
562
		$result = $this->query( 'jetpack.vpDeleteAttachment', array(
563
			'post_id' => $post_id,
564
			'nonce' => $_POST['vp_nonces']['delete'],
565
		) );
566
567
		if ( is_wp_error( $result ) )
568
			return wp_send_json_error( 'xml rpc request error' );
569
570
		wp_send_json_success();
571
	}
572
573
	/**
574
	 * Register VideoPress admin scripts.
575
	 */
576
	function enqueue_admin_scripts() {
577
		if ( did_action( 'videopress_enqueue_admin_scripts' ) )
578
			return;
579
580
		wp_enqueue_script( 'videopress-admin', plugins_url( 'videopress-admin.js', __FILE__ ), array( 'jquery', 'media-views', 'media-models' ), $this->version );
581
		wp_enqueue_style( 'videopress-admin', plugins_url( 'videopress-admin.css', __FILE__ ), array(), $this->version );
582
583
		$caps = array();
584 View Code Duplication
		foreach( array( 'read_videos', 'edit_videos', 'delete_videos', 'upload_videos' ) as $cap )
585
			$caps[ $cap ] = $this->can( $cap );
586
587
		$l10n = array(
588
			'selectVideoFile' => __( 'Please select a video file to upload.', 'jetpack' ),
589
			'videoUploading' => __( 'Your video is uploading... Please do not close this window.', 'jetpack' ),
590
			'unknownError' => __( 'An unknown error has occurred. Please try again later.', 'jetpack' ),
591
			'videoUploaded' => __( 'Your video has successfully been uploaded. It will appear in your VideoPress Library shortly.', 'jetpack' ),
592
			'VideoPressLibraryRouter' => __( 'VideoPress Library', 'jetpack' ),
593
			'uploadVideoRouter' => __( 'Upload a Video', 'jetpack' ),
594
			'insertVideoButton' => __( 'Insert Video', 'jetpack' ),
595
596
		);
597
598
		wp_localize_script( 'videopress-admin', 'VideoPressAdminSettings', array(
599
			'caps' => $caps,
600
			'l10n' => $l10n,
601
		) );
602
		
603
		/**
604
		 * Fires after VideoPress scripts are enqueued in the dashboard.
605
		 *
606
		 * @since 2.5.0
607
		 */
608
		do_action( 'videopress_enqueue_admin_scripts' );
609
	}
610
611
	/**
612
	 * Get an array of available ratings. Keys are options, values are labels.
613
	 */
614
	function get_available_ratings() {
615
		return array(
616
			'G' => 'G',
617
			'PG-13' => 'PG-13',
618
			'R-17' => 'R',
619
			'X-18' => 'X',
620
		);
621
	}
622
623
	/**
624
	 * Additional VideoPress media templates.
625
	 */
626
	function print_media_templates() {
627
		$options = $this->get_options();
628
		?>
629
		<script type="text/html" id="tmpl-videopress-attachment">
630
			<# if ( data.vp_ogg_url ) { #>
631
			<label class="setting vp-setting">
632
				<span><?php _e( 'Ogg File URL', 'jetpack' ); ?></span>
633
				<input type="text" value="{{ data.vp_ogg_url }}" onclick="this.focus();this.select();" readonly />
634
				<p class="help"><?php _e( 'Location of the Ogg video file.', 'jetpack' ); ?></p>
635
			</label>
636
			<# } #>
637
638
			<label class="setting vp-setting">
639
				<span><?php _e( 'Share', 'jetpack' ); ?></span>
640
				<input class="vp-checkbox" type="checkbox" <# if ( '1' === data.vp_share ) { #>checked<# } #> <# if ( ! data.can.save ) { #>disabled<# } #> />
641
				<label>
642
					<?php _e( 'Display share menu and allow viewers to embed or download this video', 'jetpack' ); ?>
643
				</label>
644
				<input class="vp-checkbox-text" type="text" value="{{ data.vp_share }}" data-setting="vp_share" style="display:none;" />
645
			</label>
646
647
			<label class="setting vp-setting">
648
				<span><?php _e( 'Rating', 'jetpack' ); ?></span>
649
650
				<?php foreach ( $this->get_available_ratings() as $value => $label ) : ?>
651
				<input class="vp-radio" type="radio" name="vp-radio-group" id="vp-rating-<?php echo sanitize_html_class( $value ); ?>" value="<?php echo esc_attr( $value ); ?>"
652
					<# if ( '<?php echo esc_attr( $value ); ?>' === data.vp_rating ) { #>checked<# } #>
653
					<# if ( ! data.can.save ) { #>disabled<# } #> />
654
				<label for="vp-rating-<?php echo sanitize_html_class( $value ); ?>"><?php echo esc_html( $label ); ?></label>
655
				<?php endforeach; ?>
656
657
				<input class="vp-radio-text" type="text" value="{{ data.vp_rating }}" data-setting="vp_rating" style="display:none;" />
658
			</label>
659
660
			<label class="setting vp-setting">
661
				<span><?php _e( 'Shortcode', 'jetpack' ); ?></span>
662
				<input type="text" value="[wpvideo {{ data.vp_guid }}]" onclick="this.focus();this.select();" readonly />
663
			</label>
664
665
			<label class="setting vp-setting vp-preview">
666
				<span><?php _e( 'Preview', 'jetpack' ); ?></span>
667
				<# if ( ! data.vp_thumbnail_url ) { #>
668
					<span class="videopress-preview-unavailable"><?php esc_html_e( 'The preview is unavailable while this video is being processed.', 'jetpack' ); ?></span>
669
				<# } else { #>
670
				<a href="#" class="videopress-preview" id="videopress-thumbnail-{{ data.vp_guid }}" data-videopress-guid="{{ data.vp_guid }}"><img src="{{ data.vp_thumbnail_url }}" /></a>
671
				<# } #>
672
			</label>
673
		</script>
674
675
		<script type="text/html" id="tmpl-videopress-media-modal">
676
			<div class="videopress-modal">
677
				<p><?php _e( 'Video Preview:', 'jetpack' ); ?></p>
678
				<div class="videopress-video-container">{{{ data.video }}}</div>
679
				<p class="submit">
680
					<a class="videopress-modal-close button" href="#"><?php _e( 'Close', 'jetpack' ); ?></a>
681
				</p>
682
			</div>
683
			<div class="videopress-modal-backdrop"></div>
684
		</script>
685
686
		<script type="text/html" id="tmpl-videopress-uploader">
687
			<div class="videopress-errors"></div>
688
			<form class="videopress-upload-form" action="" method="post" target="videopress_upload_frame" enctype="multipart/form-data">
689
				<input type="hidden" name="action" value="videopress_upload" />
690
				<input type="hidden" name="videopress_blog_id" value="0" />
691
				<input type="hidden" name="videopress_token" value="0" />
692
				<?php $formats = 'ogv, mp4, m4v, mov, wmv, avi, mpg, 3gp, 3g2'; ?>
693
				<?php
694
					$max_upload_size = 0;
695
					if ( ! empty( $options['meta']['max_upload_size'] ) )
696
						$max_upload_size = absint( $options['meta']['max_upload_size'] );
697
698
					$upload_size_unit = $max_upload_size;
699
					$byte_sizes = array( 'KB', 'MB', 'GB' );
700
701
					for ( $u = -1; $upload_size_unit > 1024 && $u < count( $byte_sizes ) - 1; $u++ )
702
						$upload_size_unit /= 1024;
703
704
					if ( $u < 0 ) {
705
						$upload_size_unit = 0;
706
						$u = 0;
707
					} else {
708
						$upload_size_unit = (int) $upload_size_unit;
709
					}
710
				?>
711
				<p><?php printf( __( 'Use the form below to upload a video to your VideoPress Library. The following video formats are supported: %s. Maximum upload file size is %d%s.', 'jetpack' ), esc_html( $formats ), esc_html( $upload_size_unit ), esc_html( $byte_sizes[ $u ] ) ); ?></p>
712
713
				<input type="file" name="videopress_file" />
714
				<?php submit_button( __( 'Upload Video', 'jetpack' ) ); ?>
715
			</form>
716
			<iframe width="0" height="0" name="videopress_upload_frame"></iframe>
717
		</script>
718
		<?php
719
	}
720
721
	/**
722
	 * Filters the VideoPress shortcode options, makes sure that
723
	 * the settings set in Jetpack's VideoPress module are applied.
724
	 */
725
	function videopress_shortcode_options( $options ) {
726
		$videopress_options = $this->get_options();
727
728
		if ( false === $options['freedom'] )
729
			$options['freedom'] = $videopress_options['freedom'];
730
731
		$options['hd'] = $videopress_options['hd'];
732
733
		return $options;
734
	}
735
736
	/**
737
	 * WordPress Shortcode Editor View JS Code
738
	 */
739
	public static function handle_editor_view_js() {
740
		global $content_width;
741
		$current_screen = get_current_screen();
742
		if ( ! isset( $current_screen->id ) || $current_screen->base !== 'post' ) {
743
			return;
744
		}
745
746
		add_action( 'admin_print_footer_scripts', array( __CLASS__, 'editor_view_js_templates' ) );
747
748
		wp_enqueue_script( 'videopress-editor-view', plugin_dir_url( __FILE__ ) . 'js/editor-view.js', array( 'wp-util', 'jquery' ), false, true );
749
		wp_localize_script( 'videopress-editor-view', 'vpEditorView', array(
750
			'home_url_host'     => parse_url( home_url(), PHP_URL_HOST ),
751
			'min_content_width' => VIDEOPRESS_MIN_WIDTH,
752
			'content_width'     => $content_width,
753
			'modal_labels'      => array(
754
				'title'     => __( 'VideoPress Shortcode', 'jetpack' ),
755
				'guid'      => __( 'Video GUID', 'jetpack' ),
756
				'w'         => __( 'Width (in pixels)', 'jetpack' ),
757
				'at'        => __( 'Start how many seconds in?', 'jetpack' ),
758
				'hd'        => __( 'Default to High Definition version?', 'jetpack' ),
759
				'permalink' => __( 'Link the video title to the video\'s URL on VideoPress.com?', 'jetpack' ),
760
				'autoplay'  => __( 'Autoplay video on load?', 'jetpack' ),
761
				'loop'      => __( 'Loop playback indefinitely?', 'jetpack' ),
762
				'freedom'   => __( 'Use only Open Source codecs? (this may degrade performance)', 'jetpack' ),
763
				'flashonly' => __( 'Use the legacy flash player? (not recommended)', 'jetpack' ),
764
			)
765
		) );
766
	}
767
768
	/**
769
	 * WordPress Editor Views
770
	 */
771
	public static function editor_view_js_templates() {
772
		/**
773
		 * This template uses the following parameters, and displays the video as an iframe:
774
		 *  - data.guid     // The guid of the video.
775
		 *  - data.width    // The width of the iframe.
776
		 *  - data.height   // The height of the iframe.
777
		 *  - data.urlargs  // Arguments serialized into a get string.
778
		 *
779
		 * In addition, the calling script will need to ensure that the following
780
		 * JS file is added to the header of the editor iframe:
781
		 *  - https://s0.wp.com/wp-content/plugins/video/assets/js/next/videopress-iframe.js
782
		 */
783
		?>
784
		<script type="text/html" id="tmpl-videopress_iframe_vnext">
785
			<div class="tmpl-videopress_iframe_next">
786
				<iframe style="display: block;" width="{{ data.width }}" height="{{ data.height }}" src="https://videopress.com/embed/{{ data.guid }}?{{ data.urlargs }}" frameborder='0' allowfullscreen></iframe>
787
			</div>
788
		</script>
789
		<?php
790
	}
791
}
792
793
// Initialize the module.
794
Jetpack_VideoPress::init();
795