Вопрос или проблема
У меня есть пользовательский тип записи, который использует несколько метаполей. В административной области я хотел бы иметь возможность искать по этим метаполям. В данный момент я реализовал это в my functions.php с помощью следующего кода:
function custom_search_query( $query ) {
if ( is_admin() && is_main_query() && $query->is_search ) {
$query->set('meta_query', array(
"relation" => "OR",
array(
'key' => 'first_name',
'value' => $query->query_vars['s'],
'compare' => 'LIKE'
),
array(
'key' => 'last_name',
'value' => $query->query_vars['s'],
'compare' => 'LIKE'
),
array(
'key' => 'email',
'value' => $query->query_vars['s'],
'compare' => 'LIKE'
)
));
$query->set('post_type', 'application'); // необязательно
};
}
add_filter( 'pre_get_posts', 'custom_search_query');
Проблема в том, что с этим кодом, если я ищу, скажем, имя “walker”, и у меня есть записи моего пользовательского типа, которые соответствуют этому критерию в метаполе, я не получаю результатов. Причина, по которой это происходит, заключается в том, что SQL, который генерируется выполняемым запросом, выглядит так:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id) WHERE 1=1
AND (((wp_posts.post_title LIKE '%walker%') OR (wp_posts.post_content LIKE '%walker%')))
AND wp_posts.post_type="application" AND (wp_posts.post_status="publish"
OR wp_posts.post_status="future" OR wp_posts.post_status="draft"
OR wp_posts.post_status="pending" OR wp_posts.post_status="private")
AND ((wp_postmeta.meta_key = 'first_name' AND CAST(wp_postmeta.meta_value AS CHAR) LIKE '%walker%')
OR (mt1.meta_key = 'last_name' AND CAST(mt1.meta_value AS CHAR) LIKE '%walker%')
OR (mt2.meta_key = 'email' AND CAST(mt2.meta_value AS CHAR) LIKE '%walker%') )
GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 20
Запрос пытается искать как в заголовке, так и в содержании записи, так и в моих пользовательских полях. Я не хочу, чтобы он искал совпадения в заголовке или содержании. Как я могу заставить запрос остановиться и таким образом вернуть результаты, которые я хочу?
Существует плагин, который называется Search everything, где вы можете уточнить, что вы хотите искать. Он обрабатывает пользовательские поля, записи и, конечно, заголовки.
function custom_post_type_search($query) {
global $pagenow, $post_type;
// Проверяем, находимся ли мы на экране администратора и это главный запрос для пользовательского типа записи
if (is_admin() && $pagenow == 'edit.php' && $post_type == 'application') {
// Проверяем, есть ли поисковой запрос
if (!empty($_GET['s'])) {
// Определяем массив пользовательских метаполей, которые вы хотите включить в поиск
$meta_fields = array('first_name', 'last_name', 'email');
// Формируем мета-запрос
$meta_query = array('relation' => 'OR');
foreach ($meta_fields as $meta_field) {
$meta_query[] = array(
'key' => $meta_field,
'value' => $_GET['s'],
'compare' => 'LIKE',
);
}
// Исключаем заголовок и контент из поиска
$query->set('s', ''); // Очищаем стандартный поиск
$query->set('search_fields', array('meta')); // Ищем только в метаполях
// Добавляем мета-запрос в основной запрос
$query->set('meta_query', $meta_query);
}
}
}
// Подключаемся к действию pre_get_posts
add_action('pre_get_posts', 'custom_post_type_search');
В приведенном выше коде, если присутствует поисковой запрос ($_GET['s']
не пуст), создается мета-запрос для указанных метаполей.
Он исключает стандартный поиск по заголовку и содержанию, устанавливая $query->set('search_fields', array('meta'))
.
Ответ или решение
Настройка поиска по метаполям в административной области WordPress
Вводные сведения
Ваша цель — создать функционал поиска в административной области WordPress, который позволит осуществлять поиск по метаполям произвольного типа записи, минуя заголовок и содержимое. Это может быть полезно, если данные, которыми вы работаете, хранятся в метаполях, и их нужно быстро найти без лишних затруднений.
Проблема
Согласно вашему описанию, текущая реализация поиска не возвращает ожидаемые результаты, поскольку SQL-запрос, создаваемый при поиске, включает условия для заголовка и содержимого записи. Вам необходимо изменить этот запрос так, чтобы он выполнял поиск только по указанным метаполям.
Решение
Для достижения поставленной задачи необходимо внести изменения в существующий код в файле functions.php
. Вот как можно это сделать:
function custom_post_type_search($query) {
global $pagenow, $post_type;
// Проверяем, что мы находимся в административной области и это основной запрос для произвольного типа записи
if (is_admin() && $pagenow == 'edit.php' && $post_type == 'application') {
// Проверяем, есть ли поисковой запрос
if (!empty($_GET['s'])) {
// Указываем массив метаполей, которые необходимо включить в поиск
$meta_fields = array('first_name', 'last_name', 'email');
// Формируем мета-запрос
$meta_query = array('relation' => 'OR');
foreach ($meta_fields as $meta_field) {
$meta_query[] = array(
'key' => $meta_field,
'value' => $_GET['s'],
'compare' => 'LIKE',
);
}
// Очищаем стандартный поиск
$query->set('s', '');
// Можно также исключить стандартное поведение поиска, установив переменную
remove_filter('posts_search', 'search_by_title_only', 10);
// Добавляем мета-запрос к основному запросу
$query->set('meta_query', $meta_query);
}
}
}
// Привязываем нашу функцию к хуку pre_get_posts
add_action('pre_get_posts', 'custom_post_type_search');
Объяснение кода
-
Проверка контекста: Код проверяет, что мы находимся в административной области (
is_admin()
), а также что это основной запрос для вашего произвольного типа записиapplication
. -
Обработка поискового запроса: Если поисковой запрос есть, мы определяем метаполя (
first_name
,last_name
,email
) и создаем мета-запрос, который будет использоваться для поиска. -
Очистка стандартного поиска: Мы обнуляем значение стандартного поля поиска (
$query->set('s', '');
), предотвращая тем самым поиск по заголовкам и содержимому. -
Удаление фильтра: Удаление фильтра
search_by_title_only
гарантирует, что поисковый запрос не будет по умолчанию включать заголовки. -
Дополнение основного запроса мета-запросом: Мы добавляем созданный нами мета-запрос в основной запрос.
Заключение
После внесения предложенных изменений в код, поиск в административной области WordPress будет фокусироваться исключительно на заданных вами метаполях. Это существенно упростит процесс поиска нужной информации и повысит его эффективность. Важно также регулярно тестировать функциональность после обновлений, чтобы убедиться в стабильности работы кода.