剖析 WordPress `wp_delete_user()` 函数源码:删除用户时如何清理所有相关数据(文章、评论等)。

各位靓仔靓女,晚上好!我是你们的老朋友,BUG终结者。今天咱们来聊聊WordPress里一个非常重要的函数:wp_delete_user()。这个函数的作用,简单粗暴地说,就是把一个用户从你的WordPress站点上彻底抹掉,就像 Thanos 打了个响指一样。但是,删除用户可不是简单地把数据库里的一条记录删掉就完事了。用户可能发过文章、写过评论、上传过媒体文件等等,这些数据都和这个用户息息相关。所以,wp_delete_user() 要做的事情,比你想象的要复杂得多。

今天,咱们就来扒一扒 wp_delete_user() 的源码,看看它到底是怎么清理这些乱七八糟的数据的,以及在实际使用中需要注意哪些坑。

一、wp_delete_user() 函数概览

首先,让我们快速浏览一下 wp_delete_user() 函数的基本结构。

/**
 * Removes all data associated with a user.
 *
 * @since 2.0.0
 *
 * @param int    $id              The user ID.
 * @param int    $reassign        Optional. ID of the user to reassign posts and links to.
 *                                Default null.
 * @param string $force_reassign  Optional. Whether to bypass the trash and force the user
 *                                posts and links to be reassigned. Default false.
 *
 * @return bool True on success, false on failure.
 */
function wp_delete_user( $id, $reassign = null, $force_reassign = false ) {
    global $wpdb;

    $id = (int) $id;

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

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

    if ( is_multisite() && ! is_super_admin( $id ) && current_user_can( 'delete_user', $id ) && ! can_edit_user( $id ) ) {
        return false;
    }

    if ( is_multisite() && is_super_admin( $id ) && ! current_user_can( 'delete_network_user', $id ) ) {
        return false;
    }

    if ( empty( $reassign ) ) {
        $reassign = 'null';
    } else {
        $reassign = (int) $reassign;
    }

    if ( $reassign === $id ) {
        return false;
    }

    //... (核心逻辑)

    return true;
}

这个函数接收三个参数:

  • $id:要删除的用户 ID。
  • $reassign:可选参数,指定将要删除用户的文章和链接重新分配给哪个用户。如果为空,则文章和链接会被删除。
  • $force_reassign:可选参数,是否强制重新分配文章和链接,绕过回收站。

二、权限检查:别想随便删人!

在开始删除用户之前,wp_delete_user() 首先会进行一系列的权限检查,确保当前用户有权限删除目标用户。 如果没权限,直接打回!

  • 用户 ID 验证: 先确认 $id 是个数字,并且确实存在对应的用户。
  • 多站点权限: 如果是多站点环境,会检查当前用户是否有权限删除目标用户。超级管理员有最高的权限,但普通用户只能删除自己创建的用户。
  • 非空 reassign 验证: 如果指定了 $reassign,确保它不是要删除的用户本身,不然就自己assign给自己,闹呢?

三、核心逻辑:一步一步清理数据

好了,经过重重关卡,终于到了核心逻辑部分。wp_delete_user() 会按照以下步骤清理数据:

  1. 删除用户的所有文章(Posts): 这是最重要的一步。用户发布的文章可能有很多,需要全部删除或者重新分配。

    if ( 'null' !== $reassign && is_numeric( $reassign ) ) {
        // Reassign posts to another user.
        $wpdb->update( $wpdb->posts, array( 'post_author' => $reassign ), array( 'post_author' => $id ) );
    } else {
        // Delete posts.
        $posts = get_posts( array( 'author' => $id, 'post_type' => 'any', 'post_status' => 'any', 'numberposts' => -1 ) );
        if ( $posts ) {
            foreach ( $posts as $post ) {
                wp_delete_post( $post->ID, true ); // true: bypass trash
            }
        }
    }

    这段代码首先判断是否指定了 $reassign 参数。如果指定了,就将所有属于该用户的文章的 post_author 字段更新为 $reassign 的值,也就是将文章的所有者更改为新的用户。如果未指定 $reassign 参数,则直接删除所有属于该用户的文章。wp_delete_post() 函数用于删除文章,第二个参数 true 表示强制删除,不放入回收站。

    注意: get_posts() 函数的 post_type 参数设置为 'any'post_status 参数设置为 'any',确保可以获取到所有类型的文章,包括草稿、私有文章等。numberposts 设置为 -1 表示获取所有文章,不受数量限制。

    这里有个小技巧,如果你想要把用户的文章放入回收站而不是直接删除,可以将 wp_delete_post() 的第二个参数改为 false

  2. 删除用户的所有链接(Links): 链接功能在 WordPress 中已经不常用了,但为了兼容性,wp_delete_user() 还是会处理用户创建的链接。

    if ( 'null' !== $reassign && is_numeric( $reassign ) ) {
        $wpdb->update( $wpdb->links, array( 'link_owner' => $reassign ), array( 'link_owner' => $id ) );
    } else {
        $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->links WHERE link_owner = %d", $id ) );
    }

    这段代码和删除文章的代码类似,也是先判断是否指定了 $reassign 参数。如果指定了,就将所有属于该用户的链接的 link_owner 字段更新为 $reassign 的值。如果未指定 $reassign 参数,则直接删除所有属于该用户的链接。

  3. 删除用户的所有评论(Comments): 用户发表的评论也需要处理。

    $comments = $wpdb->get_results( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE user_id = %d", $id ) );
    if ( $comments ) {
        foreach ( $comments as $comment ) {
            wp_delete_comment( $comment->comment_ID, true ); // true: force delete
        }
    }

    这段代码首先查询所有属于该用户的评论,然后使用 wp_delete_comment() 函数删除这些评论。第二个参数 true 表示强制删除,不放入回收站。

    注意: 如果你的评论很多,这个过程可能会比较慢。

  4. 删除用户的所有媒体文件(Attachments): 用户上传的媒体文件也需要处理。通常情况下,这些媒体文件会作为文章的附件存在,所以在删除文章的时候就已经被删除了。但是,如果有些媒体文件没有被关联到任何文章,就需要单独处理。

    $attachments = get_posts( array(
        'post_type'   => 'attachment',
        'author'      => $id,
        'numberposts' => -1,
        'post_status' => 'any',
        'fields'      => 'ids',
    ) );
    
    if ( $attachments ) {
        foreach ( $attachments as $attachment_id ) {
            wp_delete_attachment( $attachment_id, true );
        }
    }

    这段代码首先查询所有属于该用户的媒体文件,然后使用 wp_delete_attachment() 函数删除这些媒体文件。第二个参数 true 表示强制删除,不放入回收站。

    注意: 删除媒体文件会同时删除对应的文件存储。

  5. 删除用户的所有自定义字段(Meta): 用户可能有一些自定义字段,也需要删除。

    delete_user_meta( $id );

    delete_user_meta() 函数会删除所有和用户相关的 meta 数据。

  6. 删除用户本身: 最后,删除用户本身。

    $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->users WHERE ID = %d", $id ) );
    $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->usermeta WHERE user_id = %d", $id ) );
    wp_cache_delete( $id, 'users' );
    wp_cache_delete( 'user_login', 'user_' . $user->user_login );
    wp_cache_delete( 'user_email', 'user_' . $user->user_email );
    clean_user_cache( $user );
    
    do_action( 'deleted_user', $id, $reassign );

    这段代码首先从 wp_users 表和 wp_usermeta 表中删除用户的记录,然后清除缓存。最后,触发 deleted_user action,允许其他插件或主题执行一些清理工作。

四、代码示例:如何使用 wp_delete_user()

// 删除用户 ID 为 123 的用户,并将文章重新分配给用户 ID 为 456 的用户
$result = wp_delete_user( 123, 456 );

if ( $result ) {
    echo '用户删除成功!';
} else {
    echo '用户删除失败!';
}

// 删除用户 ID 为 789 的用户,直接删除文章
$result = wp_delete_user( 789 );

if ( $result ) {
    echo '用户删除成功!';
} else {
    echo '用户删除失败!';
}

五、注意事项和常见问题

  • 谨慎操作: wp_delete_user() 函数会永久删除用户及其相关数据,请务必谨慎操作。
  • 备份数据: 在删除用户之前,建议备份数据库,以防万一。
  • 插件冲突: 有些插件可能会修改 wp_delete_user() 函数的行为,导致数据清理不完整。如果遇到问题,可以尝试禁用插件。
  • 大批量删除: 如果需要删除大量用户,建议使用 WP-CLI,它可以更高效地执行批量操作。
  • 自定义数据: 如果你的主题或插件使用了自定义的数据库表来存储用户数据,需要在 deleted_user action 中手动清理这些数据。

六、深入解析:deleted_user Action

deleted_user action 是一个非常重要的钩子,它允许你在用户删除后执行一些自定义的操作。比如,你可以使用这个钩子来清理和用户相关的自定义数据,或者发送邮件通知管理员。

add_action( 'deleted_user', 'my_custom_user_deletion_cleanup', 10, 2 );

function my_custom_user_deletion_cleanup( $user_id, $reassign ) {
    // 清理和用户相关的自定义数据
    global $wpdb;
    $wpdb->query( $wpdb->prepare( "DELETE FROM my_custom_table WHERE user_id = %d", $user_id ) );

    // 发送邮件通知管理员
    $to = '[email protected]';
    $subject = '用户已删除';
    $message = "用户 ID 为 {$user_id} 的用户已被删除。";
    wp_mail( $to, $subject, $message );
}

七、总结:wp_delete_user() 的职责

清理对象 清理方式
文章 (Posts) 如果 $reassign 有值,更新 post_author 字段,否则使用 wp_delete_post() 函数删除文章。
链接 (Links) 如果 $reassign 有值,更新 link_owner 字段,否则直接删除链接。
评论 (Comments) 使用 wp_delete_comment() 函数删除评论。
媒体文件 (Attachments) 使用 wp_delete_attachment() 函数删除媒体文件。
用户 Meta 使用 delete_user_meta() 函数删除所有用户 Meta 数据。
用户记录 wp_userswp_usermeta 表中删除用户记录。
缓存 清除用户缓存。
钩子 (Hooks) 触发 deleted_user action。

总而言之,wp_delete_user() 函数的任务就是彻底地清理和用户相关的所有数据,确保不会留下任何残留。虽然这个过程看似简单,但实际上涉及到很多细节。只有深入理解了 wp_delete_user() 的源码,才能更好地使用它,避免出现数据丢失或者清理不完整的问题。

好了,今天的分享就到这里。希望通过今天的讲解,大家对 wp_delete_user() 函数有了更深入的了解。记住,删除用户需谨慎,备份数据是王道!下次再见!

发表回复

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