WordPress 插件开发教程手册 — 任务计划 WP Cron

Cron 是基于时间的任务调度系统,可以在 Unix 系统上使用,WP-Cron 是 WordPress 中处理任务的基于时间的任务调度系统,WordPress 的几个核心功能如检查更新和定制发布功能,都使用了 WP-Cron 系统。

WP-Cron 的工作原理是,在页面加载的时候,检查计划任务列表以查看需要运行的任务,计划中的任务将在页面加载时执行。WP-Cron 和 Unix 系统的 Cron 运行方式不一样,他只在页面加载时触发。如果我们安排了一个任务在下午 2:00 运行,而在下午 5:00 之前没有发生任何页面加载,则该计划任务不会运行。

为什么使用 WP-Cron

为什么使用 WP-Cron 呢?很多虚拟主机不允许用户访问系统 Cron,但 WordPress 核心和许多插件需要一个 Cron 系统来执行基于时间的任务。Cron 是一个非常有用的工具,因此 WordPress 提供了通过页面加载触发的基于时间的 WP-Cron 系统。虽然该系统不一定会在特定的时间运行,WP-Cron 也有一定的几率完成我们的计划任务。 使用 WordPress API 来设置 Cron 任务比在 WordPress 之外使用其他方法设置更加简单。

如果 Unix 系统的任务没有在特定的时间执行,他就永远不会执行了。而 WP-Cron 将在下一次页面加载的时候执行过期而没有运行的任务,不管这个任务过期过久。任务将一直在队列中,直到有一个页面加载时触发他们,因此,通过 WP-Cron 设置的计划任务不会丢失。

理解 WordPress 任务计划

Unix 系统的 Cron 在特定的时间运行(比如,每个小时的第五分钟),与系统 Cron 不同,WP-Cron 使用时间间隔来模拟系统 Cron,首先给第一个任务一个运行时间,然后设置一个时间间隔,以秒为单位,之后按照时间间隔重复任务。例如,我们安排了一个下午 2:00 开始,间隔 300 秒(5分钟)的计划任务,该任务首先在下午 2:00 运行一次,然后在下午 2:05 运行,然后每隔 5 分钟运行一次。

为了简化计划任务,WordPress 提供了三个默认时间间隔和一个添加自定义间隔的简单方法。我们可以创建一个过滤器来添加自定义时间间隔,如:

add_filter( 'cron_schedules', 'example_add_cron_interval' );

function example_add_cron_interval( $schedules ) {
   $schedules['five_seconds'] = array(
      'interval' => 5,
      'display'  => esc_html__( 'Every Five Seconds' ),
   );

   return $schedules;
}

此过滤器函数创建了一个新的时间间隔,允许我们每 5 秒钟运行一次 Cron 任务。

注意:WP-Cron 的所有时间间隔以秒为单位。

调度 WP Cron 事件

计划周期性任务

为了让我们的任务执行,我们需要创建一个自定义钩子,并挂载一个回调函数到这个钩子上,这是非常重要的一步,忘了这一步,我们的任务计划永远不会被执行。

下面的示例中,我们将创建一个钩子,第一个参数是钩子的名称,第二个参数是挂载到钩子上的回调函数的名称。

add_action( 'bl_cron_hook', 'bl_cron_exec' );

现在,我们来进行实际的任务调度。另一个需要注意的事情是 WP-Cron 在调度任务时比较简单,没有去重的功能,任务是由为任务提供的钩子驱动的,但是如果多次调用 wp_schedule_event() ,及时使用相同的钩子名称,该任务也会被多次调用。如果我们的代码在每个页面皆在时执行任务,可能导致该任务被执行很多次,这可不是个好主意。WordPress 提供了一个 wp_next_scheduled() 函数来帮助我们检查一个特定的任务是否已经被调度。

wp_next_scheduled() 接收一个参数——钩子的名称,返回一个包含下一个执行时间戳的字符串,或 false 用来表示任务没有被调度,使用方法如下:

wp_next_scheduled( 'bl_cron_hook' );

我们使用 wp_schedule_event() 来完成重复任务调度,该函数需要三个必需的参数,一个附加参数。我们可以用附加参数传递给一个数组给执行 WP-Cron 任务的回调函数。我们将重点介绍前三个参数,参数如下:

  1. $timestamp – 首次执行此任务的 Unix 时间戳
  2. $recurrence – 执行任务的重复时间间隔的名称
  3. $hook – 用来调用的自定义钩子名称

我们将使用 5 秒的时间间隔和我们之前创建的钩子来演示一下:

wp_schedule_event( time(), 'five_seconds', 'bl_cron_hook' );

记住,我们需要首先确保该任务计划尚未被安排,完整代码如下:

if ( ! wp_next_scheduled( 'bl_cron_hook' ) ) {
   wp_schedule_event( time(), 'five_seconds', 'bl_cron_hook' );
}

取消任务计划调度

当我们不再需要某个计划任务时,我们可以使用 wp_unschedule_event() 函数来取消任务计划调度,该函数有两个参数:

  1. $timestamp – 下一次任务的时间戳
  2. $hook –用来调用的自定义钩子名称

这个函数不仅可以取消在每个时间戳执行的计划任务,还可以取消未来所有的重复任务计划。如果不知道下一个任务的时间戳,可以使用 wp_next_scheduled() 函数查找,该函数需要一个参数:

  1. $hook –用来调用的自定义钩子名称

把上面的代码放在一起,看起来应该像下面这样。

$timestamp = wp_next_scheduled( 'bl_cron_hook' );
wp_unschedule_event( $timestamp, 'bl_cron_hook' );

当我们不再需要某些任务计划的时候,及时取消这些任务计划非常重要,因为 WordPress 会继续尝试执行他们。取消计划任务的重要时机就是插件禁用时,而 WordPress.org 插件目录中的很多插件都忘记了这一点,不能自行清理不再需要的任务计划。如果你发现了一个这样的插件,可以尝试联系插件作者更新他们的代码。WordPress 为我们提供了一个名为 register_deactivation_hook() 函数,允许开发人员在插件停用的时候运行一个函数,设置起来非常简单,示例如下:

register_deactivation_hook( __FILE__, 'bl_deactivate' );

function bl_deactivate() {
   $timestamp = wp_next_scheduled( 'bl_cron_hook' );
   wp_unschedule_event( $timestamp, 'bl_cron_hook' );
}

挂载 WP-Cron 到系统任务调度器

如我们上面介绍的,WP-Cron 的执行依赖于页面加载,不一定会严格定期执行,如果我们有关键任务需要必需按时执行,这会是一个问题,幸运的是,我们有一个简单的解决办法来避免这个问题。只需将系统的任务计划设置为按我们所需的时间间隔(或在特定的时间)运行即可。最简单的解决办法是使用工具向 wp-cron.php 文件发送 Web 请求。

在我们的系统上安排了任务计划之后,WordPress 将不再需要在每个页面加载时帮我们执行任务计划,我们可以禁用掉这个功能,来节约这个不必要的服务器开销。WP-Cron 可以在 wp-config.php 中设置一个常量来禁用,在 wp-config.php 中添加以下代码即可。

define('DISABLE_WP_CRON', true);

Windows 系统

Windows 系统中,基于时间的任务系统叫 Task Scheduler,我们可以通过控制面板中的 “管理工具” 找到这个系统。如何设置任务因服务器设置而异。一种方法是使用 PowerShell 和一个基本任务,创建基本任务后,可以使用以下命令来调用 WordPress Cron 脚本。

powershell Invoke-WebRequest http://YOUR_SITE_URL/wp-cron.php

Mac OS X 和 Linux

Mac OS X 和 Linux 都使用 Cron 作为基于时间的调度系统,他们通常可以使用下面的命令从终端访问。

crontab -e

应该注意的是,任务将以常规用户或根用户的身份运行,具体取决于运行该命令的系统用户。Cron 有一个特定的语法。

  • 分钟
  • 小时
  • 一月中的天数
  • 日期
  • 一周中的天数
  • 需要执行的命令

设置计划任务时,不考虑的时间段使用 * 号代替,例如,如果我们需要每隔 15 分钟运行一次命令,而不考虑小时、日期和月份,计划任务设置如下:

15 * * * * command

许多服务器都自带了 wget 工具,我们可以使用这个工具来访问 WordPress 的 Cron 脚本。

wget http://YOUR_SITE_URL/wp-cron.php

每天凌晨触发网站的 WordPress Cron 的 Unix Cron 设置如下:

0 0 * * * wget http://YOUR_SITE_URL/wp-cron.php

如何简单测试 WP-Cron

在本教程中,我们将创建一个插件,每 5 秒运行一次任务并显示一条消息。为了测试,我们直接在浏览器中加载 wp-cron.php 文件并将数据输出到浏览器。否则我们将需要执行一些其他操作,可能会需要操作数据库,因为计划任务操作通常不会在站点上显示输出。让我们快速完成初始步骤来获取这一设置。

创建一个插件文件

在 wp-content/plugins 文件夹中创建一个文件夹 “my-wp-cron-test” 和 “my-wp-cron-test.php” 文件。当然,也可以用其他名称。打开我们刚才创建的 PHP 文件,开始编辑:

<?php
/*
Plugin Name: My WP-Cron Test
*/

上面的代码设置了在 WordPress 插件页面中显示的名称,不要忘了启用插件。

测试代码

在浏览器中打开 YOUR_SITE_URL/wp-cron.php 页面。

查看当前所有已计划的任务

WordPress 有一个未公开的函数 _get_cron_array,该函数返回当前所有计划任务的数组,我们将使用 var_dump 函数来输出所有计划任务。在插件中加入以下代码:

echo '<pre>'; var_dump( _get_cron_array() ); echo '</pre>';

放到一个容易调用的函数中如下:

function bl_print_tasks() {
   echo '<pre>'; var_dump( _get_cron_array() ); echo '</pre>';
}

本站提供 WordPress 主题定制开发服务

本站长期承接 WordPress 主题、插件、基于 WooCommerce 的商店商城开发业务。 我们有 8 年 WordPress 开发经验,如果你想 用 WordPress 开发网站, 请联系 QQ: 470266798,或邮箱: 4626395@gmail.com 咨询。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*