WordPress 用户查询的秘密:get_users()
和 WP_User_Query
联袂演出
大家好,我是今天的讲师,人称“代码界的包打听”。今天我们要聊聊 WordPress 里一个看似简单,实则暗藏玄机的函数:get_users()
。别看它名字朴实无华,背后可是站着一位实力派演员——WP_User_Query
。
我们要搞清楚,get_users()
并不是单打独斗,它只是 WP_User_Query
的一个便捷接口。就像你在餐厅点菜,服务员(get_users()
)帮你把菜单(参数)告诉厨房(WP_User_Query
),然后把做好的菜(用户列表)端给你。
所以,要彻底理解用户查询,咱们必须深入 WP_User_Query
的源码,看看它是如何把各种筛选条件变成 SQL 查询语句,最终从数据库里捞出我们想要的用户。
get_users()
:友好的前端
先来简单回顾一下 get_users()
的用法。它接受一个数组作为参数,这个数组里可以包含各种筛选条件,比如角色、ID、用户名等等。
$args = array(
'role' => 'editor', // 只获取编辑
'number' => 10, // 最多获取 10 个用户
'orderby' => 'registered', // 按注册时间排序
'order' => 'ASC', // 升序排列
);
$editors = get_users( $args );
foreach ( $editors as $editor ) {
echo $editor->user_login . '<br>';
}
这段代码非常简单,它会获取 10 个注册时间最早的编辑,并输出他们的用户名。 那么,get_users()
内部到底发生了什么呢?
实际上,get_users()
做的主要就是两个事情:
- 实例化
WP_User_Query
对象: 它把我们传入的参数传递给WP_User_Query
的构造函数。 - 返回查询结果: 调用
WP_User_Query
对象的get_results()
方法,获取查询到的用户对象列表。
可以用下面的伪代码来表示:
function get_users( $args = array() ) {
$user_query = new WP_User_Query( $args );
return $user_query->get_results();
}
所以,真正的幕后英雄是 WP_User_Query
。接下来,让我们深入剖析这个类。
WP_User_Query
:幕后英雄的自我修养
WP_User_Query
类负责构建和执行用户查询。它的主要任务包括:
- 解析查询参数: 接收并处理各种查询参数,比如角色、ID、用户名等等。
- 构建 SQL 查询语句: 根据解析后的参数,动态构建 SQL 查询语句。
- 执行查询: 连接数据库,执行 SQL 查询语句。
- 返回查询结果: 将查询结果转换成用户对象列表。
让我们从 WP_User_Query
的构造函数开始,一步步揭开它的神秘面纱。
构造函数:接收参数,初始化变量
public function __construct( $query = null ) {
$this->query_vars_defaults = array(
'blog_id' => get_current_blog_id(),
'role' => '',
'role__in' => array(),
'role__not_in' => array(),
'meta_key' => '',
'meta_value' => '',
'meta_compare' => '',
'meta_query' => array(),
'date_query' => null,
'who' => '',
'search' => '',
'search_columns' => array(),
'include' => array(),
'exclude' => array(),
'orderby' => 'login',
'order' => 'ASC',
'offset' => '',
'number' => '',
'paged' => 1,
'count_total' => true,
'fields' => 'all',
'has_published_posts' => null,
'nicename' => '',
'nicename__in' => array(),
'nicename__not_in' => array(),
);
$this->query_vars = $this->query_vars_defaults;
if ( ! empty( $query ) ) {
$this->query( $query );
}
}
构造函数主要做了三件事:
- 定义默认查询参数:
$this->query_vars_defaults
定义了所有可能的查询参数及其默认值。 这些参数涵盖了用户查询的方方面面,从角色到排序方式,从数量限制到分页等等。 - 初始化查询参数:
$this->query_vars
是实际使用的查询参数,初始值等于默认参数。 - 调用
query()
方法: 如果传入了查询参数,就调用query()
方法来解析这些参数。
query()
方法:参数解析的核心
query()
方法是 WP_User_Query
的核心方法之一。它负责解析传入的查询参数,并根据这些参数来构建 SQL 查询语句。
public function query( $query ) {
global $wpdb;
$this->query_vars = wp_parse_args( $query, $this->query_vars_defaults );
$this->query_vars = apply_filters( 'pre_user_query', $this->query_vars );
// ... 省略大量代码 ...
$this->prepare_query();
$this->results = $wpdb->get_results( $this->request );
if ( $this->query_vars['count_total'] ) {
$this->set_found_users();
}
return $this->results;
}
这个方法的主要步骤如下:
- 合并参数:
wp_parse_args()
函数将传入的查询参数与默认参数合并,确保所有可能的参数都有值。 - 应用过滤器:
apply_filters( 'pre_user_query', $this->query_vars )
允许开发者通过过滤器来修改查询参数。这提供了一种灵活的方式来定制用户查询。 - 准备查询:
$this->prepare_query()
方法根据解析后的参数,构建 SQL 查询语句。 这是整个过程中最复杂的部分,我们稍后会详细讲解。 - 执行查询:
$wpdb->get_results( $this->request )
使用 WordPress 的数据库对象$wpdb
来执行 SQL 查询语句,并将结果保存在$this->results
中。 - 计算总数: 如果
count_total
参数为true
,则调用$this->set_found_users()
方法来计算符合条件的用户总数。 - 返回结果: 返回查询到的用户对象列表。
prepare_query()
方法:SQL 查询语句的构建大师
prepare_query()
方法是构建 SQL 查询语句的关键。它根据各种查询参数,动态生成 SQL 语句的不同部分,并将它们组合在一起。
protected function prepare_query() {
global $wpdb;
$qv =& $this->query_vars;
$fields = $this->get_fields();
// ... 省略大量代码 ...
$where = $this->get_where();
$orderby = $this->get_orderby();
$limits = $this->get_limits();
$this->request = "SELECT {$fields} FROM {$wpdb->users} {$join} WHERE 1=1 {$where} {$orderby} {$limits}";
$this->query = $this->request; // For back compat.
if ( $qv['count_total'] ) {
$this->request_count = "SELECT COUNT(*) FROM {$wpdb->users} {$join} WHERE 1=1 {$where}";
}
}
这个方法的主要步骤如下:
- 获取查询字段:
$this->get_fields()
方法根据fields
参数,确定要查询的字段。 默认情况下,查询所有字段。 - 构建 JOIN 子句: 根据
meta_query
和has_published_posts
参数,可能需要连接usermeta
表和posts
表。 - 构建 WHERE 子句:
$this->get_where()
方法根据各种查询参数,构建WHERE
子句。 这是最复杂的部分,我们稍后会详细讲解。 - 构建 ORDER BY 子句:
$this->get_orderby()
方法根据orderby
和order
参数,构建ORDER BY
子句。 - 构建 LIMIT 子句:
$this->get_limits()
方法根据number
和offset
参数,构建LIMIT
子句。 - 组合 SQL 语句: 将各个部分组合在一起,形成完整的 SQL 查询语句,并将其保存在
$this->request
属性中。 - 构建 COUNT 查询语句: 如果
count_total
参数为true
,则构建用于计算总数的 SQL 查询语句,并将其保存在$this->request_count
属性中。
get_where()
方法:WHERE 子句的构建艺术
get_where()
方法负责构建 SQL 查询语句的 WHERE
子句。 它根据各种查询参数,动态生成不同的条件,并将它们组合在一起。
protected function get_where() {
global $wpdb;
$qv =& $this->query_vars;
$where = '';
if ( ! empty( $qv['who'] ) ) {
switch ( $qv['who'] ) {
case 'authors':
$where .= ' AND ID IN ( SELECT post_author FROM ' . $wpdb->posts . ' WHERE post_status = "publish" )';
break;
}
}
if ( ! empty( $qv['include'] ) ) {
$ids = implode( ',', array_map( 'intval', $qv['include'] ) );
$where .= " AND ID IN ($ids)";
} elseif ( ! empty( $qv['exclude'] ) ) {
$ids = implode( ',', array_map( 'intval', $qv['exclude'] ) );
$where .= " AND ID NOT IN ($ids)";
}
if ( ! empty( $qv['search'] ) ) {
$where .= $this->get_search_sql( $qv['search'], $qv['search_columns'] );
}
if ( '' !== $qv['nicename'] ) {
$where .= " AND user_nicename = '" . esc_sql( $qv['nicename'] ) . "'";
}
if ( ! empty( $qv['nicename__in'] ) ) {
$nicenames = implode( "', '", array_map( 'esc_sql', $qv['nicename__in'] ) );
$where .= " AND user_nicename IN ( '" . $nicenames . "' )";
}
if ( ! empty( $qv['nicename__not_in'] ) ) {
$nicenames = implode( "', '", array_map( 'esc_sql', $qv['nicename__not_in'] ) );
$where .= " AND user_nicename NOT IN ( '" . $nicenames . "' )";
}
if ( ! empty( $qv['role'] ) ) {
if ( is_array( $qv['role'] ) ) {
$roles = implode( "', '", array_map( 'esc_sql', $qv['role'] ) );
$where .= " AND {$wpdb->users}.ID IN ( SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' AND meta_value LIKE '%"{$roles}"%' )";
} else {
$where .= " AND {$wpdb->users}.ID IN ( SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' AND meta_value LIKE '%"{$qv['role']}"%' )";
}
}
if ( ! empty( $qv['role__in'] ) ) {
$roles = implode( "', '", array_map( 'esc_sql', $qv['role__in'] ) );
$where .= " AND {$wpdb->users}.ID IN ( SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' AND meta_value LIKE '%"{$roles}"%' )";
}
if ( ! empty( $qv['role__not_in'] ) ) {
$roles = implode( "', '", array_map( 'esc_sql', $qv['role__not_in'] ) );
$where .= " AND {$wpdb->users}.ID NOT IN ( SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' AND meta_value LIKE '%"{$roles}"%' )";
}
if ( ! empty( $qv['meta_query'] ) ) {
$meta_query = new WP_Meta_Query( $qv['meta_query'] );
$where .= $meta_query->get_sql( 'user', $wpdb->users, 'ID' );
} elseif ( ! empty( $qv['meta_key'] ) || ! empty( $qv['meta_value'] ) ) {
$where .= $this->get_meta_sql( $qv['meta_key'], $qv['meta_value'], $qv['meta_compare'] );
}
if ( ! empty( $qv['date_query'] ) ) {
$date_query = new WP_Date_Query( $qv['date_query'], 'user_registered' );
$where .= $date_query->get_sql();
}
return $where;
}
这个方法会根据不同的查询参数,添加不同的 WHERE 条件。 例如:
who
参数: 用于筛选作者。include
和exclude
参数: 用于包含或排除特定的用户 ID。search
参数: 用于搜索用户名、昵称、邮箱等字段。nicename
参数: 用于匹配用户昵称。role
参数: 用于筛选具有特定角色的用户。 这个条件会连接usermeta
表,并使用LIKE
运算符来匹配用户角色。meta_query
参数: 用于进行复杂的自定义字段查询。 它会使用WP_Meta_Query
类来构建meta_query
子句。date_query
参数: 用于按注册日期进行筛选。 它会使用WP_Date_Query
类来构建date_query
子句。
实例分析:一个更复杂的例子
假设我们要查询所有订阅者(subscriber)并且注册时间在2023年1月1日之后的,并且自定义字段 "city" 的值为 "New York" 的用户。
$args = array(
'role' => 'subscriber',
'date_query' => array(
array(
'column' => 'user_registered',
'after' => '2023-01-01',
),
),
'meta_query' => array(
array(
'key' => 'city',
'value' => 'New York',
'compare' => '=',
),
),
);
$users = get_users( $args );
在这个例子中,WP_User_Query
会构建如下的 SQL 查询语句(简化版):
SELECT *
FROM wp_users
INNER JOIN wp_usermeta ON (wp_users.ID = wp_usermeta.user_id)
WHERE 1=1
AND wp_users.ID IN (SELECT user_id FROM wp_usermeta WHERE meta_key = 'wp_capabilities' AND meta_value LIKE '%"subscriber"%')
AND user_registered >= '2023-01-01 00:00:00'
AND ((wp_usermeta.meta_key = 'city' AND wp_usermeta.meta_value = 'New York'))
这个查询语句会连接 wp_users
表和 wp_usermeta
表,并根据角色、注册时间和自定义字段的值进行筛选。
总结:get_users()
和 WP_User_Query
的完美配合
get_users()
函数和 WP_User_Query
类是 WordPress 中用户查询的黄金搭档。 get_users()
提供了一个简单易用的接口,而 WP_User_Query
则负责处理复杂的查询逻辑。
通过深入了解 WP_User_Query
的源码,我们可以更好地理解 WordPress 如何查询用户数据,并能够更灵活地定制用户查询。
希望今天的讲座能够帮助大家更深入地理解 WordPress 的用户查询机制。 记住,理解源码是成为 WordPress 大神的必经之路!
表格总结:常用参数与对应的 SQL 条件
参数名称 | 描述 | 对应的 SQL 条件 |
---|---|---|
role |
指定用户角色,例如 ‘administrator’, ‘editor’, ‘author’, ‘subscriber’ 等。 | AND {$wpdb->users}.ID IN ( SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' AND meta_value LIKE '%"{$role}"%') |
include |
指定要包含的用户 ID 列表,例如 array(1, 2, 3) 。 |
AND ID IN (1,2,3) |
exclude |
指定要排除的用户 ID 列表,例如 array(4, 5, 6) 。 |
AND ID NOT IN (4,5,6) |
search |
指定要搜索的字符串,用于搜索用户名、昵称、邮箱等字段。 | 对应 get_search_sql() 函数生成的 SQL,例如 AND ( user_login LIKE '%search_term%' OR user_nicename LIKE '%search_term%' OR user_email LIKE '%search_term%' OR display_name LIKE '%search_term%' ) |
meta_query |
用于进行复杂的自定义字段查询。 | 使用 WP_Meta_Query 类生成 SQL,例如 AND ( (wp_usermeta.meta_key = 'city' AND wp_usermeta.meta_value = 'New York' AND wp_usermeta.meta_compare = '=' ) ) |
date_query |
用于按注册日期进行筛选。 | 使用 WP_Date_Query 类生成 SQL,例如 AND user_registered >= '2023-01-01 00:00:00' |
orderby |
指定排序字段,例如 ‘ID’, ‘login’, ‘nicename’, ’email’, ‘url’, ‘registered’, ‘display_name’, ‘post_count’。 | ORDER BY user_login ASC (例如,如果 orderby 为 ‘login’ 且 order 为 ‘ASC’) |
order |
指定排序方式,’ASC’ (升序) 或 ‘DESC’ (降序)。 | 决定 ORDER BY 子句的排序方向。 |
number |
指定要返回的用户数量。 | LIMIT 10 (例如,如果 number 为 10) |
offset |
指定要跳过的用户数量,用于分页。 | LIMIT 10, 10 (例如,如果 number 为 10 且 offset 为 10,则跳过前 10 个用户,并返回接下来的 10 个用户) |
nicename |
匹配用户昵称 | AND user_nicename = 'john' (例如, 匹配昵称为 john 的用户) |
nicename__in |
匹配用户昵称 (允许数组) | AND user_nicename IN ( 'john', 'jane' ) (例如, 匹配昵称为 john 或者 jane 的用户) |
nicename__not_in |
排除用户昵称 (允许数组) | AND user_nicename NOT IN ( 'john', 'jane' ) (例如, 排除昵称为 john 或者 jane 的用户) |
role__in |
指定要包含的多个用户角色 | AND {$wpdb->users}.ID IN ( SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' AND meta_value LIKE '%"{$role1}"%' ) AND {$wpdb->users}.ID IN ( SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' AND meta_value LIKE '%"{$role2}"%') (根据包含的角色数量生成多个IN语句) |
role__not_in |
指定要排除的多个用户角色 | AND {$wpdb->users}.ID NOT IN ( SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' AND meta_value LIKE '%"{$role1}"%' ) AND {$wpdb->users}.ID NOT IN ( SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' AND meta_value LIKE '%"{$role2}"%') (根据排除的角色数量生成多个NOT IN语句) |