Title: WP_Upgrader::run
Published: April 25, 2014
Last modified: February 24, 2026

---

# WP_Upgrader::run( array $options ): array|false|󠀁[WP_Error](https://developer.wordpress.org/reference/classes/wp_error/)󠁿

## In this article

 * [Description](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#description)
 * [Parameters](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#parameters)
 * [Return](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#return)
 * [Source](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#source)
 * [Hooks](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#hooks)
 * [Related](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#related)
 * [Changelog](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#changelog)

[ Back to top](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#wp--skip-link--target)

Runs an upgrade/installation.

## 󠀁[Description](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#description)󠁿

Attempts to download the package (if it is not a local file), unpack it, and install
it in the destination folder.

## 󠀁[Parameters](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#parameters)󠁿

 `$options`arrayrequired

Array or string of arguments for upgrading/installing a package.

 * `package` string
 * The full path or URI of the package to install.
    Default empty.
 * `destination` string
 * The full path to the destination folder.
    Default empty.
 * `clear_destination` bool
 * Whether to delete any files already in the destination folder. Default false.
 * `clear_working` bool
 * Whether to delete the files from the working directory after copying them to 
   the destination.
    Default true.
 * `abort_if_destination_exists` bool
 * Whether to abort the installation if the destination folder already exists. When
   true, `$clear_destination` should be false. Default true.
 * `is_multi` bool
 * Whether this run is one of multiple upgrade/installation actions being performed
   in bulk. When true, the skin WP_Upgrader::header() and WP_Upgrader::footer() 
   aren’t called. Default false.
 * `hook_extra` array
 * Extra arguments to pass to the filter hooks called by [WP_Upgrader::run()](https://developer.wordpress.org/reference/classes/wp_upgrader/run/).

## 󠀁[Return](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#return)󠁿

 array|false|[WP_Error](https://developer.wordpress.org/reference/classes/wp_error/)
The result from self::install_package() on success, otherwise a [WP_Error](https://developer.wordpress.org/reference/classes/wp_error/),
or false if unable to connect to the filesystem.

## 󠀁[Source](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#source)󠁿

    ```php
    public function run( $options ) {

    	$defaults = array(
    		'package'                     => '', // Please always pass this.
    		'destination'                 => '', // ...and this.
    		'clear_destination'           => false,
    		'clear_working'               => true,
    		'abort_if_destination_exists' => true, // Abort if the destination directory exists. Pass clear_destination as false please.
    		'is_multi'                    => false,
    		'hook_extra'                  => array(), // Pass any extra $hook_extra args here, this will be passed to any hooked filters.
    	);

    	$options = wp_parse_args( $options, $defaults );

    	/**
    	 * Filters the package options before running an update.
    	 *
    	 * See also 'upgrader_process_complete'.
    	 *
    	 * @since 4.3.0
    	 *
    	 * @param array $options {
    	 *     Options used by the upgrader.
    	 *
    	 *     @type string $package                     Package for update.
    	 *     @type string $destination                 Update location.
    	 *     @type bool   $clear_destination           Clear the destination resource.
    	 *     @type bool   $clear_working               Clear the working resource.
    	 *     @type bool   $abort_if_destination_exists Abort if the Destination directory exists.
    	 *     @type bool   $is_multi                    Whether the upgrader is running multiple times.
    	 *     @type array  $hook_extra {
    	 *         Extra hook arguments.
    	 *
    	 *         @type string $action               Type of action. Default 'update'.
    	 *         @type string $type                 Type of update process. Accepts 'plugin', 'theme', or 'core'.
    	 *         @type bool   $bulk                 Whether the update process is a bulk update. Default true.
    	 *         @type string $plugin               Path to the plugin file relative to the plugins directory.
    	 *         @type string $theme                The stylesheet or template name of the theme.
    	 *         @type string $language_update_type The language pack update type. Accepts 'plugin', 'theme',
    	 *                                            or 'core'.
    	 *         @type object $language_update      The language pack update offer.
    	 *     }
    	 * }
    	 */
    	$options = apply_filters( 'upgrader_package_options', $options );

    	if ( ! $options['is_multi'] ) { // Call $this->header separately if running multiple times.
    		$this->skin->header();
    	}

    	// Connect to the filesystem first.
    	$res = $this->fs_connect( array( WP_CONTENT_DIR, $options['destination'] ) );
    	// Mainly for non-connected filesystem.
    	if ( ! $res ) {
    		if ( ! $options['is_multi'] ) {
    			$this->skin->footer();
    		}
    		return false;
    	}

    	$this->skin->before();

    	if ( is_wp_error( $res ) ) {
    		$this->skin->error( $res );
    		$this->skin->after();
    		if ( ! $options['is_multi'] ) {
    			$this->skin->footer();
    		}
    		return $res;
    	}

    	/*
    	 * Download the package. Note: If the package is the full path
    	 * to an existing local file, it will be returned untouched.
    	 */
    	$download = $this->download_package( $options['package'], false, $options['hook_extra'] );

    	/*
    	 * Allow for signature soft-fail.
    	 * WARNING: This may be removed in the future.
    	 */
    	if ( is_wp_error( $download ) && $download->get_error_data( 'softfail-filename' ) ) {

    		// Don't output the 'no signature could be found' failure message for now.
    		if ( 'signature_verification_no_signature' !== $download->get_error_code() || WP_DEBUG ) {
    			// Output the failure error as a normal feedback, and not as an error.
    			$this->skin->feedback( $download->get_error_message() );

    			// Report this failure back to WordPress.org for debugging purposes.
    			wp_version_check(
    				array(
    					'signature_failure_code' => $download->get_error_code(),
    					'signature_failure_data' => $download->get_error_data(),
    				)
    			);
    		}

    		// Pretend this error didn't happen.
    		$download = $download->get_error_data( 'softfail-filename' );
    	}

    	if ( is_wp_error( $download ) ) {
    		$this->skin->error( $download );
    		$this->skin->after();
    		if ( ! $options['is_multi'] ) {
    			$this->skin->footer();
    		}
    		return $download;
    	}

    	$delete_package = ( $download !== $options['package'] ); // Do not delete a "local" file.

    	// Unzips the file into a temporary directory.
    	$working_dir = $this->unpack_package( $download, $delete_package );
    	if ( is_wp_error( $working_dir ) ) {
    		$this->skin->error( $working_dir );
    		$this->skin->after();
    		if ( ! $options['is_multi'] ) {
    			$this->skin->footer();
    		}
    		return $working_dir;
    	}

    	// With the given options, this installs it to the destination directory.
    	$result = $this->install_package(
    		array(
    			'source'                      => $working_dir,
    			'destination'                 => $options['destination'],
    			'clear_destination'           => $options['clear_destination'],
    			'abort_if_destination_exists' => $options['abort_if_destination_exists'],
    			'clear_working'               => $options['clear_working'],
    			'hook_extra'                  => $options['hook_extra'],
    		)
    	);

    	/**
    	 * Filters the result of WP_Upgrader::install_package().
    	 *
    	 * @since 5.7.0
    	 *
    	 * @param array|WP_Error $result     Result from WP_Upgrader::install_package().
    	 * @param array          $hook_extra Extra arguments passed to hooked filters.
    	 */
    	$result = apply_filters( 'upgrader_install_package_result', $result, $options['hook_extra'] );

    	$this->skin->set_result( $result );

    	if ( is_wp_error( $result ) ) {
    		// An automatic plugin update will have already performed its rollback.
    		if ( ! empty( $options['hook_extra']['temp_backup'] ) ) {
    			$this->temp_restores[] = $options['hook_extra']['temp_backup'];

    			/*
    			 * Restore the backup on shutdown.
    			 * Actions running on `shutdown` are immune to PHP timeouts,
    			 * so in case the failure was due to a PHP timeout,
    			 * it will still be able to properly restore the previous version.
    			 *
    			 * Zero arguments are accepted as a string can sometimes be passed
    			 * internally during actions, causing an error because
    			 * `WP_Upgrader::restore_temp_backup()` expects an array.
    			 */
    			add_action( 'shutdown', array( $this, 'restore_temp_backup' ), 10, 0 );
    		}
    		$this->skin->error( $result );

    		if ( ! method_exists( $this->skin, 'hide_process_failed' ) || ! $this->skin->hide_process_failed( $result ) ) {
    			$this->skin->feedback( 'process_failed' );
    		}
    	} else {
    		// Installation succeeded.
    		$this->skin->feedback( 'process_success' );
    	}

    	$this->skin->after();

    	// Clean up the backup kept in the temporary backup directory.
    	if ( ! empty( $options['hook_extra']['temp_backup'] ) ) {
    		// Delete the backup on `shutdown` to avoid a PHP timeout.
    		add_action( 'shutdown', array( $this, 'delete_temp_backup' ), 100, 0 );
    	}

    	if ( ! $options['is_multi'] ) {

    		/**
    		 * Fires when the upgrader process is complete.
    		 *
    		 * See also 'upgrader_package_options'.
    		 *
    		 * @since 3.6.0
    		 * @since 3.7.0 Added to WP_Upgrader::run().
    		 * @since 4.6.0 `$translations` was added as a possible argument to `$hook_extra`.
    		 *
    		 * @param WP_Upgrader $upgrader   WP_Upgrader instance. In other contexts this might be a
    		 *                                Theme_Upgrader, Plugin_Upgrader, Core_Upgrade, or Language_Pack_Upgrader instance.
    		 * @param array       $hook_extra {
    		 *     Array of bulk item update data.
    		 *
    		 *     @type string $action       Type of action. Default 'update'.
    		 *     @type string $type         Type of update process. Accepts 'plugin', 'theme', 'translation', or 'core'.
    		 *     @type bool   $bulk         Whether the update process is a bulk update. Default true.
    		 *     @type array  $plugins      Array of the basename paths of the plugins' main files.
    		 *     @type array  $themes       The theme slugs.
    		 *     @type array  $translations {
    		 *         Array of translations update data.
    		 *
    		 *         @type string $language The locale the translation is for.
    		 *         @type string $type     Type of translation. Accepts 'plugin', 'theme', or 'core'.
    		 *         @type string $slug     Text domain the translation is for. The slug of a theme/plugin or
    		 *                                'default' for core translations.
    		 *         @type string $version  The version of a theme, plugin, or core.
    		 *     }
    		 * }
    		 */
    		do_action( 'upgrader_process_complete', $this, $options['hook_extra'] );

    		$this->skin->footer();
    	}

    	return $result;
    }
    ```

[View all references](https://developer.wordpress.org/reference/files/wp-admin/includes/class-wp-upgrader.php/)
[View on Trac](https://core.trac.wordpress.org/browser/tags/6.9.4/src/wp-admin/includes/class-wp-upgrader.php#L773)
[View on GitHub](https://github.com/WordPress/wordpress-develop/blob/6.9.4/src/wp-admin/includes/class-wp-upgrader.php#L773-L993)

## 󠀁[Hooks](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#hooks)󠁿

 [apply_filters( ‘upgrader_install_package_result’, array|WP_Error $result, array $hook_extra )](https://developer.wordpress.org/reference/hooks/upgrader_install_package_result/)

Filters the result of [WP_Upgrader::install_package()](https://developer.wordpress.org/reference/classes/wp_upgrader/install_package/).

 [apply_filters( ‘upgrader_package_options’, array $options )](https://developer.wordpress.org/reference/hooks/upgrader_package_options/)

Filters the package options before running an update.

 [do_action( ‘upgrader_process_complete’, WP_Upgrader $upgrader, array $hook_extra )](https://developer.wordpress.org/reference/hooks/upgrader_process_complete/)

Fires when the upgrader process is complete.

## 󠀁[Related](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#related)󠁿

| Uses | Description | 
| [WP_Upgrader::fs_connect()](https://developer.wordpress.org/reference/classes/wp_upgrader/fs_connect/)`wp-admin/includes/class-wp-upgrader.php` |

Connects to the filesystem.

  | 
| [WP_Upgrader::download_package()](https://developer.wordpress.org/reference/classes/wp_upgrader/download_package/)`wp-admin/includes/class-wp-upgrader.php` |

Downloads a package.

  | 
| [WP_Upgrader::unpack_package()](https://developer.wordpress.org/reference/classes/wp_upgrader/unpack_package/)`wp-admin/includes/class-wp-upgrader.php` |

Unpacks a compressed package file.

  | 
| [WP_Upgrader::install_package()](https://developer.wordpress.org/reference/classes/wp_upgrader/install_package/)`wp-admin/includes/class-wp-upgrader.php` |

Install a package.

  | 
| [wp_version_check()](https://developer.wordpress.org/reference/functions/wp_version_check/)`wp-includes/update.php` |

Checks WordPress version against the newest version.

  | 
| [wp_parse_args()](https://developer.wordpress.org/reference/functions/wp_parse_args/)`wp-includes/functions.php` |

Merges user defined arguments into defaults array.

  | 
| [apply_filters()](https://developer.wordpress.org/reference/functions/apply_filters/)`wp-includes/plugin.php` |

Calls the callback functions that have been added to a filter hook.

  | 
| [add_action()](https://developer.wordpress.org/reference/functions/add_action/)`wp-includes/plugin.php` |

Adds a callback function to an action hook.

  | 
| [do_action()](https://developer.wordpress.org/reference/functions/do_action/)`wp-includes/plugin.php` |

Calls the callback functions that have been added to an action hook.

  | 
| [is_wp_error()](https://developer.wordpress.org/reference/functions/is_wp_error/)`wp-includes/load.php` |

Checks whether the given variable is a WordPress Error.

  |

[Show 5 more](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#)
[Show less](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#)

## 󠀁[Changelog](https://developer.wordpress.org/reference/classes/wp_upgrader/run/?output_format=md#changelog)󠁿

| Version | Description | 
| [2.8.0](https://developer.wordpress.org/reference/since/2.8.0/) | Introduced. |

## User Contributed Notes

You must [log in](https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Fclasses%2Fwp_upgrader%2Frun%2F)
before being able to contribute a note or feedback.