WordPress 定时任务不准怎么办(2026 实操):一天只触发 33 次,换成系统 crontab

先看一个数字

昨天翻了一下站点的 nginx 日志:一整天 9720 条请求,打到 wp-cron.php 的只有 33 次。

9720 除以 33,平均 44 分钟才被触发一次,而 WordPress 的定时任务本该随时能跑。原因在于默认的 WP-Cron 不是真的定时器,它靠「有人访问页面」来顺带触发:每个 PHP 请求结束前,WordPress 查一遍有没有到期的事件,有就丢个后台请求去打 wp-cron.php。

缓存一开,绝大多数访问在边缘或者 Cache Enabler 那层就被返回了,压根不经过 PHP,触发源就没了。今天上午这半天更夸张,8 个多小时 4395 条请求,wp-cron.php 只出现了 21 次。定时发布迟到、备份漏跑、清理任务堆积,大多是这个原因。

先确认你自己的站是不是也这样

三条命令,一分钟看清现状。

  1. wp cron test:看页面触发是不是开着,输出 Success: WP-Cron spawning is working as expected. 就说明 cron 还挂在页面访问上。
  2. 数一下日志:grep -c 'wp-cron.php' /www/wwwlogs/你的域名.log。数字跟你预期的频率差很多,问题就坐实了。
  3. 列一下待跑事件:wp cron event list --fields=hook,next_run_relative,能同时看到有哪些事件、下次什么时候跑。

第一步:关掉页面触发的 WP-Cron

改 wp-config.php 前先备份:cp wp-config.php wp-config.php.bak。

然后在 / That's all, stop editing! Happy publishing. / 这行之前加一句:

define('DISABLE_WP_CRON', true);

位置别放错,一定要在 require_once ABSPATH . 'wp-settings.php'; 之前,放到后面不生效。

改完 WordPress 就不再自己触发了,这时候如果还没做第二步,所有定时任务会彻底停摆,定时发布发不出去、自动更新也不检查,这个中间状态别停太久。

第二步:让系统的 crontab 来敲它

关键有两点,用绝对路径,用对 PHP 版本。

我在那台机器上踩的坑是:站点跑 php-fpm 8.1,装着 redis 扩展;命令行的默认 php 却是 8.2,没装。直接拿默认 php 跑 WP-CLI,凡是碰对象缓存的命令都会报 Object Cache Pro requires the redis PHP extension,然后降级到内存缓存继续跑。所以命令里要写死 php 的路径:

*/5 * * * * flock -n /tmp/wpcron.lock sudo -u www -H /www/server/php/81/bin/php /usr/local/bin/wp --path=/www/wwwroot/你的站点 cron event run --due-now >/dev/null 2>&1

拆开说几处。*/5 是每 5 分钟一次;flock -n 拿一把锁,上一次没跑完就直接跳过,避免任务叠着跑;sudo -u www 用网站属主身份执行;--due-now 只跑到期的事件,不是把整个队列重跑一遍。

用宝塔面板的可以走面板 → 计划任务 → 任务类型选「Shell 脚本」,周期填 N 分钟,脚本内容填上面 sudo 之后那一段。注意宝塔的计划任务默认以 root 执行,脚本里务必自己带上 sudo -u www,否则插件生成的新文件属主变成 root,网站之后改不动。

第三步:怎么知道真生效了

最直接的办法是排一个一次性的假事件,看它会不会自己消失:

# 排一个 1 分钟后到期的测试事件
sudo -u www -H /www/server/php/81/bin/php /usr/local/bin/wp --path=/www/wwwroot/你的站点 \
  cron event schedule kira_test "+1 minute"

# 等 5 分钟后再看,列表里应该没有 kira_test 了
sudo -u www -H /www/server/php/81/bin/php /usr/local/bin/wp --path=/www/wwwroot/你的站点 \
  cron event list --fields=hook,next_run_relative | grep kira_test

另一个信号在日志里。走 WP-CLI 跑 cron 不发 HTTP 请求,所以 grep -c 'wp-cron.php' 的数字会慢慢归零,原来那些 POST /wp-cron.php?doing_wp_cron=... 记录会消失。看到这个,就说明页面触发确实关掉了、任务也改走系统定时了。

常见坑与回滚

cron 的 PATH 很短,php、wp 都可能找不到,一律写绝对路径。

CLI 的 PHP 跟 fpm 的 PHP 常常不是同一个版本,扩展也可能不一样。用 /www/server/php/81/bin/php -m | grep redis 对一下,对不上就换路径,别猜。

关了 WP-Cron 却忘了加系统任务,是最常见的翻车方式,表现是定时彻底不动,而不是变慢。

要回滚,把 wp-config.php 里那句 define('DISABLE_WP_CRON', true); 删掉,再把 crontab -e 里那条删掉或注释掉,页面触发就回来了,直接用备份的 wp-config.php.bak 覆盖也行。

顺带一句,别用 curl 定时去打 wp-cron.php 这条老路。缓存会把它拦掉,防火墙也可能拦,而且它还得先走一遍 PHP-FPM,才轮到 WP-CLI 干同样的活。

最后

站点本来就挂了 Redis 对象缓存(写法在「WordPress 接上 Redis 对象缓存」那篇里),CLI 里 redis 扩展没加载这个坑也是那次顺带发现的。定时任务平时没什么存在感,一旦它稳了,异地备份(见「WordPress 全站自动备份与恢复」)和 Uptime Kuma 那套告警(见「用 Docker 搭一套自己的监控告警」)才敢放心交给它,不然你守的是一排不会响的闹钟。

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容