Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 68
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
Jetpack_JSON_API_Plugins_Install_Endpoint
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 2
132
0.00% covered (danger)
0.00%
0 / 1
 install
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
42
 validate_plugins
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
30
1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3use Automattic\Jetpack\Plugins_Installer;
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// POST /sites/%s/plugins/%s/install
12new Jetpack_JSON_API_Plugins_Install_Endpoint(
13    array(
14        'description'             => 'Install a plugin to your jetpack blog',
15        'group'                   => '__do_not_document',
16        'stat'                    => 'plugins:1:install',
17        'min_version'             => '1',
18        'max_version'             => '1.1',
19        'method'                  => 'POST',
20        'path'                    => '/sites/%s/plugins/%s/install',
21        'path_labels'             => array(
22            '$site'   => '(int|string) The site ID, The site domain',
23            '$plugin' => '(int|string) The plugin slug to install',
24        ),
25        'response_format'         => Jetpack_JSON_API_Plugins_Endpoint::$_response_format,
26        'allow_jetpack_site_auth' => true,
27        'example_request_data'    => array(
28            'headers' => array(
29                'authorization' => 'Bearer YOUR_API_TOKEN',
30            ),
31        ),
32        'example_request'         => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/akismet/install',
33    )
34);
35
36new Jetpack_JSON_API_Plugins_Install_Endpoint(
37    array(
38        'description'             => 'Install a plugin to your jetpack blog',
39        'group'                   => '__do_not_document',
40        'stat'                    => 'plugins:1:install',
41        'min_version'             => '1.2',
42        'method'                  => 'POST',
43        'path'                    => '/sites/%s/plugins/%s/install',
44        'path_labels'             => array(
45            '$site'   => '(int|string) The site ID, The site domain',
46            '$plugin' => '(int|string) The plugin slug to install',
47        ),
48        'response_format'         => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2,
49        'allow_jetpack_site_auth' => true,
50        'example_request_data'    => array(
51            'headers' => array(
52                'authorization' => 'Bearer YOUR_API_TOKEN',
53            ),
54        ),
55        'example_request'         => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/akismet/install',
56    )
57);
58
59/**
60 * Plugins install enedpoint class.
61 *
62 * POST /sites/%s/plugins/%s/install
63 *
64 * @phan-constructor-used-for-side-effects
65 */
66class Jetpack_JSON_API_Plugins_Install_Endpoint extends Jetpack_JSON_API_Plugins_Endpoint {
67
68    /**
69     * Needed capabilities.
70     *
71     * @var string
72     */
73    protected $needed_capabilities = 'install_plugins';
74
75    /**
76     * The action.
77     *
78     * @var string
79     */
80    protected $action = 'install';
81
82    /**
83     * Installation.
84     *
85     * @return bool|WP_Error
86     */
87    protected function install() {
88        $result = '';
89        foreach ( $this->plugins as $index => $slug ) {
90            $result = Plugins_Installer::install_plugin( $slug );
91            if ( is_wp_error( $result ) ) {
92                $this->log[ $slug ][] = $result->get_error_message();
93                if ( ! $this->bulk ) {
94                    return $result;
95                }
96            }
97        }
98
99        if ( ! $result ) {
100            return new WP_Error( 'plugin_install_failed', __( 'Plugin install failed because the result was invalid.', 'jetpack' ) );
101        }
102
103        if ( is_wp_error( $result ) ) {
104            return $result;
105        }
106
107        // No errors, install worked. Now replace the slug with the actual plugin id
108        // @todo This code looks a bit suspect; why do we loop through plugins and only look at the last one?
109        // @phan-suppress-next-line PhanPossiblyUndeclaredVariable -- we return early if there is an issue; otherwise $index and $slug are set in the foreach loop
110        $this->plugins[ $index ] = Plugins_Installer::get_plugin_id_by_slug( $slug );
111
112        return true;
113    }
114
115    /**
116     * Validate the plugins.
117     *
118     * @return bool|WP_Error
119     */
120    protected function validate_plugins() {
121        if ( empty( $this->plugins ) || ! is_array( $this->plugins ) ) {
122            return new WP_Error( 'missing_plugins', __( 'No plugins found.', 'jetpack' ) );
123        }
124
125        foreach ( $this->plugins as $slug ) {
126            // make sure it is not already installed
127            if ( Plugins_Installer::get_plugin_id_by_slug( $slug ) ) {
128                return new WP_Error( 'plugin_already_installed', __( 'The plugin is already installed', 'jetpack' ) );
129            }
130        }
131
132        return true;
133    }
134}