WordPress源码深度解析之:`WordPress`的`Cron`:如何通过系统`Cron`替代`wp-cron.php`。

各位老铁,晚上好!我是你们的老朋友,今天咱们聊点刺激的,关于WordPress的“定时炸弹”—— wp-cron.php,以及如何把它驯服,让真正的系统Cron来接管。

开场白:wp-cron.php,你是爱还是恨?

大家伙都知道,WordPress有很多定时任务,比如定时发布文章、清理垃圾评论、更新插件等等。这些任务的执行,大部分都要依赖一个叫做 wp-cron.php 的文件。

这玩意儿,说白了,就是一个模拟Cron的脚本。它不是真正的系统Cron,而是通过在每次页面加载时,检查是否有到期的任务需要执行。如果任务到期了,就执行一下。

问题来了,这种机制有啥缺点呢?

  • 性能问题: 每次页面加载都要检查,增加了服务器的负担,尤其是在访问量大的时候。
  • 不可靠性: 如果网站访问量很低,或者服务器缓存机制导致 wp-cron.php 没有被触发,定时任务可能就无法按时执行。
  • 资源占用: 即使没有需要执行的任务,wp-cron.php 仍然会被调用,浪费服务器资源。

总之,wp-cron.php 就像一个不靠谱的临时工,干活效率低,还容易出岔子。

所以,今天咱们的目标就是:干掉这个临时工,让专业的系统Cron来接管WordPress的定时任务!

第一部分:了解系统 Cron

在开始之前,咱们得先了解一下什么是系统Cron。

系统Cron,是类Unix系统(包括Linux、macOS)自带的一个任务调度器。它可以按照预定的时间,自动执行指定的命令或脚本。简单来说,就是给服务器设置一个闹钟,让它在指定的时间做指定的事情。

系统Cron的配置文件通常是 crontab,可以使用 crontab -e 命令来编辑。

crontab 文件的格式是这样的:

*     *     *   *    * command to be executed
-     -     -   -    -
|     |     |   |    |
|     |     |   |    +----- day of the week (0 - 7) (Sunday=0 or 7)
|     |     |   +--------- month (1 - 12)
|     |     +------------- day of the month (1 - 31)
|     +------------------- hour (0 - 23)
+------------------------- minute (0 - 59)
  • * 表示所有值。
  • command to be executed 是要执行的命令或脚本的路径。

举个例子,下面这个 crontab 条目表示每分钟执行一次 /path/to/your/script.sh 脚本:

* * * * * /path/to/your/script.sh

第二部分:禁用 wp-cron.php

在开始使用系统Cron之前,咱们得先禁用掉 wp-cron.php,避免两者冲突。

禁用 wp-cron.php 很简单,只需要在 wp-config.php 文件中添加以下代码:

define('DISABLE_WP_CRON', true);

这行代码告诉WordPress,不要再使用 wp-cron.php 来执行定时任务了。

第三部分:配置系统 Cron

接下来,咱们就要配置系统Cron,让它来接管WordPress的定时任务。

首先,我们需要找到 wp-cron.php 文件的完整路径。这个路径通常是 你的WordPress根目录/wp-cron.php

然后,使用 crontab -e 命令打开 crontab 文件。

根据你的需求,添加一个或多个 crontab 条目。

一般来说,建议每隔一段时间(例如每5分钟或每15分钟)执行一次 wp-cron.php

下面是一些示例:

  • 每5分钟执行一次:

    */5 * * * * /usr/bin/php /path/to/your/wp-cron.php >/dev/null 2>&1
  • 每15分钟执行一次:

    */15 * * * * /usr/bin/php /path/to/your/wp-cron.php >/dev/null 2>&1
  • 每小时执行一次:

    0 * * * * /usr/bin/php /path/to/your/wp-cron.php >/dev/null 2>&1

注意:

  • /usr/bin/php 是PHP解释器的路径,你需要根据你的服务器配置修改。可以使用 which php 命令来查找PHP解释器的路径。
  • /path/to/your/wp-cron.phpwp-cron.php 文件的完整路径,你需要根据你的WordPress安装目录修改。
  • >/dev/null 2>&1 表示将输出和错误信息都丢弃,避免 cron 发送邮件。

第四部分:代码实现:让WordPress知道Cron已经接管

虽然我们禁用了 wp-cron.php,并配置了系统Cron,但是WordPress本身并不知道Cron已经接管了定时任务。因此,我们需要一些代码来告诉WordPress,让它不要再尝试自己执行定时任务。

可以在 functions.php 文件或者自定义插件中添加以下代码:

/**
 * 禁用 WordPress 默认的 WP-Cron,并添加一个指示器,告诉插件Cron已经接管。
 */
add_filter( 'pre_option_disable_wp_cron', '__return_true' );

/**
 * 添加一个选项,用于检查系统 Cron 是否正在运行。
 */
add_action( 'init', 'check_external_cron' );

function check_external_cron() {
    if ( ! get_option( 'external_cron_running' ) ) {
        update_option( 'external_cron_running', 'yes', false );
    }
}

/**
 * 定期检查外部 Cron 是否仍然在运行。
 */
add_action( 'wp', 'schedule_external_cron_check' );

function schedule_external_cron_check() {
    if ( ! wp_next_scheduled( 'check_external_cron_status' ) ) {
        wp_schedule_event( time(), 'hourly', 'check_external_cron_status' );
    }
}

add_action( 'check_external_cron_status', 'check_external_cron_status' );

function check_external_cron_status() {
    if ( get_option( 'external_cron_running' ) !== 'yes' ) {
        // 外部 Cron 可能没有正确配置或停止运行。
        // 在这里可以添加一些警告或错误处理代码。
        error_log( '警告:外部 Cron 可能没有正确配置或停止运行!' );
    }
}

/**
 *  每次 WP-Cron 尝试运行时,记录一条消息(仅用于调试)。
 */
add_action( 'wp_cron', 'log_wp_cron_attempt' );

function log_wp_cron_attempt() {
    error_log( 'WP-Cron 尝试运行,但应该被禁用!' );
}

/**
 *  如果需要,可以手动触发 WP-Cron(仅用于调试)。
 *  在浏览器中访问: yourdomain.com/?doing_wp_cron=1
 */

这段代码做了以下几件事:

  1. add_filter( 'pre_option_disable_wp_cron', '__return_true' );: 再次确认禁用 wp-cron.php,确保万无一失。
  2. check_external_cron(): 添加一个选项 external_cron_running,用于标记系统Cron是否正在运行。
  3. schedule_external_cron_check()check_external_cron_status(): 定期检查 external_cron_running 选项的值,如果发现系统Cron停止运行,就记录一条错误日志,方便排查问题。
  4. log_wp_cron_attempt(): 每次 wp-cron.php 尝试运行时,记录一条错误日志,方便调试。

第五部分:代码实现:WordPress插件形式

将上面的代码封装成一个简单的WordPress插件,方便管理和部署。

创建一个名为 external-cron 的文件夹,并在该文件夹中创建以下两个文件:

  • external-cron.php (插件主文件)
  • external-cron-admin.php (插件管理页面)

external-cron.php (插件主文件):

<?php
/**
 * Plugin Name: External Cron for WordPress
 * Description: Disables WP-Cron and provides tools to verify external cron setup.
 * Version: 1.0.0
 * Author: Your Name
 */

// 确保文件被 WordPress 加载
if ( ! defined( 'ABSPATH' ) ) {
    exit; // Exit if accessed directly.
}

// 禁用 WordPress 默认的 WP-Cron
define( 'DISABLE_WP_CRON', true );

/**
 * 添加插件管理菜单
 */
add_action( 'admin_menu', 'external_cron_add_admin_menu' );

function external_cron_add_admin_menu() {
    add_options_page(
        'External Cron Settings',
        'External Cron',
        'manage_options',
        'external-cron-settings',
        'external_cron_settings_page'
    );
}

/**
 * 插件管理页面回调函数
 */
function external_cron_settings_page() {
    include_once( plugin_dir_path( __FILE__ ) . 'external-cron-admin.php' );
}

/**
 * 添加一个指示器,告诉插件Cron已经接管。
 */
add_filter( 'pre_option_disable_wp_cron', '__return_true' );

/**
 * 添加一个选项,用于检查系统 Cron 是否正在运行。
 */
add_action( 'init', 'check_external_cron' );

function check_external_cron() {
    if ( ! get_option( 'external_cron_running' ) ) {
        update_option( 'external_cron_running', 'yes', false );
    }
}

/**
 * 定期检查外部 Cron 是否仍然在运行。
 */
add_action( 'wp', 'schedule_external_cron_check' );

function schedule_external_cron_check() {
    if ( ! wp_next_scheduled( 'check_external_cron_status' ) ) {
        wp_schedule_event( time(), 'hourly', 'check_external_cron_status' );
    }
}

add_action( 'check_external_cron_status', 'check_external_cron_status' );

function check_external_cron_status() {
    if ( get_option( 'external_cron_running' ) !== 'yes' ) {
        // 外部 Cron 可能没有正确配置或停止运行。
        // 在这里可以添加一些警告或错误处理代码。
        error_log( '警告:外部 Cron 可能没有正确配置或停止运行!' );
    }
}

/**
 *  每次 WP-Cron 尝试运行时,记录一条消息(仅用于调试)。
 */
add_action( 'wp_cron', 'log_wp_cron_attempt' );

function log_wp_cron_attempt() {
    error_log( 'WP-Cron 尝试运行,但应该被禁用!' );
}

// 插件激活时执行的操作
register_activation_hook( __FILE__, 'external_cron_activation' );

function external_cron_activation() {
    // 插件激活时,设置一个初始值,表示 Cron 正在运行
    update_option( 'external_cron_running', 'yes', false );
}

// 插件停用时执行的操作
register_deactivation_hook( __FILE__, 'external_cron_deactivation' );

function external_cron_deactivation() {
    // 插件停用时,删除 Cron 运行状态的选项
    delete_option( 'external_cron_running' );
    // 清除所有计划的事件
    wp_clear_scheduled_hook( 'check_external_cron_status' );
}

/**
 *  如果需要,可以手动触发 WP-Cron(仅用于调试)。
 *  在浏览器中访问: yourdomain.com/?doing_wp_cron=1
 */

external-cron-admin.php (插件管理页面):

<div class="wrap">
    <h1>External Cron Settings</h1>
    <p>This plugin disables WP-Cron and uses an external cron job to run WordPress scheduled tasks.</p>

    <h2>Configuration</h2>
    <p>To configure the external cron job, you need to add a line to your server's crontab. Here's an example:</p>

    <pre><code>*/15 * * * * /usr/bin/php <?php echo ABSPATH; ?>wp-cron.php >/dev/null 2>&1</code></pre>

    <p><strong>Important:</strong></p>
    <ul>
        <li>Replace <code>/usr/bin/php</code> with the correct path to your PHP executable. You can find this by running <code>which php</code> in your terminal.</li>
        <li>Make sure the path to <code>wp-cron.php</code> is correct. In most cases, it will be in your WordPress root directory.</li>
    </ul>

    <h2>Status</h2>
    <?php
    $cron_running = get_option( 'external_cron_running' );
    if ( $cron_running === 'yes' ) {
        echo '<p style="color: green;"><strong>External Cron is running.</strong></p>';
    } else {
        echo '<p style="color: red;"><strong>External Cron is NOT running. Please check your configuration.</strong></p>';
    }
    ?>

    <h2>Troubleshooting</h2>
    <ul>
        <li>Check your server's cron logs for any errors.</li>
        <li>Make sure the <code>wp-cron.php</code> file is executable.</li>
        <li>Ensure your PHP installation has the necessary extensions enabled.</li>
    </ul>
</div>

external-cron 文件夹上传到 WordPress 的 wp-content/plugins 目录下,然后在 WordPress 后台激活该插件。

这个插件做了以下事情:

  1. 禁用 wp-cron.php 插件激活后,会自动禁用 wp-cron.php
  2. 添加管理页面: 在 WordPress 后台的“设置”菜单下添加一个“External Cron”子菜单,用于显示插件的配置信息和运行状态。
  3. 检查 Cron 运行状态: 插件会定期检查系统Cron是否正在运行,并在管理页面上显示状态。
  4. 提供配置说明: 在管理页面上提供系统Cron的配置示例和注意事项。

第六部分:测试与验证

配置完成后,我们需要测试一下,确保系统Cron能够正确地执行WordPress的定时任务。

  1. 查看系统Cron日志: 查看服务器的Cron日志(通常位于 /var/log/cron),确认 wp-cron.php 脚本是否被定期执行。
  2. 创建一个定时发布的文章: 在WordPress后台创建一个定时发布的文章,并设置发布时间为几分钟后。然后,等待几分钟,查看文章是否按时发布。
  3. 使用 WP Crontrol 插件: 安装并激活 WP Crontrol 插件,它可以显示WordPress的所有定时任务,并允许你手动执行这些任务。通过这个插件,你可以更直观地了解系统Cron是否正确地执行了WordPress的定时任务。

第七部分:进阶技巧

  • 使用 WP-CLI: WP-CLI 是 WordPress 的命令行工具,可以使用它来执行 wp-cron.php。例如:

    wp cron event run --due-now
  • 优化 wp-cron.php wp-cron.php 文件本身也可以进行一些优化,例如禁用不必要的任务,减少数据库查询等等。

总结

通过禁用 wp-cron.php 并配置系统Cron,我们可以大大提高WordPress网站的性能和可靠性。虽然配置过程稍微复杂一些,但是带来的好处是显而易见的。

最后,记住一点:

  • 在修改任何配置文件之前,一定要备份!
  • 在测试过程中,遇到问题不要慌,仔细查看日志,一步一步排查。

希望今天的分享对大家有所帮助! 如果有什么问题,欢迎随时提问。 咱们下期再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注