Wordpress - Wordpress Update Plugin Hook/Action? Since 3.9

I don't think an action has been added. You can look at version details for any version and see any new actions added.

The WordPress Way to run code on plugin update is what is described here:

The proper way to handle an upgrade path is to only run an upgrade procedure when you need to. Ideally, you would store a “version” in your plugin’s database option, and then a version in the code. If they do not match, you would fire your upgrade procedure, and then set the database option to equal the version in the code. This is how many plugins handle upgrades, and this is how core works as well.

and with code example here:

function myplugin_update_db_check() {
    global $jal_db_version;
    if (get_site_option( 'jal_db_version' ) != $jal_db_version) {
        jal_install();
    }
}
add_action( 'plugins_loaded', 'myplugin_update_db_check' );

Since WordPress 3.9 you can use upgrader_process_complete hook.
See reference 1, 2

Here is an example code:

<?php 
/**
 * Plugin Name: Test plugin 1
 * Plugin URI: http://rundiz.com
 * Description: A very simple plugin for testing. This plugin do nothing.
 * Version: 0.1.8
 * Author: Vee Winch
 * Author URI: http://rundiz.com
 * License: MIT
 * License URI: https://opensource.org/licenses/MIT
 * Text Domain: test-plugin1
 * Domain Path: 
 */


$wppstp1_version = '0.1.8';


add_action('upgrader_process_complete', 'wppstp1_upgrade', 10, 2);// will working only this plugin activated.
function wppstp1_upgrade(\WP_Upgrader $upgrader_object, $hook_extra)
{
    global $wppstp1_version;

    if (is_array($hook_extra) && array_key_exists('action', $hook_extra) && array_key_exists('type', $hook_extra) && array_key_exists('plugins', $hook_extra)) {
        // check first that array contain required keys to prevent undefined index error.
        if ($hook_extra['action'] == 'update' && $hook_extra['type'] == 'plugin' && is_array($hook_extra['plugins']) && !empty($hook_extra['plugins'])) {
            // if this action is update plugin.
            $this_plugin = plugin_basename(__FILE__);

            foreach ($hook_extra['plugins'] as $each_plugin) {
                if ($each_plugin == $this_plugin) {
                    // if this plugin is in the updated plugins.
                    // don't process anything from new version of code here, because it will work on old version of the plugin.
                    file_put_contents(WP_CONTENT_DIR . '/test.txt', 'v'.$wppstp1_version."\r\n", FILE_APPEND); // you will always get the previous version even you update to the new version.
                    // set transient to let it run later.
                    set_transient('wppstp1_updated', 1);
                }
            }// endforeach;
            unset($each_plugin);
        }// endif update plugin and plugins not empty.
    }// endif; $hook_extra
}// wppstp1_upgrade


add_action('plugins_loaded', 'wppstp1_runUpdatedPlugin');
function wppstp1_runUpdatedPlugin()
{
    global $wppstp1_version;

    if (get_transient('wppstp1_updated') && current_user_can('manage_options')) {
        // if plugin updated and current user is admin.
        file_put_contents(WP_CONTENT_DIR . '/test-update-by-transient.txt', 'v'.$wppstp1_version."\r\n", FILE_APPEND);// you will always get the updated version here.

        // update code here.

        // delete transient.
        delete_transient('wppstp1_updated');
    }
}// wppstp1_runUpdatedPlugin

Once plugin updated, it will set the task into db using set_transient() function. It is not recommend to add update code while calling upgrader_process_complete hook.
Next, if you browse to other admin page, the plugins_loaded hook will work and the update code will be working there.

Please note that this plugin must be activated to make update hook working.
This is not working on activate plugin so, if you want the code that works on activate the plugin you have to code it in register_activation_hook() function.


From the discussion where they decided not to add a custom hook/function specific to upgrade, it sounds like "most people" (as of 4 years ago) use register_activation_hook, since it's called when a plugin is upgraded through the admin page; most examples I've seen since then follow that trend.

For most usage I would suggest not hooking through plugins_loaded, as it would get called on every page load. The exception to this is mentioned in the discussion: upgrade paths via FTP/SVN are 'edge cases', since WP wouldn't have a mechanism to know that the plugin was changed, in which case the previous answer might be more relevant.

See https://gist.github.com/zaus/c08288c68b7f487193d1 for a 'simple framework' example using register_activation_hook.