: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
// 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 ) ) {
if ( ! wp_doing_cron() ) {
$this->skin->feedback( 'maintenance_end' );
$wp_filesystem->delete( $file );
* Creates a lock using WordPress options.
* @global wpdb $wpdb The WordPress database abstraction object.
* @param string $lock_name The name of this unique lock.
* @param int $release_timeout Optional. The duration in seconds to respect an existing lock.
* @return bool False if a lock couldn't be created or if the lock is still valid. True otherwise.
public static function create_lock( $lock_name, $release_timeout = null ) {
if ( ! $release_timeout ) {
$release_timeout = HOUR_IN_SECONDS;
$lock_option = $lock_name . '.lock';
$lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'off') /* LOCK */", $lock_option, time() ) );
$lock_result = get_option( $lock_option );
// If a lock couldn't be created, and there isn't a lock, bail.
// Check to see if the lock is still valid. If it is, bail.
if ( $lock_result > ( time() - $release_timeout ) ) {
// There must exist an expired lock, clear it and re-gain it.
WP_Upgrader::release_lock( $lock_name );
return WP_Upgrader::create_lock( $lock_name, $release_timeout );
// Update the lock, as by this point we've definitely got a lock, just need to fire the actions.
update_option( $lock_option, time() );
* Releases an upgrader lock.
* @see WP_Upgrader::create_lock()
* @param string $lock_name The name of this unique lock.
* @return bool True if the lock was successfully released. False on failure.
public static function release_lock( $lock_name ) {
return delete_option( $lock_name . '.lock' );
* Moves the plugin or theme being updated into a temporary backup directory.
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
* @param string[] $args {
* Array of data for the temporary backup.
* @type string $slug Plugin or theme slug.
* @type string $src Path to the root directory for plugins or themes.
* @type string $dir Destination subdirectory name. Accepts 'plugins' or 'themes'.
* @return bool|WP_Error True on success, false on early exit, otherwise WP_Error.
public function move_to_temp_backup_dir( $args ) {
if ( empty( $args['slug'] ) || empty( $args['src'] ) || empty( $args['dir'] ) ) {
* Skip any plugin that has "." as its slug.
* A slug of "." will result in a `$src` value ending in a period.
* On Windows, this will cause the 'plugins' folder to be moved,
* and will cause a failure when attempting to call `mkdir()`.
if ( '.' === $args['slug'] ) {
if ( ! $wp_filesystem->wp_content_dir() ) {
return new WP_Error( 'fs_no_content_dir', $this->strings['fs_no_content_dir'] );
$dest_dir = $wp_filesystem->wp_content_dir() . 'upgrade-temp-backup/';
$sub_dir = $dest_dir . $args['dir'] . '/';
// Create the temporary backup directory if it does not exist.
if ( ! $wp_filesystem->is_dir( $sub_dir ) ) {
if ( ! $wp_filesystem->is_dir( $dest_dir ) ) {
$wp_filesystem->mkdir( $dest_dir, FS_CHMOD_DIR );
if ( ! $wp_filesystem->mkdir( $sub_dir, FS_CHMOD_DIR ) ) {
// Could not create the backup directory.
return new WP_Error( 'fs_temp_backup_mkdir', $this->strings['temp_backup_mkdir_failed'] );
$src_dir = $wp_filesystem->find_folder( $args['src'] );
$src = trailingslashit( $src_dir ) . $args['slug'];
$dest = $dest_dir . trailingslashit( $args['dir'] ) . $args['slug'];
// Delete the temporary backup directory if it already exists.
if ( $wp_filesystem->is_dir( $dest ) ) {
$wp_filesystem->delete( $dest, true );
// Move to the temporary backup directory.
$result = move_dir( $src, $dest, true );
if ( is_wp_error( $result ) ) {
return new WP_Error( 'fs_temp_backup_move', $this->strings['temp_backup_move_failed'] );
* Restores the plugin or theme from temporary backup.
* @since 6.6.0 Added the `$temp_backups` parameter.
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
* @param array[] $temp_backups {
* Optional. An array of temporary backups.
* Information about the backup.
* @type string $dir The temporary backup location in the upgrade-temp-backup directory.
* @type string $slug The item's slug.
* @type string $src The directory where the original is stored. For example, `WP_PLUGIN_DIR`.
* @return bool|WP_Error True on success, false on early exit, otherwise WP_Error.
public function restore_temp_backup( array $temp_backups = array() ) {
$errors = new WP_Error();
if ( empty( $temp_backups ) ) {
$temp_backups = $this->temp_restores;
foreach ( $temp_backups as $args ) {
if ( empty( $args['slug'] ) || empty( $args['src'] ) || empty( $args['dir'] ) ) {
if ( ! $wp_filesystem->wp_content_dir() ) {
$errors->add( 'fs_no_content_dir', $this->strings['fs_no_content_dir'] );
$src = $wp_filesystem->wp_content_dir() . 'upgrade-temp-backup/' . $args['dir'] . '/' . $args['slug'];
$dest_dir = $wp_filesystem->find_folder( $args['src'] );
$dest = trailingslashit( $dest_dir ) . $args['slug'];
if ( $wp_filesystem->is_dir( $src ) ) {
if ( $wp_filesystem->is_dir( $dest ) && ! $wp_filesystem->delete( $dest, true ) ) {
sprintf( $this->strings['temp_backup_restore_failed'], $args['slug'] )
$result = move_dir( $src, $dest, true );
if ( is_wp_error( $result ) ) {
sprintf( $this->strings['temp_backup_restore_failed'], $args['slug'] )
return $errors->has_errors() ? $errors : true;
* Deletes a temporary backup.
* @since 6.6.0 Added the `$temp_backups` parameter.
* @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
* @param array[] $temp_backups {
* Optional. An array of temporary backups.
* Information about the backup.
* @type string $dir The temporary backup location in the upgrade-temp-backup directory.
* @type string $slug The item's slug.
* @type string $src The directory where the original is stored. For example, `WP_PLUGIN_DIR`.
* @return bool|WP_Error True on success, false on early exit, otherwise WP_Error.
public function delete_temp_backup( array $temp_backups = array() ) {
$errors = new WP_Error();
if ( empty( $temp_backups ) ) {
$temp_backups = $this->temp_backups;
foreach ( $temp_backups as $args ) {
if ( empty( $args['slug'] ) || empty( $args['dir'] ) ) {
if ( ! $wp_filesystem->wp_content_dir() ) {
$errors->add( 'fs_no_content_dir', $this->strings['fs_no_content_dir'] );
$temp_backup_dir = $wp_filesystem->wp_content_dir() . "upgrade-temp-backup/{$args['dir']}/{$args['slug']}";
if ( ! $wp_filesystem->delete( $temp_backup_dir, true ) ) {
'temp_backup_delete_failed',
sprintf( $this->strings['temp_backup_delete_failed'], $args['slug'] )
return $errors->has_errors() ? $errors : true;
/** Plugin_Upgrader class */
require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
/** Theme_Upgrader class */
require_once ABSPATH . 'wp-admin/includes/class-theme-upgrader.php';
/** Language_Pack_Upgrader class */
require_once ABSPATH . 'wp-admin/includes/class-language-pack-upgrader.php';
/** Core_Upgrader class */
require_once ABSPATH . 'wp-admin/includes/class-core-upgrader.php';
/** File_Upload_Upgrader class */
require_once ABSPATH . 'wp-admin/includes/class-file-upload-upgrader.php';
/** WP_Automatic_Updater class */
require_once ABSPATH . 'wp-admin/includes/class-wp-automatic-updater.php';