Вопрос или проблема
У меня есть пользовательский тип записи, и я хотел бы искать по заголовкам И пользовательскому мета-ключу. Я попробовал несколько различных вариантов, но могу искать только по заголовкам ИЛИ моему пользовательскому мета-ключу, но не по обоим. Мне не нужно искать по содержимому.
Вот что у меня есть, это успешно ищет по моему мета-ключу, но не ищет по заголовку.
add_action( 'pre_get_posts', 'filter_files_admin_columns' );
function filter_files_admin_columns( $query ) {
if ( !is_admin() || 'eri-files' !== $query->get( 'post_type' ) ) {
return;
}
// Очистить параметр поиска 's'
$search_term = $query->get( 's' );
$query->set( 's', '' );
if ( !empty( $search_term ) ) {
$meta_query = [
'relation' => 'OR',
[
'key' => '',
'value' => $search_term,
'compare' => 'LIKE',
],
];
// Определить пользовательские поля для поиска
$custom_fields = [ '_post_url' ];
// Сформировать мета-запрос
foreach ( $custom_fields as $custom_field ) {
$meta_query[] = [
'key' => $custom_field,
'value' => $search_term,
'compare' => 'LIKE',
];
}
// Установить meta_query
$query->set( 'meta_query', $meta_query );
}
}
Я пытался просто начать с $meta_query = [ 'relation' => 'OR' ];
, а также сменить первый ключ на 'post_title'
, но это не дало результата.
Я понимаю, что очистка поискового термина с помощью $query->set( 's', '' );
предотвращает поиск по заголовку, но без этого я не могу заставить это искать по мета-ключу. Поэтому я пытаюсь вернуть поддержку заголовка. Если есть другой способ заставить его искать по моему мета-ключу, не очищая поисковой термин, дайте мне знать.
После того как я задал тот же вопрос нескольким AI-чат-ботам, CoPilot наконец дал мне ответ, который работает для обоих:
add_action( 'pre_get_posts', 'filter_files_admin_columns' );
function filter_files_admin_columns( $query ) {
if ( !is_admin() || 'eri-files' !== $query->get( 'post_type' ) ) {
return;
}
add_filter( 'posts_search', 'custom_search_query', 10, 2 );
function custom_search_query( $search, $wp_query ) {
global $wpdb;
if ( empty( $search ) ) {
return $search;
}
$search_term = $wp_query->get( 's' );
if ( ! $search_term ) {
return $search;
}
$search = "AND (
{$wpdb->posts}.post_title LIKE '%" . esc_sql( $wpdb->esc_like( $search_term ) ) . "%'
OR {$wpdb->posts}.ID IN (
SELECT post_id
FROM {$wpdb->postmeta}
WHERE meta_key = '_post_url'
AND meta_value LIKE '%" . esc_sql( $wpdb->esc_like( $search_term ) ) . "%'
)
)";
return $search;
}
}
Заголовок записи не хранится в метаданных, поэтому добавление его туда не сработает. Я подозреваю, что сохранение параметра s
и добавление meta_query
для _post_url
(пользовательский мета-ключ) должны сработать (не тестировалось):
add_action( 'pre_get_posts', static function ( $query ) {
if ( ! is_admin() || 'eri-files' !== $query->get( 'post_type' ) ) {
return;
}
if ( empty( $query->get( 's' ) ) {
return;
}
$query->set( 'meta_query', array(
array(
'key' => '_post_url',
'value' => $query->get( 's' ),
'compare' => 'LIKE',
),
) );
// Ограничить поиск до столбца post_title.
$query->set( 'search_columns', array( 'post_title' ) );
} );
Это должно вернуть записи, где как заголовок записи, так и метаданные _post_url
соответствуют поисковому термину.
Ответ или решение
Для того чтобы осуществлять поиск по наименованиям и пользовательским мета-полям в административной панели WordPress, необходимо использовать хук pre_get_posts
и дополнительно обработать стандартный механизм поиска. В этом ответе я представлю вам детальный подход к реализации данной задачи.
Определение проблемы
Вы стремитесь к тому, чтобы осуществлять поиск не только по заголовкам ваших пользовательских записей, но и по пользовательским мета-данным, таким как мета-ключ ‘_post_url’. При этом важно сохранить возможность поиска по заголовкам, вместо того, чтобы попусту очищать поисковый запрос, как это было в вашем предыдущем решении.
Рекомендации по реализации
Ниже приведен пример кода, который позволяет выполнять поиск одновременно по заголовкам и пользовательским мета-данным. Этот код добавляется в файл functions.php
вашей темы или в специальный плагин.
add_action( 'pre_get_posts', 'filter_files_admin_columns' );
function filter_files_admin_columns( $query ) {
// Проверяем, что мы в админке, и что текущий пост-тип соответствует нашему.
if ( !is_admin() || 'eri-files' !== $query->get( 'post_type' ) ) {
return;
}
// Получаем поисковый термин.
$search_term = $query->get( 's' );
if ( empty( $search_term ) ) {
return;
}
// Отменяем стандартный механизм поиска.
add_filter( 'posts_search', 'custom_search_query', 10, 2 );
function custom_search_query( $search, $wp_query ) {
global $wpdb;
// Проверяем, пустой ли запрос.
if ( empty( $search ) ) {
return $search;
}
// Получаем поисковый термин.
$search_term = $wp_query->get( 's' );
if ( ! $search_term ) {
return $search;
}
// Формируем индивидуальный SQL-запрос для поиска по заголовкам и мета-ключу.
$search = " AND (
{$wpdb->posts}.post_title LIKE '%" . esc_sql( $wpdb->esc_like( $search_term ) ) . "%'
OR {$wpdb->posts}.ID IN (
SELECT post_id
FROM {$wpdb->postmeta}
WHERE meta_key = '_post_url'
AND meta_value LIKE '%" . esc_sql( $wpdb->esc_like( $search_term ) ) . "%'
)
)";
return $search;
}
}
Объяснение кода
-
Проверка условий: Мы проверяем, что текущий запрос выполняется в административной панели и что пост-тип соответствует ‘eri-files’.
-
Получение поискового термина: Если поисковый термин пуст, мы завершаем выполнение функции.
-
Перезапись механизма поиска: С помощью хука
add_filter('posts_search', ...)
мы создаем кастомный поиск по заголовкам и мета-данным. -
Формирование запроса: Мы используем SQL запроса для поиска в заголовках (
post_title
) и в экземплярах мета-данных (_post_url
). Используемesc_sql
иesc_like
, чтобы избежать SQL-инъекций и корректно экранировать специальные символы.
Заключение
С помощью описанного метода вы сможете сочетать поиск по заголовкам и мета-данным в административной панели WordPress. Это повысит удобство использования и эффективность работы с пользовательским пост-типом. Убедитесь, что вы протестировали этот код в безопасной среде перед развёртыванием на производственном сайте.