pre_user_query. Фильтрация пользователей перед выводом на сайте (изменение SQL запроса).

Прежде всего нужно понять один важный момент. Когда я только увидел в коде экшн pre_user_query, я подумал: «А, наверное это что-то наподобие pre_get_posts, но только для пользователей».

Ничего подобного. На самом деле существуют два основных фильтра, связанных с полечением пользователей:

  1. pre_get_users (как раз он и является аналогом pre_get_posts для постов) выполняется до того, как спарсится SQL запрос и позволяет поменять какие-то параметры WP_User_Query, например количество выводимых пользователей, их сортировка и т.д.
  2. pre_user_query вступает в действие уже после того, как спарсится SQL запрос, непосредственно перед его выполнением. Ему и посвятим этот пост.

Если вы пришли сюда не за готовым примером, а для того, чтобы во всём разобраться, то предлагаю начать с того, чтобы вставить код ниже в functions.php вашей текущей темы и перейти на любую страницу сайта, где присутствует вывод пользователей, например в список пользователей в админке.

add_action( 'pre_user_query', 'true_funkciya' );
 
function true_funkciya( $zapros ){
    print_r( $zapros );
}

Статья рассчитана на пользователей, которые уже кое-в-чём понимают, поэтому я не буду объяснять значение простых функций наподобие print_r().

И ещё кое-что, если ваша версия WordPress ниже, чем 3.1, то pre_user_query у вас работать не будет (попробуйте использовать вместо неё pre_user_search, а ещё лучше — обновитесь).

Окей, а теперь давайте на примерах посмотрим, что с этим можно сделать.

1. Скрытый пользователь.

Итак, как полностью скрыть какого-либо пользователя из сайта и админки, но при этом сам он себя будет видеть. Конечно при помощи pre_user_query.

add_action('pre_user_query','true_skrivaem_polzovatelya');
 
function true_skrivaem_polzovatelya( $zapros ) {
 
    // так как сам себя пользователь видеть должен, поэтому нам понадобится следующее условия
    $tekuchij_polzovatel = wp_get_current_user();
    if ($tekuchij_polzovatel->ID != 2) { // я взял пользователя с ID = 2, вы можете использовать любого другого
        global $wpdb;
        // используем обычную str_replace() для того, чтобы исключить пользователя из SQL запроса 
        $zapros->query_where = str_replace('WHERE 1=1', "WHERE 1=1 AND {$wpdb->users}.ID<>2", $zapros->query_where); // если будете менять ID, то не забудьте поменять и тут
    }
 
}

Что можно понять из этого примера?

  • То, что я извращаюсь с транслитом (надеюсь, это не слишком мешает, просто у меня есть ещё и англоязычный блог, на который я переношу многие из статей — не хочу получить дубликаты кода).
  • Условие на проверку текущего пользователя вы кстати можете вынести за пределы функции и поставить под условие add_action(), в принципе получится вот так:
    $tekuchij_polzovatel = wp_get_current_user();
    if ($tekuchij_polzovatel->ID != 2)
        add_action('pre_user_query','true_skrivaem_polzovatelya');
  • Хоть пользователь и пропадёт из сайта, для того, чтобы полностью всех обмануть, вам также придётся поработать со счетчиками количества пользователей, для того, чтобы вам было понятно, о чём я говорю, вот скриншот:
    Несоответствие отображаемого количества пользователей и значения счетчика.

    Но не стоит беспокоиться, этот счетчик тоже можно спокойно поправить парой хуков, только это уже пожалуй тема отдельного поста.

  • Как видите, мы просто заменили WHERE-часть запроса, те, кто хорошо знаком с базами данных, увидит здесь гораздо большую свободу действий.

2. Если пользователь не администратор, то скрываем всех администраторов

По сути всё основывается на том же принципе, что и в предыдущем примере, только SQL-запрос станет намного интереснее. Пример будет также основываться на ролях пользователей, про которые можно почитать здесь.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
add_action('pre_user_query','true_skrivaem_administratorov');
 
function true_skrivaem_administratorov( $zapros ) {
 
    // так же, как и в предыдущем примере получаем текущего пользователя и убеждаемся, что он не администратор
    // разумеется тут можно использовать любую свою проверку
    $tekuchij_polzovatel = wp_get_current_user();
    if ( $tekuchij_polzovatel->roles[0] != 'administrator' ) { 
        global $wpdb;
        $zapros->query_where = str_replace(
            'WHERE 1=1', 
            "WHERE 1=1 AND {$wpdb->users}.ID IN (
                SELECT {$wpdb->usermeta}.user_id FROM $wpdb->usermeta 
                    WHERE {$wpdb->usermeta}.meta_key = '{$wpdb->prefix}capabilities'
                    AND {$wpdb->usermeta}.meta_value NOT LIKE '%administrator%')", 
            $zapros->query_where
        );
    }
}

Если вам всё ещё многое непонятно, могу порекомендовать почитать статью про базы данных в WordPress, про $wpdb тут.

Теперь же краткое описание того, что сделали — как известно, название роли пользователя хранится в таблице базы данных wp_usermeta (заменить wp_ на используемый у вас префикс) под ключом wp_capabilities. И в примере мы получили только тех пользователей, у которых в значении wp_capabilities в базе данных отсутствует administrator.

3. Расширенный поиск пользователей

По умолчанию WordPress позволяет производить поиск пользователей по уже определенным полям, например по логину user_login, емайлу user_email, URL user_url, отображаемому имени display_name, айди ID и по нику user_nicename. Всё, что нам разрешается, это исключить какие-либо из колонок из поиска при помощи фильтра user_search_columns.

Однако и тут pre_user_query открывает перед нами новые возможности — мы можем можем включить в поиск как любые метаданные пользователя, так и заголовки постов!

add_action('pre_user_query','true_poisk_po_meta');
 
 
function true_poisk_po_meta( $zapros ){
    // прежде всего делаем несколько проверок, для того, чтобы код применялся только при поиске пользователей
    if ( $zapros->query_vars['search'] ){
        $poisk = trim( $zapros->query_vars['search'], '*' );
        if ( $_REQUEST['s'] == $poisk ){
            global $wpdb;
 
            // добавляем Имя first_name пользователя в поиск
            $zapros->query_from .= " JOIN {$wpdb->usermeta} fn ON fn.user_id = {$wpdb->users}.ID AND fn.meta_key = 'first_name'";
 
            // добавляем любые метаданные пользователя
            // $zapros->query_from .= " JOIN {$wpdb->usermeta} cstm ON cstm.user_id = {$wpdb->users}.ID AND cstm.meta_key = 'ВАШ ПРОИЗВОЛЬНЫЙ meta_key'";
 
            // ну и пример с заголовками постов (я включил все посты, любого статуса и типа, но вы можете это доработать)
            $zapros->query_from .= " JOIN {$wpdb->posts} psts ON psts.post_author = {$wpdb->users}.ID";
 
            // решаем, по каким полям в итоге производить поиск
            $posik_po = array( 'user_login', 'user_email', 'fn.meta_value', 'psts.post_title' );
 
            // применяем к запросу
            $zapros->query_where = 'WHERE 1=1' . $zapros->get_search_sql( $poisk, $posik_po, 'both' );
        }
    }
}

Источник: misha.blog

Миша Рудрастых

Путешествует по миру и рассказывает всем о WordPress лично, у себя в блогах и на курсах в Санкт-Петербурге. Умеет просто объяснять сложные вещи, делает это красиво. Организовывает неплохие WordCamp's, но совсем не умеет слушать чужие доклады.

Добавить комментарий

%d такие блоггеры, как: