剖析 WordPress `_wp_check_for_updates()` 函数的源码:它如何通过 `wp_cron` 检查更新。

嘿,各位代码爱好者!今天咱们来聊聊 WordPress 里面一个相当重要的函数:_wp_check_for_updates()。别看名字好像很长,其实它干的事情很简单,就是默默地检查 WordPress 的核心、插件和主题有没有新版本。而它背后的机制,则离不开 WordPress 的定时任务系统 wp_cron

咱们今天要像剥洋葱一样,一层一层地扒开这个函数的源码,看看它是怎么通过 wp_cron 来完成更新检查任务的。放心,我会尽量用大白话,保证你听得懂,看得明白。

开场白:为什么需要自动更新检查?

想象一下,你辛辛苦苦搭建了一个 WordPress 网站,运行了几个月后,突然发现网站被人黑了,或者出现了莫名其妙的 bug。事后调查发现,罪魁祸首竟然是使用了过时的插件或者主题。

这是多么令人沮丧的事情!为了避免这种情况发生,我们需要定期检查 WordPress 及其组件的更新。手动检查当然可以,但是谁会每天都记得去检查呢?所以,自动更新检查就显得尤为重要了。

_wp_check_for_updates() 函数:更新检查的指挥官

_wp_check_for_updates() 函数位于 wp-includes/update.php 文件中。这个函数是整个更新检查流程的指挥官,它负责协调各个组件,获取更新信息,并将其存储到数据库中。

让我们先来看看这个函数的大致结构:

function _wp_check_for_updates() {
    global $wpdb;

    if ( ! is_network_admin() && ! is_user_member_of_blog() ) {
        return;
    }

    if ( get_site_transient( 'doing_wp_cron' ) ) {
        return;
    }

    $current = get_site_transient( 'update_core' );

    if ( isset( $current->last_checked ) && ( time() - $current->last_checked < 3600 ) ) {
        return;
    }

    wp_version_check();
    wp_update_plugins();
    wp_update_themes();

    /**
     * Fires after the WordPress update check is run.
     *
     * @since 3.0.0
     *
     * @param WP_Upgrader|null $upgrader WP_Upgrader instance, or null
     *                                    if not available.
     */
    do_action( 'wp_maybe_update');
}

看起来是不是有点长?别怕,我们来逐行分析:

  1. global $wpdb;: 这一行不用多说,就是引入全局的 $wpdb 对象,用于执行数据库操作。

  2. if ( ! is_network_admin() && ! is_user_member_of_blog() ) { return; }: 这个条件判断语句用于检查当前用户是否有权限进行更新检查。只有网络管理员(在 WordPress Multisite 环境下)或者当前博客的管理员才能执行更新检查。

  3. if ( get_site_transient( 'doing_wp_cron' ) ) { return; }: 这是个很重要的判断!它检查一个名为 doing_wp_cronsite_transient 是否存在。 site_transient 是一种在数据库中存储临时数据的方式,用于避免重复执行某些耗时的操作。如果 doing_wp_cron 存在,说明已经有另一个 wp_cron 进程正在运行,那么就直接返回,避免并发执行更新检查。

  4. $current = get_site_transient( 'update_core' );: 获取 WordPress 核心的更新信息。这些信息包括当前 WordPress 版本、最新版本、更新包下载地址等等。

  5. if ( isset( $current->last_checked ) && ( time() - $current->last_checked < 3600 ) ) { return; }: 这是一个时间间隔检查。它检查上次更新检查的时间是否超过了一个小时(3600 秒)。如果没超过,说明最近已经检查过了,就没必要再次检查了。这个机制可以避免过于频繁地请求 WordPress 官方服务器,减轻服务器压力。

  6. wp_version_check();: 这是核心函数之一,用于检查 WordPress 核心是否有新版本。

  7. wp_update_plugins();: 用于检查插件是否有新版本。

  8. wp_update_themes();: 用于检查主题是否有新版本。

  9. do_action( 'wp_maybe_update');: 这是一个钩子函数,允许其他插件或者主题在更新检查之后执行一些自定义的操作。

wp_cron:幕后的定时任务调度员

好了,我们已经了解了 _wp_check_for_updates() 函数的作用,但是还有一个关键问题:这个函数是什么时候被调用的呢?答案就是 wp_cron

wp_cron 是 WordPress 自带的一个简单的定时任务系统。它实际上并不是一个真正的 cron 守护进程,而是一种模拟的 cron 机制。它的工作原理是:当有用户访问 WordPress 网站时,WordPress 会检查是否有需要执行的定时任务。如果有,就执行这些任务。

那么,_wp_check_for_updates() 函数是如何被添加到 wp_cron 的任务列表中的呢?

这通常是通过 wp_schedule_event() 函数来实现的。这个函数可以将一个函数添加到 wp_cron 的任务列表中,并指定执行的时间间隔。

例如,在 wp-includes/cron.php 文件中,你可以找到类似这样的代码:

if ( ! wp_next_scheduled( 'wp_version_check' ) ) {
    wp_schedule_event( time(), 'twicedaily', 'wp_version_check' );
}

这段代码的意思是:如果 wp_version_check 这个函数还没有被添加到 wp_cron 的任务列表中,那么就将它添加到任务列表中,并指定每隔 12 小时(twicedaily)执行一次。

wp_version_check 实际上是 _wp_version_check 的一个包装器,最终还是会调用 _wp_check_for_updates() 函数。

深入 wp_version_check():WordPress 核心更新检查

wp_version_check() 函数是负责检查 WordPress 核心是否有新版本的。它的主要工作流程如下:

  1. 获取当前 WordPress 版本信息: 这个很简单,直接从 $wp_version 全局变量中获取。

  2. 构建 API 请求: wp_version_check() 函数会向 WordPress 官方 API 发送一个 HTTP 请求,请求中包含了当前 WordPress 版本信息、当前站点信息等等。

  3. 发送 HTTP 请求: 使用 wp_remote_post() 函数发送 HTTP 请求。

  4. 解析 API 响应: API 响应通常是一个 JSON 格式的数据,包含了最新 WordPress 版本信息、更新包下载地址等等。

  5. 存储更新信息: 将解析后的更新信息存储到 site_transient 中,方便后续使用。

让我们来看看 wp_version_check() 函数的关键代码片段:

function wp_version_check( $deprecated = '' ) {
    global $wp_version, $wp_local_package;

    if ( ! empty( $deprecated ) ) {
        _deprecated_argument( __FUNCTION__, '3.8', null );
    }

    if ( get_site_transient( 'doing_wp_cron' ) ) {
        return false;
    }

    $timeout = 3;

    $options = array(
        'timeout' => $timeout,
        'body' => array(
            'version' => $wp_version,
            'php' => phpversion(),
            'locale' => get_locale(),
            'mysql' => $wpdb->db_version(),
            'blogs' => $wpdb->blogid,
            'users' => $wpdb->get_var( "SELECT COUNT(ID) FROM $wpdb->users" ),
            'multisite_enabled' => is_multisite(),
            'initial_db_version' => get_site_option( 'initial_db_version' ),
        ),
        'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url()
    );

    // Include an MD5 hash of the WordPress package.
    if ( isset( $wp_local_package ) ) {
        $options['body']['local_package'] = md5_file( ABSPATH . WPINC . '/version.php' );
    }

    $url = 'https://api.wordpress.org/core/version-check/1.7/?' . http_build_query( $options['body'], '', '&' );
    $response = wp_remote_get( $url, $options );

    if ( is_wp_error( $response ) ) {
        return false;
    }

    $body = wp_remote_retrieve_body( $response );

    if ( empty( $body ) ) {
        return false;
    }

    $decoded_response = json_decode( $body );

    if ( ! is_object( $decoded_response ) ) {
        return false;
    }

    if ( isset( $decoded_response->offers ) && is_array( $decoded_response->offers ) ) {
        foreach ( $decoded_response->offers as &$offer ) {
            if ( isset( $offer->packages ) && ! is_array( $offer->packages ) ) {
                $offer->packages = array( $offer->packages );
            }
        }
    }

    set_site_transient( 'update_core', $decoded_response, 3 * HOUR_IN_SECONDS );

    return true;
}

注意看 $options['body'] 数组,这里面包含了发送给 WordPress 官方 API 的数据。 'url' 变量定义了 API 端点。 set_site_transient( 'update_core', $decoded_response, 3 * HOUR_IN_SECONDS ); 这行代码将 API 响应存储到 site_transient 中,过期时间为 3 小时。

wp_update_plugins()wp_update_themes():插件和主题更新检查

wp_update_plugins()wp_update_themes() 函数的原理与 wp_version_check() 类似,都是通过发送 HTTP 请求到 WordPress 官方 API 或者第三方 API,获取插件和主题的更新信息,并将这些信息存储到 site_transient 中。

不同之处在于:

  • wp_update_plugins() 函数需要遍历所有已安装的插件,并为每个插件构建 API 请求。
  • wp_update_themes() 函数需要遍历所有已安装的主题,并为每个主题构建 API 请求。
  • 插件和主题的 API 端点可能不同,有些插件和主题可能使用 WordPress 官方 API,有些则可能使用第三方 API。

wp_cron 的一些问题与优化

虽然 wp_cron 用起来很方便,但是它也有一些局限性:

  1. 依赖用户访问: wp_cron 只有在有用户访问 WordPress 网站时才会执行。如果网站访问量很低,那么定时任务可能无法按时执行。

  2. 性能问题: 每次有用户访问网站时,WordPress 都会检查是否有需要执行的定时任务,这会增加服务器的负担。

为了解决这些问题,可以考虑以下优化方案:

  • 使用真正的 cron 守护进程: 可以将 wp_cron 禁用,然后使用服务器上的真正的 cron 守护进程来定时执行 wp-cron.php 文件。这样可以确保定时任务按时执行,并且不会影响网站的性能。
  • 使用第三方插件: 有一些第三方插件可以优化 wp_cron 的性能,例如 WP Crontrol 插件。

总结

好了,今天的讲座就到这里。我们一起深入剖析了 WordPress 的 _wp_check_for_updates() 函数,了解了它是如何通过 wp_cron 来检查更新的。

让我们来总结一下:

函数/机制 作用
_wp_check_for_updates() 更新检查的指挥官,负责协调各个组件,获取更新信息,并将其存储到数据库中。
wp_cron WordPress 自带的定时任务系统,用于定时执行某些任务。
wp_version_check() 检查 WordPress 核心是否有新版本。
wp_update_plugins() 检查插件是否有新版本。
wp_update_themes() 检查主题是否有新版本。
site_transient 在数据库中存储临时数据,用于避免重复执行某些耗时的操作。

希望今天的讲座对你有所帮助。记住,理解 WordPress 的底层机制,可以帮助你更好地使用和定制 WordPress,打造出更强大的网站。下次再见!

发表回复

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