Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
48.28% covered (danger)
48.28%
84 / 174
23.08% covered (danger)
23.08%
3 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_VideoPress
49.12% covered (danger)
49.12%
84 / 171
23.08% covered (danger)
23.08%
3 / 13
324.67
0.00% covered (danger)
0.00%
0 / 1
 init
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 on_init
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 enqueue_jwt_token_bridge
n/a
0 / 0
n/a
0 / 0
1
 enqueue_media_new_scripts
95.83% covered (success)
95.83%
23 / 24
0.00% covered (danger)
0.00%
0 / 1
6
 get_media_new_upload_limits
100.00% covered (success)
100.00%
50 / 50
100.00% covered (success)
100.00%
1 / 1
5
 jetpack_module_deactivated
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 can
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
72
 enqueue_admin_styles
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 delete_video_wpcom
n/a
0 / 0
n/a
0 / 0
1
 enqueue_admin_scripts
0.00% covered (danger)
0.00%
0 / 39
0.00% covered (danger)
0.00%
0 / 1
12
 maybe_get_attached_url_for_videopress
n/a
0 / 0
n/a
0 / 0
1
 videopress_pluploder_config
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 should_override_media_uploader
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
12
 is_videopress_enabled
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 print_in_footer_open_media_add_new
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 add_video_upload_mimes
n/a
0 / 0
n/a
0 / 0
1
 filter_video_mimes
n/a
0 / 0
n/a
0 / 0
1
 wp_mime_type_icon
n/a
0 / 0
n/a
0 / 0
1
 add_videopress_extenstion
n/a
0 / 0
n/a
0 / 0
1
1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3use Automattic\Jetpack\Assets;
4use Automattic\Jetpack\Current_Plan;
5use Automattic\Jetpack\Status;
6use Automattic\Jetpack\VideoPress\Attachment_Handler;
7use Automattic\Jetpack\VideoPress\Jwt_Token_Bridge;
8use Automattic\Jetpack\VideoPress\Options as VideoPress_Options;
9
10if ( ! defined( 'ABSPATH' ) ) {
11    exit( 0 );
12}
13
14/**
15 * VideoPress in Jetpack
16 */
17class Jetpack_VideoPress {
18    /**
19     * Module name.
20     *
21     * @var string
22     */
23    public $module = 'videopress';
24
25    /**
26     * Singleton
27     */
28    public static function init() {
29        static $instance = false;
30
31        if ( ! $instance ) {
32            $instance = new Jetpack_VideoPress();
33        }
34
35        return $instance;
36    }
37
38    /**
39     * Jetpack_VideoPress constructor.
40     *
41     * Sets up the initializer and makes sure that videopress activates and deactivates properly.
42     */
43    private function __construct() {
44        add_action( 'init', array( $this, 'on_init' ) );
45        add_action( 'jetpack_deactivate_module_videopress', array( $this, 'jetpack_module_deactivated' ) );
46    }
47
48    /**
49     * Fires on init
50     */
51    public function on_init() {
52        add_action( 'wp_enqueue_media', array( $this, 'enqueue_admin_scripts' ) );
53        add_filter( 'plupload_default_settings', array( $this, 'videopress_pluploder_config' ) );
54
55        add_action( 'admin_print_footer_scripts', array( $this, 'print_in_footer_open_media_add_new' ) );
56        add_action( 'admin_head', array( $this, 'enqueue_admin_styles' ) );
57        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_media_new_scripts' ) );
58
59        VideoPress_Scheduler::init();
60    }
61
62    /**
63     * Enqueues the jwt bridge script.
64     *
65     * @deprecated 11.3
66     */
67    public function enqueue_jwt_token_bridge() {
68        _deprecated_function( __METHOD__, 'jetpack-11.3', 'Automattic\Jetpack\VideoPress\Jwt_Token_Bridge::enqueue_jwt_token_bridge' );
69        return Jwt_Token_Bridge::enqueue_jwt_token_bridge();
70    }
71
72    /**
73     * Enqueues the script that routes media-new.php video uploads to VideoPress.
74     *
75     * The classic uploader on media-new.php builds a raw plupload.Uploader
76     * (via plupload-handlers) instead of wp.Uploader, so the override in
77     * videopress-plupload.js never engages there. This companion script
78     * registers the same videopress_check_uploads plupload filter and
79     * re-targets video uploads to VideoPress. The filter is injected into the
80     * uploader settings through the plupload_init filter, which
81     * media_upload_form() applies when it renders later in the request.
82     *
83     * @param string $hook_suffix The current admin page.
84     */
85    public function enqueue_media_new_scripts( $hook_suffix ) {
86        if ( 'media-new.php' !== $hook_suffix ) {
87            return;
88        }
89
90        if ( ! $this->is_videopress_enabled() ) {
91            return;
92        }
93
94        // Version with the served file's mtime so browsers and page caches pick
95        // up new builds even when JETPACK__VERSION has not changed (branch
96        // testing, beta builds).
97        $script_relative = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG
98            ? 'modules/videopress/js/videopress-media-new.js'
99            : '_inc/build/videopress/js/videopress-media-new.min.js';
100        $script_path     = JETPACK__PLUGIN_DIR . $script_relative;
101        $script_version  = file_exists( $script_path ) ? (string) filemtime( $script_path ) : JETPACK__VERSION;
102
103        wp_enqueue_script(
104            'videopress-media-new',
105            Assets::get_file_url_for_environment(
106                '_inc/build/videopress/js/videopress-media-new.min.js',
107                'modules/videopress/js/videopress-media-new.js'
108            ),
109            array(
110                'jquery',
111                'plupload-handlers',
112            ),
113            $script_version,
114            true
115        );
116
117        wp_localize_script( 'videopress-media-new', 'videoPressMediaNew', $this->get_media_new_upload_limits() );
118
119        add_filter( 'plupload_init', array( $this, 'videopress_pluploder_config' ) );
120    }
121
122    /**
123     * Returns the free-plan upload limit data used by the media-new.php script.
124     *
125     * The free plan includes a single video upload, so the script needs to know
126     * whether the site has a paid VideoPress plan, whether the free upload has
127     * already been used, and where to send the user to upgrade. Mirrors the
128     * checks behind the VideoPress dashboard's upgrade notice: the paid check
129     * matches Admin_UI::initial_state()'s paidFeatures, and the used check
130     * matches the dashboard's VideoPress video count (video/videopress
131     * attachments).
132     *
133     * @return array
134     */
135    public function get_media_new_upload_limits() {
136        $has_videopress_purchase = Current_Plan::supports( 'videopress-1tb-storage' )
137            || Current_Plan::supports( 'videopress-unlimited-storage' )
138            || ( function_exists( 'wpcom_site_has_feature' ) && wpcom_site_has_feature( 'videopress' ) );
139
140        $has_used_video = false;
141        if ( ! $has_videopress_purchase ) {
142            $videopress_videos = get_posts(
143                array(
144                    'post_type'      => 'attachment',
145                    'post_status'    => 'inherit',
146                    'post_mime_type' => 'video/videopress',
147                    'posts_per_page' => 1,
148                    'fields'         => 'ids',
149                )
150            );
151
152            $has_used_video = count( $videopress_videos ) > 0;
153        }
154
155        $upgrade_url = sprintf(
156            'https://wordpress.com/checkout/%s/jetpack_videopress?redirect_to=%s',
157            rawurlencode( ( new Status() )->get_site_suffix() ),
158            rawurlencode( admin_url( 'media-new.php' ) )
159        );
160
161        $allowed_html = array(
162            'a' => array( 'href' => array() ),
163        );
164
165        return array(
166            'hasVideoPressPurchase' => $has_videopress_purchase,
167            'hasUsedVideo'          => $has_used_video,
168            'strings'               => array(
169                'usedVideoUpload'        => sprintf(
170                    wp_kses(
171                        /* translators: %s is the url to upgrade the VideoPress plan */
172                        __( 'You have used your free video upload. The free plan includes one video upload. <a href="%s">Upgrade now</a> to unlock unlimited videos, 1TB of storage, and more!', 'jetpack' ),
173                        $allowed_html
174                    ),
175                    esc_url( $upgrade_url )
176                ),
177                'multipleVideos'         => sprintf(
178                    wp_kses(
179                        /* translators: %s is the url to upgrade the VideoPress plan */
180                        __( 'The free plan includes one video upload. <a href="%s">Upgrade now</a> to upload more videos and unlock unlimited videos, 1TB of storage, and more!', 'jetpack' ),
181                        $allowed_html
182                    ),
183                    esc_url( $upgrade_url )
184                ),
185                'multipleVideosSelected' => sprintf(
186                    wp_kses(
187                        /* translators: %s is the url to upgrade the VideoPress plan */
188                        __( 'Uploading multiple videos requires a paid plan. The free plan includes one video upload. <a href="%s">Upgrade now</a> to unlock unlimited videos, 1TB of storage, and more!', 'jetpack' ),
189                        $allowed_html
190                    ),
191                    esc_url( $upgrade_url )
192                ),
193            ),
194        );
195    }
196
197    /**
198     * Runs when the VideoPress module is deactivated.
199     */
200    public function jetpack_module_deactivated() {
201        VideoPress_Options::delete_options();
202    }
203
204    /**
205     * Similar to current_user_can, but internal to VideoPress.
206     *
207     * @param string $cap Capability name.
208     * @param int    $user_id User ID.
209     * @return bool Returns true if the given VideoPress capability is allowed by the given user.
210     */
211    public function can( $cap, $user_id = false ) {
212        if ( ! $user_id ) {
213            $user_id = get_current_user_id();
214        }
215
216        // Connection owners are allowed to do all the things.
217        if ( Jetpack::connection()->is_connection_owner( $user_id ) ) {
218            return true;
219        }
220
221        // Additional and internal caps checks
222        if ( ! user_can( $user_id, 'upload_files' ) ) {
223            return false;
224        }
225
226        if ( 'edit_videos' === $cap && ! user_can( $user_id, 'edit_others_posts' ) ) {
227            return false;
228        }
229
230        if ( 'delete_videos' === $cap && ! user_can( $user_id, 'delete_others_posts' ) ) {
231            return false;
232        }
233
234        return true;
235    }
236
237    /**
238     * Register and enqueue VideoPress admin styles.
239     */
240    public function enqueue_admin_styles() {
241        wp_register_style( 'videopress-admin', plugins_url( 'videopress-admin.css', __FILE__ ), array(), JETPACK__VERSION );
242        wp_enqueue_style( 'videopress-admin' );
243    }
244
245    /**
246     * Attempts to delete a VideoPress video from wp.com.
247     * Will block the deletion from continuing if certain errors return from the wp.com API.
248     *
249     * @param Boolean $delete if the deletion should occur or not (unused).
250     * @param WP_Post $post the post object.
251     *
252     * @deprecated 11.3
253     *
254     * @return null|WP_Error|Boolean null if deletion should continue.
255     */
256    public function delete_video_wpcom( $delete, $post ) {
257        _deprecated_function( __METHOD__, 'jetpack-11.3', 'Automattic\Jetpack\VideoPress\Attachment_Handler::delete_video_wpcom' );
258        return Attachment_Handler::delete_video_wpcom( $delete, $post );
259    }
260
261    /**
262     * Register VideoPress admin scripts.
263     */
264    public function enqueue_admin_scripts() {
265        if ( did_action( 'videopress_enqueue_admin_scripts' ) ) {
266            return;
267        }
268
269        if ( $this->should_override_media_uploader() ) {
270            wp_enqueue_script(
271                'videopress-plupload',
272                Assets::get_file_url_for_environment(
273                    '_inc/build/videopress/js/videopress-plupload.min.js',
274                    'modules/videopress/js/videopress-plupload.js'
275                ),
276                array(
277                    'jquery',
278                    'wp-plupload',
279                ),
280                JETPACK__VERSION,
281                true
282            );
283
284            wp_enqueue_script(
285                'videopress-uploader',
286                Assets::get_file_url_for_environment(
287                    '_inc/build/videopress/js/videopress-uploader.min.js',
288                    'modules/videopress/js/videopress-uploader.js'
289                ),
290                array(
291                    'videopress-plupload',
292                ),
293                JETPACK__VERSION,
294                true
295            );
296
297            wp_enqueue_script(
298                'media-video-widget-extensions',
299                Assets::get_file_url_for_environment(
300                    '_inc/build/videopress/js/media-video-widget-extensions.min.js',
301                    'modules/videopress/js/media-video-widget-extensions.js'
302                ),
303                array(),
304                JETPACK__VERSION,
305                true
306            );
307        }
308
309        /**
310         * Fires after VideoPress scripts are enqueued in the dashboard.
311         *
312         * @since 2.5.0
313         */
314        do_action( 'videopress_enqueue_admin_scripts' );
315    }
316
317    /**
318     * Returns the VideoPress URL for the give post id, otherwise returns the provided default.
319     *
320     * This is an attachment-based filter handler.
321     *
322     * @deprecated 11.3
323     *
324     * @param string $default The default return value if post id is not a VideoPress video.
325     * @param int    $post_id The post id for the current attachment.
326     */
327    public function maybe_get_attached_url_for_videopress( $default, $post_id ) {
328        _deprecated_function( __METHOD__, 'jetpack-11.3', 'Automattic\Jetpack\VideoPress\Attachment_Handler::maybe_get_attached_url_for_videopress' );
329        return Attachment_Handler::maybe_get_attached_url_for_videopress( $default, $post_id );
330    }
331
332    /**
333     * Modify the default plupload config to turn on VideoPress specific filters.
334     *
335     * @param array $config The plupload config.
336     */
337    public function videopress_pluploder_config( $config ) {
338
339        if ( ! isset( $config['filters']['max_file_size'] ) ) {
340            $config['filters']['max_file_size'] = wp_max_upload_size() . 'b';
341        }
342
343        $config['filters']['videopress_check_uploads'] = $config['filters']['max_file_size'];
344
345        // We're doing our own check in the videopress_check_uploads filter.
346        unset( $config['filters']['max_file_size'] );
347
348        return $config;
349    }
350
351    /**
352     * Helper function to determine if the media uploader should be overridden.
353     *
354     * The rules are simple, only try to load the script when on the edit post or new post pages.
355     *
356     * @return bool
357     */
358    protected function should_override_media_uploader() {
359        global $pagenow;
360
361        // Only load in the admin
362        if ( ! is_admin() ) {
363            return false;
364        }
365
366        $acceptable_pages = array(
367            'post-new.php',
368            'post.php',
369            'upload.php',
370            'customize.php',
371        );
372
373        // Only load on the post, new post, or upload pages.
374        if ( ! in_array( $pagenow, $acceptable_pages, true ) ) {
375            return false;
376        }
377
378        return $this->is_videopress_enabled();
379    }
380
381    /**
382     * Detects if VideoPress is enabled.
383     *
384     * @return bool
385     */
386    protected function is_videopress_enabled() {
387        $options = VideoPress_Options::get_options();
388
389        return $options['shadow_blog_id'] > 0;
390    }
391
392    /**
393     * A work-around / hack to make it possible to go to the media library with the add new box open.
394     *
395     * @return bool
396     */
397    public function print_in_footer_open_media_add_new() {
398        global $pagenow;
399
400        // Only load in the admin
401        if ( ! is_admin() ) {
402            return false;
403        }
404
405        if ( $pagenow !== 'upload.php' ) {
406            return false;
407        }
408
409        if ( ! isset( $_GET['action'] ) || $_GET['action'] !== 'add-new' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
410            return false;
411        }
412
413        ?>
414            <script type="text/javascript">
415                ( function( $ ) {
416                    window.setTimeout( function() {
417                        $('#wp-media-grid .page-title-action').click();
418                    }, 500 );
419
420                }( jQuery ) );
421            </script>
422        <?php
423    }
424
425    /**
426     * Makes sure that all video mimes are added in, as multi site installs can remove them.
427     *
428     * @deprecated 11.3
429     *
430     * @param array $existing_mimes Mime types to extend/filter.
431     * @return array
432     */
433    public function add_video_upload_mimes( $existing_mimes = array() ) {
434        _deprecated_function( __METHOD__, 'jetpack-11.3', 'Automattic\Jetpack\VideoPress\Attachment_Handler::add_video_upload_mimes' );
435        return Attachment_Handler::add_video_upload_mimes( $existing_mimes );
436    }
437
438    /**
439     * Filter designed to get rid of non video mime types.
440     *
441     * @deprecated 11.3
442     *
443     * @param string $value Mime type to filter.
444     * @return int
445     */
446    public function filter_video_mimes( $value ) {
447        _deprecated_function( __METHOD__, 'jetpack-11.3', 'Automattic\Jetpack\VideoPress\Attachment_Handler::filter_video_mimes' );
448        return Attachment_Handler::filter_video_mimes( $value );
449    }
450
451    /**
452     * Filter the mime type icon.
453     *
454     * @param string $icon Icon path.
455     * @param string $mime Mime type.
456     * @param int    $post_id Post ID.
457     *
458     * @deprecated 11.3
459     *
460     * @return string
461     */
462    public function wp_mime_type_icon( $icon, $mime, $post_id ) {
463        _deprecated_function( __METHOD__, 'jetpack-11.3', 'Automattic\Jetpack\VideoPress\Attachment_Handler::wp_mime_type_icon' );
464        return Attachment_Handler::wp_mime_type_icon( $icon, $mime, $post_id );
465    }
466
467    /**
468     * Filter the list of supported video formats.
469     *
470     * @param array $extensions Supported video formats.
471     *
472     * @deprecated 11.3
473     *
474     * @return array
475     */
476    public function add_videopress_extenstion( $extensions ) {
477        _deprecated_function( __METHOD__, 'jetpack-11.3', 'Automattic\Jetpack\VideoPress\Attachment_Handler::add_videopress_extenstion' );
478        return Attachment_Handler::add_videopress_extenstion( $extensions );
479    }
480}
481
482// Initialize the module.
483Jetpack_VideoPress::init();