Completed
Push — feature/videopress-uploader ( 5f48a8...dee1ca )
by
unknown
27:25 queued 17:36
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 %
Metric Value
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( 'jetpack_activate_module_videopress', array( $this, 'jetpack_module_activated' ) );
27
		add_action( 'jetpack_deactivate_module_videopress', array( $this, 'jetpack_module_deactivated' ) );
28
	}
29
30
	/**
31
	 * Fires on init since is_connection_owner should wait until the user is initialized by $wp->init();
32
	 */
33
	function on_init() {
34
		$options = $this->get_options();
35
36
		// Only the connection owner can configure this module.
37
		if ( $this->is_connection_owner() ) {
38
			Jetpack::enable_module_configurable( $this->module );
39
			Jetpack::module_configuration_load( $this->module, array( $this, 'jetpack_configuration_load' ) );
40
			Jetpack::module_configuration_screen( $this->module, array( $this, 'jetpack_configuration_screen' ) );
41
		}
42
43
		// Only if the current user can manage the VideoPress library and one has been connected.
44
		if ( $this->can( 'read_videos' ) && $options['blog_id'] ) {
45
			add_action( 'wp_enqueue_media', array( $this, 'enqueue_admin_scripts' ) );
46
			add_action( 'print_media_templates', array( $this, 'print_media_templates' ) );
47
48
			// Load these at priority -1 so they're fired before Core's are.
49
			add_action( 'wp_ajax_query-attachments', array( $this, 'wp_ajax_query_attachments' ), -1 );
50
			add_action( 'wp_ajax_save-attachment', array( $this, 'wp_ajax_save_attachment' ), -1 );
51
			add_action( 'wp_ajax_save-attachment-compat', array( $this, 'wp_ajax_save_attachment' ), -1 );
52
			add_action( 'wp_ajax_delete-post', array( $this, 'wp_ajax_delete_post' ), -1 );
53
54
			add_action( 'admin_menu', array( $this, 'admin_menu' ) );
55
		}
56
57
		if ( $this->can( 'upload_videos' ) && $options['blog_id'] ) {
58
			add_action( 'wp_ajax_videopress-get-upload-token', array( $this, 'wp_ajax_videopress_get_upload_token' ) );
59
			add_filter( 'plupload_default_settings', array( $this, 'videopress_pluploder_config' ) );
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
		$options = $this->get_options();
70
71
		$args = array(
72
			'method'  => 'POST',
73
		);
74
75
		$endpoint = "sites/{$options['blog_id']}/media/token";
76
		$result = Jetpack_Client::wpcom_json_api_request_as_blog( $endpoint, Jetpack_Client::WPCOM_JSON_API_VERSION, $args );
77
78
		$response = json_decode( $result['body'], true );
79
80
		if ( is_wp_error( $response ) )
81
			return wp_send_json_error( array( 'message' => __( 'Could not obtain a VideoPress upload token. Please try again later.', 'jetpack' ) ) );
82
83
		if ( empty( $response['upload_blog_id'] ) || empty( $response['upload_token'] ) )
84
			return wp_send_json_error( array( 'message' => __( 'Could not obtain a VideoPress upload token. Please try again later.', 'jetpack' ) ) );
85
86
		$response['upload_action_url'] = self::make_media_upload_path( $response['upload_blog_id'] );
87
88
		return wp_send_json_success( $response );
89
	}
90
91
	/**
92
	 * Get the upload api path.
93
	 *
94
	 * @param $blog_id
95
	 * @return string
96
	 */
97
	function make_media_upload_path( $blog_id ) {
98
		return sprintf(
99
			'%s://%s/rest/v%s/sites/%s/media/new',
100
			'https',
101
			JETPACK__WPCOM_JSON_API_HOST,
102
			Jetpack_Client::WPCOM_JSON_API_VERSION,
103
			$blog_id
104
		);
105
	}
106
107
	/**
108
	 * Modify the default plupload config to turn on videopress specific filters.
109
	 */
110
	function videopress_pluploder_config( $config ) {
111
		$config['filters']['videopress_check_uploads'] = 1;
112
		return $config;
113
	}
114
115
	/**
116
	 * Get VideoPress options
117
	 */
118
	function get_options() {
119
		$defaults = array(
120
			'blogs' => array(),
121
			'blog_id' => 0,
122
			'access' => '',
123
			'allow-upload' => false,
124
			'freedom' => false,
125
			'hd' => false,
126
			'meta' => array(
127
				'max_upload_size' => 0,
128
			),
129
		);
130
131
		$options = Jetpack_Options::get_option( $this->option_name, array() );
132
133
		// If options have not been saved yet, check for older VideoPress plugin options.
134
		if ( empty( $options ) ) {
135
			$options['freedom'] = (bool) get_option( 'video_player_freedom', false );
136
			$options['hd'] = (bool) get_option( 'video_player_high_quality', false );
137
		}
138
139
		$options = array_merge( $defaults, $options );
140
		return $options;
141
	}
142
143
	/**
144
	 * Update VideoPress options
145
	 */
146
	function update_options( $options ) {
147
		Jetpack_Options::update_option( $this->option_name, $options );
148
	}
149
150
	/**
151
	 * Runs when the VideoPress module is activated.
152
	 */
153
	function jetpack_module_activated() {
154
		if ( ! $this->is_connection_owner() )
155
			return;
156
157
		$options = $this->get_options();
158
159
		// Ask WordPress.com for a list of VideoPress blogs
160
		$result = $this->query( 'jetpack.vpGetBlogs' );
161
		if ( ! is_wp_error( $result ) )
162
			$options['blogs'] = $result;
163
164
		// If there's at least one available blog, let's use it.
165
		if ( is_array( $options['blogs'] ) && count( $options['blogs'] ) > 0 )
166
			$options['blog_id'] = $options['blogs'][0]['blog_id'];
167
168
		$this->update_options( $options );
169
	}
170
171
	/**
172
	 * Runs when the VideoPress module is deactivated.
173
	 */
174
	function jetpack_module_deactivated() {
175
		Jetpack_Options::delete_option( $this->option_name );
176
	}
177
178
	/**
179
	 * Remote Query
180
	 *
181
	 * Performs a remote XML-RPC query using Jetpack's IXR Client. And also
182
	 * appends some useful stuff about this setup to the query.
183
	 *
184
	 * @return the Jetpack_IXR_Client object after querying.
185
	 */
186
	function query( $method, $args = null ) {
187
		$options = $this->get_options();
188
		Jetpack::load_xml_rpc_client();
189
		$xml = new Jetpack_IXR_Client( array(
190
			'user_id' => JETPACK_MASTER_USER, // All requests are on behalf of the connection owner.
191
		) );
192
193
		$params = array(
194
			'args' => $args,
195
			'video_blog_id' => $options['blog_id'],
196
			'caps' => array(),
197
		);
198
199
		// Let Jetpack know about our local caps.
200 View Code Duplication
		foreach ( array( 'read_videos', 'edit_videos', 'delete_videos', 'upload_videos' ) as $cap )
201
			if ( $this->can( $cap ) )
202
				$params['caps'][] = $cap;
203
204
		$xml->query( $method, $params );
205
206
		if ( $xml->isError() )
207
			return new WP_Error( 'xml_rpc_error', 'An XML-RPC error has occurred.' );
208
209
		$response = $xml->getResponse();
210
211
		// If there's any metadata with the response, save it for future use.
212
		if ( is_array( $response ) && isset( $response['meta'] ) ) {
213
			$options = $this->get_options();
214
			if ( $response['meta'] !== $options['meta'] ) {
215
				$options['meta'] = array_merge( $options['meta'], $response['meta'] );
216
				$this->update_options( $options );
217
			}
218
		}
219
220
		if ( is_array( $response ) && isset( $response['result'] ) )
221
			return $response['result'];
222
223
		return $response;
224
	}
225
226
	/**
227
	 * Runs before the VideoPress Configuration screen loads, useful
228
	 * to update options and yield errors.
229
	 */
230
	function jetpack_configuration_load() {
231
		$this->enqueue_admin_scripts();
232
233
		/**
234
		 * Save configuration
235
		 */
236
		if ( ! empty( $_POST['action'] ) && $_POST['action'] == 'videopress-save' ) {
237
			check_admin_referer( 'videopress-settings' );
238
			$options = $this->get_options();
239
240
			if ( isset( $_POST['blog_id'] ) && in_array( $_POST['blog_id'], wp_list_pluck( $options['blogs'], 'blog_id' ) ) )
241
				$options['blog_id'] = $_POST['blog_id'];
242
243
			// Allow the None setting too.
244
			if ( isset( $_POST['blog_id'] ) && $_POST['blog_id'] == 0 )
245
				$options['blog_id'] = 0;
246
247
			/**
248
			 * @see $this->can()
249
			 */
250
			if ( isset( $_POST['videopress-access'] ) && in_array( $_POST['videopress-access'], array( '', 'read', 'edit', 'delete' ) ) )
251
				$options['access'] = $_POST['videopress-access'];
252
253
			$options['freedom'] = isset( $_POST['videopress-freedom'] );
254
			$options['hd'] = isset( $_POST['videopress-hd'] );
255
256
			// Allow upload only if some level of access has been granted, and uploads were allowed.
257
			$options['allow-upload'] = false;
258
			if ( ! empty( $options['access'] ) && isset( $_POST['videopress-upload'] ) )
259
				$options['allow-upload'] = true;
260
261
			$this->update_options( $options );
262
			Jetpack::state( 'message', 'module_configured' );
263
			wp_safe_redirect( Jetpack::module_configuration_url( $this->module ) );
264
		}
265
266
		/**
267
		 * Refresh the list of available WordPress.com blogs
268
		 */
269
		if ( ! empty( $_GET['videopress'] ) && $_GET['videopress'] == 'refresh-blogs' ) {
270
			check_admin_referer( 'videopress-settings' );
271
			$options = $this->get_options();
272
273
			$result = $this->query( 'jetpack.vpGetBlogs' );
274
			if ( ! is_wp_error( $result ) ) {
275
				$options['blogs'] = $result;
276
				$this->update_options( $options );
277
			}
278
279
			wp_safe_redirect( Jetpack::module_configuration_url( $this->module ) );
280
		}
281
	}
282
283
	/**
284
	 * Renders the VideoPress Configuration screen in Jetpack.
285
	 */
286
	function jetpack_configuration_screen() {
287
		$options = $this->get_options();
288
		$refresh_url = wp_nonce_url( add_query_arg( 'videopress', 'refresh-blogs' ), 'videopress-settings' );
289
		?>
290
		<div class="narrow">
291
			<form method="post" id="videopress-settings">
292
				<input type="hidden" name="action" value="videopress-save" />
293
				<?php wp_nonce_field( 'videopress-settings' ); ?>
294
295
				<table id="menu" class="form-table">
296
					<tr>
297
						<th scope="row" colspan="2">
298
							<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>
299
						</th>
300
					</tr>
301
					<tr>
302
						<th scope="row">
303
							<label><?php _e( 'Connected WordPress.com Blog', 'jetpack' ); ?></label>
304
						</th>
305
						<td>
306
							<select name="blog_id">
307
								<option value="0" <?php selected( $options['blog_id'], 0 ); ?>> <?php esc_html_e( 'None', 'jetpack' ); ?></option>
308
								<?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...
309
								<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>
310
								<?php endforeach; ?>
311
							</select>
312
							<p class="description"><?php _e( 'Only videos from the selected blog will be available in your media library.', 'jetpack' ); ?>
313
								<?php printf( __( '<a href="%s">Click here</a> to refresh this list.', 'jetpack' ), esc_url( $refresh_url ) ); ?>
314
							</p>
315
						</td>
316
					</tr>
317
					<tr>
318
						<th scope="row">
319
							<label><?php _e( 'Video Library Access', 'jetpack' ); ?></label>
320
						</th>
321
						<td>
322
							<label><input type="radio" name="videopress-access" value="" <?php checked( '', $options['access'] ); ?> />
323
								<?php _e( 'Do not allow other users to access my VideoPress library', 'jetpack' ); ?></label><br/>
324
							<label><input type="radio" name="videopress-access" value="read" <?php checked( 'read', $options['access'] ); ?> />
325
								<?php _e( 'Allow users to access my videos', 'jetpack' ); ?></label><br/>
326
							<label><input type="radio" name="videopress-access" value="edit" <?php checked( 'edit', $options['access'] ); ?> />
327
								<?php _e( 'Allow users to access and edit my videos', 'jetpack' ); ?></label><br/>
328
							<label><input type="radio" name="videopress-access" value="delete" <?php checked( 'delete', $options['access'] ); ?> />
329
								<?php _e( 'Allow users to access, edit, and delete my videos', 'jetpack' ); ?></label><br/><br />
330
331
							<label><input type="checkbox" name="videopress-upload" value="1" <?php checked( $options['allow-upload'] ); ?> />
332
								<?php _e( 'Allow users to upload videos', 'jetpack' ); ?></label><br />
333
						</td>
334
					</tr>
335
					<tr>
336
						<th scope="row">
337
							<label for="videopress-freedom"><?php _e( 'Free formats', 'jetpack' ); ?></label>
338
						</th>
339
						<td>
340
							<label><input type="checkbox" name="videopress-freedom" id="videopress-freedom" <?php checked( $options['freedom'] ); ?> />
341
								<?php _e( 'Only display videos in free software formats', 'jetpack' ); ?></label>
342
							<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>
343
						</td>
344
					</tr>
345
					<tr>
346
						<th scope="row">
347
							<label for="videopress-hd"><?php _e( 'Default quality', 'jetpack' ); ?></label>
348
						</th>
349
						<td>
350
							<label><input type="checkbox" name="videopress-hd" id="videopress-hd" <?php checked( $options['hd'] ); ?> />
351
								<?php _e( 'Display higher quality video by default.', 'jetpack' ); ?></label>
352
							<p class="description"><?php _e( 'This setting may be overridden for individual videos.', 'jetpack' ); ?></p>
353
						</td>
354
					</tr>
355
				</table>
356
357
				<?php submit_button(); ?>
358
			</form>
359
		</div>
360
		<?php
361
	}
362
363
	function admin_menu() {
364
		add_media_page( __( 'VideoPress Library', 'jetpack' ), __( 'VideoPress', 'jetpack' ), 'upload_files', 'videopress-library', array( $this, 'admin_menu_library' ) );
365
	}
366
367
	function admin_menu_library() {
368
		wp_enqueue_media();
369
		$this->enqueue_admin_scripts();
370
		?>
371
		<div class="wrap" style="max-width: 600px;">
372
			<?php screen_icon(); ?>
373
	        <h2><?php _e( 'VideoPress Library', 'jetpack' ); ?></h2>
374
	        <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>
375
	        <p class="hide-if-no-js"><a href="#" id="videopress-browse" class="button"><?php _e( 'Browse Your VideoPress Library', 'jetpack' ); ?></a></p>
376
	        <p class="hide-if-js description"><?php _e( 'Please enable JavaScript support in your browser to use VideoPress.', 'jetpack' ); ?></p>
377
	    </div>
378
		<?php
379
	}
380
381
	/**
382
	 * A can of coke
383
	 *
384
	 * Similar to current_user_can, but internal to VideoPress. Returns
385
	 * true if the given VideoPress capability is allowed by the given user.
386
	 */
387
	function can( $cap, $user_id = false ) {
388
		if ( ! $user_id )
389
			$user_id = get_current_user_id();
390
391
		// Connection owners are allowed to do all the things.
392
		if ( $this->is_connection_owner( $user_id ) )
393
			return true;
394
395
		/**
396
		 * The access setting can be set by the connection owner, to allow sets
397
		 * of operations to other site users. Each access value corresponds to
398
		 * an array of things they can do.
399
		 */
400
401
		$options = $this->get_options();
402
		$map = array(
403
			'read'   => array( 'read_videos' ),
404
			'edit'   => array( 'read_videos', 'edit_videos' ),
405
			'delete' => array( 'read_videos', 'edit_videos', 'delete_videos' ),
406
		);
407
408
		if ( ! array_key_exists( $options['access'], $map ) )
409
			return false;
410
411
		if ( ! in_array( $cap, $map[ $options['access'] ] ) && 'upload_videos' != $cap )
412
			return false;
413
414
		// Additional and intrenal caps checks
415
416
		if ( ! user_can( $user_id, 'upload_files' ) )
417
			return false;
418
419
		if ( 'edit_videos' == $cap && ! user_can( $user_id, 'edit_others_posts' ) )
420
			return false;
421
422
		if ( 'delete_videos' == $cap && ! user_can( $user_id, 'delete_others_posts' ) )
423
			return false;
424
425
		if ( 'upload_videos' == $cap && ! $options['allow-upload'] )
426
			return false;
427
428
		return true;
429
	}
430
431
	/**
432
	 * Returns true if the provided user is the Jetpack connection owner.
433
	 */
434
	function is_connection_owner( $user_id = false ) {
435
		if ( ! $user_id )
436
			$user_id = get_current_user_id();
437
438
		$user_token = Jetpack_Data::get_access_token( JETPACK_MASTER_USER );
439
		return $user_token && is_object( $user_token ) && isset( $user_token->external_user_id ) && $user_id === $user_token->external_user_id;
440
	}
441
442
	/**
443
	 * Our custom AJAX callback for the query-attachments action
444
	 * used in the media modal. By-passed if not for VideoPress.
445
	 */
446
	function wp_ajax_query_attachments() {
447
448
		// Watch for VideoPress calls
449
		if ( ! isset( $_POST['query']['videopress'] ) )
450
			return;
451
452
		if ( ! $this->can( 'read_videos' ) )
453
			return wp_send_json_error( 'permission denied' );
454
455
		// Get and sanitize query arguments.
456
		$query_args = $this->sanitize_wp_query_args( $_POST['query'] );
457
458
		// Fire a remote WP_Query
459
		$result = $this->query( 'jetpack.vpQuery', $query_args );
460
461
		if ( is_wp_error( $result ) )
462
			return wp_send_json_error( 'xml rpc request error' );
463
464
		$items = $result;
465
466
		foreach ( $items as $key => $item ) {
467
468
			// Check local permissions
469
			if ( ! $this->can( 'edit_videos' ) )
470
				unset( $item['vp_nonces']['update'] );
471
472
			if ( ! $this->can( 'delete_videos' ) )
473
				unset( $item['vp_nonces']['delete'] );
474
475
			// Add a second pair of nonces for the .org blog.
476
			$item['nonces'] = array();
477 View Code Duplication
			if ( ! empty( $item['vp_nonces']['update'] ) )
478
				$item['nonces']['update'] = wp_create_nonce( 'update-videopress-post_' . $item['id'] );
479
480 View Code Duplication
			if ( ! empty( $item['vp_nonces']['delete'] ) )
481
				$item['nonces']['delete'] = wp_create_nonce( 'delete-videopress-post_' . $item['id'] );
482
483
			$item['vp_embed'] = videopress_shortcode_callback( array(
484
				$item['vp_guid'],
485
				'autoplay' => true,
486
				'flashonly' => true,
487
				'w' => 440,
488
			) );
489
490
			$items[ $key ] = $item;
491
		}
492
493
		wp_send_json_success( $items );
494
	}
495
496
	/**
497
	 * Sanitize user-provided WP_Query arguments
498
	 *
499
	 * These might be sent to the VideoPress server, for a remote WP_Query
500
	 * call so let's make sure they're sanitized and safe to send.
501
	 */
502
	function sanitize_wp_query_args( $args ) {
503
		$args = shortcode_atts( array(
504
			'posts_per_page' => 40,
505
			'orderby' => 'date',
506
			'order' => 'desc',
507
			'paged' => 1,
508
			's' => '',
509
		), (array) $args, 'wpvideo' );
510
511
		$args['posts_per_page'] = absint( $args['posts_per_page'] );
512
513
		$args['orderby'] = strtolower( $args['orderby'] );
514
		$args['orderby'] = ( in_array( $args['orderby'], array( 'date' ) ) ) ? $args['orderby'] : 'date';
515
516
		$args['order'] = strtolower( $args['order'] );
517
		$args['order'] = ( in_array( $args['order'], array( 'asc', 'desc' ) ) ) ? $args['order'] : 'desc';
518
519
		$args['paged'] = absint( $args['paged'] );
520
		$args['s'] = sanitize_text_field( $args['s'] );
521
		return $args;
522
	}
523
524
	/**
525
	 * Custom AJAX callback for the save-attachment action. If the request was
526
	 * not for a VideoPress object, core's fallback action will kick in.
527
	 */
528
	function wp_ajax_save_attachment() {
529
		if ( ! isset( $_POST['is_videopress'] ) )
530
			return;
531
532
		if ( ! $this->can( 'edit_videos' ) )
533
			return wp_send_json_error( 'permission denied' );
534
535
		$post_id = 0;
536 View Code Duplication
		if ( ! isset( $_POST['id'] ) || ! $post_id = absint( $_POST['id'] ) )
537
			wp_send_json_error();
538
539
		if ( ! isset( $_POST['vp_nonces']['update'] ) )
540
			wp_send_json_error();
541
542
		check_ajax_referer( 'update-videopress-post_' . $post_id, 'nonce' );
543
544
		$changes = ( ! empty( $_POST['changes'] ) ) ? (array) $_POST['changes'] : array();
545
		$changes = shortcode_atts( array(
546
			'title' => null,
547
			'caption' => null,
548
			'description' => null,
549
550
			'vp_share' => null,
551
			'vp_rating' => null,
552
		), $changes, 'wpvideo' );
553
554
		if ( ! is_null( $changes['vp_share'] ) )
555
			$changes['vp_share'] = (bool) $changes['vp_share'];
556
557
		if ( ! is_null( $changes['vp_rating'] ) )
558
			$changes['vp_rating'] = ( array_key_exists( $changes['vp_rating'], $this->get_available_ratings() ) ) ? $changes['vp_rating'] : null;
559
560
		// Remove null-values
561
		foreach ( $changes as $key => $value )
562
			if ( is_null( $value ) )
563
				unset( $changes[ $key ] );
564
565
		$result = $this->query( 'jetpack.vpSaveAttachment', array(
566
			'post_id' => $post_id,
567
			'changes' => $changes,
568
			'nonce' => $_POST['vp_nonces']['update'],
569
		) );
570
571
		if ( is_wp_error( $result ) )
572
			return wp_send_json_error( 'xml rpc request error' );
573
574
		wp_send_json_success();
575
	}
576
577
	/**
578
	 * Custom AJAX callback for the delete-post action, only for VideoPress objects.
579
	 */
580
	function wp_ajax_delete_post() {
581
		if ( ! isset( $_POST['is_videopress'] ) )
582
			return;
583
584
		if ( ! $this->can( 'delete_videos' ) )
585
			return wp_send_json_error( 'permission denied' );
586
587
		$post_id = 0;
588 View Code Duplication
		if ( ! isset( $_POST['id'] ) || ! $post_id = absint( $_POST['id'] ) )
589
			wp_send_json_error();
590
591
		if ( ! isset( $_POST['vp_nonces']['delete'] ) )
592
			wp_send_json_error();
593
594
		check_ajax_referer( 'delete-videopress-post_' . $post_id );
595
596
		$result = $this->query( 'jetpack.vpDeleteAttachment', array(
597
			'post_id' => $post_id,
598
			'nonce' => $_POST['vp_nonces']['delete'],
599
		) );
600
601
		if ( is_wp_error( $result ) )
602
			return wp_send_json_error( 'xml rpc request error' );
603
604
		wp_send_json_success();
605
	}
606
607
	/**
608
	 * Register VideoPress admin scripts.
609
	 */
610
	function enqueue_admin_scripts() {
611
		if ( did_action( 'videopress_enqueue_admin_scripts' ) )
612
			return;
613
614
		wp_enqueue_script( 'videopress-uploader', plugins_url( 'js/videopress-uploader.js', __FILE__) , array( 'jquery', 'wp-plupload' ), $this->version );
615
		wp_enqueue_script( 'videopress-admin', plugins_url( 'js/videopress-admin.js', __FILE__ ), array( 'jquery', 'media-views', 'media-models' ), $this->version );
616
		wp_enqueue_style( 'videopress-admin', plugins_url( 'videopress-admin.css', __FILE__ ), array(), $this->version );
617
618
		$caps = array();
619 View Code Duplication
		foreach( array( 'read_videos', 'edit_videos', 'delete_videos', 'upload_videos' ) as $cap )
620
			$caps[ $cap ] = $this->can( $cap );
621
622
		$l10n = array(
623
			'selectVideoFile' => __( 'Please select a video file to upload.', 'jetpack' ),
624
			'videoUploading' => __( 'Your video is uploading... Please do not close this window.', 'jetpack' ),
625
			'unknownError' => __( 'An unknown error has occurred. Please try again later.', 'jetpack' ),
626
			'videoUploaded' => __( 'Your video has successfully been uploaded. It will appear in your VideoPress Library shortly.', 'jetpack' ),
627
			'VideoPressLibraryRouter' => __( 'VideoPress Library', 'jetpack' ),
628
			'uploadVideoRouter' => __( 'Upload a Video', 'jetpack' ),
629
			'insertVideoButton' => __( 'Insert Video', 'jetpack' ),
630
631
		);
632
633
		wp_localize_script( 'videopress-admin', 'VideoPressAdminSettings', array(
634
			'caps' => $caps,
635
			'l10n' => $l10n,
636
		) );
637
		
638
		/**
639
		 * Fires after VideoPress scripts are enqueued in the dashboard.
640
		 *
641
		 * @since 2.5.0
642
		 */
643
		do_action( 'videopress_enqueue_admin_scripts' );
644
	}
645
646
	/**
647
	 * Get an array of available ratings. Keys are options, values are labels.
648
	 */
649
	function get_available_ratings() {
650
		return array(
651
			'G' => 'G',
652
			'PG-13' => 'PG-13',
653
			'R-17' => 'R',
654
			'X-18' => 'X',
655
		);
656
	}
657
658
	/**
659
	 * Additional VideoPress media templates.
660
	 */
661
	function print_media_templates() {
662
		$options = $this->get_options();
663
		?>
664
		<script type="text/html" id="tmpl-videopress-attachment">
665
			<# if ( data.vp_ogg_url ) { #>
666
			<label class="setting vp-setting">
667
				<span><?php _e( 'Ogg File URL', 'jetpack' ); ?></span>
668
				<input type="text" value="{{ data.vp_ogg_url }}" onclick="this.focus();this.select();" readonly />
669
				<p class="help"><?php _e( 'Location of the Ogg video file.', 'jetpack' ); ?></p>
670
			</label>
671
			<# } #>
672
673
			<label class="setting vp-setting">
674
				<span><?php _e( 'Share', 'jetpack' ); ?></span>
675
				<input class="vp-checkbox" type="checkbox" <# if ( '1' === data.vp_share ) { #>checked<# } #> <# if ( ! data.can.save ) { #>disabled<# } #> />
676
				<label>
677
					<?php _e( 'Display share menu and allow viewers to embed or download this video', 'jetpack' ); ?>
678
				</label>
679
				<input class="vp-checkbox-text" type="text" value="{{ data.vp_share }}" data-setting="vp_share" style="display:none;" />
680
			</label>
681
682
			<label class="setting vp-setting">
683
				<span><?php _e( 'Rating', 'jetpack' ); ?></span>
684
685
				<?php foreach ( $this->get_available_ratings() as $value => $label ) : ?>
686
				<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 ); ?>"
687
					<# if ( '<?php echo esc_attr( $value ); ?>' === data.vp_rating ) { #>checked<# } #>
688
					<# if ( ! data.can.save ) { #>disabled<# } #> />
689
				<label for="vp-rating-<?php echo sanitize_html_class( $value ); ?>"><?php echo esc_html( $label ); ?></label>
690
				<?php endforeach; ?>
691
692
				<input class="vp-radio-text" type="text" value="{{ data.vp_rating }}" data-setting="vp_rating" style="display:none;" />
693
			</label>
694
695
			<label class="setting vp-setting">
696
				<span><?php _e( 'Shortcode', 'jetpack' ); ?></span>
697
				<input type="text" value="[wpvideo {{ data.vp_guid }}]" onclick="this.focus();this.select();" readonly />
698
			</label>
699
700
			<label class="setting vp-setting vp-preview">
701
				<span><?php _e( 'Preview', 'jetpack' ); ?></span>
702
				<# if ( ! data.vp_thumbnail_url ) { #>
703
					<span class="videopress-preview-unavailable"><?php esc_html_e( 'The preview is unavailable while this video is being processed.', 'jetpack' ); ?></span>
704
				<# } else { #>
705
				<a href="#" class="videopress-preview" id="videopress-thumbnail-{{ data.vp_guid }}" data-videopress-guid="{{ data.vp_guid }}"><img src="{{ data.vp_thumbnail_url }}" /></a>
706
				<# } #>
707
			</label>
708
		</script>
709
710
		<script type="text/html" id="tmpl-videopress-media-modal">
711
			<div class="videopress-modal">
712
				<p><?php _e( 'Video Preview:', 'jetpack' ); ?></p>
713
				<div class="videopress-video-container">{{{ data.video }}}</div>
714
				<p class="submit">
715
					<a class="videopress-modal-close button" href="#"><?php _e( 'Close', 'jetpack' ); ?></a>
716
				</p>
717
			</div>
718
			<div class="videopress-modal-backdrop"></div>
719
		</script>
720
721
		<script type="text/html" id="tmpl-videopress-uploader">
722
			<div class="videopress-errors"></div>
723
			<form class="videopress-upload-form" action="" method="post" target="videopress_upload_frame" enctype="multipart/form-data">
724
				<input type="hidden" name="action" value="videopress_upload" />
725
				<input type="hidden" name="videopress_blog_id" value="0" />
726
				<input type="hidden" name="videopress_token" value="0" />
727
				<?php $formats = 'ogv, mp4, m4v, mov, wmv, avi, mpg, 3gp, 3g2'; ?>
728
				<?php
729
					$max_upload_size = 0;
730
					if ( ! empty( $options['meta']['max_upload_size'] ) )
731
						$max_upload_size = absint( $options['meta']['max_upload_size'] );
732
733
					$upload_size_unit = $max_upload_size;
734
					$byte_sizes = array( 'KB', 'MB', 'GB' );
735
736
					for ( $u = -1; $upload_size_unit > 1024 && $u < count( $byte_sizes ) - 1; $u++ )
737
						$upload_size_unit /= 1024;
738
739
					if ( $u < 0 ) {
740
						$upload_size_unit = 0;
741
						$u = 0;
742
					} else {
743
						$upload_size_unit = (int) $upload_size_unit;
744
					}
745
				?>
746
				<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>
747
748
				<input type="file" name="videopress_file" />
749
				<?php submit_button( __( 'Upload Video', 'jetpack' ) ); ?>
750
			</form>
751
			<iframe width="0" height="0" name="videopress_upload_frame"></iframe>
752
		</script>
753
		<?php
754
	}
755
756
	/**
757
	 * Filters the VideoPress shortcode options, makes sure that
758
	 * the settings set in Jetpack's VideoPress module are applied.
759
	 */
760
	function videopress_shortcode_options( $options ) {
761
		$videopress_options = $this->get_options();
762
763
		if ( false === $options['freedom'] )
764
			$options['freedom'] = $videopress_options['freedom'];
765
766
		$options['hd'] = $videopress_options['hd'];
767
768
		return $options;
769
	}
770
771
}
772
773
// Initialize the module.
774
Jetpack_VideoPress::init();
775