大家好,我是你们今天的码农老司机,准备好了吗?今天要带大家深入挖掘WordPress世界里一个看似简单,实则暗藏玄机的函数:get_users()
。别看它只有短短几个字母,背后可是连接着一个强大的查询引擎——WP_User_Query
类。
咱们今天就来一场源码解剖,看看get_users()
是如何驾驭WP_User_Query
,从数据库里捞出一堆用户信息的。
第一幕:初识get_users()
——简单易用,却不简单
首先,我们来看看get_users()
的庐山真面目,它位于 WordPress 的 wp-includes/user.php
文件中。
/**
* Retrieves a list of users.
*
* @since 2.1.0
*
* @param string|array $args Optional. Array or string of arguments to pass to WP_User_Query.
* See WP_User_Query::prepare_query() for information on accepted arguments.
* @return array Array of WP_User objects.
*/
function get_users( $args = array() ) {
$wp_user_query = new WP_User_Query( $args );
return $wp_user_query->get_results();
}
看到了吗?是不是出乎意料的简洁? 它主要做了两件事:
-
实例化
WP_User_Query
:$wp_user_query = new WP_User_Query( $args );
这行代码是关键。它把传入的$args
参数(如果没有传,就用默认的空数组)传递给WP_User_Query
类的构造函数。 -
获取结果:
$wp_user_query->get_results();
这行代码调用了WP_User_Query
对象的get_results()
方法,获取查询结果,并返回一个包含WP_User
对象的数组。
到这里,你可能会想:“就这?就这?这也太简单了吧!” 别急,好戏还在后头。真正的魔法,都藏在 WP_User_Query
类的内部。
第二幕:走进WP_User_Query
——查询引擎的核心
WP_User_Query
类的定义位于 wp-includes/class-wp-user-query.php
文件中。它是一个专门用于查询用户信息的类,提供了丰富的查询参数和方法,可以让你灵活地检索 WordPress 数据库中的用户数据。
我们先来看看WP_User_Query
构造函数做了什么。
/**
* Constructor.
*
* @since 3.1.0
*
* @param string|array $query Optional. Array or string of Query parameters.
*/
public function __construct( $query = null ) {
$this->prepare_query( $query );
$this->query();
}
构造函数做了两件事,prepare_query
和query
。
prepare_query()
:参数解析与准备
prepare_query()
方法负责解析传入的查询参数,并根据这些参数构建 SQL 查询语句。 它是整个查询过程的基石。
/**
* Prepares the query variables.
*
* @since 3.1.0
*
* @param string|array $query String or array of Query parameters.
*/
public function prepare_query( $query = '' ) {
global $wpdb;
if ( empty( $query ) ) {
$query = $this->query_vars;
}
$this->query_vars = wp_parse_args( $query, $this->query_vars );
$this->query_vars = sanitize_user_query( $this->query_vars );
/**
* Fires before the WP_User_Query->prepare_query() method runs.
*
* @since 3.7.0
*
* @param WP_User_Query $this The current WP_User_Query instance (passed by reference).
*/
do_action_ref_array( 'pre_user_query', array( &$this ) );
if ( isset( $this->query_vars['number'] ) && ( $this->query_vars['number'] < 1 || ! is_numeric( $this->query_vars['number'] ) ) ) {
$this->query_vars['number'] = '';
unset( $this->query_vars['number'] );
}
$this->process_id_query();
$this->process_login_query();
$this->process_name_query();
$this->process_email_query();
$this->process_url_query();
$this->process_nicename_query();
$this->process_include_exclude_query();
$this->process_meta_query();
$this->process_date_query();
// Combine querystring vars asking for IDs with an 'include' query.
if ( ! empty( $this->query_vars['include'] ) ) {
$ids = wp_parse_id_list( $this->query_vars['include'] );
$ids = array_map( 'intval', $ids );
$this->query_vars['include'] = implode( ',', $ids );
}
if ( isset( $this->query_vars['fields'] ) ) {
if ( 'all' === $this->query_vars['fields'] ) {
$this->query_fields = "$wpdb->users.*";
} elseif ( 'all_with_meta' === $this->query_vars['fields'] ) {
$this->query_fields = " DISTINCT $wpdb->users.*, umeta.*";
$this->get_meta = true;
} elseif ( 'ID' === $this->query_vars['fields'] ) {
$this->query_fields = "$wpdb->users.ID";
} elseif ( 'ids' === $this->query_vars['fields'] ) {
$this->query_fields = "$wpdb->users.ID";
} elseif ( 'count' === $this->query_vars['fields'] ) {
$this->query_fields = 'COUNT(*)';
} else {
$this->query_fields = "$wpdb->users.ID";
}
}
$this->parse_search( $this->query_vars );
/**
* Fires after the WP_User_Query->prepare_query() method runs.
*
* @since 3.1.0
*
* @param WP_User_Query $this The current WP_User_Query instance (passed by reference).
*/
do_action_ref_array( 'user_query_pre_get_users', array( &$this ) );
$this->where = apply_filters_ref_array( 'user_search_where', array( $this->where, &$this ) );
$this->orderby = apply_filters_ref_array( 'user_search_orderby', array( $this->orderby, &$this ) );
}
这段代码看起来很长,但其实主要做了以下几件事:
-
参数合并与清洗: 使用
wp_parse_args()
将传入的参数与默认参数合并,并使用sanitize_user_query()
对参数进行安全过滤,防止 SQL 注入。 -
处理各种查询条件: 接下来,
prepare_query()
会根据传入的参数,调用一系列process_*_query()
方法来构建 SQL 查询的WHERE
子句。 例如:process_id_query()
: 处理include
和exclude
参数,用于根据用户 ID 筛选用户。process_login_query()
: 处理login
参数,用于根据用户名筛选用户。process_email_query()
: 处理email
参数,用于根据邮箱筛选用户。process_meta_query()
: 处理meta_query
参数,用于根据用户元数据筛选用户。这个非常重要,允许你根据自定义字段进行查询。process_date_query()
: 处理date_query
参数,用于根据用户注册日期筛选用户。
-
处理查询字段: 根据
fields
参数,确定要查询哪些字段。 常见的选项有:all
: 查询所有字段 ($wpdb->users.*
)ids
: 只查询用户 ID ($wpdb->users.ID
)count
: 只查询用户数量 (COUNT(*)
)
-
处理搜索关键词: 如果传入了
search
参数,parse_search()
方法会构建 SQL 查询的WHERE
子句,用于根据关键词搜索用户名、邮箱等字段。 -
应用过滤器:
prepare_query()
方法还使用了user_search_where
和user_search_orderby
过滤器,允许开发者自定义 SQL 查询的WHERE
和ORDER BY
子句。 这提供了极大的灵活性,可以满足各种复杂的查询需求。
query()
:执行查询,获取结果
query()
方法负责执行构建好的 SQL 查询语句,并从数据库中获取用户数据。
/**
* Executes the query, with the current variables.
*
* @since 3.1.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @return array|int List of found user IDs or array of WP_User objects.
*/
public function query() {
global $wpdb;
$this->prepare_sql();
/**
* Fires before the WP_User_Query executes the query.
*
* @since 3.5.0
*
* @param WP_User_Query $this The current WP_User_Query instance (passed by reference).
*/
do_action_ref_array( 'pre_get_users', array( &$this ) );
if ( 'count' === $this->query_vars['fields'] ) {
$this->total_users = (int) $wpdb->get_var( $this->request );
return;
}
$this->results = $wpdb->get_results( $this->request );
if ( $this->get_meta && ! empty( $this->results ) ) {
update_meta_cache( 'user', wp_list_pluck( $this->results, 'ID' ) );
}
$this->total_users = $wpdb->get_var( $this->get_total );
if ( $this->results ) {
if ( 'ids' === $this->query_vars['fields'] || 'ID' === $this->query_vars['fields'] ) {
$this->results = array_map( 'intval', $this->results );
} else {
$this->results = array_map( 'get_userdata', $this->results );
}
}
return;
}
让我们来拆解一下:
-
准备SQL语句 调用
prepare_sql()
方法,将之前的各种参数组合成最终可以执行的SQL查询语句。 -
执行查询: 使用
$wpdb->get_results()
方法执行 SQL 查询,并将结果存储在$this->results
属性中。 -
处理元数据: 如果设置了
fields
为all_with_meta
,则调用update_meta_cache()
函数,预加载用户元数据,提高性能。 -
处理结果: 根据
fields
参数,将查询结果转换为相应的格式。 如果fields
为ids
,则将结果转换为整数数组。 否则,将结果转换为WP_User
对象数组。 -
获取总数: 执行
$wpdb->get_var( $this->get_total )
获取符合条件的总用户数,并存储在$this->total_users
属性中。
get_results()
:返回最终结果
/**
* Retrieve query results.
*
* @since 3.1.0
*
* @return array|int An array of WP_User objects, or array of user IDs.
* Returns the user count if querying for a count.
*/
public function get_results() {
if ( isset( $this->query_vars['fields'] ) && 'count' === $this->query_vars['fields'] ) {
return intval( $this->total_users );
}
return $this->results;
}
这个方法非常简单,它仅仅根据查询字段(fields
)的不同返回查询结果。 如果查询字段是count
,那么它返回总用户数,否则返回包含用户对象的数组。
第三幕:get_users()
的参数详解——灵活定制你的查询
get_users()
函数接收一个 $args
参数,它是一个数组,用于指定查询条件。 WP_User_Query
类支持的参数非常丰富,可以满足各种复杂的查询需求。 下面是一些常用的参数:
参数名 | 类型 | 描述 |
---|---|---|
blog_id |
int | 只在多站点环境下有效。指定要查询用户的站点 ID。 |
include |
array/string | 指定要包含的用户 ID。 |
exclude |
array/string | 指定要排除的用户 ID。 |
search |
string | 搜索关键词。用于搜索用户名、邮箱等字段。 |
search_columns |
array | 指定要搜索的字段。默认为 array( 'user_login', 'user_email', 'display_name' ) 。 |
orderby |
string | 排序字段。默认为 login 。 常用的选项有 ID , login , email , nicename , registered , display_name 。 |
order |
string | 排序方式。默认为 ASC 。 常用的选项有 ASC (升序) 和 DESC (降序)。 |
number |
int | 每页显示的用户数量。默认为空,表示显示所有用户。 |
offset |
int | 偏移量。用于分页显示用户。 |
paged |
int | 当前页码。用于分页显示用户。 |
role |
string/array | 指定要查询的用户角色。 |
meta_key |
string | 用户元数据键名。用于根据用户元数据筛选用户。 必须与 meta_value 或 meta_query 配合使用。 |
meta_value |
string/array | 用户元数据键值。用于根据用户元数据筛选用户。 必须与 meta_key 配合使用。 |
meta_compare |
string | 用户元数据比较运算符。默认为 = 。 常用的选项有 = , != , > , >= , < , <= , LIKE , NOT LIKE , IN , NOT IN , BETWEEN , NOT BETWEEN , REGEXP , NOT REGEXP , RLIKE 。 |
meta_query |
array | 用于构建复杂的元数据查询。 数组中的每个元素都是一个子查询,包含 key , value , compare 等参数。 |
date_query |
array | 用于根据用户注册日期筛选用户。 数组中的每个元素都是一个日期查询条件,包含 year , month , day , after , before , inclusive 等参数。 |
fields |
string | 指定要查询的字段。默认为空,表示查询所有字段。 常用的选项有 all , ids , count 。 |
第四幕:实战演练——代码示例
光说不练假把式,我们来几个实际的例子,看看如何使用 get_users()
函数和 WP_User_Query
类。
例1: 获取所有用户
$users = get_users();
foreach ( $users as $user ) {
echo '用户ID: ' . $user->ID . ', 用户名: ' . $user->user_login . '<br>';
}
例2: 获取 ID 为 1, 3, 5 的用户
$args = array(
'include' => array( 1, 3, 5 )
);
$users = get_users( $args );
foreach ( $users as $user ) {
echo '用户ID: ' . $user->ID . ', 用户名: ' . $user->user_login . '<br>';
}
例3: 获取注册时间在 2023 年 1 月 1 日之后的用户
$args = array(
'date_query' => array(
array(
'after' => '2023-01-01',
'inclusive' => true, // 包含 2023-01-01
),
),
);
$users = get_users( $args );
foreach ( $users as $user ) {
echo '用户ID: ' . $user->ID . ', 用户名: ' . $user->user_login . ', 注册时间: ' . $user->user_registered . '<br>';
}
例4: 获取用户角色为 editor 的用户
$args = array(
'role' => 'editor'
);
$users = get_users( $args );
foreach ( $users as $user ) {
echo '用户ID: ' . $user->ID . ', 用户名: ' . $user->user_login . ', 角色: ' . implode( ', ', $user->roles ) . '<br>';
}
例5: 使用 meta_query
获取自定义字段 favorite_color
为 ‘blue’ 的用户
$args = array(
'meta_query' => array(
array(
'key' => 'favorite_color',
'value' => 'blue',
'compare' => '='
)
)
);
$users = get_users( $args );
foreach ( $users as $user ) {
echo '用户ID: ' . $user->ID . ', 用户名: ' . $user->user_login . ', 喜欢的颜色: ' . get_user_meta( $user->ID, 'favorite_color', true ) . '<br>';
}
例6: 分页显示用户
$paged = ( get_query_var( 'paged' ) ) ? get_query_var( 'paged' ) : 1;
$per_page = 10;
$args = array(
'number' => $per_page,
'offset' => ( $paged - 1 ) * $per_page,
'paged' => $paged,
);
$users = get_users( $args );
echo '<p>当前页: ' . $paged . '</p>';
echo '<ul>';
foreach ( $users as $user ) {
echo '<li>用户ID: ' . $user->ID . ', 用户名: ' . $user->user_login . '</li>';
}
echo '</ul>';
// 显示分页链接
$total_users = get_users( array( 'fields' => 'count' ) );
$total_pages = ceil( $total_users / $per_page );
echo paginate_links( array(
'base' => get_pagenum_link(1) . '%_%',
'format' => '/page/%#%',
'current' => $paged,
'total' => $total_pages,
) );
第五幕:总结与展望
通过今天的源码剖析,我们了解了 get_users()
函数是如何利用 WP_User_Query
类,从数据库中灵活地查询用户信息的。 WP_User_Query
类提供了丰富的查询参数和方法,可以满足各种复杂的查询需求。 同时,WordPress 还提供了 user_search_where
和 user_search_orderby
过滤器,允许开发者自定义 SQL 查询的 WHERE
和 ORDER BY
子句,进一步扩展了查询的灵活性。
掌握了 get_users()
和 WP_User_Query
,你就掌握了在 WordPress 中查询用户的核心技能。 以后再遇到用户查询相关的需求,就可以游刃有余地解决问题了。
当然,WP_User_Query
类还有很多高级用法,例如使用 meta_query
构建更复杂的元数据查询,使用 date_query
构建更灵活的日期查询等。 这些就留给你们自己去探索和学习了。
希望今天的讲座对大家有所帮助。 祝大家编码愉快!