大家好,欢迎来到今天的“WordPress定时炸弹揭秘”讲座!今天咱们要聊聊WordPress的wp_schedule_event()
函数,看看它背地里是怎么搞事情,把定时任务偷偷藏到数据库里的。
准备好了吗?咱们开始拆解这个“定时炸弹”!
一、定时任务,你瞅啥?瞅你咋滴!
首先,我们得搞清楚,什么是定时任务? 简单来说,就是让WordPress在未来的某个时间点自动执行一些代码。比如:
- 定时发布文章: 设定好时间,WordPress自动帮你把文章发出去了。
- 清理数据库: 定期清理那些过期的临时数据,让数据库保持苗条身材。
- 发送邮件: 每天定时发送邮件通知用户。
这些任务都需要一个机制来告诉WordPress:“嘿,老兄,到点儿了,该干活儿了!” wp_schedule_event()
就是负责安排这些活儿的“包工头”。
二、wp_schedule_event()
:包工头登场
wp_schedule_event()
函数的原型是这样的:
/**
* Schedules a hook to run at a specific time.
*
* @since 2.1.0
*
* @param int $timestamp A Unix timestamp that indicates when the event should run.
* @param string $hook The name of the action hook to execute.
* @param array $args Optional. An array of arguments to pass to the hook's callback function.
* Default empty array.
*
* @return bool True if the event was successfully scheduled, false otherwise.
*/
function wp_schedule_event( $timestamp, $hook, $args = array() ) {
global $wp_filter;
$timestamp = (int) $timestamp;
/**
* Fires just before a scheduled event is about to be scheduled.
*
* @since 2.1.0
*
* @param int $timestamp A Unix timestamp that indicates when the event should run.
* @param string $hook The name of the action hook to execute.
* @param array $args An array of arguments to pass to the hook's callback function.
*/
do_action( 'schedule_event', $timestamp, $hook, $args );
// Don't schedule events that occur in the past.
if ( $timestamp < time() ) {
return false;
}
$crons = _get_cron_array();
$key = md5( $hook . serialize( $args ) );
if ( isset( $crons[$timestamp][$key] ) ) {
return false;
}
$crons[$timestamp][$key] = array(
'hook' => $hook,
'args' => $args,
'schedule' => false, // 表示这是一个一次性事件,没有重复周期
);
uasort( $crons, 'sort_timestamp' );
_set_cron_array( $crons );
/**
* Fires after a scheduled event is scheduled.
*
* @since 2.1.0
*
* @param int $timestamp A Unix timestamp that indicates when the event should run.
* @param string $hook The name of the action hook to execute.
* @param array $args An array of arguments to pass to the hook's callback function.
*/
do_action( 'scheduled_event', $timestamp, $hook, $args );
return true;
}
这个函数接收三个参数:
$timestamp
: Unix时间戳,告诉WordPress什么时候执行这个任务。比如time() + 3600
表示一个小时后。$hook
: 动作钩子(action hook)的名字。 当时间到了,WordPress会触发这个钩子,执行挂载到这个钩子上的函数。$args
: 传递给钩子函数的参数。 可以是一个数组,包含你需要传递给钩子函数的任何数据。
三、wp_options
表:幕后大Boss
wp_schedule_event()
并没有直接往数据库里写数据。它只是把定时任务的信息添加到一个叫做$crons
的数组里。 真正把这些信息存到数据库里的是 _set_cron_array()
函数。而_set_cron_array()
函数最终会更新 wp_options
表里的 cron
选项。
wp_options
表是WordPress用来存储各种配置信息的。 cron
选项就是用来存储定时任务的“秘密基地”。
四、_get_cron_array()
: 获取定时任务
在将新的定时任务写入数据库之前,我们需要先从数据库中读取现有的定时任务。这个工作由_get_cron_array()
函数完成。
/**
* Retrieve cron info array.
*
* @since 2.1.0
*
* @return array Cron array.
*/
function _get_cron_array() {
global $wpdb;
$key = 'cron';
$cron = wp_cache_get( $key, 'options' );
if ( false === $cron ) {
$cron = get_option( $key );
if ( empty( $cron ) ) {
$cron = array();
}
wp_cache_add( $key, $cron, 'options' );
}
return $cron;
}
这个函数首先尝试从WordPress的对象缓存中获取cron
选项。如果缓存中没有,它会从wp_options
表中读取。如果wp_options
表中也没有cron
选项,它会返回一个空数组。
五、_set_cron_array()
: 保存定时任务
现在,我们来看_set_cron_array()
函数,它负责将定时任务保存到数据库。
/**
* Update cron info array.
*
* @since 2.1.0
*
* @param array $cron Cron array.
*/
function _set_cron_array( $cron ) {
wp_cache_set( 'cron', $cron, 'options' );
update_option( 'cron', $cron );
}
这个函数首先将cron
数组保存到WordPress的对象缓存中,然后使用update_option()
函数将cron
数组更新到wp_options
表中。
六、cron
选项的数据结构:定时任务的藏宝图
cron
选项存储的是一个序列化的数组。 这个数组的结构有点复杂,咱们来解剖一下:
array(
[timestamp1] => array( // Unix时间戳,表示任务的执行时间
[md5_hash1] => array( // 通过hook和args计算出的MD5哈希值,作为任务的唯一标识
'hook' => 'my_custom_hook', // 动作钩子的名字
'args' => array( 'arg1' => 'value1', 'arg2' => 'value2' ), // 传递给钩子函数的参数
'schedule' => false, // 定时任务的类型 (false表示一次性任务)
),
[md5_hash2] => array(
'hook' => 'another_hook',
'args' => array(),
'schedule' => false,
),
),
[timestamp2] => array(
[md5_hash3] => array(
'hook' => 'yet_another_hook',
'args' => array( 'id' => 123 ),
'schedule' => false,
),
),
);
- 最外层数组的键: 是Unix时间戳,表示任务应该执行的时间。
- 第二层数组的键: 是一个MD5哈希值,这个哈希值是通过
hook
和args
计算出来的。 用来保证任务的唯一性。 如果hook
和args
相同,那么这个任务就会被认为是重复的,不会被添加。 - 第二层数组的值: 是一个包含
hook
、args
和schedule
的关联数组。
字段 | 含义 |
---|---|
hook |
动作钩子的名称,WordPress会在指定时间触发这个钩子。 |
args |
传递给钩子函数的参数数组。 |
schedule |
定时任务的类型。 false 表示一次性任务。 如果是重复任务,会是 ‘hourly’、’daily’、’weekly’ 等。 |
七、wp-cron.php
:定时炸弹的引爆器
WordPress并不是真的“定时”执行任务。 它实际上是通过一个叫做wp-cron.php
的文件来模拟定时任务的。
每次有人访问WordPress站点时,WordPress会检查是否需要执行任何定时任务。 如果需要,它就会调用wp-cron.php
来执行这些任务。
wp-cron.php
文件会:
- 加载WordPress核心文件: 这样才能访问数据库和各种函数。
- 获取
cron
选项: 从wp_options
表里读取定时任务的信息。 - 检查是否有到期的任务: 遍历
cron
数组,找出时间戳小于当前时间的任务。 - 执行到期的任务: 循环遍历到期的任务,并使用
do_action()
函数触发相应的动作钩子。 - 清理已执行的任务: 从
cron
数组中删除已经执行过的任务(对于一次性任务)。 - 更新
cron
选项: 把更新后的cron
数组存回wp_options
表。
八、代码示例:安排一场约会
咱们来写一段代码,演示如何使用wp_schedule_event()
来安排一个定时任务。
<?php
/**
* 安排一个定时任务,在10分钟后执行 my_custom_function 函数.
*/
function schedule_my_event() {
// 计算10分钟后的时间戳
$timestamp = time() + (10 * 60);
// 如果事件没有被安排过,则安排事件
if ( ! wp_next_scheduled( 'my_custom_hook' ) ) {
wp_schedule_event( $timestamp, 'my_custom_hook', array( 'user_id' => 123 ) );
}
}
add_action( 'init', 'schedule_my_event' );
/**
* 定时任务要执行的函数.
*
* @param array $args 传递过来的参数.
*/
function my_custom_function( $args ) {
// 在这里编写你要执行的代码
// 比如,发送一封邮件,或者更新数据库
$user_id = $args['user_id'];
wp_mail( '[email protected]', '定时任务执行了!', 'User ID: ' . $user_id );
error_log('定时任务执行了!User ID: ' . $user_id); //写入错误日志,方便调试
}
add_action( 'my_custom_hook', 'my_custom_function' );
这段代码做了以下几件事:
schedule_my_event()
函数:- 计算10分钟后的时间戳。
- 使用
wp_schedule_event()
函数安排一个定时任务,在10分钟后执行my_custom_hook
钩子。 - 传递一个包含
user_id
的数组作为参数。 - 使用
wp_next_scheduled()
函数检查是否已经安排了名为my_custom_hook
的事件。 如果没有安排过,才安排事件,避免重复安排。
my_custom_function()
函数:- 是定时任务要执行的函数。
- 接收传递过来的参数
$args
。 - 发送一封邮件,并在错误日志中写入一条消息,表示任务已经执行。
九、手动触发定时任务
有时候,你可能需要手动触发定时任务,而不需要等待WordPress自动执行。 这可以通过访问wp-cron.php
文件来实现。
在浏览器中输入你的WordPress站点的URL,后面加上/wp-cron.php
。例如:
http://your-website.com/wp-cron.php
访问这个URL会强制WordPress执行所有到期的定时任务。
十、一些注意事项
- 不要过度使用定时任务: 过多的定时任务会影响网站的性能,尤其是如果你的服务器配置不高。
- 选择合适的定时任务类型: 如果你的任务只需要执行一次,就使用一次性任务。 如果需要定期执行,就选择合适的重复周期(hourly, daily, weekly等)。
- 注意时区问题: 确保你的服务器时区和WordPress时区设置正确,否则定时任务可能会在错误的时间执行。
- 使用
wp_clear_scheduled_hook()
函数取消定时任务: 如果你不再需要某个定时任务,可以使用wp_clear_scheduled_hook()
函数来取消它。
十一、取消定时任务
如果你想取消一个已经安排的定时任务,可以使用 wp_clear_scheduled_hook()
函数。
/**
* Unschedules a hook that is scheduled to run at a specific time.
*
* @since 2.1.0
*
* @param string $hook The name of the action hook to unschedule.
* @param array $args Optional. An array of arguments to pass to the hook's callback function.
* Default empty array.
*
* @return bool True when the event is unscheduled, false otherwise.
*/
function wp_clear_scheduled_hook( $hook, $args = array() ) {
$crons = _get_cron_array();
$key = md5( $hook . serialize( $args ) );
foreach ( $crons as $timestamp => $cron ) {
if ( isset( $cron[$key] ) ) {
unset( $crons[$timestamp][$key] );
if ( empty( $crons[$timestamp] ) ) {
unset( $crons[$timestamp] );
}
_set_cron_array( $crons );
return true;
}
}
return false;
}
这个函数接收两个参数:
$hook
: 要取消的钩子的名称。$args
: 传递给钩子函数的参数数组。 必须和安排定时任务时使用的参数完全一致,才能正确取消。
例如,要取消我们之前安排的 my_custom_hook
定时任务,可以这样写:
wp_clear_scheduled_hook( 'my_custom_hook', array( 'user_id' => 123 ) );
十二、重复性定时任务
除了wp_schedule_event()
之外,WordPress还提供了wp_schedule_event()
的进化版:wp_schedule_recurring_event()
,用于创建重复性的定时任务。
/**
* Schedules a hook to run repeatedly.
*
* @since 2.1.0
*
* @param int $timestamp A Unix timestamp that indicates when the first event should run.
* @param string $recurrence How often the event should subsequently recur. See {@link wp_get_schedules()}.
* @param string $hook The name of the action hook to execute.
* @param array $args Optional. An array of arguments to pass to the hook's callback function.
* Default empty array.
*
* @return bool True if the event was successfully scheduled, false otherwise.
*/
function wp_schedule_recurring_event( $timestamp, $recurrence, $hook, $args = array() ) {
global $wp_filter;
$timestamp = (int) $timestamp;
/**
* Fires just before a recurring event is about to be scheduled.
*
* @since 2.1.0
*
* @param int $timestamp A Unix timestamp that indicates when the first event should run.
* @param string $recurrence How often the event should subsequently recur. See {@link wp_get_schedules()}.
* @param string $hook The name of the action hook to execute.
* @param array $args An array of arguments to pass to the hook's callback function.
*/
do_action( 'schedule_event', $timestamp, $recurrence, $hook, $args );
// Don't schedule events that occur in the past.
if ( $timestamp < time() ) {
return false;
}
$crons = _get_cron_array();
$key = md5( $hook . serialize( $args ) );
if ( isset( $crons[$timestamp][$key] ) ) {
return false;
}
$crons[$timestamp][$key] = array(
'hook' => $hook,
'args' => $args,
'schedule' => $recurrence, // 关键区别:这里存储了重复周期
);
uasort( $crons, 'sort_timestamp' );
_set_cron_array( $crons );
/**
* Fires after a recurring event is scheduled.
*
* @since 2.1.0
*
* @param int $timestamp A Unix timestamp that indicates when the first event should run.
* @param string $recurrence How often the event should subsequently recur. See {@link wp_get_schedules()}.
* @param string $hook The name of the action hook to execute.
* @param array $args An array of arguments to pass to the hook's callback function.
*/
do_action( 'scheduled_event', $timestamp, $recurrence, $hook, $args );
return true;
}
这个函数与wp_schedule_event()
类似,但增加了一个$recurrence
参数,用于指定重复周期。 WordPress预定义了一些重复周期,你可以使用wp_get_schedules()
函数获取这些周期。
/**
* Retrieve supported recurrence schedules.
*
* @since 2.1.0
*
* @return array Named array of schedule names suitable for display.
*/
function wp_get_schedules() {
$schedules = array(
'hourly' => array(
'interval' => HOUR_IN_SECONDS,
'display' => __( 'Once Hourly' ),
),
'twicedaily' => array(
'interval' => 12 * HOUR_IN_SECONDS,
'display' => __( 'Twice Daily' ),
),
'daily' => array(
'interval' => DAY_IN_SECONDS,
'display' => __( 'Once Daily' ),
),
'weekly' => array(
'interval' => WEEK_IN_SECONDS,
'display' => __( 'Once Weekly' ),
),
);
/**
* Filters the cron schedules available in WordPress.
*
* @since 2.1.0
*
* @param array $schedules An associative array of schedules keyed by schedule name.
*/
return apply_filters( 'cron_schedules', $schedules );
}
wp_get_schedules()
函数返回一个包含预定义重复周期的数组,例如hourly
、daily
、weekly
等。你也可以通过cron_schedules
过滤器添加自定义的重复周期。
十三、代码示例:安排一个每日任务
<?php
/**
* 安排一个每日定时任务,在每天的上午8点执行 my_daily_function 函数.
*/
function schedule_my_daily_event() {
// 计算今天上午8点的时间戳
$timestamp = strtotime( 'today 8:00' );
// 如果今天上午8点已经过去了,则安排明天的上午8点
if ( $timestamp < time() ) {
$timestamp = strtotime( 'tomorrow 8:00' );
}
// 如果事件没有被安排过,则安排事件
if ( ! wp_next_scheduled( 'my_daily_hook' ) ) {
wp_schedule_recurring_event( $timestamp, 'daily', 'my_daily_hook', array( 'site_url' => get_site_url() ) );
}
}
add_action( 'init', 'schedule_my_daily_event' );
/**
* 每日定时任务要执行的函数.
*
* @param array $args 传递过来的参数.
*/
function my_daily_function( $args ) {
// 在这里编写你要执行的代码
// 比如,备份数据库,或者发送每日报告
$site_url = $args['site_url'];
wp_mail( '[email protected]', '每日定时任务执行了!', 'Site URL: ' . $site_url );
error_log('每日定时任务执行了!Site URL: ' . $site_url); //写入错误日志,方便调试
}
add_action( 'my_daily_hook', 'my_daily_function' );
这段代码与之前的示例类似,但使用了wp_schedule_recurring_event()
函数来安排一个每日定时任务。 任务会在每天的上午8点执行my_daily_hook
钩子。
十四、总结
好了,今天的“WordPress定时炸弹揭秘”讲座就到这里了。 希望通过今天的讲解,你已经对wp_schedule_event()
函数的工作原理有了更深入的了解。
记住,定时任务是一把双刃剑。 合理使用可以提高网站的自动化程度,但过度使用会影响网站的性能。 所以,一定要谨慎使用,并定期检查和清理你的定时任务。
如果还有什么疑问,欢迎随时提问。 感谢大家的参与!