详解 WordPress `wp_update_plugins()` 和 `wp_update_themes()` 函数的源码:它们如何处理插件和主题的更新。

大家好,我是你们今天的WordPress更新函数源码剖析讲师,咱们今天不讲虚的,直接上干货,带大家一起扒一扒WordPress的wp_update_plugins()wp_update_themes()这两个“更新小能手”的底裤。

开场白:更新的艺术,远不止点个按钮那么简单

咱们平时用WordPress,点一下“更新”按钮,插件或者主题就乖乖升级了,感觉一切都很简单。但你知道背后发生了什么吗?wp_update_plugins()wp_update_themes()这两个函数就是幕后英雄,它们负责检查更新、下载新版本、解压安装,然后默默地守护着你的网站安全。

第一部分: wp_update_plugins() – 插件更新的秘密

wp_update_plugins()函数位于/wp-admin/includes/update.php文件中,它的主要职责是更新插件。

1. 初始准备:检查权限和环境

首先,函数会检查当前用户是否有权限更新插件。毕竟,不能让随便什么人都能“动手动脚”嘛。

function wp_update_plugins() {
    include_once ABSPATH . 'wp-admin/includes/plugin.php'; // 加载插件管理函数
    include_once ABSPATH . 'wp-admin/includes/update.php'; // 确保更新函数可用

    if ( ! current_user_can( 'update_plugins' ) ) {
        wp_die(
            sprintf(
                '<h1>%1$s</h1><p>%2$s</p>',
                __( 'Cheatin’ uh?' ),
                __( 'You do not have sufficient permissions to update plugins for this site.' )
            ),
            403
        );
    }

    // 检查是否禁用文件编辑
    if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
        wp_die( __( 'File modifications are disabled.' ) );
    }

    // 检查是否安装了WordPress文件系统抽象层 (Filesystem API)
    $wp_filesystem = WP_Filesystem(); // 初始化文件系统
    if ( ! $wp_filesystem ) {
        return false; // 如果初始化失败,则返回false
    }

    // ... 更多代码
}

这段代码做了几件事:

  • 加载依赖文件: 确保plugin.phpupdate.php中的函数可用。
  • 权限检查: current_user_can( 'update_plugins' )检查当前用户是否拥有update_plugins权限。如果没权限,直接报错,不给更新。
  • 禁用文件修改检查: DISALLOW_FILE_MODS常量如果被定义为true,说明网站管理员禁止了文件修改,这时候也无法更新。
  • 文件系统API检查: WP_Filesystem()函数初始化WordPress的文件系统API。如果初始化失败(比如权限问题),更新也会失败。

2. 获取插件更新信息:从哪里知道有更新?

接下来,wp_update_plugins()会获取插件的更新信息。这个信息通常来自WordPress.org官方插件仓库,或者你自己搭建的私有仓库(如果你有的话)。

    $current = get_site_transient( 'update_plugins' );

    if ( ! isset( $current->response ) || ! is_array( $current->response ) ) {
        $current->response = array();
    }

    $plugins = isset( $_POST['plugins'] ) ? (array) $_POST['plugins'] : array();

    // ... 更多代码

这里:

  • get_site_transient( 'update_plugins' ) 从数据库中获取缓存的插件更新信息。这个信息包含了哪些插件需要更新,以及新版本的下载地址等。
  • $_POST['plugins']: 客户端(通常是WordPress后台)通过POST请求传递要更新的插件列表。

3. 开始更新循环:一个一个来,排队升级

现在,有了需要更新的插件列表,就可以开始逐个更新了。

    $errors   = array();
    $results  = array();

    set_time_limit( 300 ); // 增加执行时间限制

    foreach ( $plugins as $plugin ) {
        $result = wp_update_plugin( $plugin ); // 调用wp_update_plugin函数更新单个插件

        if ( is_wp_error( $result ) ) {
            $errors[ $plugin ] = $result;
        } else {
            $results[ $plugin ] = true;
        }
    }

    // ... 更多代码
  • 循环更新: foreach循环遍历需要更新的插件。
  • 单个插件更新: wp_update_plugin( $plugin )函数负责更新单个插件。这个函数才是真正的“干活的”。
  • 错误处理: 如果更新过程中出现错误,is_wp_error( $result )会检测到,并将错误信息记录下来。

4. wp_update_plugin():单个插件更新的流程

wp_update_plugin()函数是更新单个插件的核心。

function wp_update_plugin( $plugin ) {
    include_once ABSPATH . 'wp-admin/includes/file.php'; // 文件操作函数
    include_once ABSPATH . 'wp-admin/includes/plugin.php'; // 插件管理函数

    $current = get_site_transient( 'update_plugins' );
    if ( ! isset( $current->response[ $plugin ] ) ) {
        return new WP_Error( 'no_update', __( 'No update available.' ) );
    }

    $r = $current->response[ $plugin ];

    $skin     = new Automatic_Upgrader_Skin(); // 使用自动升级皮肤
    $upgrader = new Plugin_Upgrader( $skin ); // 创建插件升级器对象

    $result = $upgrader->upgrade( $plugin, array(
        'clear_update_cache' => false, // 不清除更新缓存,因为可能还有其他插件需要更新
    ) );

    if ( is_wp_error( $result ) ) {
        return $result;
    } elseif ( $result ) {
        // 插件更新成功后,清除插件缓存
        clean_plugins_cache();
    }

    return true;
}
  • 检查更新信息: 确保该插件确实有更新可用。
  • 创建升级器: Plugin_Upgrader类负责处理插件的下载、解压、安装等操作。
  • 开始升级: $upgrader->upgrade( $plugin )执行升级操作。
  • 清理缓存: clean_plugins_cache()清除插件缓存,确保WordPress能正确识别新版本。

5. Plugin_Upgrader::upgrade():升级的细节

Plugin_Upgrader::upgrade()函数是插件升级的关键。它会:

  1. 备份插件: (如果需要)在升级前备份旧版本的插件,以防万一。
  2. 下载新版本: 从更新服务器下载新版本的插件压缩包。
  3. 解压插件: 将压缩包解压到临时目录。
  4. 停用插件: 停用旧版本的插件。
  5. 删除旧版本: 删除旧版本的插件目录。
  6. 移动新版本: 将解压后的新版本插件移动到插件目录。
  7. 启用插件: 重新启用插件。
  8. 清理临时文件: 删除临时文件。

这个过程涉及到很多文件操作,如果权限不足或者文件系统出现问题,升级就会失败。

第二部分: wp_update_themes() – 主题更新的艺术

wp_update_themes()函数位于/wp-admin/includes/update.php文件中,它的作用和wp_update_plugins()类似,只不过是负责更新主题。

1. 初始准备:检查权限和环境

和更新插件一样,更新主题也需要权限。

function wp_update_themes() {
    include_once ABSPATH . 'wp-admin/includes/theme.php'; // 加载主题管理函数
    include_once ABSPATH . 'wp-admin/includes/update.php'; // 确保更新函数可用

    if ( ! current_user_can( 'update_themes' ) ) {
        wp_die(
            sprintf(
                '<h1>%1$s</h1><p>%2$s</p>',
                __( 'Cheatin’ uh?' ),
                __( 'You do not have sufficient permissions to update themes for this site.' )
            ),
            403
        );
    }

    // 检查是否禁用文件编辑
    if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
        wp_die( __( 'File modifications are disabled.' ) );
    }

    // 检查是否安装了WordPress文件系统抽象层 (Filesystem API)
    $wp_filesystem = WP_Filesystem();
    if ( ! $wp_filesystem ) {
        return false;
    }

    // ... 更多代码
}

这段代码和wp_update_plugins()的初始准备几乎一样,只是权限检查变成了current_user_can( 'update_themes' )

2. 获取主题更新信息

wp_update_themes()会从数据库中获取缓存的主题更新信息。

    $current = get_site_transient( 'update_themes' );

    if ( ! isset( $current->response ) || ! is_array( $current->response ) ) {
        $current->response = array();
    }

    $themes = isset( $_POST['themes'] ) ? (array) $_POST['themes'] : array();

    // ... 更多代码
  • get_site_transient( 'update_themes' ):获取缓存的主题更新信息。
  • $_POST['themes']:客户端传递要更新的主题列表。

3. 开始更新循环

    $errors   = array();
    $results  = array();

    set_time_limit( 300 );

    foreach ( $themes as $theme ) {
        $result = wp_update_theme( $theme ); // 调用wp_update_theme更新单个主题

        if ( is_wp_error( $result ) ) {
            $errors[ $theme ] = $result;
        } else {
            $results[ $theme ] = true;
        }
    }

    // ... 更多代码
  • 循环更新: 遍历要更新的主题。
  • 单个主题更新: wp_update_theme( $theme )负责更新单个主题。
  • 错误处理: 记录更新过程中出现的错误。

4. wp_update_theme():单个主题更新的流程

function wp_update_theme( $theme ) {
    include_once ABSPATH . 'wp-admin/includes/file.php'; // 文件操作函数
    include_once ABSPATH . 'wp-admin/includes/theme.php'; // 主题管理函数

    $current = get_site_transient( 'update_themes' );
    if ( ! isset( $current->response[ $theme ] ) ) {
        return new WP_Error( 'no_update', __( 'No update available.' ) );
    }

    $r = $current->response[ $theme ];

    $skin     = new Automatic_Upgrader_Skin(); // 使用自动升级皮肤
    $upgrader = new Theme_Upgrader( $skin ); // 创建主题升级器对象

    $result = $upgrader->upgrade( $theme, array(
        'clear_update_cache' => false, // 不清除缓存,因为可能还有其他主题需要更新
    ) );

    if ( is_wp_error( $result ) ) {
        return $result;
    } elseif ( $result ) {
        // 主题更新成功后,清除主题缓存
        clean_theme_cache();
    }

    return true;
}
  • 检查更新信息: 确保该主题确实有更新可用。
  • 创建升级器: Theme_Upgrader类负责处理主题的下载、解压、安装等操作。
  • 开始升级: $upgrader->upgrade( $theme )执行升级操作。
  • 清理缓存: clean_theme_cache()清除主题缓存。

5. Theme_Upgrader::upgrade():升级的细节

Theme_Upgrader::upgrade()函数的流程和Plugin_Upgrader::upgrade()非常相似:

  1. 备份主题: (如果需要)备份旧版本的主题。
  2. 下载新版本: 从更新服务器下载新版本的主题压缩包。
  3. 解压主题: 将压缩包解压到临时目录。
  4. 删除旧版本: 删除旧版本的主题目录。
  5. 移动新版本: 将解压后的新版本主题移动到主题目录。
  6. 清理临时文件: 删除临时文件。

第三部分:一些关键的类和函数

咱们来总结一下,在插件和主题更新过程中,几个关键的类和函数:

类/函数 作用
WP_Filesystem() WordPress文件系统API,用于文件操作,例如读取、写入、删除文件。
get_site_transient() 从数据库中获取瞬态数据(transient),瞬态数据是临时存储的数据,用于缓存更新信息等。
Plugin_Upgrader 插件升级器类,负责处理插件的下载、解压、安装等操作。
Theme_Upgrader 主题升级器类,负责处理主题的下载、解压、安装等操作。
Automatic_Upgrader_Skin 自动升级皮肤类,用于在后台显示升级过程的信息,例如下载进度、解压进度等。
wp_update_plugin() 更新单个插件的函数。
wp_update_theme() 更新单个主题的函数。
clean_plugins_cache() 清除插件缓存,确保WordPress能正确识别新版本。
clean_theme_cache() 清除主题缓存,确保WordPress能正确识别新版本。

第四部分:常见问题和注意事项

  • 权限问题: 更新插件和主题需要服务器有足够的权限。如果权限不足,可能会导致更新失败。
  • 文件系统问题: 如果服务器的文件系统出现问题,例如磁盘空间不足、文件损坏等,也可能导致更新失败。
  • 兼容性问题: 新版本的插件或主题可能与你的WordPress版本或其他插件不兼容。在更新之前,最好先备份网站,以防万一。
  • 缓存问题: 有时候,即使插件或主题已经更新成功,WordPress仍然显示旧版本。这时候,可以尝试清除缓存。
  • 网络问题: 下载新版本的插件或主题需要连接到更新服务器。如果网络连接不稳定,可能会导致下载失败。
  • 更新失败后的处理: 如果更新失败,不要慌张。首先查看错误日志,找到错误原因。然后,可以尝试手动更新,或者恢复备份。

总结:更新虽易,理解不易,且行且珍惜

wp_update_plugins()wp_update_themes()这两个函数,看似简单,背后却隐藏着复杂的逻辑。理解它们的源码,可以帮助我们更好地理解WordPress的更新机制,解决更新过程中遇到的问题,甚至可以自定义更新流程。

希望今天的讲解对大家有所帮助。记住,更新有风险,操作需谨慎!在更新之前,一定要备份网站!备份!备份!重要的事情说三遍。

今天就到这里,下课!

发表回复

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