I'm making a wordpress plugin. What are typical things I should include in the uninstall feature?

For example, should I delete any tables I created in the install function?

Do I clean up my option entries?

Anything else?

link|improve this question

78% accept rate
feedback

2 Answers

up vote 15 down vote accepted

There are three different functions for stuff like:

  • Uninstall
  • Deactivation
  • Activation

How-to trigger functions savely during the szenrios

The following shows the right to savely hook functions that get triggered during the mentioned actions.

Note: You can simply take the three register_*_hook()* functions and the class and drop into your plugin.

// If you got your de-/activation/uninstall class in another file, uncomment the following line:
include_once plugin_dir_path( __FILE__ ).'filename.php';

// register a function - or better a class function - to run on activation/deactivation
// You can use __FILE__ even when your class is not in the file, that contains the plugin comment
// Add this to your main/init file (that has the plugin header comment)
register_activation_hook( __FILE__, array( 'YourPluginNameInit', 'on_activate' ) );
register_deactivation_hook( __FILE__, array( 'YourPluginNameInit', 'on_deactivate' ) );
register_uninstall_hook( __FILE__, array( 'YourPluginNameInit', 'on_uninstall' ) );

The De-/Activation/Uninstall Class - It's plug & play!

The following example shows a basic class that only needs to get functions added, which are needed to run during the szenarios.

// Class example (inside ex. filename.php):
if ( ! class_exists('YourPluginNameInit' ) ) :
/**
 * This class triggers functions that run during activation/deactivation & uninstallation
 * NOTE: All comments are just my *suggestions*.
 */
class YourPluginNameInit
{
    // Set this to true to get the state of origin, so you don't need to always uninstall during development.
    const STATE_OF_ORIGIN = false;


    function __construct( $case = false )
    {
        if ( ! $case )
            wp_die( 'Busted! You should not call this class directly', 'Doing it wrong!' );

        switch( $case )
        {
            case 'activate' :
                // add_action calls and else
                # @example:
                add_action( 'init', array( &$this, 'activate_cb' ) );
                break;

            case 'deactivate' : 
                // reset the options
                # @example:
                add_action( 'init', array( &$this, 'deactivate_cb' ) );
                break;

            case 'uninstall' : 
                // delete the tables
                # @example:
                add_action( 'init', array( &$this, 'uninstall_cb' ) );
                break;
        }
    }

    /**
     * Set up tables, add options, etc. - All preparation that only needs to be done once
     */
    function on_activate()
    {
        new YourPluginNameInit( 'activate' );
    }

    /**
     * Do nothing like removing settings, etc. 
     * The user could reactivate the plugin and wants everything in the state before activation.
     * Take a constant to remove everything, so you can develop & test easier.
     */
    function on_deactivate()
    {
        $case = 'deactivate';
        if ( STATE_OF_ORIGIN )
            $case = 'uninstall';

        new YourPluginNameInit( $case );
    }

    /**
     * Remove/Delete everything - If the user wants to uninstall, then he wants the state of origin.
     * 
     * Will be called when the user clicks on the uninstall link that calls for the plugin to uninstall itself
     */
    function on_uninstall()
    {
        // important: check if the file is the one that was registered with the uninstall hook (function)
        if ( __FILE__ != WP_UNINSTALL_PLUGIN )
            return;

        new YourPluginNameInit( 'uninstall' );
    }

    function activate_cb()
    {
        // Stuff like adding default option values to the DB
        wp_die( '<h1>This is run on <code>init</code> during activation.</h1>', 'Activation hook example' );
    }

    function deactivate_cb()
    {
        // if you need to output messages in the 'admin_notices' field, do it like this:
        $this->error( "Some message.<br />" );
        // if you need to output messages in the 'admin_notices' field AND stop further processing, do it like this:
        $this->error( "Some message.<br />", TRUE );
        // Stuff like remove_option(); etc.
        wp_die( '<h1>This is run on <code>init</code> during deactivation.</h1>', 'Deactivation hook example' );
    }

    function uninstall_cb()
    {
        // Stuff like delete tables, etc.
        wp_die( '<h1>This is run on <code>init</code> during uninstallation</h1>', 'Uninstallation hook example' );
    }
    /**
     * trigger_error()
     * 
     * @param (string) $error_msg
     * @param (boolean) $fatal_error | catched a fatal error - when we exit, then we can't go further than this point
     * @param unknown_type $error_type
     * @return void
     */
    function error( $error_msg, $fatal_error = false, $error_type = E_USER_ERROR )
    {
        if( isset( $_GET['action'] ) && 'error_scrape' == $_GET['action'] ) 
        {
            echo "{$error_msg}\n";
            if ( $fatal_error )
                exit;
        }
        else 
        {
            trigger_error( $error_msg, $error_type );
        }
    }
}
endif;

Those functions are only run during the three mentioned szenrios. Afaik there's also something for update. I'm sure you can easily extend the shown class to run during update too.

Update

Sadly so far there's no possibility to run something on plugin/theme install or update/upgrade. Gladly there's a work-around: Hook a custom function to a custom option (yea, it's lame - but it works).

function prefix_upgrade_plugin() 
{
    $v = 'plugin_db_version';
    $update_option = null;
    // Upgrade to version 2
    if ( 2 !== get_option( $v ) ) 
    {
        if ( 2 < get_option( $v ) )
        {
            // Callback function must return true on success
            $update_option = custom_upgrade_cb_fn_v3();

            // Only update option if it was an success
            if ( $update_option )
                update_option( $v, 2 );
        }
    }

    // Upgrade to version 3, runs just after upgrade to version 2
    if ( 3 !== get_option( $v ) ) 
    {
        // re-run from beginning if previous update failed
        if ( 2 < get_option( $v ) )
            return prefix_upgrade_plugin();

        if ( 3 < get_option( $v ) )
        {
            // Callback function must return true on success
            $update_option = custom_upgrade_cb_fn_v3();

            // Only update option if it was an success
            if ( $update_option )
                update_option( $v, 3 );
        }
    }

    // Return the result from the update cb fn, so we can test for success/fail/error
    if ( $update_option )
        return $update_option;

return false;
}
add_action('admin_init', 'prefix_upgrade_plugin' );

Source

link|improve this answer
This is great BUT what I really want to know are things that I should include in my deactivation method...for example, should I delete my tables in the database or leave them in case the user changes their mind and re-activates the plugin? – redconservatory Aug 15 '11 at 21:25
Ad "BUT": I mentioned that there are 3 methods. One for activation, one for temporary deactivation and one for unstall. Imho "uninstall" says "Remove me and everything I did", while "deactivate" is a temporary state and might be redone. But: See update. I added comments about your Q + extended it with some development recommendations. – kaiser Aug 15 '11 at 21:55
2  
Ah I understand now. Just a question, when does uninstalled get called? When the files are deleted?? – redconservatory Aug 16 '11 at 22:40
Hm. Good Q. plugin.php is the file that holds register_uninstall_hook & gets loaded with the early files in wp-settings.php (which is the main file to always look at). I update the Q with the docblocks from core. – kaiser Aug 17 '11 at 8:14
I also added the check for the WP_UNINSTALL_PLUGIN constant, which is basically the file name, so you can hold your uninstall functions in a separate file and avoid the execution of other functions that sit in your plugins files. – kaiser Aug 17 '11 at 8:20
show 6 more comments
feedback

I wasted so much time trying to get it working. The problem is that init hook not working inside of registering hooks. I suppose that not one hook (action or filter) will not work so early.

Read the notes by link below. http://codex.wordpress.org/Function_Reference/register_activation_hook

It says: "Registering the hook inside your plugins_loaded hook is too late and it won't run! (Even when it seems to work for register_deactivation_hook until the wp_loaded hook.)"

link|improve this answer
I'm the one who updated the codex to what you mentioned, so this is considered in the above ↑ answer. :) – kaiser Feb 28 at 0:00
feedback

Your Answer

 
or
required, but never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.