Completed
Push — whitelist/sync ( 830219...fbc430 )
by
unknown
13:02 queued 02:23
created

Jetpack_JSON_API_Plugins_Modify_Endpoint::update()   B

Complexity

Conditions 7
Paths 12

Size

Total Lines 64
Code Lines 30

Duplication

Lines 3
Ratio 4.69 %

Importance

Changes 0
Metric Value
cc 7
eloc 30
nc 12
nop 0
dl 3
loc 64
rs 7.2058
c 0
b 0
f 0

How to fix   Long Method   

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
		'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...
21
		'example_request_data' => array(
22
			'headers' => array(
23
				'authorization' => 'Bearer YOUR_API_TOKEN'
24
			),
25
			'body'    => array(
26
				'action' => 'update',
27
			)
28
		),
29
		'example_request'      => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello'
30
	)
31
);
32
33
new Jetpack_JSON_API_Plugins_Modify_Endpoint(
34
	array(
35
		'description'          => 'Activate/Deactivate a list of plugins on your Jetpack Site, or set automatic updates',
36
		'min_version'          => '1',
37
		'max_version'          => '1.1',
38
		'method'               => 'POST',
39
		'path'                 => '/sites/%s/plugins',
40
		'stat'                 => 'plugins:modify',
41
		'path_labels'          => array(
42
			'$site' => '(int|string) The site ID, The site domain',
43
		),
44
		'request_format'       => array(
45
			'action'       => '(string) Possible values are \'update\'',
46
			'autoupdate'   => '(bool) Whether or not to automatically update the plugin',
47
			'active'       => '(bool) Activate or deactivate the plugin',
48
			'network_wide' => '(bool) Do action network wide (default value: false)',
49
			'plugins'      => '(array) A list of plugin ids to modify',
50
		),
51
		'response_format'      => array(
52
			'plugins'     => '(array:plugin) An array of plugin objects.',
53
			'updated'     => '(array) A list of plugin ids that were updated. Only present if action is update.',
54
			'not_updated' => '(array) A list of plugin ids that were not updated. Only present if action is update.',
55
			'log'         => '(array) Update log. Only present if action is update.',
56
		),
57
		'example_request_data' => array(
58
			'headers' => array(
59
				'authorization' => 'Bearer YOUR_API_TOKEN'
60
			),
61
			'body'    => array(
62
				'active'  => true,
63
				'plugins' => array(
64
					'jetpack/jetpack',
65
					'akismet/akismet',
66
				),
67
			)
68
		),
69
		'example_request'      => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins'
70
	)
71
);
72
73
new Jetpack_JSON_API_Plugins_Modify_Endpoint(
74
	array(
75
		'description'          => 'Update a Plugin on your Jetpack Site',
76
		'min_version'          => '1',
77
		'max_version'          => '1.1',
78
		'method'               => 'POST',
79
		'path'                 => '/sites/%s/plugins/%s/update/',
80
		'stat'                 => 'plugins:1:update',
81
		'path_labels'          => array(
82
			'$site'   => '(int|string) The site ID, The site domain',
83
			'$plugin' => '(string) The plugin ID',
84
		),
85
		'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...
86
		'example_request_data' => array(
87
			'headers' => array(
88
				'authorization' => 'Bearer YOUR_API_TOKEN'
89
			),
90
		),
91
		'example_request'      => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello/update'
92
	)
93
);
94
95
class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_Endpoint {
96
	// POST  /sites/%s/plugins/%s
97
	// POST  /sites/%s/plugins
98
	protected $slug = null;
99
	protected $needed_capabilities = 'activate_plugins';
100
	protected $action = 'default_action';
101
	protected $expected_actions = array( 'update', 'install', 'delete', 'update_translations' );
102
103
	public function callback( $path = '', $blog_id = 0, $object = null ) {
104
		Jetpack_JSON_API_Endpoint::validate_input( $object );
105
		switch ( $this->action ) {
106
			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...
107
				$this->needed_capabilities = 'delete_plugins';
108
			case 'update_translations':
109
			case 'update' :
110
				$this->needed_capabilities = 'update_plugins';
111
				break;
112
			case 'install' :
113
				$this->needed_capabilities = 'install_plugins';
114
				break;
115
		}
116
117
		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...
118
			$this->needed_capabilities = 'update_plugins';
119
		}
120
121
		return parent::callback( $path, $blog_id, $object );
122
	}
123
124
	public function default_action() {
125
		$args = $this->input();
126
127
		if ( isset( $args['autoupdate'] ) && is_bool( $args['autoupdate'] ) ) {
128
			if ( $args['autoupdate'] ) {
129
				$this->autoupdate_on();
130
			} else {
131
				$this->autoupdate_off();
132
			}
133
		}
134
135
		if ( isset( $args['active'] ) && is_bool( $args['active'] ) ) {
136
			if ( $args['active'] ) {
137
				// We don't have to check for activate_plugins permissions since we assume that the user has those
138
				// Since we set them via $needed_capabilities.
139
				return $this->activate();
140
			} else {
141
				if ( $this->current_user_can( 'deactivate_plugins' ) ) {
142
					return $this->deactivate();
143
				} else {
144
					return new WP_Error( 'unauthorized_error', __( 'Plugin deactivation is not allowed', 'jetpack' ), '403' );
145
				}
146
			}
147
		}
148
149 View Code Duplication
		if ( isset( $args['autoupdate_translations'] ) && is_bool( $args['autoupdate_translations'] ) ) {
150
			if ( $args['autoupdate_translations'] ) {
151
				$this->autoupdate_translations_on();
152
			} else {
153
				$this->autoupdate_translations_off();
154
			}
155
		}
156
157
		return true;
158
	}
159
160
	protected function autoupdate_on() {
161
		$autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins', array() );
162
		$autoupdate_plugins = array_unique( array_merge( $autoupdate_plugins, $this->plugins ) );
163
		Jetpack_Options::update_option( 'autoupdate_plugins', $autoupdate_plugins );
164
	}
165
166
	protected function autoupdate_off() {
167
		$autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins', array() );
168
		$autoupdate_plugins = array_diff( $autoupdate_plugins, $this->plugins );
169
		Jetpack_Options::update_option( 'autoupdate_plugins', $autoupdate_plugins );
170
	}
171
172
	protected function autoupdate_translations_on() {
173
		$autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() );
174
		$autoupdate_plugins = array_unique( array_merge( $autoupdate_plugins, $this->plugins ) );
175
		Jetpack_Options::update_option( 'autoupdate_plugins_translations', $autoupdate_plugins );
176
	}
177
178
	protected function autoupdate_translations_off() {
179
		$autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() );
180
		$autoupdate_plugins = array_diff( $autoupdate_plugins, $this->plugins );
181
		Jetpack_Options::update_option( 'autoupdate_plugins_translations', $autoupdate_plugins );
182
	}
183
184
	protected function activate() {
185
		$permission_error = false;
186
		foreach ( $this->plugins as $plugin ) {
187
188
			if ( ! $this->current_user_can( 'activate_plugin', $plugin ) ) {
189
				$this->log[ $plugin ]['error'] = __( 'Sorry, you are not allowed to activate this plugin.' );
190
				$has_errors                  = true;
191
				$permission_error            = true;
192
				continue;
193
			}
194
195 View Code Duplication
			if ( ( ! $this->network_wide && Jetpack::is_plugin_active( $plugin ) ) || is_plugin_active_for_network( $plugin ) ) {
196
				$this->log[ $plugin ]['error'] = __( 'The Plugin is already active.', 'jetpack' );
197
				$has_errors                  = true;
198
				continue;
199
			}
200
201 View Code Duplication
			if ( ! $this->network_wide && is_network_only_plugin( $plugin ) && is_multisite() ) {
202
				$this->log[ $plugin ]['error'] = __( 'Plugin can only be Network Activated', 'jetpack' );
203
				$has_errors                  = true;
204
				continue;
205
			}
206
207
			$result = activate_plugin( $plugin, '', $this->network_wide );
208
209 View Code Duplication
			if ( is_wp_error( $result ) ) {
210
				$this->log[ $plugin ]['error'] = $result->get_error_messages();
211
				$has_errors                  = true;
212
				continue;
213
			}
214
215
			$success = Jetpack::is_plugin_active( $plugin );
216
			if ( $success && $this->network_wide ) {
217
				$success &= is_plugin_active_for_network( $plugin );
218
			}
219
220 View Code Duplication
			if ( ! $success ) {
221
				$this->log[ $plugin ]['error'] = $result->get_error_messages;
222
				$has_errors                  = true;
223
				continue;
224
			}
225
			$this->log[ $plugin ][] = __( 'Plugin activated.', 'jetpack' );
226
		}
227
228 View Code Duplication
		if ( ! $this->bulk && isset( $has_errors )  ) {
229
			$plugin = $this->plugins[0];
230
			if ( $permission_error ) {
231
				return new WP_Error( 'unauthorized_error', $this->log[ $plugin ]['error'], 403 );
232
			}
233
			return new WP_Error( 'activation_error', $this->log[ $plugin ]['error'] );
234
		}
235
	}
236
237
	protected function current_user_can( $capability, $plugin = null ) {
238
		global $wp_version;
239
		if ( version_compare( $wp_version, '4.9-beta2' ) >= 0 ) {
240
			if ( $plugin ) {
241
				return current_user_can( $capability, $plugin );
242
			}
243
			return current_user_can( $capability );
244
		}
245
		// Assume that the user has the activate plugins capability.
246
		return current_user_can( 'activate_plugins' );
247
248
	}
249
250
	protected function deactivate() {
251
		$permission_error = false;
252
		foreach ( $this->plugins as $plugin ) {
253 View Code Duplication
			if ( ! $this->current_user_can('deactivate_plugin', $plugin ) ) {
254
				$error = $this->log[ $plugin ]['error'] = __( 'Sorry, you are not allowed to deactivate this plugin.', 'jetpack' );
255
				$permission_error = true;
256
				continue;
257
			}
258
259 View Code Duplication
			if ( ! Jetpack::is_plugin_active( $plugin ) ) {
260
				$error = $this->log[ $plugin ]['error'] = __( 'The Plugin is already deactivated.', 'jetpack' );
261
				continue;
262
			}
263
264
			deactivate_plugins( $plugin, false, $this->network_wide );
265
266
			$success = ! Jetpack::is_plugin_active( $plugin );
267
			if ( $success && $this->network_wide ) {
268
				$success &= ! is_plugin_active_for_network( $plugin );
269
			}
270
271 View Code Duplication
			if ( ! $success ) {
272
				$error = $this->log[ $plugin ]['error'] = __( 'There was an error deactivating your plugin', 'jetpack' );
273
				continue;
274
			}
275
			$this->log[ $plugin ][] = __( 'Plugin deactivated.', 'jetpack' );
276
		}
277 View Code Duplication
		if ( ! $this->bulk && isset( $error ) ) {
278
			if ( $permission_error ) {
279
				return new WP_Error( 'unauthorized_error', $error, 403 );
280
			}
281
			return new WP_Error( 'deactivation_error', $error );
282
		}
283
	}
284
285
	protected function update() {
286
287
		wp_clean_plugins_cache();
288
		ob_start();
289
		wp_update_plugins(); // Check for Plugin updates
290
		ob_end_clean();
291
292
		$update_plugins = get_site_transient( 'update_plugins' );
293
294
		if ( isset( $update_plugins->response ) ) {
295
			$plugin_updates_needed = array_keys( $update_plugins->response );
296
		} else {
297
			$plugin_updates_needed = array();
298
		}
299
300
		$update_attempted = false;
301
302
		include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
303
304
		// unhook this functions that output things before we send our response header.
305
		remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
306
		remove_action( 'upgrader_process_complete', 'wp_version_check' );
307
		remove_action( 'upgrader_process_complete', 'wp_update_themes' );
308
309
		$result = false;
310
311
		foreach ( $this->plugins as $plugin ) {
312
313
			if ( ! in_array( $plugin, $plugin_updates_needed ) ) {
314
				$this->log[ $plugin ][] = __( 'No update needed', 'jetpack' );
315
				continue;
316
			}
317
318
			/**
319
			 * Pre-upgrade action
320
			 *
321
			 * @since 3.9.3
322
			 *
323
			 * @param array $plugin            Plugin data
324
			 * @param array $plugin            Array of plugin objects
325
			 * @param bool  $updated_attempted false for the first update, true subsequently
326
			 */
327
			do_action( 'jetpack_pre_plugin_upgrade', $plugin, $this->plugins, $update_attempted );
328
329
			$update_attempted = true;
330
331
			// Object created inside the for loop to clean the messages for each plugin
332
			$skin = new Automatic_Upgrader_Skin();
333
			// The Automatic_Upgrader_Skin skin shouldn't output anything.
334
			$upgrader = new Plugin_Upgrader( $skin );
335
			$upgrader->init();
336
			// This avoids the plugin to be deactivated.
337
			// Using bulk upgrade puts the site into maintenance mode during the upgrades
338
			$result = $upgrader->bulk_upgrade( array( $plugin ) );
339
340
			$this->log[ $plugin ] = $upgrader->skin->get_upgrade_messages();
341
		}
342
343 View Code Duplication
		if ( ! $this->bulk && ! $result && $update_attempted ) {
344
			return new WP_Error( 'update_fail', __( 'There was an error updating your plugin', 'jetpack' ), 400 );
345
		}
346
347
		return $this->default_action();
348
	}
349
350
	function update_translations() {
351
		include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
352
353
		// Clear the cache.
354
		wp_clean_plugins_cache();
355
		ob_start();
356
		wp_update_plugins(); // Check for Plugin updates
357
		ob_end_clean();
358
359
		$available_updates = get_site_transient( 'update_plugins' );
360
		if ( ! isset( $available_updates->translations ) || empty( $available_updates->translations ) ) {
361
			return new WP_Error( 'nothing_to_translate' );
362
		}
363
364
		$update_attempted = false;
365
		$result           = false;
366
		foreach ( $this->plugins as $plugin ) {
367
			$this->slug  = Jetpack_Autoupdate::get_plugin_slug( $plugin );
368
			$translation = array_filter( $available_updates->translations, array( $this, 'get_translation' ) );
369
370
			if ( empty( $translation ) ) {
371
				$this->log[ $plugin ][] = __( 'No update needed', 'jetpack' );
372
				continue;
373
			}
374
375
			/**
376
			 * Pre-upgrade action
377
			 *
378
			 * @since 4.4
379
			 *
380
			 * @param array $plugin           Plugin data
381
			 * @param array $plugin           Array of plugin objects
382
			 * @param bool  $update_attempted false for the first update, true subsequently
383
			 */
384
			do_action( 'jetpack_pre_plugin_upgrade_translations', $plugin, $this->plugins, $update_attempted );
385
386
			$update_attempted = true;
387
388
			$skin     = new Automatic_Upgrader_Skin();
389
			$upgrader = new Language_Pack_Upgrader( $skin );
390
			$upgrader->init();
391
392
			$result = $upgrader->upgrade( (object) $translation[0] );
393
394
			$this->log[$plugin] = $upgrader->skin->get_upgrade_messages();
395
		}
396
397
		if ( ! $this->bulk && ! $result ) {
398
			return new WP_Error( 'update_fail', __( 'There was an error updating your plugin', 'jetpack' ), 400 );
399
		}
400
401
		return true;
402
	}
403
404
	protected function get_translation( $translation ) {
405
		return ( $translation['slug'] === $this->slug );
406
	}
407
}
408