Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 90
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_JSON_API_Plugins_New_Endpoint
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 3
156
0.00% covered (danger)
0.00%
0 / 1
 validate_call
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 validate_input
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 install
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
72
1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3use Automattic\Jetpack\Automatic_Install_Skin;
4
5if ( ! defined( 'ABSPATH' ) ) {
6    exit( 0 );
7}
8
9require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
10require_once ABSPATH . 'wp-admin/includes/file.php';
11
12// POST /sites/%s/plugins/new
13new Jetpack_JSON_API_Plugins_New_Endpoint(
14    array(
15        'description'             => 'Install a plugin to a Jetpack site by uploading a zip file',
16        'group'                   => '__do_not_document',
17        'stat'                    => 'plugins:new',
18        'min_version'             => '1',
19        'max_version'             => '1.1',
20        'method'                  => 'POST',
21        'path'                    => '/sites/%s/plugins/new',
22        'path_labels'             => array(
23            '$site' => '(int|string) Site ID or domain',
24        ),
25        'request_format'          => array(
26            'zip' => '(array) Reference to an uploaded plugin package zip file.',
27        ),
28        'response_format'         => Jetpack_JSON_API_Plugins_Endpoint::$_response_format,
29        'allow_jetpack_site_auth' => true,
30        'example_request_data'    => array(
31            'headers' => array(
32                'authorization' => 'Bearer YOUR_API_TOKEN',
33            ),
34        ),
35        'example_request'         => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/new',
36    )
37);
38
39new Jetpack_JSON_API_Plugins_New_Endpoint(
40    array(
41        'description'             => 'Install a plugin to a Jetpack site by uploading a zip file',
42        'group'                   => '__do_not_document',
43        'stat'                    => 'plugins:new',
44        'min_version'             => '1.2',
45        'method'                  => 'POST',
46        'path'                    => '/sites/%s/plugins/new',
47        'path_labels'             => array(
48            '$site' => '(int|string) Site ID or domain',
49        ),
50        'request_format'          => array(
51            'zip' => '(array) Reference to an uploaded plugin package zip file.',
52        ),
53        'response_format'         => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2,
54        'allow_jetpack_site_auth' => true,
55        'example_request_data'    => array(
56            'headers' => array(
57                'authorization' => 'Bearer YOUR_API_TOKEN',
58            ),
59        ),
60        'example_request'         => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/new',
61    )
62);
63
64/**
65 * Plugins new endpoint class.
66 *
67 * POST /sites/%s/plugins/new
68 *
69 * @phan-constructor-used-for-side-effects
70 */
71class Jetpack_JSON_API_Plugins_New_Endpoint extends Jetpack_JSON_API_Plugins_Endpoint {
72
73    /**
74     * Needed capabilities.
75     *
76     * @var string
77     */
78    protected $needed_capabilities = 'install_plugins';
79
80    /**
81     * The action.
82     *
83     * @var string
84     */
85    protected $action = 'install';
86
87    /**
88     * Validate call.
89     *
90     * @param int    $_blog_id - the blog ID.
91     * @param string $capability - the capability.
92     * @param bool   $check_manage_active - check if manage is active.
93     *
94     * @return bool|WP_Error a WP_Error object or true if things are good.
95     */
96    protected function validate_call( $_blog_id, $capability, $check_manage_active = true ) {
97        $validate = parent::validate_call( $_blog_id, $capability, $check_manage_active );
98        if ( is_wp_error( $validate ) ) {
99
100            // Lets delete the attachment... if the user doesn't have the right permissions to do things.
101            $args = $this->input();
102            if ( isset( $args['zip'][0]['id'] ) ) {
103                wp_delete_attachment( $args['zip'][0]['id'], true );
104            }
105        }
106
107        return $validate;
108    }
109
110    /**
111     * No need to try to validate the plugin since we didn't pass one in.
112     *
113     * @param string $plugin - the plugin we're validating.
114     */
115    protected function validate_input( $plugin ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
116        $this->bulk    = false;
117        $this->plugins = array();
118    }
119
120    /**
121     * Install the plugin.
122     *
123     * @return bool|WP_Error
124     */
125    public function install() {
126        $args = $this->input();
127
128        if ( isset( $args['zip'][0]['id'] ) ) {
129            $plugin_attachment_id = $args['zip'][0]['id'];
130            $local_file           = get_attached_file( $plugin_attachment_id );
131            if ( ! $local_file ) {
132                return new WP_Error( 'local-file-does-not-exist' );
133            }
134            $skin     = new Automatic_Install_Skin();
135            $upgrader = new Plugin_Upgrader( $skin );
136
137            $pre_install_plugin_list = get_plugins();
138            $result                  = $upgrader->install( $local_file );
139
140            // clean up.
141            wp_delete_attachment( $plugin_attachment_id, true );
142
143            if ( is_wp_error( $result ) ) {
144                return $result;
145            }
146
147            $after_install_plugin_list = get_plugins();
148            $plugin                    = array_values( array_diff( array_keys( $after_install_plugin_list ), array_keys( $pre_install_plugin_list ) ) );
149
150            if ( ! $result ) {
151                $error_code = $skin->get_main_error_code();
152                $message    = $skin->get_main_error_message();
153                if ( empty( $message ) ) {
154                    $message = __( 'An unknown error occurred during installation', 'jetpack' );
155                }
156
157                if ( 'download_failed' === $error_code ) {
158                    $error_code = 'no_package';
159                }
160
161                return new WP_Error( $error_code, $message, 400 );
162            }
163
164            if ( empty( $plugin ) ) {
165                return new WP_Error( 'plugin_already_installed' );
166            }
167
168            $this->plugins           = $plugin;
169            $this->log[ $plugin[0] ] = $upgrader->skin->get_upgrade_messages();
170
171            return true;
172        }
173
174        return new WP_Error( 'no_plugin_installed' );
175    }
176}