/** * Download and install a plugin update. * * @since 4.0.0 * @param int $pid The project ID. * @param bool $die_on_error Default is true. Otherwise function will * return false on error. * @return bool True on success. */ public function update_project($pid, $die_on_error = true) { // Refresh local project cache before the update starts. WPMUDEV_Dashboard::$site->set_option('refresh_local_flag', true); $local_projects = WPMUDEV_Dashboard::$site->get_cached_projects(); // Now make sure that the project is updated, no matter what! WPMUDEV_Dashboard::$api->calculate_upgrades($local_projects, $pid); if (!$this->is_project_installed($pid)) { if ($die_on_error) { wp_send_json_error(array('message' => __('Project not installed', 'wdpmudev'))); } else { error_log('WPMU DEV error: Update failed - project not installed'); return false; } } $project = WPMUDEV_Dashboard::$site->get_project_infos($pid); // Upfront special: If updating a child theme first update parent. if ($project->need_upfront) { $upfront = WPMUDEV_Dashboard::$site->get_project_infos($this->id_upfront); // Time condition to avoid repeated UF checks if there was an error. $check = (int) WPMUDEV_Dashboard::$site->get_option('last_check_upfront'); if (!$upfront->is_installed) { if (time() > $check + 3 * MINUTE_IN_SECONDS) { WPMUDEV_Dashboard::$site->set_option('last_check_upfront', time()); $this->install_project($upfront->pid, $error, false); } } elseif ($upfront->version_installed != $upfront->version_latest) { if (time() > $check + 3 * MINUTE_IN_SECONDS) { WPMUDEV_Dashboard::$site->set_option('last_check_upfront', time()); $this->update_project($upfront->pid, false); } } } // For plugins_api.. include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; include_once ABSPATH . 'wp-admin/includes/plugin-install.php'; // Save on a bit of bandwidth. $api = plugins_api('plugin_information', array('slug' => 'wpmudev_install-' . $pid, 'fields' => array('sections' => false))); if (is_wp_error($api)) { if ($die_on_error) { wp_send_json_error(array('message' => __('No data found', 'wpmudev'))); } else { error_log('WPMU DEV error: Update failed - no upgrade data found'); return false; } } ob_start(); $skin = new Automatic_Upgrader_Skin(); $result = false; $success = false; $update_file = $project->filename; /* * Set before the update: * WP will refresh local cache via action-hook before the install() * method is finished. That refresh call must scan the FS again. */ $this->flush_fs_cache = true; $this->flush_info_cache = true; switch ($project->type) { case 'plugin': wp_update_plugins(); $upgrader = new Plugin_Upgrader($skin); $result = $upgrader->bulk_upgrade(array($update_file)); break; case 'theme': wp_update_themes(); $upgrader = new Theme_Upgrader($skin); $update_file = dirname($update_file); $result = $upgrader->upgrade($update_file); break; } // Check for errors. if (is_array($result) && empty($result[$update_file]) && is_wp_error($skin->result)) { $result = $skin->result; } $details = ob_get_clean(); $err_data = array('error_code' => 'U000', 'message' => __('Update failed', 'wpmudev'), 'details' => $details, 'pid' => $pid); if (is_array($result) && !empty($result[$update_file])) { $plugin_update_data = current($result); if (true === $plugin_update_data) { $err_data['error_code'] = 'U001'; $err_data['message'] = implode('<br>', $skin->get_upgrade_messages()); error_log('WPMU DEV error: Update failed | ' . json_encode($err_data)); if ($die_on_error) { $this->send_json_error($err_data); } else { return false; } } } elseif (is_wp_error($result)) { $err_data['error_code'] = 'U002'; $err_data['message'] = $result->get_error_message(); error_log('WPMU DEV error: Update failed | ' . json_encode($err_data)); if ($die_on_error) { $this->send_json_error($err_data); } else { return false; } } elseif (is_bool($result) && !$result) { // $upgrader->upgrade() returned false. // Possibly because WordPress did not find an update for the project. $err_data['error_code'] = 'U003'; $err_data['message'] = __('Could not find update source', 'wpmudev'); error_log('WPMU DEV error: Update failed | ' . json_encode($err_data)); if ($die_on_error) { $this->send_json_error($err_data); } else { return false; } } // API call to inform wpmudev site about the change. $this->refresh_local_projects('remote'); // Check if the update was successful. $project = WPMUDEV_Dashboard::$site->get_project_infos($pid); if ($project->version_installed != $project->version_latest) { if ($die_on_error) { wp_send_json_error(array('message' => __('Update failed. Maybe wrong folder permissions.', 'wdpmudev'))); } else { error_log('WPMU DEV error: Upgrade failed - Maybe wrong folder permissions.'); return false; } } return true; }
/** * Update an item, if appropriate. * * @since 3.7.0 * * @param string $type The type of update being checked: 'core', 'theme', 'plugin', 'translation'. * @param object $item The update offer. */ public function update($type, $item) { $skin = new Automatic_Upgrader_Skin(); switch ($type) { case 'core': // The Core upgrader doesn't use the Upgrader's skin during the actual main part of the upgrade, instead, firing a filter. add_filter('update_feedback', array($skin, 'feedback')); $upgrader = new Core_Upgrader($skin); $context = ABSPATH; break; case 'plugin': $upgrader = new Plugin_Upgrader($skin); $context = WP_PLUGIN_DIR; // We don't support custom Plugin directories, or updates for WPMU_PLUGIN_DIR break; case 'theme': $upgrader = new Theme_Upgrader($skin); $context = get_theme_root($item->theme); break; case 'translation': $upgrader = new Language_Pack_Upgrader($skin); $context = WP_CONTENT_DIR; // WP_LANG_DIR; break; } // Determine whether we can and should perform this update. if (!$this->should_update($type, $item, $context)) { return false; } $upgrader_item = $item; switch ($type) { case 'core': $skin->feedback(__('Updating to WordPress %s'), $item->version); $item_name = sprintf(__('WordPress %s'), $item->version); break; case 'theme': $upgrader_item = $item->theme; $theme = wp_get_theme($upgrader_item); $item_name = $theme->Get('Name'); $skin->feedback(__('Updating theme: %s'), $item_name); break; case 'plugin': $upgrader_item = $item->plugin; $plugin_data = get_plugin_data($context . '/' . $upgrader_item); $item_name = $plugin_data['Name']; $skin->feedback(__('Updating plugin: %s'), $item_name); break; case 'translation': $language_item_name = $upgrader->get_name_for_update($item); $item_name = sprintf(__('Translations for %s'), $language_item_name); $skin->feedback(sprintf(__('Updating translations for %1$s (%2$s)…'), $language_item_name, $item->language)); break; } $allow_relaxed_file_ownership = false; if ('core' == $type && isset($item->new_files) && !$item->new_files) { $allow_relaxed_file_ownership = true; } // Boom, This sites about to get a whole new splash of paint! $upgrade_result = $upgrader->upgrade($upgrader_item, array('clear_update_cache' => false, 'pre_check_md5' => false, 'attempt_rollback' => true, 'allow_relaxed_file_ownership' => $allow_relaxed_file_ownership)); // If the filesystem is unavailable, false is returned. if (false === $upgrade_result) { $upgrade_result = new WP_Error('fs_unavailable', __('Could not access filesystem.')); } // Core doesn't output this, so let's append it so we don't get confused. if ('core' == $type) { if (is_wp_error($upgrade_result)) { $skin->error(__('Installation Failed'), $upgrade_result); } else { $skin->feedback(__('WordPress updated successfully')); } } $this->update_results[$type][] = (object) array('item' => $item, 'result' => $upgrade_result, 'name' => $item_name, 'messages' => $skin->get_upgrade_messages()); return $upgrade_result; }
/** * Download and install a single plugin/theme update. * * @since 4.0.0 * @param int/string $pid The project ID or a plugin slug. * @return bool True on success. */ public function upgrade($pid) { $this->clear_error(); // Is a WPMU DEV project? $is_dev = is_numeric($pid); if ($is_dev) { $pid = (int) $pid; $infos = $this->prepare_dev_upgrade($pid); if (!$infos) { return false; } $filename = 'theme' == $infos['type'] ? dirname($infos['filename']) : $infos['filename']; $slug = $infos['slug']; $type = $infos['type']; } elseif (is_string($pid)) { // No need to check if the plugin exists/is installed. WP will check it. list($type, $filename) = explode(':', $pid); $slug = 'plugin' == $type && false !== strpos($filename, '/') ? dirname($filename) : $filename; } else { $this->set_error($pid, 'UPG.07', __('Invalid upgrade call', 'wdpmudev')); return false; } // For plugins_api/themes_api.. include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; include_once ABSPATH . 'wp-admin/includes/plugin-install.php'; include_once ABSPATH . 'wp-admin/includes/theme-install.php'; include_once ABSPATH . 'wp-admin/includes/file.php'; ob_start(); $skin = new Automatic_Upgrader_Skin(); $result = false; $success = false; /* * Set before the update: * WP will refresh local cache via action-hook before the install() * method is finished. That refresh call must scan the FS again. */ WPMUDEV_Dashboard::$site->clear_local_file_cache(); switch ($type) { case 'plugin': // Save on a bit of bandwidth. $api = plugins_api('plugin_information', array('slug' => $slug, 'fields' => array('sections' => false))); if (is_wp_error($api)) { $this->set_error($pid, 'UPG.02', __('No data found', 'wdpmudev')); return false; } wp_update_plugins(); $active_blog = is_plugin_active($filename); $active_network = is_multisite() && is_plugin_active_for_network($filename); $upgrader = new Plugin_Upgrader($skin); $result = $upgrader->upgrade($filename); /* * Note: The following plugin activation is an intended and * needed step. During upgrade() WordPress deactivates the * plugin network- and site-wide. By default the user would * see a upgrade-results page with the option to activate the * plugin again. We skip that screen and restore original state. */ if ($active_blog) { activate_plugin($filename, false, false, true); } if ($active_network) { activate_plugin($filename, false, true, true); } break; case 'theme': // Save on a bit of bandwidth. $api = themes_api('theme_information', array('slug' => $slug, 'fields' => array('sections' => false))); if (is_wp_error($api)) { $this->set_error($pid, 'UPG.02', __('No data found', 'wdpmudev')); return false; } wp_update_themes(); $upgrader = new Theme_Upgrader($skin); $result = $upgrader->upgrade($filename); break; default: $this->set_error($pid, 'UPG.08', __('Invalid upgrade call', 'wpmudev')); return false; } // Check for errors. if (is_array($result) && empty($result[$filename]) && is_wp_error($skin->result)) { $result = $skin->result; } $details = ob_get_clean(); if (is_array($result) && !empty($result[$filename])) { $plugin_update_data = current($result); if (true === $plugin_update_data) { $this->set_error($pid, 'UPG.03', implode('<br>', $skin->get_upgrade_messages())); return false; } } elseif (is_wp_error($result)) { $this->set_error($pid, 'UPG.04', $result->get_error_message()); return false; } elseif (is_bool($result) && !$result) { // $upgrader->upgrade() returned false. // Possibly because WordPress did not find an update for the project. $this->set_error($pid, 'UPG.05', __('Could not find update in transient, or filesystem permissions', 'wpmudev')); return false; } if ($is_dev) { // API call to inform wpmudev site about the change, as it's a single we can let it do that at the end to avoid multiple pings WPMUDEV_Dashboard::$site->schedule_shutdown_refresh(); // Check if the update was successful. $project = WPMUDEV_Dashboard::$site->get_project_infos($pid); if (version_compare($project->version_installed, $project->version_latest, '<')) { $this->set_error($pid, 'UPG.06', __('There was an unknown error', 'wpmudev')); return false; } } return true; }