分析 WordPress `_wp_check_for_updates()` 函数的源码:它如何检查核心、插件和主题的更新。

各位观众老爷,晚上好!我是老码,今天跟大家聊聊WordPress的更新机制,重点剖析一下_wp_check_for_updates()这个函数,看看它是怎么像个勤劳的小蜜蜂一样,检查核心、插件和主题的更新的。准备好,我们要开始深入挖掘了,前方高能,请系好安全带!

开场白:WordPress更新的重要性 (装个样子,要不直接进入主题显得太生硬了)

在开始之前,咱们先唠叨两句。为啥要关注WordPress的更新?原因很简单:

  • 安全!安全!安全! (重要的事情说三遍)过时的代码就像没关好的大门,给黑客留下可乘之机。
  • 新功能: WordPress和它的插件、主题都在不断进化,更新能让你用上更酷炫的功能。
  • 性能优化: 新版本往往会修复Bug,提升速度,让你的网站跑得更快更稳。
  • 兼容性: 为了更好地支持新技术和插件,及时更新是必要的。

总而言之,保持WordPress更新,是保证网站健康长寿的关键。

第一幕:_wp_check_for_updates() 函数概览

_wp_check_for_updates()函数是WordPress更新检查的核心,它位于wp-includes/update.php文件中。这个函数主要负责:

  1. 检查WordPress核心是否有更新。
  2. 检查已安装的插件是否有更新。
  3. 检查已安装的主题是否有更新。

它并不是直接检查更新,而是触发一系列操作,最终通过WordPress.org的API获取更新信息。

第二幕:源码解析——核心更新检查

让我们深入代码,看看它是怎么工作的。以下是_wp_check_for_updates()函数的部分代码,为了方便讲解,我做了适当的简化和注释:

function _wp_check_for_updates() {
    // 权限检查,只有管理员才能触发更新检查
    if ( ! current_user_can( 'update_core' ) ) {
        return;
    }

    // 避免重复检查,设置一个transient来限制频率
    if ( get_site_transient( 'update_core' ) ) {
        return;
    }

    // 触发核心更新检查
    wp_version_check();

    // 触发插件更新检查
    wp_update_plugins();

    // 触发主题更新检查
    wp_update_themes();

    // ... 其他操作,如显示更新通知等 ...
}

可以看到,_wp_check_for_updates()首先进行权限检查,确保只有管理员才能执行更新检查。然后,它使用get_site_transient()检查是否已经进行了更新检查。如果已经检查过,为了避免服务器压力,会直接返回。

接下来,它调用了三个重要的函数:wp_version_check()wp_update_plugins()wp_update_themes(),分别负责核心、插件和主题的更新检查。

我们先来看看wp_version_check()函数,它负责检查WordPress核心是否有更新。

function wp_version_check() {
    global $wp_version, $wp_local_package;

    // 检查是否有本地包定义,如果有,跳过更新检查
    if ( isset( $wp_local_package ) ) {
        return;
    }

    // 设置更新检查的transient
    set_site_transient( 'update_core', (object) array( 'last_checked' => time() ), 12 * HOUR_IN_SECONDS );

    $options = array(
        'timeout' => ( ( defined( 'DOING_CRON' ) && DOING_CRON ) ? 30 : 3 ), // Cron任务超时时间长一些
        'body' => array(
            'version' => $wp_version,
            'php' => phpversion(),
            'locale' => get_locale(),
            'mysql' => function_exists( 'mysqli_get_server_info' ) ? mysqli_get_server_info( wp_db() ) : 'N/A',
            'blogs' => is_multisite() ? get_blog_count() : 1,
            'users' => function_exists( 'get_user_count' ) ? get_user_count() : 1,
            'multisite_enabled' => is_multisite(),
            'initial_db_version' => get_site_option( 'initial_db_version' ),
            'wp_install' => ( ! is_multisite() && defined( 'WP_INSTALLING' ) && WP_INSTALLING ) ? '1' : '0',
        ),
        'user-agent' => 'WordPress/' . $wp_version . '; ' . get_bloginfo( 'url' )
    );

    // 使用 wp_remote_post 向 WordPress.org 发送请求
    $response = wp_remote_post( 'https://api.wordpress.org/core/version-check/1.7/', $options );

    // 处理响应
    if ( is_wp_error( $response ) ) {
        return false;
    }

    $body = wp_remote_retrieve_body( $response );

    if ( $body ) {
        $update_data = json_decode( $body );

        if ( is_object( $update_data ) ) {
            // 将更新数据保存到 transient 中
            set_site_transient( 'update_core', $update_data, 12 * HOUR_IN_SECONDS );
        }
    }

    return true;
}

这个函数做了以下几件事:

  1. 检查本地包: 如果定义了本地包,说明使用的是自定义的WordPress版本,跳过更新检查。
  2. 设置Transient: 使用set_site_transient()设置一个Transient,防止频繁检查更新。
  3. 构建请求: 构建一个包含WordPress版本、PHP版本、语言区域等信息的数组,作为POST请求的body。
  4. 发送请求: 使用wp_remote_post()函数向https://api.wordpress.org/core/version-check/1.7/发送POST请求,获取更新信息。
  5. 处理响应: 解析返回的JSON数据,将更新信息保存到Transient中,以便后续使用。

表格:wp_version_check() 函数请求参数

参数名称 描述
version 当前 WordPress 版本
php PHP 版本
locale WordPress 语言区域设置 (如:zh_CN)
mysql MySQL 版本
blogs 如果是多站点,则为博客数量,否则为 1
users 用户数量
multisite_enabled 是否启用多站点
initial_db_version 初始数据库版本
wp_install 如果正在安装 WordPress (非多站点),则为 1,否则为 0。 这参数只会在 WordPress 首次安装时发送,帮助 WordPress.org 了解新安装的情况。

第三幕:源码解析——插件更新检查

接下来,我们看看wp_update_plugins()函数,它负责检查插件是否有更新。

function wp_update_plugins() {
    if ( ! current_user_can( 'update_plugins' ) ) {
        return;
    }

    $plugins = get_plugins(); // 获取所有已安装的插件信息
    $active  = get_option( 'active_plugins', array() ); // 获取所有激活的插件

    $current = get_site_transient( 'update_plugins' );
    if ( isset( $current->last_checked ) && 12 * HOUR_IN_SECONDS > ( time() - $current->last_checked ) ) {
        return;
    }

    $all_plugins = array();

    // 遍历所有插件,构建请求数据
    foreach ( $plugins as $plugin_file => $plugin_data ) {
        $all_plugins[ $plugin_file ] = _get_plugin_data_markup_translate( $plugin_file, $plugin_data );
    }

    $options = array(
        'timeout' => ( ( defined( 'DOING_CRON' ) && DOING_CRON ) ? 30 : 3 ),
        'body' => array(
            'plugins' => wp_json_encode( $all_plugins ), // 将插件信息编码为 JSON
            'active'  => wp_json_encode( $active ),    // 将激活的插件信息编码为 JSON
            'locale'  => get_locale(),
            'version' => $GLOBALS['wp_version'],
        ),
        'user-agent' => 'WordPress/' . $GLOBALS['wp_version'] . '; ' . get_bloginfo( 'url' )
    );

    // 发送请求到 WordPress.org
    $response = wp_remote_post( 'https://api.wordpress.org/plugins/update-check/1.1/', $options );

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

    $body = wp_remote_retrieve_body( $response );

    if ( $body ) {
        $update_data = json_decode( $body );

        if ( is_object( $update_data ) ) {
            // 更新插件信息
            set_site_transient( 'update_plugins', $update_data, 12 * HOUR_IN_SECONDS );
        }
    }

    return true;
}

wp_update_plugins()函数的工作流程如下:

  1. 权限检查: 确保当前用户有更新插件的权限。
  2. 获取插件信息: 使用get_plugins()函数获取所有已安装的插件信息,get_option( 'active_plugins' )获取激活的插件列表。
  3. 检查Transient: 检查是否已经进行了更新检查。
  4. 构建请求数据: 遍历所有插件,构建包含插件信息的数组,然后将数组编码为JSON格式。
  5. 发送请求: 使用wp_remote_post()函数向https://api.wordpress.org/plugins/update-check/1.1/发送POST请求,获取插件更新信息。
  6. 处理响应: 解析返回的JSON数据,将更新信息保存到Transient中。

表格:wp_update_plugins() 函数请求参数

参数名称 描述
plugins 一个 JSON 编码的数组,包含所有已安装插件的信息,每个插件的信息包括插件名称、版本、作者等。
active 一个 JSON 编码的数组,包含所有已激活插件的文件名。
locale WordPress 语言区域设置 (如:zh_CN)
version 当前 WordPress 版本

第四幕:源码解析——主题更新检查

最后,我们来看看wp_update_themes()函数,它负责检查主题是否有更新。

function wp_update_themes() {
    if ( ! current_user_can( 'update_themes' ) ) {
        return;
    }

    $themes = wp_get_themes(); // 获取所有已安装的主题信息

    $current = get_site_transient( 'update_themes' );
    if ( isset( $current->last_checked ) && 12 * HOUR_IN_SECONDS > ( time() - $current->last_checked ) ) {
        return;
    }

    $all_themes = array();

    // 构建请求数据
    foreach ( $themes as $stylesheet => $theme ) {
        $all_themes[ $stylesheet ] = array(
            'name'       => $theme->get( 'Name' ),
            'version'    => $theme->get( 'Version' ),
            'author'     => $theme->get( 'Author' ),
            'template'   => $theme->get_template(),
            'stylesheet' => $theme->get_stylesheet(),
        );
    }

    $options = array(
        'timeout' => ( ( defined( 'DOING_CRON' ) && DOING_CRON ) ? 30 : 3 ),
        'body' => array(
            'themes'  => wp_json_encode( $all_themes ), // 将主题信息编码为 JSON
            'locale'  => get_locale(),
            'version' => $GLOBALS['wp_version'],
        ),
        'user-agent' => 'WordPress/' . $GLOBALS['wp_version'] . '; ' . get_bloginfo( 'url' )
    );

    // 发送请求到 WordPress.org
    $response = wp_remote_post( 'https://api.wordpress.org/themes/update-check/1.1/', $options );

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

    $body = wp_remote_retrieve_body( $response );

    if ( $body ) {
        $update_data = json_decode( $body );

        if ( is_object( $update_data ) ) {
            // 更新主题信息
            set_site_transient( 'update_themes', $update_data, 12 * HOUR_IN_SECONDS );
        }
    }

    return true;
}

wp_update_themes()函数的工作流程与wp_update_plugins()类似:

  1. 权限检查: 确保当前用户有更新主题的权限。
  2. 获取主题信息: 使用wp_get_themes()函数获取所有已安装的主题信息。
  3. 检查Transient: 检查是否已经进行了更新检查。
  4. 构建请求数据: 遍历所有主题,构建包含主题信息的数组,然后将数组编码为JSON格式。
  5. 发送请求: 使用wp_remote_post()函数向https://api.wordpress.org/themes/update-check/1.1/发送POST请求,获取主题更新信息。
  6. 处理响应: 解析返回的JSON数据,将更新信息保存到Transient中。

表格:wp_update_themes() 函数请求参数

参数名称 描述
themes 一个 JSON 编码的数组,包含所有已安装主题的信息,每个主题的信息包括主题名称、版本、作者、模板目录和样式表目录。
locale WordPress 语言区域设置 (如:zh_CN)
version 当前 WordPress 版本

第五幕:Transient 的作用

在上述三个函数中,都用到了get_site_transient()set_site_transient()函数。Transient API是WordPress提供的一种缓存机制,用于临时存储数据。在这里,它的作用是:

  • 防止频繁检查更新: 通过设置一个Transient,可以限制更新检查的频率,避免对WordPress.org服务器造成过大的压力,也减少了自身服务器的资源消耗。
  • 缓存更新信息: 将从WordPress.org获取的更新信息保存到Transient中,方便后续使用,避免重复请求。

Transient类似于一个带过期时间的option,可以设置过期时间,过期后会自动删除。

第六幕:总结与思考

_wp_check_for_updates()函数通过调用wp_version_check()wp_update_plugins()wp_update_themes(),分别检查核心、插件和主题的更新。这些函数都使用了wp_remote_post()函数向WordPress.org发送请求,获取更新信息,并将更新信息保存到Transient中。

整个更新检查机制的设计思路是:

  • 集中管理: 通过一个函数统一管理更新检查。
  • 权限控制: 只有管理员才能触发更新检查。
  • 频率限制: 使用Transient API限制更新检查的频率。
  • 远程获取: 通过API从WordPress.org获取更新信息。
  • 缓存优化: 使用Transient API缓存更新信息,减少重复请求。

一些可以深入思考的问题:

  1. 安全性: 如何保证从WordPress.org获取的更新信息的安全性?
  2. 性能优化: 除了Transient API,还有哪些可以用来优化更新检查的性能?
  3. 自定义更新: 如何实现自定义的更新检查机制,例如检查自定义插件或主题的更新?
  4. 错误处理: 如果与 WordPress.org 的连接失败,如何优雅地处理错误,避免影响用户体验?

结尾:保持更新,远离Bug!

好了,今天的讲座就到这里。希望通过这次深入的源码解析,大家对WordPress的更新机制有了更清晰的了解。记住,保持WordPress核心、插件和主题的更新,是保证网站安全、稳定和高效的关键。下次再见!

发表回复

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