Plugin Removal
If your plugin writes any data anywhere: to options, the database, files, etc., then when completely removing the plugin, it makes sense to also delete all data that relates only to it, so that it does not remain as dead weight.
The process of removing a plugin is initiated when a user deactivates the plugin and then clicks the "Delete" link in the admin panel on the plugins page.
Inexperienced developers sometimes make the mistake of using the plugin deactivation hook to remove its data from everywhere. This is incorrect - only temporary data should be deleted (cleared) upon deactivation, while all data should be deleted only upon removal of the plugin.
It looks something like this:
Scenario | deactivation | deletion |
---|---|---|
Removing options from the wp_options table | no | yes |
Clearing cache | yes | no |
In addition, note that when a plugin is deleted, the deactivation hook has already been triggered... That is, an active plugin is always deactivated first and only then deleted - it is impossible to delete a plugin while it is active...
How does deletion occur?
Before deleting a plugin (the "delete" link on the plugins page), WordPress performs certain actions that allow you to remove all traces of the plugin's presence on the site. The advantage of using this approach is that you do not need to worry about warning users about the removal of traces of the plugin before actually deleting the plugin itself. This is a kind of plugin removal API - WordPress does part of the work for you...
Two ways to uninstall plugins
WordPress developers have provided two options for completely removing a plugin:
-
Create a file uninstall.php in the root directory of the plugin.
- Use the function register_uninstall_hook() - it triggers during the deletion of the plugin.
#1 File uninstall.php
If during the deletion of the plugin WordPress finds the file uninstall.php
in its folder, the code of this file will be executed. Important: in this case, the deactivation hook will no longer work!
An important point is the mandatory use of the constant WP_UNINSTALL_PLUGIN
check in this file. This is necessary for security, to prevent direct access to this file.
The plugin files will be deleted after the code of the file uninstall.php
is executed.
This file should contain the code that deletes everything related to the plugin: options, database tables, custom fields, etc.
This process is irreversible!
Always check for the presence of the constant WP_UNINSTALL_PLUGIN
in the file uninstall.php
before performing any actions. This protects against direct access to the file.
The constant WP_UNINSTALL_PLUGIN
is defined by WordPress at the moment the file uninstall.php
is called (when the plugin is deleted) and will not be defined if the file uninstall.php
is accessed directly.
Also, the constant WP_UNINSTALL_PLUGIN
will only be defined after the file uninstall.php has been found in the plugin folder. It will not be set when using the plugin removal technique via hook.
IMPORTANT! At the moment the file uninstall.php
is triggered, no code from the plugin is executed! None of its files (except uninstall.php) are included! Therefore, any file inclusions, classes, constant definitions need to be done separately.
Example of file uninstall.php
<?php /** * IMPORTANT! No plugin files are included here! * * Only basic WordPress functions are available here. * * If any plugin functions or classes are needed for deletion, * include files and initialize the necessary classes here. */ defined( 'WP_UNINSTALL_PLUGIN' ) || exit; // Deleting options and everything else. delete_option( 'my_option' );
Example of file uninstall.php for Multisite
uninstall.php is not executed separately for each site in the network. Therefore, the deletion logic for multisite needs to be written separately:
/** * IMPORTANT! No plugin files are included here! * * Only basic WordPress functions are available here. * * If any plugin functions or classes are needed for deletion, * include files and initialize the necessary classes here. */ defined( 'WP_UNINSTALL_PLUGIN' ) || exit; if( is_multisite() ){ $blog_ids = get_sites( [ 'fields' => 'ids' ] ); foreach( $blog_ids as $blog_id ){ switch_to_blog( $blog_id ); my_plugin_uninstall(); restore_current_blog(); } } else { my_plugin_uninstall(); } function my_plugin_uninstall(){ delete_option( 'my_plugin_option' ); // deleting other data... }
Debugging during plugin deletion
To check how deletion works, but without actually deleting the plugin files, simply add die()
at the end of the file uninstall.php. You can also output any data, for example, using print_r() or in some other way.
To see the debugging result when the plugin deletion is triggered via AJAX, open the developer panel in Chrome (the "Network" tab). There, during the AJAX call, you can see the result of the request.
#2 Function register_uninstall_hook()
The method of creating the file uninstall.php is more preferable compared to this method.
The function register_uninstall_hook() works differently than the activation and deactivation functions of the plugin: register_activation_hook() and register_deactivation_hook().
When a plugin is deleted and there is no uninstall.php file in its directory, but the main plugin file contains the removal function register_uninstall_hook(), this function will be called for the plugin removal.
When using register_uninstall_hook(), all actions and codes of the plugin must be inside functions and connected via hooks, i.e., no actions of the plugin should be openly present in the plugin files, because otherwise, during the deletion process, they will also be triggered and may interfere with the deletion process.
It is not recommended to use this method as it requires a good understanding of how and what works in this case. And even then, a mistake can still be made. But if this is the only removal option suitable for your plugin, then follow these rules:
- Do not run (initialize) the plugin code directly in the file - do this via the plugins_loaded hook or later.
- It is better to use the removal file unistall.php.
Example of plugin uninstallation code via hook:
register_uninstall_hook( __FILE__, 'my_uninstall_hook' ); function my_uninstall_hook(){ delete_option('my_option'); }
This code should be in the main plugin file. If register_uninstall_hook() needs to be placed in another file, then in the first parameter (instead of __FILE__), you need to specify the path to the main plugin file.