/** * Get the value of a site transient. * * If the transient does not exist, does not have a value, or has expired, * then the return value will be false. * * @since 2.9.0 * * @see get_transient() * * @param string $transient Transient name. Expected to not be SQL-escaped. * @return mixed Value of transient. */ function get_site_transient($transient) { /** * Filter the value of an existing site transient. * * The dynamic portion of the hook name, `$transient`, refers to the transient name. * * Passing a truthy value to the filter will effectively short-circuit retrieval, * returning the passed value instead. * * @since 2.9.0 * @since 4.4.0 The `$transient` parameter was added * * @param mixed $pre_site_transient The default value to return if the site transient does not exist. * Any value other than false will short-circuit the retrieval * of the transient, and return the returned value. * @param string $transient Transient name. */ $pre = apply_filters('pre_site_transient_' . $transient, false, $transient); if (false !== $pre) { return $pre; } if (wp_using_ext_object_cache()) { $value = wp_cache_get($transient, 'site-transient'); } else { // Core transients that do not have a timeout. Listed here so querying timeouts can be avoided. $no_timeout = array('update_core', 'update_plugins', 'update_themes'); $transient_option = '_site_transient_' . $transient; if (!in_array($transient, $no_timeout)) { $transient_timeout = '_site_transient_timeout_' . $transient; $timeout = get_network_option($transient_timeout); if (false !== $timeout && $timeout < time()) { delete_network_option($transient_option); delete_network_option($transient_timeout); $value = false; } } if (!isset($value)) { $value = get_network_option($transient_option); } } /** * Filter the value of an existing site transient. * * The dynamic portion of the hook name, `$transient`, refers to the transient name. * * @since 2.9.0 * @since 4.4.0 The `$transient` parameter was added * * @param mixed $value Value of site transient. * @param string $transient Transient name. */ return apply_filters('site_transient_' . $transient, $value, $transient); }
/** * Removes a option by name for the current network. * * @since 2.8.0 * @since 4.4.0 Modified into wrapper for delete_network_option() * * @see delete_network_option() * * @param string $option Name of option to remove. Expected to not be SQL-escaped. * @return bool True, if succeed. False, if failure. */ function delete_site_option($option) { return delete_network_option(null, $option); }
/** * Upgrade the core of WordPress. * * This will create a .maintenance file at the base of the WordPress directory * to ensure that people can not access the web site, when the files are being * copied to their locations. * * The files in the {@link $_old_files} list will be removed and the new files * copied from the zip file after the database is upgraded. * * The files in the {@link $_new_bundled_files} list will be added to the installation * if the version is greater than or equal to the old version being upgraded. * * The steps for the upgrader for after the new release is downloaded and * unzipped is: * 1. Test unzipped location for select files to ensure that unzipped worked. * 2. Create the .maintenance file in current WordPress base. * 3. Copy new WordPress directory over old WordPress files. * 4. Upgrade WordPress to new version. * 4.1. Copy all files/folders other than wp-content * 4.2. Copy any language files to WP_LANG_DIR (which may differ from WP_CONTENT_DIR * 4.3. Copy any new bundled themes/plugins to their respective locations * 5. Delete new WordPress directory path. * 6. Delete .maintenance file. * 7. Remove old files. * 8. Delete 'update_core' option. * * There are several areas of failure. For instance if PHP times out before step * 6, then you will not be able to access any portion of your site. Also, since * the upgrade will not continue where it left off, you will not be able to * automatically remove old files and remove the 'update_core' option. This * isn't that bad. * * If the copy of the new WordPress over the old fails, then the worse is that * the new WordPress directory will remain. * * If it is assumed that every file will be copied over, including plugins and * themes, then if you edit the default theme, you should rename it, so that * your changes remain. * * @since 2.7.0 * * @global WP_Filesystem_Base $wp_filesystem * @global array $_old_files * @global array $_new_bundled_files * @global wpdb $wpdb * @global string $wp_version * @global string $required_php_version * @global string $required_mysql_version * * @param string $from New release unzipped path. * @param string $to Path to old WordPress installation. * @return WP_Error|null WP_Error on failure, null on success. */ function update_core($from, $to) { global $wp_filesystem, $_old_files, $_new_bundled_files, $wpdb; @set_time_limit(300); /** * Filter feedback messages displayed during the core update process. * * The filter is first evaluated after the zip file for the latest version * has been downloaded and unzipped. It is evaluated five more times during * the process: * * 1. Before WordPress begins the core upgrade process. * 2. Before Maintenance Mode is enabled. * 3. Before WordPress begins copying over the necessary files. * 4. Before Maintenance Mode is disabled. * 5. Before the database is upgraded. * * @since 2.5.0 * * @param string $feedback The core update feedback messages. */ apply_filters('update_feedback', __('Verifying the unpacked files…')); // Sanity check the unzipped distribution. $distro = ''; $roots = array('/wordpress/', '/wordpress-mu/'); foreach ($roots as $root) { if ($wp_filesystem->exists($from . $root . 'readme.html') && $wp_filesystem->exists($from . $root . 'wp-includes/version.php')) { $distro = $root; break; } } if (!$distro) { $wp_filesystem->delete($from, true); return new WP_Error('insane_distro', __('The update could not be unpacked')); } /** * Import $wp_version, $required_php_version, and $required_mysql_version from the new version * $wp_filesystem->wp_content_dir() returned unslashed pre-2.8 * * @global string $wp_version * @global string $required_php_version * @global string $required_mysql_version */ global $wp_version, $required_php_version, $required_mysql_version; $versions_file = trailingslashit($wp_filesystem->wp_content_dir()) . 'upgrade/version-current.php'; if (!$wp_filesystem->copy($from . $distro . 'wp-includes/version.php', $versions_file)) { $wp_filesystem->delete($from, true); return new WP_Error('copy_failed_for_version_file', __('The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.'), 'wp-includes/version.php'); } $wp_filesystem->chmod($versions_file, FS_CHMOD_FILE); require WP_CONTENT_DIR . '/upgrade/version-current.php'; $wp_filesystem->delete($versions_file); $php_version = phpversion(); $mysql_version = $wpdb->db_version(); $old_wp_version = $wp_version; // The version of WordPress we're updating from $development_build = false !== strpos($old_wp_version . $wp_version, '-'); // a dash in the version indicates a Development release $php_compat = version_compare($php_version, $required_php_version, '>='); if (file_exists(WP_CONTENT_DIR . '/db.php') && empty($wpdb->is_mysql)) { $mysql_compat = true; } else { $mysql_compat = version_compare($mysql_version, $required_mysql_version, '>='); } if (!$mysql_compat || !$php_compat) { $wp_filesystem->delete($from, true); } if (!$mysql_compat && !$php_compat) { return new WP_Error('php_mysql_not_compatible', sprintf(__('The update cannot be installed because WordPress %1$s requires PHP version %2$s or higher and MySQL version %3$s or higher. You are running PHP version %4$s and MySQL version %5$s.'), $wp_version, $required_php_version, $required_mysql_version, $php_version, $mysql_version)); } elseif (!$php_compat) { return new WP_Error('php_not_compatible', sprintf(__('The update cannot be installed because WordPress %1$s requires PHP version %2$s or higher. You are running version %3$s.'), $wp_version, $required_php_version, $php_version)); } elseif (!$mysql_compat) { return new WP_Error('mysql_not_compatible', sprintf(__('The update cannot be installed because WordPress %1$s requires MySQL version %2$s or higher. You are running version %3$s.'), $wp_version, $required_mysql_version, $mysql_version)); } /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters('update_feedback', __('Preparing to install the latest version…')); // Don't copy wp-content, we'll deal with that below // We also copy version.php last so failed updates report their old version $skip = array('wp-content', 'wp-includes/version.php'); $check_is_writable = array(); // Check to see which files don't really need updating - only available for 3.7 and higher if (function_exists('get_core_checksums')) { // Find the local version of the working directory $working_dir_local = WP_CONTENT_DIR . '/upgrade/' . basename($from) . $distro; $checksums = get_core_checksums($wp_version, isset($wp_local_package) ? $wp_local_package : 'en_US'); if (is_array($checksums) && isset($checksums[$wp_version])) { $checksums = $checksums[$wp_version]; } // Compat code for 3.7-beta2 if (is_array($checksums)) { foreach ($checksums as $file => $checksum) { if ('wp-content' == substr($file, 0, 10)) { continue; } if (!file_exists(ABSPATH . $file)) { continue; } if (!file_exists($working_dir_local . $file)) { continue; } if (md5_file(ABSPATH . $file) === $checksum) { $skip[] = $file; } else { $check_is_writable[$file] = ABSPATH . $file; } } } } // If we're using the direct method, we can predict write failures that are due to permissions. if ($check_is_writable && 'direct' === $wp_filesystem->method) { $files_writable = array_filter($check_is_writable, array($wp_filesystem, 'is_writable')); if ($files_writable !== $check_is_writable) { $files_not_writable = array_diff_key($check_is_writable, $files_writable); foreach ($files_not_writable as $relative_file_not_writable => $file_not_writable) { // If the writable check failed, chmod file to 0644 and try again, same as copy_dir(). $wp_filesystem->chmod($file_not_writable, FS_CHMOD_FILE); if ($wp_filesystem->is_writable($file_not_writable)) { unset($files_not_writable[$relative_file_not_writable]); } } // Store package-relative paths (the key) of non-writable files in the WP_Error object. $error_data = version_compare($old_wp_version, '3.7-beta2', '>') ? array_keys($files_not_writable) : ''; if ($files_not_writable) { return new WP_Error('files_not_writable', __('The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.'), implode(', ', $error_data)); } } } /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters('update_feedback', __('Enabling Maintenance mode…')); // Create maintenance file to signal that we are upgrading $maintenance_string = '<?php $upgrading = ' . time() . '; ?>'; $maintenance_file = $to . '.maintenance'; $wp_filesystem->delete($maintenance_file); $wp_filesystem->put_contents($maintenance_file, $maintenance_string, FS_CHMOD_FILE); /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters('update_feedback', __('Copying the required files…')); // Copy new versions of WP files into place. $result = _copy_dir($from . $distro, $to, $skip); if (is_wp_error($result)) { $result = new WP_Error($result->get_error_code(), $result->get_error_message(), substr($result->get_error_data(), strlen($to))); } // Since we know the core files have copied over, we can now copy the version file if (!is_wp_error($result)) { if (!$wp_filesystem->copy($from . $distro . 'wp-includes/version.php', $to . 'wp-includes/version.php', true)) { $wp_filesystem->delete($from, true); $result = new WP_Error('copy_failed_for_version_file', __('The update cannot be installed because we will be unable to copy some files. This is usually due to inconsistent file permissions.'), 'wp-includes/version.php'); } $wp_filesystem->chmod($to . 'wp-includes/version.php', FS_CHMOD_FILE); } // Check to make sure everything copied correctly, ignoring the contents of wp-content $skip = array('wp-content'); $failed = array(); if (isset($checksums) && is_array($checksums)) { foreach ($checksums as $file => $checksum) { if ('wp-content' == substr($file, 0, 10)) { continue; } if (!file_exists($working_dir_local . $file)) { continue; } if (file_exists(ABSPATH . $file) && md5_file(ABSPATH . $file) == $checksum) { $skip[] = $file; } else { $failed[] = $file; } } } // Some files didn't copy properly if (!empty($failed)) { $total_size = 0; foreach ($failed as $file) { if (file_exists($working_dir_local . $file)) { $total_size += filesize($working_dir_local . $file); } } // If we don't have enough free space, it isn't worth trying again. // Unlikely to be hit due to the check in unzip_file(). $available_space = @disk_free_space(ABSPATH); if ($available_space && $total_size >= $available_space) { $result = new WP_Error('disk_full', __('There is not enough free disk space to complete the update.')); } else { $result = _copy_dir($from . $distro, $to, $skip); if (is_wp_error($result)) { $result = new WP_Error($result->get_error_code() . '_retry', $result->get_error_message(), substr($result->get_error_data(), strlen($to))); } } } // Custom Content Directory needs updating now. // Copy Languages if (!is_wp_error($result) && $wp_filesystem->is_dir($from . $distro . 'wp-content/languages')) { if (WP_LANG_DIR != ABSPATH . WPINC . '/languages' || @is_dir(WP_LANG_DIR)) { $lang_dir = WP_LANG_DIR; } else { $lang_dir = WP_CONTENT_DIR . '/languages'; } if (!@is_dir($lang_dir) && 0 === strpos($lang_dir, ABSPATH)) { // Check the language directory exists first $wp_filesystem->mkdir($to . str_replace(ABSPATH, '', $lang_dir), FS_CHMOD_DIR); // If it's within the ABSPATH we can handle it here, otherwise they're out of luck. clearstatcache(); // for FTP, Need to clear the stat cache } if (@is_dir($lang_dir)) { $wp_lang_dir = $wp_filesystem->find_folder($lang_dir); if ($wp_lang_dir) { $result = copy_dir($from . $distro . 'wp-content/languages/', $wp_lang_dir); if (is_wp_error($result)) { $result = new WP_Error($result->get_error_code() . '_languages', $result->get_error_message(), substr($result->get_error_data(), strlen($wp_lang_dir))); } } } } /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters('update_feedback', __('Disabling Maintenance mode…')); // Remove maintenance file, we're done with potential site-breaking changes $wp_filesystem->delete($maintenance_file); // 3.5 -> 3.5+ - an empty twentytwelve directory was created upon upgrade to 3.5 for some users, preventing installation of Twenty Twelve. if ('3.5' == $old_wp_version) { if (is_dir(WP_CONTENT_DIR . '/themes/twentytwelve') && !file_exists(WP_CONTENT_DIR . '/themes/twentytwelve/style.css')) { $wp_filesystem->delete($wp_filesystem->wp_themes_dir() . 'twentytwelve/'); } } // Copy New bundled plugins & themes // This gives us the ability to install new plugins & themes bundled with future versions of WordPress whilst avoiding the re-install upon upgrade issue. // $development_build controls us overwriting bundled themes and plugins when a non-stable release is being updated if (!is_wp_error($result) && (!defined('CORE_UPGRADE_SKIP_NEW_BUNDLED') || !CORE_UPGRADE_SKIP_NEW_BUNDLED)) { foreach ((array) $_new_bundled_files as $file => $introduced_version) { // If a $development_build or if $introduced version is greater than what the site was previously running if ($development_build || version_compare($introduced_version, $old_wp_version, '>')) { $directory = '/' == $file[strlen($file) - 1]; list($type, $filename) = explode('/', $file, 2); // Check to see if the bundled items exist before attempting to copy them if (!$wp_filesystem->exists($from . $distro . 'wp-content/' . $file)) { continue; } if ('plugins' == $type) { $dest = $wp_filesystem->wp_plugins_dir(); } elseif ('themes' == $type) { $dest = trailingslashit($wp_filesystem->wp_themes_dir()); } else { continue; } if (!$directory) { if (!$development_build && $wp_filesystem->exists($dest . $filename)) { continue; } if (!$wp_filesystem->copy($from . $distro . 'wp-content/' . $file, $dest . $filename, FS_CHMOD_FILE)) { $result = new WP_Error("copy_failed_for_new_bundled_{$type}", __('Could not copy file.'), $dest . $filename); } } else { if (!$development_build && $wp_filesystem->is_dir($dest . $filename)) { continue; } $wp_filesystem->mkdir($dest . $filename, FS_CHMOD_DIR); $_result = copy_dir($from . $distro . 'wp-content/' . $file, $dest . $filename); // If a error occurs partway through this final step, keep the error flowing through, but keep process going. if (is_wp_error($_result)) { if (!is_wp_error($result)) { $result = new WP_Error(); } $result->add($_result->get_error_code() . "_{$type}", $_result->get_error_message(), substr($_result->get_error_data(), strlen($dest))); } } } } //end foreach } // Handle $result error from the above blocks if (is_wp_error($result)) { $wp_filesystem->delete($from, true); return $result; } // Remove old files foreach ($_old_files as $old_file) { $old_file = $to . $old_file; if (!$wp_filesystem->exists($old_file)) { continue; } $wp_filesystem->delete($old_file, true); } // Remove any Genericons example.html's from the filesystem _upgrade_422_remove_genericons(); // Upgrade DB with separate request /** This filter is documented in wp-admin/includes/update-core.php */ apply_filters('update_feedback', __('Upgrading database…')); $db_upgrade_url = admin_url('upgrade.php?step=upgrade_db'); wp_remote_post($db_upgrade_url, array('timeout' => 60)); // Clear the cache to prevent an update_option() from saving a stale db_version to the cache wp_cache_flush(); // (Not all cache backends listen to 'flush') wp_cache_delete('alloptions', 'options'); // Remove working directory $wp_filesystem->delete($from, true); // Force refresh of update information if (function_exists('delete_site_transient')) { delete_site_transient('update_core'); } else { delete_option('update_core'); } /** * Fires after WordPress core has been successfully updated. * * @since 3.3.0 * * @param string $wp_version The current WordPress version. */ do_action('_core_updated_successfully', $wp_version); // Clear the option that blocks auto updates after failures, now that we've been successful. if (function_exists('delete_network_option')) { delete_network_option('auto_core_update_failed'); } return $wp_version; }
function delete_global_option($option) { global $wpdb; $option = trim($option); if (empty($option)) { return false; } wp_protect_special_option($option); // Get the ID, if no ID then return $row = $wpdb->get_row($wpdb->prepare("SELECT autoload FROM {$wpdb->global_options} WHERE option_name = %s", $option)); if (is_null($row)) { return false; } /** * Fires immediately before a global option is deleted. * * The dynamic portion of the hook name, `$option`, refers to the option name. * * @since 1.0.0 * * @param string $option Name of the option to delete. */ do_action('pre_delete_global_option_' . $option, $option); if (!is_multinetwork()) { $result = delete_network_option(null, $option); } else { $result = $wpdb->delete($wpdb->global_options, array('option_name' => $option)); if (!wp_installing()) { if ('yes' == $row->autoload) { $alloptions = wp_load_global_alloptions(); if (is_array($alloptions) && isset($alloptions[$option])) { unset($alloptions[$option]); wp_cache_set('alloptions', $alloptions, 'global-options'); } } else { wp_cache_delete($option, 'global-options'); } } } if ($result) { /** * Fires after a specific global option has been deleted. * * The dynamic portion of the hook name, `$option`, refers to the option name. * * @since 1.0.0 * * @param string $option Name of the deleted option. */ do_action("delete_global_option_{$option}", $option); /** * Fires after a global option has been deleted. * * @since 1.0.0 * * @param string $option Name of the deleted option. */ do_action('deleted_global_option', $option); return true; } return false; }
/** * Executes network-level upgrade routines. * * @since 3.0.0 * * @global int $wp_current_db_version * @global wpdb $wpdb */ function upgrade_network() { global $wp_current_db_version, $wpdb; // Always. if (is_main_network()) { /* * Deletes all expired transients. The multi-table delete syntax is used * to delete the transient record from table a, and the corresponding * transient_timeout record from table b. */ $time = time(); $sql = "DELETE a, b FROM {$wpdb->sitemeta} a, {$wpdb->sitemeta} b\n\t\t\tWHERE a.meta_key LIKE %s\n\t\t\tAND a.meta_key NOT LIKE %s\n\t\t\tAND b.meta_key = CONCAT( '_site_transient_timeout_', SUBSTRING( a.meta_key, 17 ) )\n\t\t\tAND b.meta_value < %d"; $wpdb->query($wpdb->prepare($sql, $wpdb->esc_like('_site_transient_') . '%', $wpdb->esc_like('_site_transient_timeout_') . '%', $time)); } // 2.8. if ($wp_current_db_version < 11549) { $wpmu_sitewide_plugins = get_network_option('wpmu_sitewide_plugins'); $active_sitewide_plugins = get_network_option('active_sitewide_plugins'); if ($wpmu_sitewide_plugins) { if (!$active_sitewide_plugins) { $sitewide_plugins = (array) $wpmu_sitewide_plugins; } else { $sitewide_plugins = array_merge((array) $active_sitewide_plugins, (array) $wpmu_sitewide_plugins); } update_network_option('active_sitewide_plugins', $sitewide_plugins); } delete_network_option('wpmu_sitewide_plugins'); delete_network_option('deactivated_sitewide_plugins'); $start = 0; while ($rows = $wpdb->get_results("SELECT meta_key, meta_value FROM {$wpdb->sitemeta} ORDER BY meta_id LIMIT {$start}, 20")) { foreach ($rows as $row) { $value = $row->meta_value; if (!@unserialize($value)) { $value = stripslashes($value); } if ($value !== $row->meta_value) { update_network_option($row->meta_key, $value); } } $start += 20; } } // 3.0 if ($wp_current_db_version < 13576) { update_network_option('global_terms_enabled', '1'); } // 3.3 if ($wp_current_db_version < 19390) { update_network_option('initial_db_version', $wp_current_db_version); } if ($wp_current_db_version < 19470) { if (false === get_network_option('active_sitewide_plugins')) { update_network_option('active_sitewide_plugins', array()); } } // 3.4 if ($wp_current_db_version < 20148) { // 'allowedthemes' keys things by stylesheet. 'allowed_themes' keyed things by name. $allowedthemes = get_network_option('allowedthemes'); $allowed_themes = get_network_option('allowed_themes'); if (false === $allowedthemes && is_array($allowed_themes) && $allowed_themes) { $converted = array(); $themes = wp_get_themes(); foreach ($themes as $stylesheet => $theme_data) { if (isset($allowed_themes[$theme_data->get('Name')])) { $converted[$stylesheet] = true; } } update_network_option('allowedthemes', $converted); delete_network_option('allowed_themes'); } } // 3.5 if ($wp_current_db_version < 21823) { update_network_option('ms_files_rewriting', '1'); } // 3.5.2 if ($wp_current_db_version < 24448) { $illegal_names = get_network_option('illegal_names'); if (is_array($illegal_names) && count($illegal_names) === 1) { $illegal_name = reset($illegal_names); $illegal_names = explode(' ', $illegal_name); update_network_option('illegal_names', $illegal_names); } } // 4.2 if ($wp_current_db_version < 31351 && $wpdb->charset === 'utf8mb4') { if (wp_should_upgrade_global_tables()) { $wpdb->query("ALTER TABLE {$wpdb->usermeta} DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))"); $wpdb->query("ALTER TABLE {$wpdb->site} DROP INDEX domain, ADD INDEX domain(domain(140),path(51))"); $wpdb->query("ALTER TABLE {$wpdb->sitemeta} DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))"); $wpdb->query("ALTER TABLE {$wpdb->signups} DROP INDEX domain_path, ADD INDEX domain_path(domain(140),path(51))"); $tables = $wpdb->tables('global'); // sitecategories may not exist. if (!$wpdb->get_var("SHOW TABLES LIKE '{$tables['sitecategories']}'")) { unset($tables['sitecategories']); } foreach ($tables as $table) { maybe_convert_table_to_utf8mb4($table); } } } // 4.3 if ($wp_current_db_version < 33055 && 'utf8mb4' === $wpdb->charset) { if (wp_should_upgrade_global_tables()) { $upgrade = false; $indexes = $wpdb->get_results("SHOW INDEXES FROM {$wpdb->signups}"); foreach ($indexes as $index) { if ('domain_path' == $index->Key_name && 'domain' == $index->Column_name && 140 != $index->Sub_part) { $upgrade = true; break; } } if ($upgrade) { $wpdb->query("ALTER TABLE {$wpdb->signups} DROP INDEX domain_path, ADD INDEX domain_path(domain(140),path(51))"); } $tables = $wpdb->tables('global'); // sitecategories may not exist. if (!$wpdb->get_var("SHOW TABLES LIKE '{$tables['sitecategories']}'")) { unset($tables['sitecategories']); } foreach ($tables as $table) { maybe_convert_table_to_utf8mb4($table); } } } }