跳到主内容

WordPress 定时任务(WP-Cron)怎么用:调度注册、时区坑与系统 cron 接管

100%
WordPress 定时任务(WP-Cron)怎么用:调度注册、时区坑与系统 cron 接管

一句话结论:WP-Cron 不是系统级的真 cron,它靠”有人访问站点”触发,流量小的站点定时任务会不准时甚至不执行。生产环境的标准解法是在 wp-config.php 里加 define('DISABLE_WP_CRON', true),再用服务器 crontab 每分钟拉一次 wp-cron.php 。下面把调度、自定义间隔、时区和排错一次讲清。

一、 WP-Cron 到底怎么跑的

WP-Cron 的工作方式是:每次页面加载时,WordPress 检查 cron 数组里有没有到期的任务,有就发一个内部请求去执行。这意味着——没人访问就没有触发;访问量大时又可能并发触发。官方插件手册明确提示:如果你的任务很吃资源,默认”等用户来访问再跑”并不合适,用户可能会对着白屏干等。

对比项WP-Cron(默认)系统 Cron + DISABLE_WP_CRON
触发方式页面访问触发服务器定时触发
准时性低流量站点可能延迟很久分钟级精确
资源占用占用访客请求进程独立进程,不影响前端
适用场景本地开发、小博客生产环境、定时发布、同步任务
判断标准:只要你的任务”必须按时发生”(定时发文、订单同步、邮件推送),就别指望 WP-Cron 默认行为,直接上系统 cron 。

二、正确注册一个定时任务

注册定时任务分三步:加钩子、判重、再调度。漏掉判重是最常见的坑——wp_schedule_event() 每次调用都会新增一条,如果放在每次页面加载都会执行的代码里,几小时就能攒出几千条重复任务。


  1. 用 add_action 把自定义钩子和真正的执行函数绑起来:add_action(‘my_daily_hook’, ‘my_daily_task’);

  2. 用 wp_next_scheduled(‘my_daily_hook’) 判断任务是否已存在,不存在才调度,避免重复堆积。

  3. 用 wp_timezone() 构造”站点时区今天 9:00″的 DateTime,再 getTimestamp() 拿到 UTC 时间戳作为首次执行时间。

  4. 调用 wp_schedule_event($timestamp, ‘daily’, ‘my_daily_hook’) 完成注册。

  5. 在插件的 register_deactivation_hook 里用 wp_unschedule_event 把任务清掉,停用后不残留。

关键代码

// 1. 绑定钩子
add_action( 'my_daily_hook', 'my_daily_task' );

// 2. 按站点时区算出"今天 9:00"
function my_next_9am() {
    $tz   = wp_timezone();
    $next = new DateTime( 'today 09:00', $tz );
    if ( $next <= new DateTime( 'now', $tz ) ) {
        $next->modify( '+1 day' );
    }
    return $next->getTimestamp();
}

// 3. 判重后调度
if ( ! wp_next_scheduled( 'my_daily_hook' ) ) {
    wp_schedule_event( my_next_9am(), 'daily', 'my_daily_hook' );
}

// 4. 停用时清理
register_deactivation_hook( __FILE__, 'my_deactivate' );
function my_deactivate() {
    $ts = wp_next_scheduled( 'my_daily_hook' );
    if ( $ts ) {
        wp_unschedule_event( $ts, 'my_daily_hook' );
    }
}

三、时区这个坑

WordPress 在启动时会把 PHP 默认时区强制设为 UTC 。所以 wp_schedule_event( strtotime('today 9am'), 'daily', ... ) 看起来对,实际建的是 UTC 9 点,落到中国时区就是下午 5 点,夏令时地区还会再漂。

正确做法是走 wp_timezone()(WP 5.3+)拿到后台”设置 → 常规”里配的时区对象,用 DateTime 构造本地时间,再 getTimestamp()——时间戳本身永远基于 UTC,偏移和夏令时都被正确处理了。

为什么不要用 date_default_timezone_set() 绕过?
因为 WordPress 内核本身就依赖”PHP 默认时区是 UTC”这个前提。你改掉它,其他依赖时间的核心逻辑可能一起出问题。用 wp_timezone() 构造时间是唯一安全解。

四、自定义执行间隔

默认只有 hourly 、 twicedaily 、 daily 三档(外加一次性任务)。要更细的粒度,用 cron_schedules 过滤器加:

add_filter( 'cron_schedules', function ( $schedules ) {
    $schedules['per_minute'] = [
        'interval' => 60,
        'display'  => '每分钟',
    ];
    return $schedules;
} );

注意顺序:必须先加 cron_schedules 过滤器,再调用 wp_schedule_event,否则自定义周期还没注册,调度会失败。

别滥用 1 分钟间隔。高频任务叠加页面缓存失效,很容易把小配置服务器拖垮;能合并成批处理就合并。

五、生产环境接入系统 Cron


  1. 编辑 wp-config.php,加入 define(‘DISABLE_WP_CRON’, true); 关掉页面触发。

  2. SSH 登录服务器执行 crontab -e,加入:*/5 * * * * /usr/bin/php -q /站点路径/wp-cron.php >/dev/null 2>&1(PHP 路径以实际为准)。

  3. 如需限制并发,可在 wp-config.php 加 define(‘WP_CRON_LOCK_TIMEOUT’, 60); 保证 60 秒内不会重复跑。

  4. 用 wp cron event list(WP-CLI)确认任务已注册,观察一两个周期确认按时触发。

如果服务器不方便开 crontab,还有两个备选:宝塔/AMH 面板的”计划任务”里选 Shell 执行;或用外部监控服务定时请求 https://你的域名/wp-cron.php?doing_wp_cron。前者更稳定,后者依赖第三方可用性。

六、任务不执行的排查清单

  • 站点开了全页面缓存且缓存规则拦掉了 wp-cron.php 请求;
  • DISABLE_WP_CRON 已开启但忘记配系统 crontab(最常见的自摆乌龙);
  • 任务回调里抛了致命错误,被静默吞掉——查 PHP error log;
  • 插件停用没清理,cron 数组里堆了几千条僵尸任务,拖慢每次加载;
  • 对象缓存(Redis/Memcached)接管后,cron 数组本身被缓存住了,改完没生效。

需要远程管理站点任务时,可以配合 WordPress REST API 进阶用法 做自定义端点;站点性能相关的排查另见 WordPress 速度优化实测。

查看官方 WP-Cron 文档

WP-Cron 和服务器 crontab 有什么区别?
WP-Cron 是”伪 cron”,靠页面访问触发,没人访问就不执行;系统 crontab 由操作系统按时触发,分钟级精确且不影响访客。生产环境应禁用 WP-Cron 改用系统 cron 。

为什么我的定时任务总是不按时执行?
最常见三个原因:站点流量太低导致没人触发;开启了全页面缓存拦掉了 wp-cron.php;或者已设置 DISABLE_WP_CRON 却没配系统 crontab 。

怎么避免重复注册同一个任务?
每次调度前先用 wp_next_scheduled(‘钩子名’) 判断,返回 false 才调用 wp_schedule_event()。否则每加载一次页面就多一条任务。

想让任务每天站点时区 9 点跑,怎么写才不偏移?
用 wp_timezone() 取站点时区,new DateTime(‘today 09:00’, $tz) 再 getTimestamp()。不要用 strtotime(‘today 9am’),那会按 UTC 计算,中国时区会变成 17 点。

插件停用后定时任务会残留吗?
会,除非你在 register_deactivation_hook 里调用 wp_unschedule_event() 清理。残留任务会在每次页面加载时被检查,长期拖慢站点。

这篇有帮助吗?
云上的幻象
云上的幻象查看主页

七彩云博客,分享 WordPress 建站实战与 AI 工具测评,覆盖服务器运维、站长工具、软件资源与电商运营干货,专注原创实用的主题插件、网站加速与安全优化教程。

762文章4评论

相关文章

评论 (0)

欢迎你,新朋友,感谢参与互动!文明发言,理性交流 · 首次评论将在审核后展示