Привет, @ user2041:
Понятно, что вам нужно изменить выполненный поиск, что можно сделать, изменив значения в экземпляре WP_User_Search
класса, используемого для поиска (исходный код можно найти по адресу, /wp-admin/includes/user.php
если вы хотите его изучить).
WP_User_Search
объекта
Вот как print_r()
выглядит этот объект с WordPress 3.0.3 при поиске термина " TEST
" и без каких-либо других плагинов, которые могут повлиять на него:
WP_User_Search Object
(
[results] =>
[search_term] => TEST
[page] => 1
[role] =>
[raw_page] =>
[users_per_page] => 50
[first_user] => 0
[last_user] =>
[query_limit] => LIMIT 0, 50
[query_orderby] => ORDER BY user_login
[query_from] => FROM wp_users
[query_where] => WHERE 1=1 AND (user_login LIKE '%TEST%' OR user_nicename LIKE '%TEST%' OR user_email LIKE '%TEST%' OR user_url LIKE '%TEST%' OR display_name LIKE '%TEST%')
[total_users_for_query] => 0
[too_many_total_users] =>
[search_errors] =>
[paging_text] =>
)
pre_user_search
Hook
Чтобы изменить значения WP_User_Search
объекта, вы будете использовать 'pre_user_search'
ловушку, которая получает текущий экземпляр объекта; Я вызвал print_r()
этот хук, чтобы получить доступ к его значениям, которые я отображал выше.
Следующий пример, который вы можете скопировать в functions.php
файл вашей темы или использовать в файле PHP для плагина, который вы пишете, добавляет возможность поиска по описанию пользователя в дополнение к возможности поиска по другим полям. Функция изменяет свойства query_from
и query_where
свойства $user_search
объекта, которые вам необходимы для понимания SQL.
Тщательная модификация SQL в хуках
Код в yoursite_pre_user_search()
функции предполагает, что ни один другой плагин не изменил query_where
предложение до него; если другой плагин изменил предложение where так, что замена 'WHERE 1=1 AND ('
на "WHERE 1=1 AND ({$description_where} OR"
больше не работает, то это тоже сломается. Гораздо сложнее написать надежное дополнение, которое не может быть нарушено другим плагином при такой модификации SQL, но это так и есть.
Добавьте начальные и конечные пробелы при вставке SQL в хуки
Также обратите внимание , что при использовании SQL , как это в WordPress , это всегда хорошая идея , чтобы включать в себя начальные и конечные пробелы такой с " INNER JOIN {$wpdb->usermeta} ON "
иным ваш запрос может содержать следующую команду, где нет пространства перед тем "INNER"
, что будет, конечно , не в состоянии : " FROM wp_postsINNER JOIN {$wpdb->usermeta} ON "
.
Используйте "{$wpdb->table_name"}
вместо имен таблиц жесткого кодирования
Затем обязательно всегда используйте $wpdb
свойства для ссылки на имена таблиц в случае, если сайт изменил префикс таблицы с 'wp_'
чего-то другого. Таким образом "{$wpdb->users}.ID"
, вместо жесткого кодирования лучше обращаться к (с двойными кавычками, а не с одинарными)"wp_users.ID"
.
Ограничьте запрос только при наличии условий поиска
И наконец, нужно изменять запрос только при наличии поискового запроса, который вы можете проверить, проверив search_term
свойство WP_User_Search
объекта.
yoursite_pre_user_search()
Функция для'pre_user_search'
add_action('pre_user_search','yoursite_pre_user_search');
function yoursite_pre_user_search($user_search) {
global $wpdb;
if (!is_null($user_search->search_term)) {
$user_search->query_from .= " INNER JOIN {$wpdb->usermeta} ON " .
"{$wpdb->users}.ID={$wpdb->usermeta}.user_id AND " .
"{$wpdb->usermeta}.meta_key='description' ";
$description_where = $wpdb->prepare("{$wpdb->usermeta}.meta_value LIKE '%s'",
"%{$user_search->search_term}%");
$user_search->query_where = str_replace('WHERE 1=1 AND (',
"WHERE 1=1 AND ({$description_where} OR ",$user_search->query_where);
}
}
Поиск каждой пары мета-ключ-значение требует SQL JOIN
Конечно, вероятная причина, по которой WordPress не позволяет выполнять поиск по полям usermeta, заключается в том, что каждое из них добавляет SQL JOIN
к запросу, а запрос с слишком большим количеством объединений может быть действительно медленным. Если вам действительно нужно выполнить поиск по многим полям, я бы создал '_search_cache'
поле в usermeta, которое собирает всю остальную информацию в одно поле usermeta, чтобы требовать только одно объединение для его поиска.
Ведущие подчеркивания в мета-ключах говорят WordPress не отображать
Обратите внимание, что подчеркивание в '_search_cache'
начале говорит WordPress, что это внутреннее значение, а не то, что когда-либо показывать пользователю.
Создайте кеш поиска с помощью 'profile_update'
и 'user_register'
хуков
Таким образом, вам нужно подключить 'profile_update'
и 'user_register'
то и другое , которые запускаются при сохранении пользователя и регистрации нового пользователя, соответственно. Вы можете получить все мета-ключи и их значения в этих хуках (но не указывать их со значениями, сериализированными или URL-кодированными массивами), а затем объединить их для хранения как одного длинного мета-значения с помощью '_search_cache'
ключа.
Хранить мета как '|'
разделенные парой ключ-значение
Я решил собрать все имена ключей и все их значения и объединить их в одну большую строку с двоеточиями (":"), отделяющими ключи от значений, и вертикальными чертами ("|"), разделяющими пары ключ-значение, как это (I обернул их в несколько строк, чтобы их можно было без прокрутки вправо):
nickname:mikeschinkel|first_name:mikeschinkel|description:This is my bio|
rich_editing:true|comment_shortcuts:false|admin_color:fresh|use_ssl:null|
wp_user_level:10|last_activity:2010-07-28 01:25:46|screen_layout_dashboard:2|
plugins_last_view:recent|screen_layout_post:2|screen_layout_page:2|
business_name:NewClarity LLC|business_description:WordPress Plugin Consulting|
phone:null|last_name:null|aim:null|yim:null|jabber:null|
people_lists_linkedin_url:null
Включает специализированный поиск по мета-использованию key:value
Добавление ключа и значений, как мы это сделали, позволяет выполнять поиск, например, " rich_editing:true
", чтобы найти всех, у кого есть богатое редактирование, или искать " phone:null
", чтобы найти тех, у кого нет номера телефона.
Но остерегайтесь артефактов поиска
Конечно, использование этой техники создает возможные нежелательные артефакты поиска, такие как поиск «бизнес», и все будут перечислены. Если это проблема, то вы можете не использовать такой сложный кеш.
yoursite_profile_update()
Функция для 'profile_update'
и'user_register'
Для функции yoursite_profile_update()
, как yoursite_pre_user_search()
описано выше, можно скопировать в functions.php
файл вашей темы или вы можете использовать в файле PHP для плагина, который вы пишете:
add_action('profile_update','yoursite_profile_update');
add_action('user_register','yoursite_profile_update');
function yoursite_profile_update($user_id) {
$metavalues = get_user_metavalues(array($user_id));
$skip_keys = array(
'wp_user-settings-time',
'nav_menu_recently_edited',
'wp_dashboard_quick_press_last_post_id',
);
foreach($metavalues[$user_id] as $index => $meta) {
if (preg_match('#^a:[0-9]+:{.*}$#ms',$meta->meta_value))
unset($metavalues[$index]); // Remove any serialized arrays
else if (preg_match_all('#[^=]+=[^&]\&#',"{$meta->meta_value}&",$m)>0)
unset($metavalues[$index]); // Remove any URL encoded arrays
else if (in_array($meta->meta_key,$skip_keys))
unset($metavalues[$index]); // Skip and uninteresting keys
else if (empty($meta->meta_value)) // Allow searching for empty
$metavalues[$index] = "{$meta->meta_key }:null";
else if ($meta->meta_key!='_search_cache') // Allow searching for everything else
$metavalues[$index] = "{$meta->meta_key }:{$meta->meta_value}";
}
$search_cache = implode('|',$metavalues);
update_user_meta($user_id,'_search_cache',$search_cache);
}
Обновленная yoursite_pre_user_search()
функция, включающая единый SQL JOIN
для поиска всех интересных мета-значений
Конечно, yoursite_profile_update()
чтобы иметь какой-либо эффект, вам нужно изменить, yoursite_pre_user_search()
чтобы использовать '_search_cache'
мета-ключ вместо описания, которое мы здесь приводим (с теми же оговорками, что и упомянутые выше):
add_action('pre_user_search','yoursite_pre_user_search');
function yoursite_pre_user_search($user_search) {
global $wpdb;
if (!is_null($user_search->search_term)) {
$user_search->query_from .= " INNER JOIN {$wpdb->usermeta} ON " .
"{$wpdb->users}.ID={$wpdb->usermeta}.user_id AND " .
"{$wpdb->usermeta}.meta_key='_search_cache' ";
$meta_where = $wpdb->prepare("{$wpdb->usermeta}.meta_value LIKE '%s'",
"%{$user_search->search_term}%");
$user_search->query_where = str_replace('WHERE 1=1 AND (',
"WHERE 1=1 AND ({$meta_where} OR ",$user_search->query_where);
}
}