各位观众老爷,大家好!今天咱们来聊聊WordPress里一个相当重要的类:WP_User_Query
。这家伙负责在数据库里捞人,哦不,是捞用户的信息。它的核心任务就是把咱们的需求翻译成SQL语句,然后把结果打包好送回来。今天我们就扒一扒它的源码,看看它是怎么干活的,重点关注SQL语句的构建和get_results()
方法。
一、WP_User_Query
:你的专属用户搜索官
想象一下,你是个HR,需要从一大堆员工信息里找到符合特定条件的人,比如“所有部门是销售部的,入职时间在2022年之后的员工”。在WordPress里,WP_User_Query
就是你的HR,它能帮你从wp_users
表以及相关的wp_usermeta
表里找到符合条件的用户。
二、构造函数:接收你的搜索指令
首先,我们来看看WP_User_Query
的构造函数,它负责接收你的搜索条件:
public function __construct( $query = null ) {
$this->query_vars_defaults = array(
'blog_id' => get_current_blog_id(),
'fields' => 'all',
'include' => array(),
'exclude' => array(),
'search' => '',
'search_columns' => array(),
'orderby' => 'login',
'order' => 'ASC',
'offset' => '',
'number' => '',
'paged' => '',
'count_total' => true,
'who' => '',
'has_published_posts' => null,
'nicename' => '',
'nicename__in' => array(),
'nicename__not_in' => array(),
'login' => '',
'login__in' => array(),
'login__not_in' => array(),
'user_email' => '',
'user_email__in' => array(),
'user_email__not_in' => array(),
'user_url' => '',
'user_url__in' => array(),
'user_url__not_in' => array(),
'ID' => '',
'ID__in' => array(),
'ID__not_in' => array(),
'meta_key' => '',
'meta_value' => '',
'meta_compare' => '',
'meta_query' => array(),
'date_query' => null,
'capability' => '',
'capability__in' => array(),
'capability__not_in' => array(),
'role' => '',
'role__in' => array(),
'role__not_in' => array(),
'lang' => '',
'feed' => '',
);
$this->query_vars = $this->query_vars_defaults;
if ( ! empty( $query ) ) {
$this->query( $query );
}
}
这个构造函数接收一个 $query
参数,它是一个数组,包含了你的搜索条件,比如'role' => 'editor'
。 构造函数会把这些条件赋值给 $this->query_vars
属性。 这些就是筛选用户的依据,各种各样的参数,应有尽有,只有你想不到,没有它不支持。
三、query()
方法:解析你的指令
query()
方法负责解析你的搜索条件,并进行一些必要的处理。
public function query( $query ) {
$this->query_vars = wp_parse_args( $query, $this->query_vars_defaults );
$this->query_vars = apply_filters( 'pre_user_query', $this->query_vars );
// Backward compatibility for meta_key => meta_value usage.
if ( ! empty( $this->query_vars['meta_key'] ) && empty( $this->query_vars['meta_query'] ) ) {
$this->query_vars['meta_query'] = array(
array(
'key' => $this->query_vars['meta_key'],
'value' => $this->query_vars['meta_value'],
'compare' => $this->query_vars['meta_compare'],
),
);
}
$this->prepare_query();
$this->get_results();
}
这里有几个关键步骤:
wp_parse_args()
: 把你的搜索条件和默认值合并起来,确保所有必要的参数都有值。apply_filters( 'pre_user_query', $this->query_vars )
: 允许你通过过滤器修改搜索条件,这为你提供了额外的灵活性。prepare_query()
: 这是最关键的一步,它负责根据你的搜索条件构建SQL语句。我们稍后会详细介绍。get_results()
: 执行SQL查询,并把结果返回给你。
四、prepare_query()
:SQL语句的魔法工厂
prepare_query()
方法是WP_User_Query
的核心,它负责把你的搜索条件翻译成SQL语句。 让我们深入了解一下它的工作原理。它内部又调用了很多其他方法,负责不同部分的SQL语句构建。
protected function prepare_query() {
global $wpdb;
$qv = $this->query_vars;
$this->query_fields = $this->get_fields();
// Prepare orderby clause.
$this->prepare_orderby();
// Assemble the query.
$fields = $this->query_fields;
$join = $this->get_sql_join();
$where = $this->get_sql_where();
$orderby = ! empty( $this->orderby ) ? "ORDER BY {$this->orderby}" : '';
$limits = $this->get_sql_limits();
$this->request = "SELECT {$fields} FROM {$wpdb->users} {$join} WHERE 1=1 {$where} {$orderby} {$limits}";
if ( $this->query_vars['count_total'] ) {
$this->query_total = "SELECT COUNT(DISTINCT {$wpdb->users}.ID) FROM {$wpdb->users} {$join} WHERE 1=1 {$where}";
}
}
这个方法做了以下几件事:
$this->get_fields()
: 确定要查询的字段,比如ID
,user_login
,user_email
。$this->prepare_orderby()
: 构建ORDER BY
子句,指定排序方式。$this->get_sql_join()
: 构建JOIN
子句,用于连接wp_users
和wp_usermeta
表(如果需要的话)。$this->get_sql_where()
: 构建WHERE
子句,根据你的搜索条件筛选用户。$this->get_sql_limits()
: 构建LIMIT
子句,用于分页。$this->request
: 把所有部分组装成完整的SQL查询语句。$this->query_total
: 如果需要统计总用户数,构建一个单独的SQL查询语句。
让我们更详细地看看get_sql_where()
方法,因为它负责构建最重要的WHERE
子句。
protected function get_sql_where() {
global $wpdb;
$where = '';
$qv = $this->query_vars;
// ID.
if ( ! empty( $qv['ID'] ) ) {
$where .= ' AND ' . $wpdb->users . '.ID = '' . esc_sql( $qv['ID'] ) . ''';
} elseif ( ! empty( $qv['ID__in'] ) ) {
$ids = array_map( 'intval', $qv['ID__in'] );
$where .= ' AND ' . $wpdb->users . '.ID IN (' . implode( ',', $ids ) . ')';
} elseif ( ! empty( $qv['ID__not_in'] ) ) {
$ids = array_map( 'intval', $qv['ID__not_in'] );
$where .= ' AND ' . $wpdb->users . '.ID NOT IN (' . implode( ',', $ids ) . ')';
}
// Login.
if ( ! empty( $qv['login'] ) ) {
$where .= ' AND ' . $wpdb->users . '.user_login = '' . esc_sql( $qv['login'] ) . ''';
} elseif ( ! empty( $qv['login__in'] ) ) {
$logins = array_map( 'esc_sql', $qv['login__in'] );
$where .= ' AND ' . $wpdb->users . '.user_login IN ('' . implode( '', '', $logins ) . '')';
} elseif ( ! empty( $qv['login__not_in'] ) ) {
$logins = array_map( 'esc_sql', $qv['login__not_in'] );
$where .= ' AND ' . $wpdb->users . '.user_login NOT IN ('' . implode( '', '', $logins ) . '')';
}
// User nicename.
if ( ! empty( $qv['nicename'] ) ) {
$where .= ' AND ' . $wpdb->users . '.user_nicename = '' . esc_sql( $qv['nicename'] ) . ''';
} elseif ( ! empty( $qv['nicename__in'] ) ) {
$nicenames = array_map( 'esc_sql', $qv['nicename__in'] );
$where .= ' AND ' . $wpdb->users . '.user_nicename IN ('' . implode( '', '', $nicenames ) . '')';
} elseif ( ! empty( $qv['nicename__not_in'] ) ) {
$nicenames = array_map( 'esc_sql', $qv['nicename__not_in'] );
$where .= ' AND ' . $wpdb->users . '.user_nicename NOT IN ('' . implode( '', '', $nicenames ) . '')';
}
// User email.
if ( ! empty( $qv['user_email'] ) ) {
$where .= ' AND ' . $wpdb->users . '.user_email = '' . esc_sql( $qv['user_email'] ) . ''';
} elseif ( ! empty( $qv['user_email__in'] ) ) {
$emails = array_map( 'esc_sql', $qv['user_email__in'] );
$where .= ' AND ' . $wpdb->users . '.user_email IN ('' . implode( '', '', $emails ) . '')';
} elseif ( ! empty( $qv['user_email__not_in'] ) ) {
$emails = array_map( 'esc_sql', $qv['user_email__not_in'] );
$where .= ' AND ' . $wpdb->users . '.user_email NOT IN ('' . implode( '', '', $emails ) . '')';
}
// User URL.
if ( ! empty( $qv['user_url'] ) ) {
$where .= ' AND ' . $wpdb->users . '.user_url = '' . esc_sql( $qv['user_url'] ) . ''';
} elseif ( ! empty( $qv['user_url__in'] ) ) {
$urls = array_map( 'esc_sql', $qv['user_url__in'] );
$where .= ' AND ' . $wpdb->users . '.user_url IN ('' . implode( '', '', $urls ) . '')';
} elseif ( ! empty( $qv['user_url__not_in'] ) ) {
$urls = array_map( 'esc_sql', $qv['user_url__not_in'] );
$where .= ' AND ' . $wpdb->users . '.user_url NOT IN ('' . implode( '', '', $urls ) . '')';
}
// Search stuff.
if ( ! empty( $qv['search'] ) ) {
$where .= $this->get_search_sql( $qv['search'], $qv['search_columns'] );
}
// Role stuff.
if ( ! empty( $qv['role'] ) ) {
$where .= $this->get_role_sql( $qv['role'] );
} elseif ( ! empty( $qv['role__in'] ) ) {
$where .= $this->get_role_sql( $qv['role__in'], 'IN' );
} elseif ( ! empty( $qv['role__not_in'] ) ) {
$where .= $this->get_role_sql( $qv['role__not_in'], 'NOT IN' );
}
// Meta query stuff.
if ( ! empty( $qv['meta_query'] ) ) {
$meta_query = new WP_Meta_Query( $qv['meta_query'] );
$where .= $meta_query->get_sql( 'user', $wpdb->users, 'ID' );
}
// Date query stuff.
if ( ! empty( $qv['date_query'] ) && is_array( $qv['date_query'] ) ) {
$date_query = new WP_Date_Query( $qv['date_query'], 'user_registered' );
$where .= $date_query->get_sql();
}
// Include/exclude stuff.
if ( ! empty( $qv['include'] ) ) {
$ids = array_map( 'intval', $qv['include'] );
$where .= ' AND ' . $wpdb->users . '.ID IN (' . implode( ',', $ids ) . ')';
} elseif ( ! empty( $qv['exclude'] ) ) {
$ids = array_map( 'intval', $qv['exclude'] );
$where .= ' AND ' . $wpdb->users . '.ID NOT IN (' . implode( ',', $ids ) . ')';
}
return $where;
}
可以看到,这个方法会根据不同的搜索条件,拼接不同的SQL片段。 例如,如果你的搜索条件包含 role
,它会调用 $this->get_role_sql()
方法来构建角色相关的SQL片段。 如果包含meta_query
, 会调用WP_Meta_Query
类来处理元数据相关的查询。
五、get_results()
:执行查询,返回结果
get_results()
方法负责执行SQL查询,并把结果返回给你。
public function get_results() {
global $wpdb;
if ( $this->results === null ) {
$this->prepare_query();
$this->results = $wpdb->get_results( $this->request );
if ( $this->query_vars['count_total'] ) {
$this->total_users = (int) $wpdb->get_var( $this->query_total );
}
}
return $this->results;
}
这个方法做了以下几件事:
$this->prepare_query()
: 确保SQL查询语句已经构建好。$wpdb->get_results( $this->request )
: 使用$wpdb
对象执行SQL查询,并把结果保存在$this->results
属性中。$wpdb->get_var( $this->query_total )
: 如果需要统计总用户数,执行统计总数的SQL查询,并把结果保存在$this->total_users
属性中。return $this->results
: 返回查询结果。
六、代码示例:实际应用
让我们看几个实际应用的例子。
示例1:查找所有管理员用户
$args = array(
'role' => 'administrator'
);
$user_query = new WP_User_Query( $args );
if ( ! empty( $user_query->results ) ) {
foreach ( $user_query->results as $user ) {
echo 'User ID: ' . $user->ID . ', User Login: ' . $user->user_login . '<br>';
}
} else {
echo 'No administrators found.';
}
这段代码会创建一个 WP_User_Query
对象,搜索条件是 role
等于 administrator
。 然后,它会遍历查询结果,并输出每个管理员用户的ID和登录名。
示例2:查找所有注册时间在2023年1月1日之后的用户
$args = array(
'date_query' => array(
array(
'after' => '2023-01-01',
'inclusive' => true,
),
),
);
$user_query = new WP_User_Query( $args );
if ( ! empty( $user_query->results ) ) {
foreach ( $user_query->results as $user ) {
echo 'User ID: ' . $user->ID . ', User Login: ' . $user->user_login . '<br>';
}
} else {
echo 'No users found registered after 2023-01-01.';
}
这段代码使用 date_query
参数来指定注册时间的范围。
示例3:查找元数据中 ‘city’ 字段值为 ‘New York’ 的用户
$args = array(
'meta_query' => array(
array(
'key' => 'city',
'value' => 'New York',
'compare' => '=',
),
),
);
$user_query = new WP_User_Query( $args );
if ( ! empty( $user_query->results ) ) {
foreach ( $user_query->results as $user ) {
echo 'User ID: ' . $user->ID . ', User Login: ' . $user->user_login . '<br>';
}
} else {
echo 'No users found with city New York.';
}
这段代码使用 meta_query
参数来指定元数据字段和值。
七、总结:WP_User_Query
的强大之处
WP_User_Query
类是WordPress里一个非常强大的工具,它可以让你方便地从数据库里检索用户信息。 它的核心在于把你的搜索条件翻译成SQL语句,并执行查询。 通过理解它的源码,你可以更好地利用它来满足你的需求,并避免一些常见的性能问题。
一些建议:
- 避免过度复杂的查询: 复杂的查询会导致性能下降。 尽量简化你的搜索条件。
- 使用缓存: 如果你的查询结果不会经常变化,可以考虑使用缓存来提高性能。
- 注意SQL注入: 始终使用
esc_sql()
函数来转义用户输入,防止SQL注入攻击。
表格总结:常用参数
参数名 | 描述 | 示例 |
---|---|---|
role |
用户的角色 | 'role' => 'editor' |
include |
只包含指定ID的用户 | 'include' => array(1, 2, 3) |
exclude |
排除指定ID的用户 | 'exclude' => array(4, 5, 6) |
search |
搜索用户的登录名、昵称、邮箱等 | 'search' => 'john' |
meta_key |
元数据键名 | 'meta_key' => 'city' |
meta_value |
元数据键值 | 'meta_value' => 'New York' |
meta_query |
更复杂的元数据查询,支持比较运算符 | 'meta_query' => array(array('key' => 'age', 'value' => 25, 'compare' => '>=')) |
date_query |
日期查询,可以根据用户注册时间进行筛选 | 'date_query' => array(array('after' => '2023-01-01')) |
orderby |
排序字段 | 'orderby' => 'user_registered' |
order |
排序方式(ASC或DESC) | 'order' => 'DESC' |
number |
每页显示的用户数 | 'number' => 10 |
offset |
偏移量,用于分页 | 'offset' => 20 |
count_total |
是否统计总用户数 | 'count_total' => true |
希望今天的讲解对大家有所帮助。 下次再见!