Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 286 |
|
0.00% |
0 / 12 |
CRAP | |
0.00% |
0 / 1 |
| Jetpack_JSON_API_Plugins_Modify_Endpoint | |
0.00% |
0 / 181 |
|
0.00% |
0 / 12 |
6480 | |
0.00% |
0 / 1 |
| callback | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
72 | |||
| default_action | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
132 | |||
| autoupdate_on | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| autoupdate_off | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| autoupdate_translations_on | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| autoupdate_translations_off | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
| activate | |
0.00% |
0 / 33 |
|
0.00% |
0 / 1 |
272 | |||
| current_user_can | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
| deactivate | |
0.00% |
0 / 24 |
|
0.00% |
0 / 1 |
110 | |||
| update | |
0.00% |
0 / 48 |
|
0.00% |
0 / 1 |
420 | |||
| update_translations | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
56 | |||
| get_translation | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| 1 | <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName |
| 2 | |
| 3 | use Automattic\Jetpack\Constants; |
| 4 | |
| 5 | if ( ! defined( 'ABSPATH' ) ) { |
| 6 | exit( 0 ); |
| 7 | } |
| 8 | |
| 9 | new Jetpack_JSON_API_Plugins_Modify_Endpoint( |
| 10 | array( |
| 11 | 'description' => 'Activate/Deactivate a Plugin on your Jetpack Site, or set automatic updates', |
| 12 | 'min_version' => '1', |
| 13 | 'max_version' => '1.1', |
| 14 | 'method' => 'POST', |
| 15 | 'path' => '/sites/%s/plugins/%s', |
| 16 | 'stat' => 'plugins:1:modify', |
| 17 | 'path_labels' => array( |
| 18 | '$site' => '(int|string) The site ID, The site domain', |
| 19 | '$plugin' => '(string) The plugin ID', |
| 20 | ), |
| 21 | 'allow_jetpack_site_auth' => true, |
| 22 | 'request_format' => array( |
| 23 | 'action' => '(string) Possible values are \'update\'', |
| 24 | 'autoupdate' => '(bool) Whether or not to automatically update the plugin', |
| 25 | 'active' => '(bool) Activate or deactivate the plugin', |
| 26 | 'network_wide' => '(bool) Do action network wide (default value: false)', |
| 27 | 'scheduled_update' => '(bool) If the update is happening as a result of a scheduled update event', |
| 28 | ), |
| 29 | 'query_parameters' => array( |
| 30 | 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event', |
| 31 | ), |
| 32 | 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, |
| 33 | 'example_request_data' => array( |
| 34 | 'headers' => array( |
| 35 | 'authorization' => 'Bearer YOUR_API_TOKEN', |
| 36 | ), |
| 37 | 'body' => array( |
| 38 | 'action' => 'update', |
| 39 | ), |
| 40 | ), |
| 41 | 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello', |
| 42 | ) |
| 43 | ); |
| 44 | |
| 45 | new Jetpack_JSON_API_Plugins_Modify_Endpoint( |
| 46 | array( |
| 47 | 'description' => 'Activate/Deactivate a list of plugins on your Jetpack Site, or set automatic updates', |
| 48 | 'min_version' => '1', |
| 49 | 'max_version' => '1.1', |
| 50 | 'method' => 'POST', |
| 51 | 'path' => '/sites/%s/plugins', |
| 52 | 'stat' => 'plugins:modify', |
| 53 | 'path_labels' => array( |
| 54 | '$site' => '(int|string) The site ID, The site domain', |
| 55 | ), |
| 56 | 'request_format' => array( |
| 57 | 'action' => '(string) Possible values are \'update\'', |
| 58 | 'autoupdate' => '(bool) Whether or not to automatically update the plugin', |
| 59 | 'active' => '(bool) Activate or deactivate the plugin', |
| 60 | 'network_wide' => '(bool) Do action network wide (default value: false)', |
| 61 | 'plugins' => '(array) A list of plugin ids to modify', |
| 62 | ), |
| 63 | 'allow_jetpack_site_auth' => true, |
| 64 | 'query_parameters' => array( |
| 65 | 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event', |
| 66 | ), |
| 67 | 'response_format' => array( |
| 68 | 'plugins' => '(array:plugin) An array of plugin objects.', |
| 69 | 'updated' => '(array) A list of plugin ids that were updated. Only present if action is update.', |
| 70 | 'not_updated' => '(array) A list of plugin ids that were not updated. Only present if action is update.', |
| 71 | 'log' => '(array) Update log. Only present if action is update.', |
| 72 | ), |
| 73 | 'example_request_data' => array( |
| 74 | 'headers' => array( |
| 75 | 'authorization' => 'Bearer YOUR_API_TOKEN', |
| 76 | ), |
| 77 | 'body' => array( |
| 78 | 'active' => true, |
| 79 | 'plugins' => array( |
| 80 | 'jetpack/jetpack', |
| 81 | 'akismet/akismet', |
| 82 | ), |
| 83 | ), |
| 84 | ), |
| 85 | 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins', |
| 86 | ) |
| 87 | ); |
| 88 | |
| 89 | new Jetpack_JSON_API_Plugins_Modify_Endpoint( |
| 90 | array( |
| 91 | 'description' => 'Update a Plugin on your Jetpack Site', |
| 92 | 'min_version' => '1', |
| 93 | 'max_version' => '1.1', |
| 94 | 'method' => 'POST', |
| 95 | 'path' => '/sites/%s/plugins/%s/update/', |
| 96 | 'stat' => 'plugins:1:update', |
| 97 | 'path_labels' => array( |
| 98 | '$site' => '(int|string) The site ID, The site domain', |
| 99 | '$plugin' => '(string) The plugin ID', |
| 100 | ), |
| 101 | 'allow_jetpack_site_auth' => true, |
| 102 | 'query_parameters' => array( |
| 103 | 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event', |
| 104 | ), |
| 105 | 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, |
| 106 | 'example_request_data' => array( |
| 107 | 'headers' => array( |
| 108 | 'authorization' => 'Bearer YOUR_API_TOKEN', |
| 109 | ), |
| 110 | ), |
| 111 | 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello/update', |
| 112 | ) |
| 113 | ); |
| 114 | |
| 115 | /** |
| 116 | * Plugins modify endpoint class. |
| 117 | * |
| 118 | * POST /sites/%s/plugins/%s |
| 119 | * POST /sites/%s/plugins |
| 120 | * |
| 121 | * @phan-constructor-used-for-side-effects |
| 122 | */ |
| 123 | class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_Endpoint { |
| 124 | |
| 125 | /** |
| 126 | * The slug. |
| 127 | * |
| 128 | * @var string |
| 129 | */ |
| 130 | protected $slug = null; |
| 131 | |
| 132 | /** |
| 133 | * Needed capabilities. |
| 134 | * |
| 135 | * @var string |
| 136 | */ |
| 137 | protected $needed_capabilities = 'activate_plugins'; |
| 138 | |
| 139 | /** |
| 140 | * Action. |
| 141 | * |
| 142 | * @var string |
| 143 | */ |
| 144 | protected $action = 'default_action'; |
| 145 | |
| 146 | /** |
| 147 | * Expected actions. |
| 148 | * |
| 149 | * @var array |
| 150 | */ |
| 151 | protected $expected_actions = array( 'update', 'install', 'delete', 'update_translations' ); |
| 152 | |
| 153 | /** |
| 154 | * Callback. |
| 155 | * |
| 156 | * @param string $path - the path. |
| 157 | * @param int $blog_id - the blog ID. |
| 158 | * @param object $object - the object. |
| 159 | * |
| 160 | * @return bool|WP_Error |
| 161 | */ |
| 162 | public function callback( $path = '', $blog_id = 0, $object = null ) { |
| 163 | |
| 164 | Jetpack_JSON_API_Endpoint::validate_input( $object ); |
| 165 | switch ( $this->action ) { |
| 166 | case 'delete': |
| 167 | $this->needed_capabilities = 'delete_plugins'; |
| 168 | break; |
| 169 | case 'update_translations': |
| 170 | case 'update': |
| 171 | $this->needed_capabilities = 'update_plugins'; |
| 172 | break; |
| 173 | case 'install': |
| 174 | $this->needed_capabilities = 'install_plugins'; |
| 175 | break; |
| 176 | } |
| 177 | |
| 178 | $args = $this->input(); |
| 179 | |
| 180 | if ( is_array( $args ) && ( isset( $args['autoupdate'] ) || isset( $args['autoupdate_translations'] ) ) ) { |
| 181 | $this->needed_capabilities = 'update_plugins'; |
| 182 | } |
| 183 | |
| 184 | return parent::callback( $path, $blog_id, $object ); |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * The default action. |
| 189 | * |
| 190 | * @return bool|WP_Error |
| 191 | */ |
| 192 | public function default_action() { |
| 193 | $args = $this->input(); |
| 194 | |
| 195 | if ( isset( $args['autoupdate'] ) && is_bool( $args['autoupdate'] ) ) { |
| 196 | if ( $args['autoupdate'] ) { |
| 197 | $this->autoupdate_on(); |
| 198 | } else { |
| 199 | $this->autoupdate_off(); |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | if ( isset( $args['active'] ) && is_bool( $args['active'] ) ) { |
| 204 | if ( $args['active'] ) { |
| 205 | // We don't have to check for activate_plugins permissions since we assume that the user has those |
| 206 | // Since we set them via $needed_capabilities. |
| 207 | return $this->activate(); |
| 208 | } elseif ( $this->current_user_can( 'deactivate_plugins' ) ) { |
| 209 | return $this->deactivate(); |
| 210 | } else { |
| 211 | return new WP_Error( 'unauthorized_error', __( 'Plugin deactivation is not allowed', 'jetpack' ), '403' ); |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | if ( isset( $args['autoupdate_translations'] ) && is_bool( $args['autoupdate_translations'] ) ) { |
| 216 | if ( $args['autoupdate_translations'] ) { |
| 217 | $this->autoupdate_translations_on(); |
| 218 | } else { |
| 219 | $this->autoupdate_translations_off(); |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | return true; |
| 224 | } |
| 225 | |
| 226 | /** |
| 227 | * Turn on autoupdate. |
| 228 | */ |
| 229 | protected function autoupdate_on() { |
| 230 | $autoupdate_plugins = (array) get_site_option( 'auto_update_plugins', array() ); |
| 231 | $autoupdate_plugins = array_unique( array_merge( $autoupdate_plugins, $this->plugins ) ); |
| 232 | update_site_option( 'auto_update_plugins', $autoupdate_plugins ); |
| 233 | } |
| 234 | |
| 235 | /** |
| 236 | * Turn off autoupdate. |
| 237 | */ |
| 238 | protected function autoupdate_off() { |
| 239 | $autoupdate_plugins = (array) get_site_option( 'auto_update_plugins', array() ); |
| 240 | $autoupdate_plugins = array_diff( $autoupdate_plugins, $this->plugins ); |
| 241 | update_site_option( 'auto_update_plugins', $autoupdate_plugins ); |
| 242 | } |
| 243 | |
| 244 | /** |
| 245 | * Turn autoupdate translations on. |
| 246 | */ |
| 247 | protected function autoupdate_translations_on() { |
| 248 | $autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() ); |
| 249 | $autoupdate_plugins = array_unique( array_merge( $autoupdate_plugins, $this->plugins ) ); |
| 250 | Jetpack_Options::update_option( 'autoupdate_plugins_translations', $autoupdate_plugins ); |
| 251 | } |
| 252 | |
| 253 | /** |
| 254 | * Turn autoupdate translations off. |
| 255 | */ |
| 256 | protected function autoupdate_translations_off() { |
| 257 | $autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() ); |
| 258 | $autoupdate_plugins = array_diff( $autoupdate_plugins, $this->plugins ); |
| 259 | Jetpack_Options::update_option( 'autoupdate_plugins_translations', $autoupdate_plugins ); |
| 260 | } |
| 261 | |
| 262 | /** |
| 263 | * Activate the plugin. |
| 264 | * |
| 265 | * @return null|WP_Error null if the activation was successful. |
| 266 | */ |
| 267 | protected function activate() { |
| 268 | $permission_error = false; |
| 269 | foreach ( $this->plugins as $plugin ) { |
| 270 | |
| 271 | if ( ! $this->current_user_can( 'activate_plugin', $plugin ) ) { |
| 272 | $this->log[ $plugin ]['error'] = __( 'Sorry, you are not allowed to activate this plugin.', 'jetpack' ); |
| 273 | $has_errors = true; |
| 274 | $permission_error = true; |
| 275 | continue; |
| 276 | } |
| 277 | |
| 278 | if ( ( ! $this->network_wide && Jetpack::is_plugin_active( $plugin ) ) || is_plugin_active_for_network( $plugin ) ) { |
| 279 | $this->log[ $plugin ]['error'] = __( 'The Plugin is already active.', 'jetpack' ); |
| 280 | $has_errors = true; |
| 281 | continue; |
| 282 | } |
| 283 | |
| 284 | if ( ! $this->network_wide && is_network_only_plugin( $plugin ) && is_multisite() ) { |
| 285 | $this->log[ $plugin ]['error'] = __( 'Plugin can only be Network Activated', 'jetpack' ); |
| 286 | $has_errors = true; |
| 287 | continue; |
| 288 | } |
| 289 | |
| 290 | $result = activate_plugin( $plugin, '', $this->network_wide ); |
| 291 | |
| 292 | if ( is_wp_error( $result ) ) { |
| 293 | $this->log[ $plugin ]['error'] = $result->get_error_messages(); |
| 294 | $has_errors = true; |
| 295 | continue; |
| 296 | } |
| 297 | |
| 298 | $success = Jetpack::is_plugin_active( $plugin ); |
| 299 | if ( $success && $this->network_wide ) { |
| 300 | $success &= is_plugin_active_for_network( $plugin ); |
| 301 | } |
| 302 | |
| 303 | if ( ! $success ) { |
| 304 | $this->log[ $plugin ]['error'] = $result->get_error_messages; |
| 305 | $has_errors = true; |
| 306 | continue; |
| 307 | } |
| 308 | $this->log[ $plugin ][] = __( 'Plugin activated.', 'jetpack' ); |
| 309 | } |
| 310 | |
| 311 | if ( ! $this->bulk && isset( $has_errors ) ) { |
| 312 | $plugin = $this->plugins[0]; |
| 313 | if ( $permission_error ) { |
| 314 | return new WP_Error( 'unauthorized_error', $this->log[ $plugin ]['error'], 403 ); |
| 315 | } |
| 316 | |
| 317 | return new WP_Error( 'activation_error', $this->log[ $plugin ]['error'] ); |
| 318 | } |
| 319 | } |
| 320 | |
| 321 | /** |
| 322 | * Check if the current user has capabilities. |
| 323 | * |
| 324 | * @param string $capability - the capability we're checking. |
| 325 | * @param string $plugin - the plugin we're checking. |
| 326 | * |
| 327 | * @return bool |
| 328 | */ |
| 329 | protected function current_user_can( $capability, $plugin = null ) { |
| 330 | // If this endpoint accepts site based authentication and a blog token is used, skip capabilities check. |
| 331 | if ( $this->accepts_site_based_authentication() ) { |
| 332 | return true; |
| 333 | } |
| 334 | if ( $plugin ) { |
| 335 | return current_user_can( $capability, $plugin ); |
| 336 | } |
| 337 | |
| 338 | return current_user_can( $capability ); |
| 339 | } |
| 340 | |
| 341 | /** |
| 342 | * Deactivate the plugin. |
| 343 | * |
| 344 | * @return null|WP_Error null if the deactivation was successful |
| 345 | */ |
| 346 | protected function deactivate() { |
| 347 | $permission_error = false; |
| 348 | foreach ( $this->plugins as $plugin ) { |
| 349 | if ( ! $this->current_user_can( 'deactivate_plugin', $plugin ) ) { |
| 350 | $error = __( 'Sorry, you are not allowed to deactivate this plugin.', 'jetpack' ); |
| 351 | $this->log[ $plugin ]['error'] = $error; |
| 352 | $permission_error = true; |
| 353 | continue; |
| 354 | } |
| 355 | |
| 356 | if ( ! Jetpack::is_plugin_active( $plugin ) ) { |
| 357 | $error = __( 'The Plugin is already deactivated.', 'jetpack' ); |
| 358 | $this->log[ $plugin ]['error'] = $error; |
| 359 | continue; |
| 360 | } |
| 361 | |
| 362 | deactivate_plugins( $plugin, false, $this->network_wide ); |
| 363 | |
| 364 | $success = ! Jetpack::is_plugin_active( $plugin ); |
| 365 | if ( $success && $this->network_wide ) { |
| 366 | $success &= ! is_plugin_active_for_network( $plugin ); |
| 367 | } |
| 368 | |
| 369 | if ( ! $success ) { |
| 370 | $error = __( 'There was an error deactivating your plugin', 'jetpack' ); |
| 371 | $this->log[ $plugin ]['error'] = $error; |
| 372 | continue; |
| 373 | } |
| 374 | $this->log[ $plugin ][] = __( 'Plugin deactivated.', 'jetpack' ); |
| 375 | } |
| 376 | if ( ! $this->bulk && isset( $error ) ) { |
| 377 | if ( $permission_error ) { |
| 378 | return new WP_Error( 'unauthorized_error', $error, 403 ); |
| 379 | } |
| 380 | |
| 381 | return new WP_Error( 'deactivation_error', $error ); |
| 382 | } |
| 383 | } |
| 384 | |
| 385 | /** |
| 386 | * Update the plugin. |
| 387 | * |
| 388 | * @return bool|WP_Error |
| 389 | */ |
| 390 | protected function update() { |
| 391 | $query_args = $this->query_args(); |
| 392 | |
| 393 | $is_automatic_update = false; |
| 394 | if ( isset( $query_args['autoupdate'] ) && $query_args['autoupdate'] || $this->scheduled_update ) { |
| 395 | $is_automatic_update = true; |
| 396 | } |
| 397 | |
| 398 | if ( $this->scheduled_update ) { |
| 399 | Constants::set_constant( 'SCHEDULED_AUTOUPDATE', true ); |
| 400 | } |
| 401 | wp_clean_plugins_cache( false ); |
| 402 | ob_start(); |
| 403 | wp_update_plugins(); // Check for Plugin updates |
| 404 | ob_end_clean(); |
| 405 | |
| 406 | $update_plugins = get_site_transient( 'update_plugins' ); |
| 407 | |
| 408 | if ( isset( $update_plugins->response ) ) { |
| 409 | $plugin_updates_needed = array_keys( $update_plugins->response ); |
| 410 | } else { |
| 411 | $plugin_updates_needed = array(); |
| 412 | } |
| 413 | |
| 414 | $update_attempted = false; |
| 415 | |
| 416 | include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; |
| 417 | |
| 418 | // unhook this functions that output things before we send our response header. |
| 419 | remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 ); |
| 420 | remove_action( 'upgrader_process_complete', 'wp_version_check' ); |
| 421 | remove_action( 'upgrader_process_complete', 'wp_update_themes' ); |
| 422 | |
| 423 | // Set the lock timeout to 15 minutes if it's scheduled update, otherwise default to one hour. |
| 424 | $lock_release_timeout = $this->scheduled_update ? 15 * MINUTE_IN_SECONDS : null; |
| 425 | |
| 426 | // Early return if unable to obtain auto_updater lock. |
| 427 | // @see https://github.com/WordPress/wordpress-develop/blob/66469efa99e7978c8824e287834135aa9842e84f/src/wp-admin/includes/class-wp-automatic-updater.php#L453. |
| 428 | if ( $is_automatic_update && ! WP_Upgrader::create_lock( 'auto_updater', $lock_release_timeout ) ) { |
| 429 | return new WP_Error( 'update_fail', __( 'Updates are already in progress.', 'jetpack' ), 400 ); |
| 430 | } |
| 431 | |
| 432 | $result = false; |
| 433 | |
| 434 | foreach ( $this->plugins as $plugin ) { |
| 435 | |
| 436 | if ( ! in_array( $plugin, $plugin_updates_needed, true ) ) { |
| 437 | $this->log[ $plugin ][] = __( 'No update needed', 'jetpack' ); |
| 438 | continue; |
| 439 | } |
| 440 | |
| 441 | // Rely on WP_Automatic_Updater class to check if a plugin item should be updated if it is a Jetpack autoupdate request. |
| 442 | if ( $is_automatic_update && ! ( new WP_Automatic_Updater() )->should_update( 'plugin', $update_plugins->response[ $plugin ], WP_PLUGIN_DIR ) ) { |
| 443 | continue; |
| 444 | } |
| 445 | |
| 446 | // Establish per plugin lock. |
| 447 | $plugin_slug = Jetpack_Autoupdate::get_plugin_slug( $plugin ); |
| 448 | if ( ! WP_Upgrader::create_lock( 'jetpack_' . $plugin_slug, $lock_release_timeout ) ) { |
| 449 | continue; |
| 450 | } |
| 451 | |
| 452 | /** |
| 453 | * Pre-upgrade action |
| 454 | * |
| 455 | * @since 3.9.3 |
| 456 | * |
| 457 | * @param array $plugin Plugin data |
| 458 | * @param array $plugin Array of plugin objects |
| 459 | * @param bool $updated_attempted false for the first update, true subsequently |
| 460 | */ |
| 461 | do_action( 'jetpack_pre_plugin_upgrade', $plugin, $this->plugins, $update_attempted ); |
| 462 | |
| 463 | $update_attempted = true; |
| 464 | |
| 465 | // Object created inside the for loop to clean the messages for each plugin |
| 466 | $skin = new WP_Ajax_Upgrader_Skin(); |
| 467 | // The Automatic_Upgrader_Skin skin shouldn't output anything. |
| 468 | $upgrader = new Plugin_Upgrader( $skin ); |
| 469 | $upgrader->init(); |
| 470 | // This avoids the plugin to be deactivated. |
| 471 | // Using bulk upgrade puts the site into maintenance mode during the upgrades |
| 472 | $result = $upgrader->bulk_upgrade( array( $plugin ) ); |
| 473 | $errors = $skin->get_errors(); |
| 474 | $this->log[ $plugin ] = $skin->get_upgrade_messages(); |
| 475 | |
| 476 | // release individual plugin lock. |
| 477 | WP_Upgrader::release_lock( 'jetpack_' . $plugin_slug ); |
| 478 | |
| 479 | if ( is_wp_error( $errors ) && $errors->get_error_code() ) { |
| 480 | return $errors; |
| 481 | } |
| 482 | } |
| 483 | |
| 484 | // release auto_udpate lock. |
| 485 | if ( $is_automatic_update ) { |
| 486 | WP_Upgrader::release_lock( 'auto_updater' ); |
| 487 | } |
| 488 | |
| 489 | if ( ! $this->bulk && ! $result && $update_attempted ) { |
| 490 | return new WP_Error( 'update_fail', __( 'There was an error updating your plugin', 'jetpack' ), 400 ); |
| 491 | } |
| 492 | |
| 493 | return $this->default_action(); |
| 494 | } |
| 495 | |
| 496 | /** |
| 497 | * Update translations. |
| 498 | * |
| 499 | * @return bool|WP_Error |
| 500 | */ |
| 501 | public function update_translations() { |
| 502 | include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; |
| 503 | |
| 504 | // Clear the cache. |
| 505 | wp_clean_plugins_cache( false ); |
| 506 | ob_start(); |
| 507 | wp_update_plugins(); // Check for Plugin updates |
| 508 | ob_end_clean(); |
| 509 | |
| 510 | $available_updates = get_site_transient( 'update_plugins' ); |
| 511 | if ( ! isset( $available_updates->translations ) || empty( $available_updates->translations ) ) { |
| 512 | return new WP_Error( 'nothing_to_translate' ); |
| 513 | } |
| 514 | |
| 515 | $update_attempted = false; |
| 516 | $result = false; |
| 517 | foreach ( $this->plugins as $plugin ) { |
| 518 | $this->slug = Jetpack_Autoupdate::get_plugin_slug( $plugin ); |
| 519 | $translation = array_filter( $available_updates->translations, array( $this, 'get_translation' ) ); |
| 520 | |
| 521 | if ( empty( $translation ) ) { |
| 522 | $this->log[ $plugin ][] = __( 'No update needed', 'jetpack' ); |
| 523 | continue; |
| 524 | } |
| 525 | |
| 526 | /** |
| 527 | * Pre-upgrade action |
| 528 | * |
| 529 | * @since 4.4.0 |
| 530 | * |
| 531 | * @param array $plugin Plugin data |
| 532 | * @param array $plugin Array of plugin objects |
| 533 | * @param bool $update_attempted false for the first update, true subsequently |
| 534 | */ |
| 535 | do_action( 'jetpack_pre_plugin_upgrade_translations', $plugin, $this->plugins, $update_attempted ); |
| 536 | |
| 537 | $update_attempted = true; |
| 538 | |
| 539 | $skin = new Automatic_Upgrader_Skin(); |
| 540 | $upgrader = new Language_Pack_Upgrader( $skin ); |
| 541 | $upgrader->init(); |
| 542 | |
| 543 | $result = $upgrader->upgrade( (object) $translation[0] ); |
| 544 | |
| 545 | $this->log[ $plugin ] = $upgrader->skin->get_upgrade_messages(); |
| 546 | } |
| 547 | |
| 548 | if ( ! $this->bulk && ! $result ) { |
| 549 | return new WP_Error( 'update_fail', __( 'There was an error updating your plugin', 'jetpack' ), 400 ); |
| 550 | } |
| 551 | |
| 552 | return true; |
| 553 | } |
| 554 | |
| 555 | /** |
| 556 | * Test whether the translation matches `$this->slug`. |
| 557 | * |
| 558 | * @param array $translation - the translation. |
| 559 | * |
| 560 | * @return bool |
| 561 | */ |
| 562 | protected function get_translation( $translation ) { |
| 563 | return ( $translation['slug'] === $this->slug ); |
| 564 | } |
| 565 | } |