同学们,大家好!今天咱们来聊聊WordPress里一个很重要的函数——deactivate_plugins()
,它可是插件卸载的幕后英雄。咱们不光要会用,还要把它扒个底朝天,看看它到底是怎么运作的。
一、deactivate_plugins()
:插件卸载的指挥官
首先,咱们得认识一下这个函数。deactivate_plugins()
,顾名思义,就是停用插件用的。它接受一个或多个插件的文件路径作为参数,然后执行一系列操作,最终让插件“下岗”。
/**
* Deactivates one or more plugins.
*
* @since 2.5.0
*
* @param string|string[] $plugins Single plugin or array of plugins to deactivate.
* @param bool $silent Optional. Whether to prevent calling the deactivate hooks. Default false.
*/
function deactivate_plugins( $plugins, $silent = false ) {
// 函数体
}
参数说明:
$plugins
: 需要停用的插件的文件路径。可以是单个字符串,也可以是字符串数组。比如'my-awesome-plugin/my-awesome-plugin.php'
或者array('my-awesome-plugin/my-awesome-plugin.php', 'another-plugin/another-plugin.php')
。$silent
: 一个可选参数,默认是false
。如果设置为true
,则会阻止调用插件的停用钩子(deactivate_{$plugin}
)。这个参数一般用不到,除非你真的不想让插件执行任何停用逻辑。
二、源码剖析:deactivate_plugins()
的内部运作
接下来,咱们进入正题,一步一步地拆解 deactivate_plugins()
的源码。为了方便讲解,我把源码简化了一下,去掉了错误处理和一些不太重要的部分,只保留了核心逻辑。
function deactivate_plugins( $plugins, $silent = false ) {
if ( ! is_array( $plugins ) ) {
$plugins = array( $plugins );
}
$current = get_option( 'active_plugins', array() );
foreach ( $plugins as $plugin ) {
$plugin = plugin_basename( trim( $plugin ) );
if ( ! in_array( $plugin, $current, true ) ) {
continue; // 插件没激活,跳过
}
$plugin_version = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin )['Version'];
$key = array_search( $plugin, $current, true );
if ( false !== $key ) {
unset( $current[ $key ] );
}
if ( ! $silent ) {
/**
* Fires before a plugin is deactivated.
*
* @since 2.5.0
*
* @param string $plugin Plugin to deactivate.
*/
do_action( 'deactivate_' . $plugin );
}
/**
* Fires after a plugin is deactivated.
*
* @since 5.5.0
*
* @param string $plugin Plugin to deactivate.
* @param string $version The plugin version.
*/
do_action( 'deactivated_plugin', $plugin, $plugin_version );
}
update_option( 'active_plugins', array_values( $current ) );
do_action( 'deactivated_plugins', $plugins );
}
咱们来一行一行地解读:
-
参数处理:
if ( ! is_array( $plugins ) ) { $plugins = array( $plugins ); }
这段代码首先检查
$plugins
是否是数组。如果不是,就把它转换成数组,方便后续处理。 -
获取已激活插件列表:
$current = get_option( 'active_plugins', array() );
这里使用
get_option()
函数从数据库中获取active_plugins
这个选项的值。这个选项存储了当前已激活的插件列表。如果这个选项不存在,就返回一个空数组。 -
循环处理每个插件:
foreach ( $plugins as $plugin ) { // ... }
接下来,代码循环遍历
$plugins
数组,对每个插件执行停用操作。 -
清理插件文件名:
$plugin = plugin_basename( trim( $plugin ) );
trim()
函数用于去除插件文件路径两端的空格。plugin_basename()
函数用于提取插件的文件名(basename)。 例如,如果$plugin
是'my-awesome-plugin/my-awesome-plugin.php'
,那么$plugin
会被转换成'my-awesome-plugin/my-awesome-plugin.php'
。 -
判断插件是否已激活:
if ( ! in_array( $plugin, $current, true ) ) { continue; // 插件没激活,跳过 }
这里使用
in_array()
函数检查当前插件是否在已激活的插件列表中。如果不在,说明插件没有激活,直接跳过本次循环。true
参数表示进行严格类型比较。 -
获取插件版本信息:
$plugin_version = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin )['Version'];
使用
get_plugin_data()
函数获取插件的头部信息,其中包括插件版本。 -
从激活列表中移除插件:
$key = array_search( $plugin, $current, true ); if ( false !== $key ) { unset( $current[ $key ] ); }
array_search()
函数用于在$current
数组中查找$plugin
对应的键值。如果找到了,就使用unset()
函数从$current
数组中移除该插件。 -
触发停用钩子:
if ( ! $silent ) { /** * Fires before a plugin is deactivated. * * @since 2.5.0 * * @param string $plugin Plugin to deactivate. */ do_action( 'deactivate_' . $plugin ); } /** * Fires after a plugin is deactivated. * * @since 5.5.0 * * @param string $plugin Plugin to deactivate. * @param string $version The plugin version. */ do_action( 'deactivated_plugin', $plugin, $plugin_version );
这是整个过程中最关键的部分!
do_action( 'deactivate_' . $plugin )
会触发一个动态的 action 钩子。这个钩子的名称是deactivate_
加上插件的文件名。 插件开发者可以在自己的插件中注册这个钩子的回调函数,以便在插件停用时执行一些清理工作,比如删除数据库表、清除缓存等等。do_action( 'deactivated_plugin', $plugin, $plugin_version )
则触发一个通用的 action 钩子,传递了插件文件名和版本信息。 -
更新激活插件列表:
update_option( 'active_plugins', array_values( $current ) );
循环结束后,使用
update_option()
函数将更新后的$current
数组保存到数据库中。array_values()
函数用于重新索引数组,确保键值是连续的数字。 -
触发停用插件后的钩子
do_action( 'deactivated_plugins', $plugins );
触发一个通用 action 钩子,传递所有停用插件的文件名。
三、deactivate_{$plugin}
钩子:插件的“遗言”
咱们重点说说 deactivate_{$plugin}
这个钩子。它是插件在被停用前执行的最后一段代码,也是插件开发者清理数据的最佳时机。
举个例子,假设你开发了一个名为 my-awesome-plugin
的插件,它的主文件是 my-awesome-plugin/my-awesome-plugin.php
。你可以在这个插件中注册 deactivate_my-awesome-plugin/my-awesome-plugin.php
钩子的回调函数,像这样:
<?php
/**
* Plugin Name: My Awesome Plugin
* Description: A plugin that does awesome things.
* Version: 1.0.0
*/
// 在插件激活时执行的操作
function my_awesome_plugin_activate() {
// 创建数据库表,初始化数据等等
}
register_activation_hook( __FILE__, 'my_awesome_plugin_activate' );
// 在插件停用时执行的操作
function my_awesome_plugin_deactivate() {
// 删除数据库表,清除缓存等等
global $wpdb;
$table_name = $wpdb->prefix . 'my_awesome_table';
$sql = "DROP TABLE IF EXISTS $table_name;";
$wpdb->query( $sql );
delete_option( 'my_awesome_plugin_options' );
}
register_deactivation_hook( __FILE__, 'my_awesome_plugin_deactivate' );
在这个例子中,my_awesome_plugin_deactivate()
函数会在插件被停用时执行。它会删除插件创建的数据库表,清除插件的配置选项。
注意: 使用 register_deactivation_hook
注册的函数,会在调用 deactivate_plugins()
时自动执行,无需使用 add_action
。register_deactivation_hook
内部会处理好与 deactivate_{$plugin}
钩子的关联。
四、deactivated_plugin
钩子:停用后的通知
deactivated_plugin
钩子提供了一个通用的通知机制,让你可以在插件停用后执行一些操作。这个钩子接收两个参数:插件文件名和版本号。
例如,你可以在你的主题或插件中注册 deactivated_plugin
钩子的回调函数,像这样:
function my_plugin_deactivated( $plugin, $version ) {
// 记录日志,发送邮件等等
error_log( "Plugin {$plugin} (version {$version}) has been deactivated." );
}
add_action( 'deactivated_plugin', 'my_plugin_deactivated', 10, 2 );
这个例子中,my_plugin_deactivated()
函数会在任何插件被停用时执行。它会将插件的文件名和版本号记录到错误日志中。
五、deactivated_plugins
钩子:批量停用后的总汇
deactivated_plugins
钩子在所有插件停用后触发,接收一个包含所有已停用插件文件名的数组。
function my_plugins_deactivated( $plugins ) {
// 记录日志,发送邮件等等
error_log( "Plugins " . implode(', ', $plugins) . " have been deactivated." );
}
add_action( 'deactivated_plugins', 'my_plugins_deactivated', 10, 1 );
六、实战演练:自定义插件停用逻辑
现在,咱们来做一个实战演练,演示如何在插件中自定义停用逻辑。
假设咱们要开发一个名为 my-custom-plugin
的插件,它会在数据库中创建一个名为 my_custom_table
的表。在插件停用时,咱们需要删除这个表。
首先,创建 my-custom-plugin.php
文件:
<?php
/**
* Plugin Name: My Custom Plugin
* Description: A plugin that creates a custom database table.
* Version: 1.0.0
*/
// 在插件激活时执行的操作
function my_custom_plugin_activate() {
global $wpdb;
$table_name = $wpdb->prefix . 'my_custom_table';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
time datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
name varchar(255) NOT NULL,
PRIMARY KEY (id)
) $charset_collate;";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
}
register_activation_hook( __FILE__, 'my_custom_plugin_activate' );
// 在插件停用时执行的操作
function my_custom_plugin_deactivate() {
global $wpdb;
$table_name = $wpdb->prefix . 'my_custom_table';
$sql = "DROP TABLE IF EXISTS $table_name;";
$wpdb->query( $sql );
}
register_deactivation_hook( __FILE__, 'my_custom_plugin_deactivate' );
在这个例子中,my_custom_plugin_activate()
函数会在插件激活时创建 my_custom_table
表。my_custom_plugin_deactivate()
函数会在插件停用时删除这个表。
七、deactivate_plugins()
的使用场景
deactivate_plugins()
函数主要用于以下场景:
- 插件管理页面: WordPress 后台的插件管理页面使用
deactivate_plugins()
函数来停用插件。 - 主题: 主题可以使用
deactivate_plugins()
函数来停用与主题不兼容的插件。 - 插件: 插件可以使用
deactivate_plugins()
函数来停用其他插件,例如,在升级插件时,可以先停用旧版本,再激活新版本。 - 代码中: 在一些特殊情况下,你可能需要在代码中使用
deactivate_plugins()
函数来停用插件,例如,在检测到安全漏洞时,可以自动停用存在漏洞的插件。
八、总结:deactivate_plugins()
的核心价值
总的来说,deactivate_plugins()
函数的核心价值在于:
- 提供了一种标准的插件停用机制: 它确保插件能够被安全地停用,而不会导致系统崩溃或其他问题。
- 允许插件开发者自定义停用逻辑: 通过
deactivate_{$plugin}
钩子,插件开发者可以在插件停用时执行一些清理工作,确保插件的数据被正确地删除。 - 提供了一种灵活的扩展机制: 通过
deactivated_plugin
钩子,其他插件或主题可以监听插件的停用事件,并执行相应的操作。
九、常见问题
问题 | 解决方案 |
---|---|
插件停用后无法完全删除数据? | 确保在 deactivate_{$plugin} 钩子的回调函数中编写了完整的删除逻辑。 |
插件停用后出现错误? | 检查 deactivate_{$plugin} 钩子的回调函数是否抛出了异常。 |
如何在代码中判断插件是否已激活? | 使用 is_plugin_active() 函数。 |
如何在代码中激活插件? | 使用 activate_plugin() 函数。 |
为什么停用插件后,网站仍然显示插件的功能? | 可能是因为插件使用了缓存。尝试清除缓存。也可能是主题或其它插件使用了插件的函数,停用该插件会导致代码报错。 |
好了,今天的讲座就到这里。希望大家通过今天的学习,能够对 deactivate_plugins()
函数有更深入的了解。记住,理解源码是成为 WordPress 大神的必经之路!下次咱们再聊聊 activate_plugins()
,看看插件激活又是怎么一回事。下课!