如何利用`WP_User_Query`和`pre_user_query`钩子进行自定义用户查询?

好的,下面是一篇关于利用WP_User_Querypre_user_query钩子进行自定义用户查询的技术文章,以讲座模式呈现。

WordPress 用户查询进阶:WP_User_Querypre_user_query

大家好!今天我们来深入探讨 WordPress 中用户查询的强大工具:WP_User_Query 类以及 pre_user_query 钩子。掌握它们,你就能构建高度定制化的用户列表,满足各种复杂的业务需求。

WP_User_Query: 灵活的用户检索利器

WP_User_Query 是 WordPress 提供的一个类,用于执行自定义的用户查询。相比直接使用 $wpdb 操作数据库,它提供了更安全、更便捷的方式来获取用户数据。

基本用法:

最简单的用法是实例化 WP_User_Query 类,并传入一个参数数组。

$args = array(
    'role' => 'subscriber', // 只查询订阅者角色
);

$user_query = new WP_User_Query( $args );

if ( ! empty( $user_query->get_results() ) ) {
    foreach ( $user_query->get_results() as $user ) {
        echo '用户名: ' . $user->user_login . '<br>';
    }
} else {
    echo '没有找到用户。';
}

这段代码会查询所有角色为 subscriber 的用户,并输出他们的用户名。

更丰富的参数:

WP_User_Query 支持大量参数,可以让你精确控制查询条件。下面是一些常用的参数:

参数名 类型 描述 示例
role string 只查询指定角色的用户。 'administrator', 'editor', 'author', 'contributor', 'subscriber'
role__in array 查询属于多个指定角色的用户。 array( 'administrator', 'editor' )
role__not_in array 排除指定角色的用户。 array( 'subscriber' )
include array 只查询指定 ID 的用户。 array( 1, 2, 3 )
exclude array 排除指定 ID 的用户。 array( 4, 5, 6 )
search string 搜索用户名、昵称、邮箱地址。 'john'
search_columns array 指定搜索的列。默认是 array( 'user_login', 'user_email', 'user_url', 'user_nicename' ) array( 'user_login', 'user_email' )
orderby string 排序字段。 'ID', 'login', 'nicename', 'email', 'url', 'registered', 'post_count'
order string 排序方式。 'ASC', 'DESC'
number int 返回的用户数量。 10
offset int 偏移量,用于分页。 20
meta_key string 查询指定用户元数据的用户。 'age'
meta_value mixed meta_key 对应的元数据值。 '30'
meta_compare string 元数据值的比较方式。 '=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS', 'NOT EXISTS'
meta_query array 更复杂的元数据查询,可以组合多个元数据条件。 见下文详细解释
date_query array 日期查询,例如查询注册时间在某个范围内的用户。 见下文详细解释
fields string 返回的字段。'ID' 只返回用户 ID,'all_with_meta' 返回所有用户数据和元数据。 'ID', 'all', 'all_with_meta'
has_published_posts mixed 根据用户是否发布过文章进行筛选。可以传递post type或者一个post type数组 true, false, 'post', array('post','page')

元数据查询 (meta_query):

meta_query 允许你根据用户元数据进行更复杂的查询。它是一个数组,可以包含多个元数据条件。

$args = array(
    'meta_query' => array(
        'relation' => 'AND', // 多个条件之间的关系,可以是 'AND' 或 'OR'
        array(
            'key'     => 'age',
            'value'   => '30',
            'compare' => '=',
            'type'    => 'NUMERIC', // 指定元数据类型
        ),
        array(
            'key'     => 'city',
            'value'   => 'New York',
            'compare' => 'LIKE',
        ),
    ),
);

$user_query = new WP_User_Query( $args );

这段代码会查询所有年龄为 30 岁且居住城市包含 "New York" 的用户。'type' 参数用于指定元数据类型,可以是 'NUMERIC', 'CHAR', 'DATE', 'DATETIME', 'BINARY', 'SIGNED', 'UNSIGNED'

日期查询 (date_query):

date_query 允许你根据用户的注册日期进行查询。

$args = array(
    'date_query' => array(
        array(
            'year'  => 2023,
            'month' => 10,
        ),
        array(
            'after'     => '2023-01-01',
            'before'    => '2023-12-31',
            'inclusive' => true, // 是否包含开始和结束日期
        ),
    ),
);

$user_query = new WP_User_Query( $args );

这段代码会查询所有 2023 年 10 月注册的用户,以及所有在 2023 年注册的用户。

获取查询结果:

WP_User_Query 提供了几个方法来获取查询结果:

  • get_results(): 返回一个 WP_User 对象数组。
  • get_total(): 返回符合条件的用户总数。
  • get_users(): 返回用户 ID 数组(如果fields参数设置为’ID’) 或者 WP_User对象数组(如果fields参数设置为’all’, 或者省略)。
$user_query = new WP_User_Query( $args );

$users = $user_query->get_results();
$total_users = $user_query->get_total();

echo '总共有 ' . $total_users . ' 个符合条件的用户。<br>';

foreach ( $users as $user ) {
    echo '用户名: ' . $user->user_login . '<br>';
}

pre_user_query: 拦截并修改查询

pre_user_query 钩子允许你在 WP_User_Query 执行 SQL 查询之前拦截并修改查询参数。这为你提供了极大的灵活性,可以根据你的需求动态调整查询条件。

基本用法:

add_action( 'pre_user_query', 'my_custom_user_query' );

function my_custom_user_query( $query ) {
    // 修改 $query 对象
    if ( is_admin() && isset( $_GET['custom_filter'] ) && $_GET['custom_filter'] == 'true' ) {
        $meta_query = array(
            array(
                'key'     => 'custom_field',
                'value'   => 'custom_value',
                'compare' => '=',
            ),
        );
        $query->set( 'meta_query', $meta_query );
    }
}

这段代码会在后台管理页面,当 URL 中包含 custom_filter=true 参数时,添加一个额外的元数据查询条件。

$query 对象:

传递给钩子函数的 $query 对象是 WP_User_Query 的实例。你可以使用它的 set() 方法来修改查询参数。

$query->set( 'role', 'editor' );
$query->set( 'orderby', 'registered' );
$query->set( 'order', 'ASC' );

条件判断:

在钩子函数中,你通常需要进行一些条件判断,以确定是否需要修改查询。常用的判断条件包括:

  • is_admin(): 判断是否在后台管理页面。
  • is_user_logged_in(): 判断用户是否已登录。
  • get_current_user_id(): 获取当前用户的 ID。
  • $_GET$_POST: 获取 URL 参数或表单数据。

优先级:

你可以通过 add_action() 函数的第三个参数来指定钩子函数的优先级。优先级越低,钩子函数执行得越早。

add_action( 'pre_user_query', 'my_custom_user_query', 10 ); // 默认优先级是 10

实例:根据用户自定义字段排序

假设你想根据用户自定义字段 age 进行排序。WP_User_Query 本身不支持直接按元数据排序,但你可以使用 pre_user_query 钩子来实现。

add_action( 'pre_user_query', 'my_custom_user_age_orderby' );

function my_custom_user_age_orderby( $query ) {
    if ( isset( $query->query_vars['orderby'] ) && $query->query_vars['orderby'] == 'age' ) {
        global $wpdb;

        $query->query_from .= " LEFT JOIN {$wpdb->usermeta} AS um ON {$wpdb->users}.ID = um.user_id AND um.meta_key = 'age'";
        $query->query_orderby = "ORDER BY CAST(um.meta_value AS SIGNED) " . ( isset( $query->query_vars['order'] ) ? $query->query_vars['order'] : 'ASC' );
    }
}

这段代码做了以下几件事:

  1. 检查 orderby 参数: 首先,它检查 WP_User_Queryorderby 参数是否设置为 age。如果是,则执行后续操作。
  2. 连接 usermeta 表: 它使用 LEFT JOINwp_users 表和 wp_usermeta 表连接起来,连接条件是 user_id 等于 wp_users 表的 ID,并且 meta_key 等于 'age'
  3. 修改 orderby 子句: 它将 orderby 子句修改为 ORDER BY CAST(um.meta_value AS SIGNED) ASCCAST(um.meta_value AS SIGNED) 用于将元数据值转换为数字类型,以便进行正确的排序。 ASC 表示升序排列,如果需要降序排列,可以将 ASC 修改为 DESC

现在,你可以在 WP_User_Query 中使用 orderby 参数来按 age 排序了:

$args = array(
    'orderby' => 'age',
    'order'   => 'DESC', // 降序排列
);

$user_query = new WP_User_Query( $args );

更复杂的例子:根据用户角色和自定义字段进行筛选和排序

假设你的网站有不同的用户角色,并且每个用户都有一个自定义字段 membership_level (例如: ‘basic’, ‘premium’, ‘vip’)。 你想创建一个用户列表,可以根据用户角色和 membership_level 进行筛选和排序。

前端筛选表单:

首先,你需要创建一个前端表单,允许用户选择角色和排序方式。

<form id="user-filter-form" method="GET">
    <label for="role">角色:</label>
    <select name="role" id="role">
        <option value="">所有角色</option>
        <option value="subscriber">订阅者</option>
        <option value="editor">编辑</option>
        <option value="author">作者</option>
        <option value="administrator">管理员</option>
    </select>

    <label for="orderby">排序方式:</label>
    <select name="orderby" id="orderby">
        <option value="login">用户名</option>
        <option value="membership_level">会员等级</option>
    </select>

    <label for="order">排序:</label>
    <select name="order" id="order">
        <option value="ASC">升序</option>
        <option value="DESC">降序</option>
    </select>

    <input type="submit" value="筛选">
</form>

<div id="user-list">
    <!-- 用户列表将在这里显示 -->
</div>

<script>
    // 使用 JavaScript/jQuery 处理表单提交和 AJAX 请求
    jQuery(document).ready(function($) {
        $('#user-filter-form').submit(function(e) {
            e.preventDefault(); // 阻止默认表单提交

            var formData = $(this).serialize(); // 获取表单数据

            $.ajax({
                url: ajaxurl, // WordPress AJAX URL
                type: 'GET',
                data: formData + '&action=filter_users', // 添加 action 参数
                success: function(response) {
                    $('#user-list').html(response); // 更新用户列表
                }
            });
        });
    });
</script>

后端处理 AJAX 请求:

接下来,你需要创建一个 PHP 函数来处理 AJAX 请求,并使用 WP_User_Query 来查询用户。

add_action( 'wp_ajax_filter_users', 'filter_users_callback' );
add_action( 'wp_ajax_nopriv_filter_users', 'filter_users_callback' ); // 允许未登录用户访问

function filter_users_callback() {
    $args = array();

    // 获取表单数据
    $role = isset( $_GET['role'] ) ? sanitize_text_field( $_GET['role'] ) : '';
    $orderby = isset( $_GET['orderby'] ) ? sanitize_text_field( $_GET['orderby'] ) : 'login';
    $order = isset( $_GET['order'] ) ? sanitize_text_field( $_GET['order'] ) : 'ASC';

    // 设置查询参数
    if ( ! empty( $role ) ) {
        $args['role'] = $role;
    }

    $args['orderby'] = $orderby;
    $args['order'] = $order;

    // 创建 WP_User_Query 对象
    $user_query = new WP_User_Query( $args );

    // 输出用户列表
    if ( ! empty( $user_query->get_results() ) ) {
        echo '<ul>';
        foreach ( $user_query->get_results() as $user ) {
            echo '<li>用户名: ' . $user->user_login . ', 会员等级: ' . get_user_meta( $user->ID, 'membership_level', true ) . '</li>';
        }
        echo '</ul>';
    } else {
        echo '没有找到用户。';
    }

    wp_die(); // 结束 AJAX 请求
}

使用 pre_user_query 钩子进行自定义排序:

最后,你需要使用 pre_user_query 钩子来处理按 membership_level 排序的情况。

add_action( 'pre_user_query', 'my_custom_membership_level_orderby' );

function my_custom_membership_level_orderby( $query ) {
    if ( isset( $query->query_vars['orderby'] ) && $query->query_vars['orderby'] == 'membership_level' ) {
        global $wpdb;

        $query->query_from .= " LEFT JOIN {$wpdb->usermeta} AS um ON {$wpdb->users}.ID = um.user_id AND um.meta_key = 'membership_level'";
        $query->query_orderby = "ORDER BY um.meta_value " . ( isset( $query->query_vars['order'] ) ? $query->query_vars['order'] : 'ASC' );
    }
}

现在,你可以通过前端表单选择用户角色和排序方式,并动态更新用户列表。

安全注意事项:

  • 数据验证和清理: 始终对用户输入的数据进行验证和清理,以防止 SQL 注入等安全问题。 使用 sanitize_text_field() 等函数来清理用户输入。
  • 权限控制: 确保只有授权用户才能访问用户数据。 使用 WordPress 的权限系统来控制用户访问权限。
  • 避免过度使用: 过度使用 pre_user_query 钩子可能会影响性能。 只在必要时才使用它,并尽量优化你的代码。

总结

今天我们学习了 WP_User_Query 类的强大功能,它能让你以安全便捷的方式进行用户查询。同时,pre_user_query 钩子则提供了更高级的自定义选项,允许你在查询执行前修改查询参数,实现各种复杂的业务逻辑。掌握这些工具,你就能在 WordPress 中构建高度定制化的用户管理系统。

一些思考

WP_User_Query提供了一种安全便捷的方式来查询用户,pre_user_query 钩子允许我们动态修改查询参数。合理利用这些工具,可以构建高度定制化的用户管理系统,满足各种复杂的业务需求。

发表回复

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