Completed
Push — try/woocommerce-analytics ( 2b8c13...0a25c9 )
by
unknown
32:37 queued 22:26
created

Jetpack_JSON_API_Plugins_Modify_Endpoint::update()   C

Complexity

Conditions 11
Paths 28

Size

Total Lines 71
Code Lines 36

Duplication

Lines 3
Ratio 4.23 %

Importance

Changes 0
Metric Value
cc 11
eloc 36
nc 28
nop 0
dl 3
loc 71
rs 5.6828
c 0
b 0
f 0

How to fix   Long Method    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
new Jetpack_JSON_API_Plugins_Modify_Endpoint(
3
	array(
4
		'description'          => 'Activate/Deactivate a Plugin on your Jetpack Site, or set automatic updates',
5
		'min_version'          => '1',
6
		'max_version'          => '1.1',
7
		'method'               => 'POST',
8
		'path'                 => '/sites/%s/plugins/%s',
9
		'stat'                 => 'plugins:1:modify',
10
		'path_labels'          => array(
11
			'$site'   => '(int|string) The site ID, The site domain',
12
			'$plugin' => '(string) The plugin ID',
13
		),
14
		'request_format'       => array(
15
			'action'       => '(string) Possible values are \'update\'',
16
			'autoupdate'   => '(bool) Whether or not to automatically update the plugin',
17
			'active'       => '(bool) Activate or deactivate the plugin',
18
			'network_wide' => '(bool) Do action network wide (default value: false)',
19
		),
20
		'query_parameters'     => array(
21
			'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event',
22
		),
23
		'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...
24
		'example_request_data' => array(
25
			'headers' => array(
26
				'authorization' => 'Bearer YOUR_API_TOKEN'
27
			),
28
			'body'    => array(
29
				'action' => 'update',
30
			)
31
		),
32
		'example_request'      => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello'
33
	)
34
);
35
36
new Jetpack_JSON_API_Plugins_Modify_Endpoint(
37
	array(
38
		'description'          => 'Activate/Deactivate a list of plugins on your Jetpack Site, or set automatic updates',
39
		'min_version'          => '1',
40
		'max_version'          => '1.1',
41
		'method'               => 'POST',
42
		'path'                 => '/sites/%s/plugins',
43
		'stat'                 => 'plugins:modify',
44
		'path_labels'          => array(
45
			'$site' => '(int|string) The site ID, The site domain',
46
		),
47
		'request_format'       => array(
48
			'action'       => '(string) Possible values are \'update\'',
49
			'autoupdate'   => '(bool) Whether or not to automatically update the plugin',
50
			'active'       => '(bool) Activate or deactivate the plugin',
51
			'network_wide' => '(bool) Do action network wide (default value: false)',
52
			'plugins'      => '(array) A list of plugin ids to modify',
53
		),
54
		'query_parameters'     => array(
55
			'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event',
56
		),
57
		'response_format'      => array(
58
			'plugins'     => '(array:plugin) An array of plugin objects.',
59
			'updated'     => '(array) A list of plugin ids that were updated. Only present if action is update.',
60
			'not_updated' => '(array) A list of plugin ids that were not updated. Only present if action is update.',
61
			'log'         => '(array) Update log. Only present if action is update.',
62
		),
63
		'example_request_data' => array(
64
			'headers' => array(
65
				'authorization' => 'Bearer YOUR_API_TOKEN'
66
			),
67
			'body'    => array(
68
				'active'  => true,
69
				'plugins' => array(
70
					'jetpack/jetpack',
71
					'akismet/akismet',
72
				),
73
			)
74
		),
75
		'example_request'      => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins'
76
	)
77
);
78
79
new Jetpack_JSON_API_Plugins_Modify_Endpoint(
80
	array(
81
		'description'          => 'Update a Plugin on your Jetpack Site',
82
		'min_version'          => '1',
83
		'max_version'          => '1.1',
84
		'method'               => 'POST',
85
		'path'                 => '/sites/%s/plugins/%s/update/',
86
		'stat'                 => 'plugins:1:update',
87
		'path_labels'          => array(
88
			'$site'   => '(int|string) The site ID, The site domain',
89
			'$plugin' => '(string) The plugin ID',
90
		),
91
		'query_parameters'     => array(
92
			'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event',
93
		),
94
		'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...
95
		'example_request_data' => array(
96
			'headers' => array(
97
				'authorization' => 'Bearer YOUR_API_TOKEN'
98
			),
99
		),
100
		'example_request'      => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello/update'
101
	)
102
);
103
104
class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_Endpoint {
105
	// POST  /sites/%s/plugins/%s
106
	// POST  /sites/%s/plugins
107
	protected $slug = null;
108
	protected $needed_capabilities = 'activate_plugins';
109
	protected $action = 'default_action';
110
	protected $expected_actions = array( 'update', 'install', 'delete', 'update_translations' );
111
112
	public function callback( $path = '', $blog_id = 0, $object = null ) {
113
		Jetpack_JSON_API_Endpoint::validate_input( $object );
114
		switch ( $this->action ) {
115
			case 'delete':
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
116
				$this->needed_capabilities = 'delete_plugins';
117
			case 'update_translations':
118
			case 'update' :
119
				$this->needed_capabilities = 'update_plugins';
120
				break;
121
			case 'install' :
122
				$this->needed_capabilities = 'install_plugins';
123
				break;
124
		}
125
126
		if ( isset( $args['autoupdate'] ) || isset( $args['autoupdate_translations'] ) ) {
0 ignored issues
show
Bug introduced by
The variable $args seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
127
			$this->needed_capabilities = 'update_plugins';
128
		}
129
130
		return parent::callback( $path, $blog_id, $object );
131
	}
132
133
	public function default_action() {
134
		$args = $this->input();
135
136
		if ( isset( $args['autoupdate'] ) && is_bool( $args['autoupdate'] ) ) {
137
			if ( $args['autoupdate'] ) {
138
				$this->autoupdate_on();
139
			} else {
140
				$this->autoupdate_off();
141
			}
142
		}
143
144
		if ( isset( $args['active'] ) && is_bool( $args['active'] ) ) {
145
			if ( $args['active'] ) {
146
				// We don't have to check for activate_plugins permissions since we assume that the user has those
147
				// Since we set them via $needed_capabilities.
148
				return $this->activate();
149
			} else {
150
				if ( $this->current_user_can( 'deactivate_plugins' ) ) {
151
					return $this->deactivate();
152
				} else {
153
					return new WP_Error( 'unauthorized_error', __( 'Plugin deactivation is not allowed', 'jetpack' ), '403' );
154
				}
155
			}
156
		}
157
158 View Code Duplication
		if ( isset( $args['autoupdate_translations'] ) && is_bool( $args['autoupdate_translations'] ) ) {
159
			if ( $args['autoupdate_translations'] ) {
160
				$this->autoupdate_translations_on();
161
			} else {
162
				$this->autoupdate_translations_off();
163
			}
164
		}
165
166
		return true;
167
	}
168
169
	protected function autoupdate_on() {
170
		$autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins', array() );
171
		$autoupdate_plugins = array_unique( array_merge( $autoupdate_plugins, $this->plugins ) );
172
		Jetpack_Options::update_option( 'autoupdate_plugins', $autoupdate_plugins );
173
	}
174
175
	protected function autoupdate_off() {
176
		$autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins', array() );
177
		$autoupdate_plugins = array_diff( $autoupdate_plugins, $this->plugins );
178
		Jetpack_Options::update_option( 'autoupdate_plugins', $autoupdate_plugins );
179
	}
180
181
	protected function autoupdate_translations_on() {
182
		$autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() );
183
		$autoupdate_plugins = array_unique( array_merge( $autoupdate_plugins, $this->plugins ) );
184
		Jetpack_Options::update_option( 'autoupdate_plugins_translations', $autoupdate_plugins );
185
	}
186
187
	protected function autoupdate_translations_off() {
188
		$autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() );
189
		$autoupdate_plugins = array_diff( $autoupdate_plugins, $this->plugins );
190
		Jetpack_Options::update_option( 'autoupdate_plugins_translations', $autoupdate_plugins );
191
	}
192
193
	protected function activate() {
194
		$permission_error = false;
195
		foreach ( $this->plugins as $plugin ) {
196
197
			if ( ! $this->current_user_can( 'activate_plugin', $plugin ) ) {
198
				$this->log[$plugin]['error'] = __( 'Sorry, you are not allowed to activate this plugin.' );
199
				$has_errors                  = true;
200
				$permission_error            = true;
201
				continue;
202
			}
203
204 View Code Duplication
			if ( ( ! $this->network_wide && Jetpack::is_plugin_active( $plugin ) ) || is_plugin_active_for_network( $plugin ) ) {
205
				$this->log[$plugin]['error'] = __( 'The Plugin is already active.', 'jetpack' );
206
				$has_errors                  = true;
207
				continue;
208
			}
209
210 View Code Duplication
			if ( ! $this->network_wide && is_network_only_plugin( $plugin ) && is_multisite() ) {
211
				$this->log[$plugin]['error'] = __( 'Plugin can only be Network Activated', 'jetpack' );
212
				$has_errors                  = true;
213
				continue;
214
			}
215
216
			$result = activate_plugin( $plugin, '', $this->network_wide );
217
218 View Code Duplication
			if ( is_wp_error( $result ) ) {
219
				$this->log[$plugin]['error'] = $result->get_error_messages();
220
				$has_errors                  = true;
221
				continue;
222
			}
223
224
			$success = Jetpack::is_plugin_active( $plugin );
225
			if ( $success && $this->network_wide ) {
226
				$success &= is_plugin_active_for_network( $plugin );
227
			}
228
229 View Code Duplication
			if ( ! $success ) {
230
				$this->log[$plugin]['error'] = $result->get_error_messages;
231
				$has_errors                  = true;
232
				continue;
233
			}
234
			$this->log[$plugin][] = __( 'Plugin activated.', 'jetpack' );
235
		}
236
237 View Code Duplication
		if ( ! $this->bulk && isset( $has_errors ) ) {
238
			$plugin = $this->plugins[0];
239
			if ( $permission_error ) {
240
				return new WP_Error( 'unauthorized_error', $this->log[$plugin]['error'], 403 );
241
			}
242
243
			return new WP_Error( 'activation_error', $this->log[$plugin]['error'] );
244
		}
245
	}
246
247
	protected function current_user_can( $capability, $plugin = null ) {
248
		global $wp_version;
249
		if ( version_compare( $wp_version, '4.9-beta2' ) >= 0 ) {
250
			if ( $plugin ) {
251
				return current_user_can( $capability, $plugin );
252
			}
253
254
			return current_user_can( $capability );
255
		}
256
257
		// Assume that the user has the activate plugins capability.
258
		return current_user_can( 'activate_plugins' );
259
260
	}
261
262
	protected function deactivate() {
263
		$permission_error = false;
264
		foreach ( $this->plugins as $plugin ) {
265 View Code Duplication
			if ( ! $this->current_user_can( 'deactivate_plugin', $plugin ) ) {
266
				$error = $this->log[$plugin]['error'] = __( 'Sorry, you are not allowed to deactivate this plugin.', 'jetpack' );
267
				$permission_error                     = true;
268
				continue;
269
			}
270
271 View Code Duplication
			if ( ! Jetpack::is_plugin_active( $plugin ) ) {
272
				$error = $this->log[$plugin]['error'] = __( 'The Plugin is already deactivated.', 'jetpack' );
273
				continue;
274
			}
275
276
			deactivate_plugins( $plugin, false, $this->network_wide );
277
278
			$success = ! Jetpack::is_plugin_active( $plugin );
279
			if ( $success && $this->network_wide ) {
280
				$success &= ! is_plugin_active_for_network( $plugin );
281
			}
282
283 View Code Duplication
			if ( ! $success ) {
284
				$error = $this->log[$plugin]['error'] = __( 'There was an error deactivating your plugin', 'jetpack' );
285
				continue;
286
			}
287
			$this->log[$plugin][] = __( 'Plugin deactivated.', 'jetpack' );
288
		}
289 View Code Duplication
		if ( ! $this->bulk && isset( $error ) ) {
290
			if ( $permission_error ) {
291
				return new WP_Error( 'unauthorized_error', $error, 403 );
292
			}
293
294
			return new WP_Error( 'deactivation_error', $error );
295
		}
296
	}
297
298
	protected function update() {
299
		$query_args = $this->query_args();
300
		if ( isset( $query_args['autoupdate'] ) && $query_args['autoupdate'] ) {
301
			Jetpack_Constants::set_constant( 'JETPACK_PLUGIN_AUTOUPDATE', true );
302
		}
303
		wp_clean_plugins_cache();
304
		ob_start();
305
		wp_update_plugins(); // Check for Plugin updates
306
		ob_end_clean();
307
308
		$update_plugins = get_site_transient( 'update_plugins' );
309
310
		if ( isset( $update_plugins->response ) ) {
311
			$plugin_updates_needed = array_keys( $update_plugins->response );
312
		} else {
313
			$plugin_updates_needed = array();
314
		}
315
316
		$update_attempted = false;
317
318
		include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
319
320
		// unhook this functions that output things before we send our response header.
321
		remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
322
		remove_action( 'upgrader_process_complete', 'wp_version_check' );
323
		remove_action( 'upgrader_process_complete', 'wp_update_themes' );
324
325
		$result = false;
326
327
		foreach ( $this->plugins as $plugin ) {
328
329
			if ( ! in_array( $plugin, $plugin_updates_needed ) ) {
330
				$this->log[$plugin][] = __( 'No update needed', 'jetpack' );
331
				continue;
332
			}
333
334
			/**
335
			 * Pre-upgrade action
336
			 *
337
			 * @since 3.9.3
338
			 *
339
			 * @param array $plugin            Plugin data
340
			 * @param array $plugin            Array of plugin objects
341
			 * @param bool  $updated_attempted false for the first update, true subsequently
342
			 */
343
			do_action( 'jetpack_pre_plugin_upgrade', $plugin, $this->plugins, $update_attempted );
344
345
			$update_attempted = true;
346
347
			// Object created inside the for loop to clean the messages for each plugin
348
			$skin = new WP_Ajax_Upgrader_Skin();
349
			// The Automatic_Upgrader_Skin skin shouldn't output anything.
350
			$upgrader = new Plugin_Upgrader( $skin );
351
			$upgrader->init();
352
			// This avoids the plugin to be deactivated.
353
			// Using bulk upgrade puts the site into maintenance mode during the upgrades
354
			$result             = $upgrader->bulk_upgrade( array( $plugin ) );
355
			$errors             = $upgrader->skin->get_errors();
356
			$this->log[$plugin] = $upgrader->skin->get_upgrade_messages();
357
358
			if ( is_wp_error( $errors ) && $errors->get_error_code() ) {
359
				return $errors;
360
			}
361
		}
362
363 View Code Duplication
		if ( ! $this->bulk && ! $result && $update_attempted ) {
364
			return new WP_Error( 'update_fail', __( 'There was an error updating your plugin', 'jetpack' ), 400 );
365
		}
366
367
		return $this->default_action();
368
	}
369
370
	function update_translations() {
371
		include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
372
373
		// Clear the cache.
374
		wp_clean_plugins_cache();
375
		ob_start();
376
		wp_update_plugins(); // Check for Plugin updates
377
		ob_end_clean();
378
379
		$available_updates = get_site_transient( 'update_plugins' );
380
		if ( ! isset( $available_updates->translations ) || empty( $available_updates->translations ) ) {
381
			return new WP_Error( 'nothing_to_translate' );
382
		}
383
384
		$update_attempted = false;
385
		$result           = false;
386
		foreach ( $this->plugins as $plugin ) {
387
			$this->slug  = Jetpack_Autoupdate::get_plugin_slug( $plugin );
388
			$translation = array_filter( $available_updates->translations, array( $this, 'get_translation' ) );
389
390
			if ( empty( $translation ) ) {
391
				$this->log[$plugin][] = __( 'No update needed', 'jetpack' );
392
				continue;
393
			}
394
395
			/**
396
			 * Pre-upgrade action
397
			 *
398
			 * @since 4.4
399
			 *
400
			 * @param array $plugin           Plugin data
401
			 * @param array $plugin           Array of plugin objects
402
			 * @param bool  $update_attempted false for the first update, true subsequently
403
			 */
404
			do_action( 'jetpack_pre_plugin_upgrade_translations', $plugin, $this->plugins, $update_attempted );
405
406
			$update_attempted = true;
407
408
			$skin     = new Automatic_Upgrader_Skin();
409
			$upgrader = new Language_Pack_Upgrader( $skin );
410
			$upgrader->init();
411
412
			$result = $upgrader->upgrade( (object) $translation[0] );
413
414
			$this->log[$plugin] = $upgrader->skin->get_upgrade_messages();
415
		}
416
417
		if ( ! $this->bulk && ! $result ) {
418
			return new WP_Error( 'update_fail', __( 'There was an error updating your plugin', 'jetpack' ), 400 );
419
		}
420
421
		return true;
422
	}
423
424
	protected function get_translation( $translation ) {
425
		return ( $translation['slug'] === $this->slug );
426
	}
427
}
428