/** * Toggle maintenance mode for the site. * * Creates/deletes the maintenance file to enable/disable maintenance mode. * * @since 2.8.0 * @access public * * @global WP_Filesystem_Base $wp_filesystem Subclass * * @param bool $enable True to enable maintenance mode, false to disable. */ public function maintenance_mode($enable = false) { global $wp_filesystem; $file = $wp_filesystem->abspath() . '.maintenance'; if ($enable) { $this->skin->feedback('maintenance_start'); // Create maintenance file to signal that we are upgrading $maintenance_string = '<?php $upgrading = ' . time() . '; ?>'; $wp_filesystem->delete($file); $wp_filesystem->put_contents($file, $maintenance_string, FS_CHMOD_FILE); } elseif (!$enable && $wp_filesystem->exists($file)) { $this->skin->feedback('maintenance_end'); $wp_filesystem->delete($file); } }
/** * 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; }
static function get_possible_failures() { $result = array(); // Lets check some reasons why it might not be working as expected include_once ABSPATH . '/wp-admin/includes/admin.php'; include_once ABSPATH . '/wp-admin/includes/class-wp-upgrader.php'; $upgrader = new WP_Automatic_Updater(); if ($upgrader->is_disabled()) { $result[] = 'autoupdates-disabled'; } if (!is_main_site()) { $result[] = 'is-not-main-site'; } if (!is_main_network()) { $result[] = 'is-not-main-network'; } if ($upgrader->is_vcs_checkout(ABSPATH)) { $result[] = 'site-on-vcs'; } if ($upgrader->is_vcs_checkout(WP_PLUGIN_DIR)) { $result[] = 'plugin-directory-on-vcs'; } if ($upgrader->is_vcs_checkout(WP_CONTENT_DIR)) { $result[] = 'content-directory-on-vcs'; } $lock = get_option('auto_updater.lock'); if ($lock > time() - HOUR_IN_SECONDS) { $result[] = 'lock-is-set'; } $skin = new Automatic_Upgrader_Skin(); include_once ABSPATH . 'wp-admin/includes/file.php'; include_once ABSPATH . 'wp-admin/includes/template.php'; if (!$skin->request_filesystem_credentials(false, ABSPATH, false)) { $result[] = 'no-system-write-access'; } if (!$skin->request_filesystem_credentials(false, WP_PLUGIN_DIR, false)) { $result[] = 'no-plugin-directory-write-access'; } if (!$skin->request_filesystem_credentials(false, WP_CONTENT_DIR, false)) { $result[] = 'no-wp-content-directory-write-access'; } return $result; }
/** * Overwrites the set_upgrader to be able to tell if we e ven have the ability to write to the files. * * @param WP_Upgrader $upgrader * */ public function set_upgrader(&$upgrader) { parent::set_upgrader($upgrader); // Check if we even have permission to. $result = $upgrader->fs_connect(array(WP_CONTENT_DIR, WP_PLUGIN_DIR)); if (!$result) { // set the string here since they are not available just yet $upgrader->generic_strings(); $this->feedback('fs_unavailable'); } }
static function can_auto_update($context, $skin = false) { if (!$skin) { $skin = new Automatic_Upgrader_Skin(); } return (bool) $skin->request_filesystem_credentials(false, $context); }
/** * 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; }
/** * 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; }
/** * Tests to see if we can and should update a specific item. * * @since 3.7.0 * @access public * * @global wpdb $wpdb WordPress database abstraction object. * * @param string $type The type of update being checked: 'core', 'theme', * 'plugin', 'translation'. * @param object $item The update offer. * @param string $context The filesystem context (a path) against which filesystem * access and status should be checked. */ public function should_update($type, $item, $context) { // Used to see if WP_Filesystem is set up to allow unattended updates. $skin = new Automatic_Upgrader_Skin(); if ($this->is_disabled()) { return false; } // Only relax the filesystem checks when the update doesn't include new files $allow_relaxed_file_ownership = false; if ('core' == $type && isset($item->new_files) && !$item->new_files) { $allow_relaxed_file_ownership = true; } // If we can't do an auto core update, we may still be able to email the user. if (!$skin->request_filesystem_credentials(false, $context, $allow_relaxed_file_ownership) || $this->is_vcs_checkout($context)) { if ('core' == $type) { $this->send_core_update_notification_email($item); } return false; } // Next up, is this an item we can update? if ('core' == $type) { $update = Core_Upgrader::should_update_to_version($item->current); } else { $update = !empty($item->autoupdate); } /** * Filter whether to automatically update core, a plugin, a theme, or a language. * * The dynamic portion of the hook name, `$type`, refers to the type of update * being checked. Can be 'core', 'theme', 'plugin', or 'translation'. * * Generally speaking, plugins, themes, and major core versions are not updated * by default, while translations and minor and development versions for core * are updated by default. * * See the {@see 'allow_dev_auto_core_updates', {@see 'allow_minor_auto_core_updates'}, * and {@see 'allow_major_auto_core_updates'} filters for a more straightforward way to * adjust core updates. * * @since 3.7.0 * * @param bool $update Whether to update. * @param object $item The update offer. */ $update = apply_filters('auto_update_' . $type, $update, $item); if (!$update) { if ('core' == $type) { $this->send_core_update_notification_email($item); } return false; } // If it's a core update, are we actually compatible with its requirements? if ('core' == $type) { global $wpdb; $php_compat = version_compare(phpversion(), $item->php_version, '>='); if (file_exists(WP_CONTENT_DIR . '/db.php') && empty($wpdb->is_mysql)) { $mysql_compat = true; } else { $mysql_compat = version_compare($wpdb->db_version(), $item->mysql_version, '>='); } if (!$php_compat || !$mysql_compat) { return false; } } return true; }
/** * Constructor. * * @since 4.6.0 * @access public * * @param array $args Options for the upgrader, see WP_Upgrader_Skin::__construct(). */ public function __construct($args = array()) { parent::__construct($args); $this->errors = new WP_Error(); }