Completed
Push — update/sync-users-enqueue-orde... ( 33db83...19456a )
by
unknown
12:33 queued 03:27
created

install()   C

Complexity

Conditions 11
Paths 22

Size

Total Lines 43
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 24
nc 22
nop 0
dl 0
loc 43
rs 5.2653
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
4
include_once ABSPATH . 'wp-admin/includes/file.php';
5
// POST /sites/%s/plugins/%s/install
6
new Jetpack_JSON_API_Plugins_Install_Endpoint(
7
	array(
8
		'description'          => 'Install a plugin to your jetpack blog',
9
		'group'                => '__do_not_document',
10
		'stat'                 => 'plugins:1:install',
11
		'min_version'          => '1',
12
		'max_version'          => '1.1',
13
		'method'               => 'POST',
14
		'path'                 => '/sites/%s/plugins/%s/install',
15
		'path_labels'          => array(
16
			'$site'   => '(int|string) The site ID, The site domain',
17
			'$plugin' => '(int|string) The plugin slug to install',
18
		),
19
		'response_format'      => Jetpack_JSON_API_Plugins_Endpoint::$_response_format,
0 ignored issues
show
Bug introduced by
The property _response_format cannot be accessed from this context as it is declared private in class Jetpack_JSON_API_Plugins_Endpoint.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
20
		'example_request_data' => array(
21
			'headers' => array(
22
				'authorization' => 'Bearer YOUR_API_TOKEN'
23
			),
24
		),
25
		'example_request'      => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/akismet/install'
26
	)
27
);
28
29
new Jetpack_JSON_API_Plugins_Install_Endpoint(
30
	array(
31
		'description'          => 'Install a plugin to your jetpack blog',
32
		'group'                => '__do_not_document',
33
		'stat'                 => 'plugins:1:install',
34
		'min_version'          => '1.2',
35
		'method'               => 'POST',
36
		'path'                 => '/sites/%s/plugins/%s/install',
37
		'path_labels'          => array(
38
			'$site'   => '(int|string) The site ID, The site domain',
39
			'$plugin' => '(int|string) The plugin slug to install',
40
		),
41
		'response_format'      => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2,
0 ignored issues
show
Bug introduced by
The property _response_format_v1_2 cannot be accessed from this context as it is declared private in class Jetpack_JSON_API_Plugins_Endpoint.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
42
		'example_request_data' => array(
43
			'headers' => array(
44
				'authorization' => 'Bearer YOUR_API_TOKEN'
45
			),
46
		),
47
		'example_request'      => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/akismet/install'
48
	)
49
);
50
51
class Jetpack_JSON_API_Plugins_Install_Endpoint extends Jetpack_JSON_API_Plugins_Endpoint {
52
53
	// POST /sites/%s/plugins/%s/install
54
	protected $needed_capabilities = 'install_plugins';
55
	protected $action = 'install';
56
57
	protected function install() {
58
		$error = '';
59
		foreach ( $this->plugins as $index => $slug ) {
60
61
			$skin     = new Jetpack_Automatic_Install_Skin();
62
			$upgrader = new Plugin_Upgrader( $skin );
63
			$zip_url  = self::generate_wordpress_org_plugin_download_link( $slug );
64
65
			$result = $upgrader->install( $zip_url );
66
67
			if ( ! $this->bulk && is_wp_error( $result ) ) {
68
				return $result;
69
			}
70
71
			$plugin     = self::get_plugin_id_by_slug( $slug );
72
			$error_code = 'install_error';
73
			if ( ! $plugin ) {
74
				$error = $this->log[ $slug ][] = __( 'There was an error installing your plugin', 'jetpack' );
75
			}
76
77
			if ( ! $this->bulk && ! $result ) {
78
				$error_code                         = $upgrader->skin->get_main_error_code();
79
				$message                            = $upgrader->skin->get_main_error_message();
80
				$error = $this->log[ $slug ][] = $message ? $message : __( 'An unknown error occurred during installation', 'jetpack' );
81
			}
82
83
			$this->log[ $plugin ] = (array) $upgrader->skin->get_upgrade_messages();
84
		}
85
86
		if ( ! $this->bulk && ! empty( $error ) ) {
87
			if ( 'download_failed' === $error_code ) {
0 ignored issues
show
Bug introduced by
The variable $error_code does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
88
				// For backwards compatibility: versions prior to 3.9 would return no_package instead of download_failed.
89
				$error_code = 'no_package';
90
			}
91
92
			return new WP_Error( $error_code, $error, 400 );
93
		}
94
95
		// replace the slug with the actual plugin id
96
		$this->plugins[$index] = $plugin;
0 ignored issues
show
Bug introduced by
The variable $plugin does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
Bug introduced by
The variable $index seems to be defined by a foreach iteration on line 59. Are you sure the iterator is never empty, otherwise this variable is not defined?

It seems like you are relying on a variable being defined by an iteration:

foreach ($a as $b) {
}

// $b is defined here only if $a has elements, for example if $a is array()
// then $b would not be defined here. To avoid that, we recommend to set a
// default value for $b.


// Better
$b = 0; // or whatever default makes sense in your context
foreach ($a as $b) {
}

// $b is now guaranteed to be defined here.
Loading history...
97
98
		return true;
99
	}
100
101
	protected function validate_plugins() {
102 View Code Duplication
		if ( empty( $this->plugins ) || ! is_array( $this->plugins ) ) {
103
			return new WP_Error( 'missing_plugins', __( 'No plugins found.', 'jetpack' ) );
104
		}
105
		foreach ( $this->plugins as $index => $slug ) {
106
			// make sure it is not already installed
107
			if ( self::get_plugin_id_by_slug( $slug ) ) {
108
				return new WP_Error( 'plugin_already_installed', __( 'The plugin is already installed', 'jetpack' ) );
109
			}
110
111
		}
112
113
		return true;
114
	}
115
116
	protected static function generate_wordpress_org_plugin_download_link( $plugin_slug ) {
117
		return "https://downloads.wordpress.org/plugin/{$plugin_slug}.latest-stable.zip";
118
	}
119
120
	protected static function get_plugin_id_by_slug( $slug ) {
121
		/** This filter is documented in wp-admin/includes/class-wp-plugins-list-table.php */
122
		$plugins = apply_filters( 'all_plugins', get_plugins() );
123
		if ( ! is_array( $plugins ) ) {
124
			return false;
125
		}
126
		foreach ( $plugins as $plugin_file => $plugin_data ) {
127
			if ( self::get_slug_from_file_path( $plugin_file ) === $slug ) {
128
				return $plugin_file;
129
			}
130
		}
131
132
		return false;
133
	}
134
135
	protected static function get_slug_from_file_path( $plugin_file ) {
136
		// Simular to get_plugin_slug() method.
137
		$slug = dirname( $plugin_file );
138
		if ( '.' === $slug ) {
139
			$slug = preg_replace( "/(.+)\.php$/", "$1", $plugin_file );
140
		}
141
142
		return $slug;
143
	}
144
}
145
146
/**
147
 * Allows us to capture that the site doesn't have proper file system access.
148
 * In order to update the plugin.
149
 */
150
class Jetpack_Automatic_Install_Skin extends Automatic_Upgrader_Skin {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
151
	/**
152
	 * Stores the last error key;
153
	 **/
154
	protected $main_error_code = 'install_error';
155
156
	/**
157
	 * Stores the last error message.
158
	 **/
159
	protected $main_error_message = 'An unknown error occurred during installation';
160
161
	/**
162
	 * Overwrites the set_upgrader to be able to tell if we e ven have the ability to write to the files.
163
	 *
164
	 * @param WP_Upgrader $upgrader
165
	 *
166
	 */
167
	public function set_upgrader( &$upgrader ) {
168
		parent::set_upgrader( $upgrader );
169
170
		// Check if we even have permission to.
171
		$result = $upgrader->fs_connect( array( WP_CONTENT_DIR, WP_PLUGIN_DIR ) );
172
		if ( ! $result ) {
173
			// set the string here since they are not available just yet
174
			$upgrader->generic_strings();
175
			$this->feedback( 'fs_unavailable' );
176
		}
177
	}
178
179
	/**
180
	 * Overwrites the error function
181
	 */
182
	public function error( $error ) {
183
		if ( is_wp_error( $error ) ) {
184
			$this->feedback( $error );
185
		}
186
	}
187
188
	private function set_main_error_code( $code ) {
189
		// Don't set the process_failed as code since it is not that helpful unless we don't have one already set.
190
		$this->main_error_code = ( $code === 'process_failed' && $this->main_error_code ? $this->main_error_code : $code );
191
	}
192
193
	private function set_main_error_message( $message, $code ) {
194
		// Don't set the process_failed as message since it is not that helpful unless we don't have one already set.
195
		$this->main_error_message = ( $code === 'process_failed' && $this->main_error_code ? $this->main_error_code : $message );
196
	}
197
198
	public function get_main_error_code() {
199
		return $this->main_error_code;
200
	}
201
202
	public function get_main_error_message() {
203
		return $this->main_error_message;
204
	}
205
206
	/**
207
	 * Overwrites the feedback function
208
	 */
209
	public function feedback( $data ) {
210
211
		$current_error = null;
212
		if ( is_wp_error( $data ) ) {
213
			$this->set_main_error_code( $data->get_error_code() );
214
			$string = $data->get_error_message();
215
		} elseif ( is_array( $data ) ) {
216
			return;
217
		} else {
218
			$string = $data;
219
		}
220
221
		if ( ! empty( $this->upgrader->strings[$string] ) ) {
222
			$this->set_main_error_code( $string );
223
224
			$current_error = $string;
225
			$string        = $this->upgrader->strings[$string];
226
		}
227
228
		if ( strpos( $string, '%' ) !== false ) {
229
			$args = func_get_args();
230
			$args = array_splice( $args, 1 );
231
			if ( ! empty( $args ) ) {
232
				$string = vsprintf( $string, $args );
233
			}
234
		}
235
236
		$string = trim( $string );
237
		$string = wp_kses(
238
			$string, array(
239
			'a'      => array(
240
				'href' => true
241
			),
242
			'br'     => true,
243
			'em'     => true,
244
			'strong' => true,
245
		)
246
		);
247
248
		$this->set_main_error_message( $string, $current_error );
249
		$this->messages[] = $string;
250
	}
251
}
252