剖析 WordPress `wp_delete_user()` 函数的源码:如何处理用户删除并清理相关数据。

各位观众老爷,咳咳,不好意思,串台了。各位WordPress开发者们,大家好!今天咱们来聊聊WordPress里一个相当重要,但又容易被忽视的函数:wp_delete_user()。这玩意儿可不是简简单单地把用户从数据库里咔嚓掉,它背后隐藏着一系列复杂的操作,稍有不慎就会造成数据丢失或者系统异常。

咱们今天的讲座就围绕着这个wp_delete_user(),由浅入深,扒一扒它的底裤,看看它到底是怎么运作的,以及在使用它的时候需要注意哪些坑。

一、wp_delete_user():你的“抹布”工程师

顾名思义,wp_delete_user()的作用就是删除用户。但它不仅仅是删除用户表里的记录,更重要的是清理与该用户相关联的各种数据,比如文章、评论、自定义字段等等。你可以把它想象成一个专业的“抹布”工程师,不仅要把用户擦掉,还要把用户留下的痕迹清理干净。

二、wp_delete_user() 的源码剖析:一步一步揭开它的面纱

咱们直接上代码,看看wp_delete_user()到底长啥样:

/**
 * Deletes a user from the database.
 *
 * @since 2.0.0
 *
 * @param int    $id              The user ID.
 * @param int    $reassign        Optional. Reassign posts and links to this user ID.
 *                                 Default is null, which means posts and links will be deleted.
 * @param bool   $force_reassign  Optional. Whether to bypass trash and force reassign posts and links to the
 *                                 user ID. Default is false.
 * @return bool|false True on success, false on failure.
 */
function wp_delete_user( $id, $reassign = null, $force_reassign = false ) {
    global $wpdb;

    $id = (int) $id;

    if ( ! get_userdata( $id ) ) {
        return false;
    }

    if ( ! current_user_can( 'delete_user', $id ) ) {
        return false;
    }

    /**
     * Fires before a user is deleted from the database.
     *
     * @since 2.0.0
     *
     * @param int $id ID of the user to delete.
     */
    do_action( 'delete_user', $id );

    $reassign = false === $reassign ? null : (int) $reassign;

    if ( null === $reassign ) {
        /**
         * Fires before the posts of a user are deleted.
         *
         * @since 2.9.0
         *
         * @param int $id ID of the user to delete.
         */
        do_action( 'delete_user_posts', $id );

        $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $id ) );

        if ( $post_ids ) {
            foreach ( $post_ids as $post_id ) {
                wp_delete_post( $post_id, true ); // Forcibly delete the post.
            }
        }
    } else {
        if ( ! get_userdata( $reassign ) ) {
            return false;
        }

        /**
         * Fires before the posts of a user are reassigned.
         *
         * @since 2.9.0
         *
         * @param int $id         ID of the user to delete.
         * @param int $reassign ID of the user to reassign posts to.
         */
        do_action( 'reassign_user_posts', $id, $reassign );

        $wpdb->update( $wpdb->posts, array( 'post_author' => $reassign ), array( 'post_author' => $id ) );

        // Clean the cache to remove any lingering data from the deleted user.
        clean_user_cache( $id );
    }

    // Delete user meta.
    delete_metadata( 'user', $id, '', '', true );

    // Delete user from usermeta table.
    $wpdb->delete( $wpdb->usermeta, array( 'user_id' => $id ) );

    // Finally, delete user from users table.
    $wpdb->delete( $wpdb->users, array( 'ID' => $id ) );

    wp_cache_delete_multiple(
        array(
            "user_caps_{$id}",
            "user_level_{$id}",
            "user_roles_{$id}",
            "user_plugins_{$id}",
        ),
        'users'
    );

    clean_user_cache( $id );

    wp_clear_auth_cookie();

    /**
     * Fires after a user is deleted from the database.
     *
     * @since 2.0.0
     *
     * @param int $id ID of the deleted user.
     */
    do_action( 'deleted_user', $id );

    return true;
}

咱们把这段代码拆开来,一步一步分析:

  1. 参数校验和权限检查:

    $id = (int) $id;
    
    if ( ! get_userdata( $id ) ) {
        return false;
    }
    
    if ( ! current_user_can( 'delete_user', $id ) ) {
        return false;
    }
    • 首先,把传入的用户ID $id 强制转换为整数,防止注入攻击。
    • 然后,使用 get_userdata() 检查该用户是否存在。如果不存在,直接返回 false,告诉你:老铁,查无此人!
    • 接下来,使用 current_user_can( 'delete_user', $id ) 检查当前用户是否有权限删除目标用户。如果没有权限,也返回 false,告诉你:没门儿!
  2. delete_user Action:

    /**
     * Fires before a user is deleted from the database.
     *
     * @since 2.0.0
     *
     * @param int $id ID of the user to delete.
     */
    do_action( 'delete_user', $id );

    在删除用户之前,触发 delete_user 这个 Action。这允许其他插件或者主题在用户删除之前执行一些自定义的操作,比如发送邮件通知、记录日志等等。这是一个很好的扩展点。

  3. 处理用户文章:删除还是转移?

    $reassign = false === $reassign ? null : (int) $reassign;
    
    if ( null === $reassign ) {
        /**
         * Fires before the posts of a user are deleted.
         *
         * @since 2.9.0
         *
         * @param int $id ID of the user to delete.
         */
        do_action( 'delete_user_posts', $id );
    
        $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $id ) );
    
        if ( $post_ids ) {
            foreach ( $post_ids as $post_id ) {
                wp_delete_post( $post_id, true ); // Forcibly delete the post.
            }
        }
    } else {
        if ( ! get_userdata( $reassign ) ) {
            return false;
        }
    
        /**
         * Fires before the posts of a user are reassigned.
         *
         * @since 2.9.0
         *
         * @param int $id         ID of the user to delete.
         * @param int $reassign ID of the user to reassign posts to.
         */
        do_action( 'reassign_user_posts', $id, $reassign );
    
        $wpdb->update( $wpdb->posts, array( 'post_author' => $reassign ), array( 'post_author' => $id ) );
    
        // Clean the cache to remove any lingering data from the deleted user.
        clean_user_cache( $id );
    }
    • 这里是整个函数的核心部分,决定了如何处理被删除用户的文章。
    • $reassign 参数决定了文章的处理方式:
      • 如果 $reassignnull (默认值),表示删除该用户的所有文章。
      • 如果 $reassign 为一个有效的用户ID,表示将该用户的所有文章转移到指定的 $reassign 用户名下。
    • 删除文章:
      • 触发 delete_user_posts Action。
      • 使用 $wpdb->get_col() 查询出该用户的所有文章ID。
      • 循环遍历所有文章ID,使用 wp_delete_post( $post_id, true ) 强制删除文章。注意这里的 true 参数,表示强制删除,不放入回收站。
    • 转移文章:
      • 首先,检查 $reassign 用户ID 是否有效。
      • 触发 reassign_user_posts Action。
      • 使用 $wpdb->update() 更新 wp_posts 表,将所有 post_author$id 的文章的 post_author 字段更新为 $reassign
      • 调用 clean_user_cache( $id ) 清理用户缓存。
  4. 清理用户元数据 (User Meta):

    // Delete user meta.
    delete_metadata( 'user', $id, '', '', true );

    使用 delete_metadata() 函数删除与该用户相关联的所有用户元数据。delete_metadata() 函数的第五个参数 true 表示删除所有与该用户ID 关联的元数据,而不管 meta_key 是什么。

  5. 删除 wp_usermeta 表中的记录:

    // Delete user from usermeta table.
    $wpdb->delete( $wpdb->usermeta, array( 'user_id' => $id ) );

    使用 $wpdb->delete() 删除 wp_usermeta 表中 user_id$id 的所有记录。

  6. 删除 wp_users 表中的记录:

    // Finally, delete user from users table.
    $wpdb->delete( $wpdb->users, array( 'ID' => $id ) );

    使用 $wpdb->delete() 删除 wp_users 表中 ID$id 的记录。 这是最后一步,真正把用户从用户表中抹去。

  7. 清理用户缓存:

    wp_cache_delete_multiple(
        array(
            "user_caps_{$id}",
            "user_level_{$id}",
            "user_roles_{$id}",
            "user_plugins_{$id}",
        ),
        'users'
    );
    
    clean_user_cache( $id );

    删除与用户相关的缓存,确保下次访问时不会加载到旧数据。这包括用户权限、等级、角色和插件等信息的缓存。

  8. 清除认证 Cookie:

    wp_clear_auth_cookie();

    清除用户的认证cookie,使其退出登录

  9. deleted_user Action:

    /**
     * Fires after a user is deleted from the database.
     *
     * @since 2.0.0
     *
     * @param int $id ID of the deleted user.
     */
    do_action( 'deleted_user', $id );
    
    return true;

    在用户删除之后,触发 deleted_user Action。这允许其他插件或者主题在用户删除之后执行一些自定义的操作,比如更新统计数据等等。

三、wp_delete_user() 的参数详解

参数名 类型 描述 默认值
$id int 要删除的用户ID。
$reassign int null 可选。如果设置为一个有效的用户ID,则将要删除用户的文章和链接重新分配给该用户。如果设置为 null,则删除要删除用户的所有文章和链接。 null
$force_reassign bool 可选。是否绕过垃圾箱并强制将文章和链接重新分配给用户 ID。 默认值为 false。 注意: 这个参数在wp_delete_user()源码里并没有使用.而是传递给了wp_delete_post().可以理解成wp_delete_user()函数会根据$reassign来决定是删除文章还是转移文章。如果删除文章,并且$force_reassign为true,那么会强制删除文章不经过回收站。如果转移文章,那么这个参数没有任何作用。 false

四、使用 wp_delete_user() 的注意事项

  1. 权限问题: 确保当前用户有删除目标用户的权限。否则,函数会直接返回 false
  2. 数据丢失: 删除用户意味着删除与该用户相关联的所有数据,包括文章、评论、自定义字段等等。在删除用户之前,务必做好数据备份。
  3. 文章处理: 仔细考虑如何处理被删除用户的文章。如果选择删除文章,请确保已经充分了解 wp_delete_post() 的行为,特别是强制删除参数 true 的影响。如果选择转移文章,请确保 $reassign 参数指定的用户名是有效的。
  4. Hook 的妙用: delete_userdeleted_user 这两个 Action 可以让你在用户删除前后执行一些自定义的操作。利用好这两个 Hook,可以实现很多有用的功能。比如:
    • delete_user Hook 中,可以发送邮件通知管理员。
    • deleted_user Hook 中,可以更新统计数据。
  5. 缓存问题: 删除用户后,务必清理用户缓存,否则可能会出现一些奇怪的问题。wp_delete_user() 已经帮你做了清理缓存的操作,但如果你在自定义的 Hook 中修改了用户数据,可能需要手动清理缓存。
  6. 关联数据: 除了文章和用户元数据,可能还有一些其他表里存储着与用户ID相关联的数据。在删除用户之前,一定要仔细检查这些表,并进行相应的清理操作。例如,某些插件可能会创建额外的表来存储用户相关的统计数据或自定义信息。

五、wp_delete_user() 的实际应用场景

  1. 用户注销: 用户主动注销账号,需要删除用户信息及其相关数据。
  2. 管理员删除用户: 管理员清理不活跃用户或者恶意用户。
  3. 用户数据迁移: 在用户数据迁移的过程中,可能需要先删除旧用户,然后再创建新用户。
  4. 测试环境清理: 在开发和测试环境中,可能需要定期清理用户数据,以便创建一个干净的测试环境。

六、一些小技巧和建议

  • 软删除: 与其直接删除用户,不如考虑使用软删除。软删除是指在用户表中添加一个 deleted 字段,当用户被删除时,只是将该字段设置为 true,而不是真正删除用户记录。这样可以方便地恢复被删除的用户,也可以保留用户的历史数据。
  • 数据备份: 在执行任何删除操作之前,务必做好数据备份。这是保护数据安全的最佳方式。
  • 错误处理: 在使用 wp_delete_user() 时,要做好错误处理。比如,检查函数返回值,判断是否删除成功。如果删除失败,要记录错误日志,方便排查问题。

七、总结

wp_delete_user() 是一个功能强大的函数,但同时也存在一定的风险。在使用它的时候,一定要小心谨慎,充分了解它的行为,做好数据备份,并做好错误处理。只有这样,才能安全地删除用户,并避免数据丢失。

希望今天的讲座能帮助大家更好地理解 wp_delete_user() 函数。如果有什么疑问,欢迎随时提问。 下课!

发表回复

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