Вопрос или проблема
Я пытаюсь отфильтровать один поиск, и мне интересно знать, находится ли слово в заголовке, содержимом или аннотации, но без успеха, и в конце концов я застрял.
$args = array(
'post_type' => 'post',
'posts_per_page' => '-1',
'search_prod_title' => $_POST['wordToSearch'],
'post_status' => 'publish',
'orderby' => 'title',
'order' => 'ASC'
);
add_filter( 'posts_where', 'title_filter', 10, 2 );
add_filter( 'posts_where', 'content_filter', 10, 2 );
add_filter( 'posts_where', 'excerpt_filter', 10, 2 );
$posts = new WP_Query($args);
remove_filter( 'posts_where', 'title_filter', 10, 2 );
remove_filter( 'posts_where', 'content_filter', 10, 2 );
remove_filter( 'posts_where', 'excerpt_filter', 10, 2 );
А мои функции фильтров следующие:
function title_filter( $where, &$wp_query )
{
global $wpdb;
if ( $search_term = $wp_query->get( 'search_prod_title' ) ) {
$where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\'';
}
return $where;
}
function content_filter( $where, &$wp_query )
{
global $wpdb;
if ( $search_term = $wp_query->get( 'search_prod_content' ) ) {
$where .= ' AND ' . $wpdb->posts . '.post_content LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\'';
}
return $where;
}
function excerpt_filter( $where, &$wp_query )
{
global $wpdb;
if ( $search_term = $wp_query->get( 'search_prod_excerpt' ) ) {
$where .= ' AND ' . $wpdb->posts . '.post_excerpt LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\'';
}
return $where;
}
Суть в том, что первая функция фильтра работает правильно, поэтому я могу искать по заголовку, и результаты хорошие, но результаты для остальных фильтров неправильные или не работают.
Ну, для тех, кто задавался тем же вопросом, я нашел решение:
Я изменил фильтр, и теперь он выглядит так:
add_filter( 'posts_where', 'general_filter', 10, 2 );
$posts = new WP_Query($args);
remove_filter( 'posts_where', 'general_filter', 10, 2 );
А функция…
function general_filter( $where, &$wp_query )
{
global $wpdb;
if ( $search_term = $wp_query->get( 'search_prod_title' ) ) {
$where .= ' AND (' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\' OR ' . $wpdb->posts . ' .post_excerpt LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\' OR ' . $wpdb->posts . ' .post_content LIKE \'%' . esc_sql( like_escape( $search_term ) ) . '%\')';
}
return $where;
}
Ошибка, в основном, заключалась в том, что весь запрос был неправильным, поэтому, отлаживая переменную $where
, я обнаружил ошибку и исправил ее. Надеюсь, это поможет кому-то.
Ответ или решение
Для фильтрации поисковых запросов в WordPress с целью нахождения слов в заголовке, содержании или аннотации поста, вы сделали значительный шаг с использованием пользовательских фильтров posts_where
. Однако, как вы заметили, первоначальный подход не давал ожидаемых результатов из-за неправильно построенного SQL-запроса. В этом ответе я подробно объясню ваш переведённый на правильный курс подход, что может помочь и другим разработчикам, столкнувшимся с аналогичными проблемами.
Как правильно фильтровать запросы в WordPress
1. Подготовка аргументов запроса
Первоначально вы создаете массив $args
для конфигурации вашего запроса. Это правильный подход, необходимо убедиться, что вы определили все нужные параметры:
$args = array(
'post_type' => 'post',
'posts_per_page' => '-1',
'search_prod_title' => $_POST['wordToSearch'],
'post_status' => 'publish',
'orderby' => 'title',
'order' => 'ASC'
);
В данном случае ключевым параметром для фильтрации будет search_prod_title
, который передает слово для поиска. Учтите, что предыдущие фильтры не работали из-за того, что отдельно вы не передавали параметры для содержимого и аннотации.
2. Оптимизация фильтров с одним объединённым фильтром
Вместо использования нескольких фильтров для каждого поля базы данных, вы объединили их в один общий фильтр general_filter
. Это значительно упрощает логику поиска и исключает вероятность пропуска некоторых условий. Вот как он выглядит:
add_filter('posts_where', 'general_filter', 10, 2);
$posts = new WP_Query($args);
remove_filter('posts_where', 'general_filter', 10, 2);
3. Реализация общего фильтра
Ваша функция general_filter
проверяет, существует ли слово для поиска и формирует SQL-запрос, который включает условия для заголовка, содержимого и аннотации:
function general_filter($where, &$wp_query)
{
global $wpdb;
if ($search_term = $wp_query->get('search_prod_title')) {
$where .= ' AND (' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql(like_escape($search_term)) . '%\'
OR ' . $wpdb->posts . '.post_excerpt LIKE \'%' . esc_sql(like_escape($search_term)) . '%\'
OR ' . $wpdb->posts . '.post_content LIKE \'%' . esc_sql(like_escape($search_term)) . '%\')';
}
return $where;
}
Почему ваш подход работает
- Упрощение логики: Объединение запроса в одну функцию снижает вероятность ошибок и повышает читаемость кода.
- Использование LIKE: Правильное применение оператора
LIKE
позволяет искать подстроки в базе данных, что соответствует вашей цели. - Экранирование данных: Использование
esc_sql()
защищает от SQL-инъекций, что повышает безопасность вашего приложения.
Заключение
Ваше решение демонстрирует, как важно использовать единую стратегию для фильтрации запросов в WordPress. Объединив логику в одну функцию, вы не только упростили процесс, но и улучшили производительность вашего запроса. Надеюсь, это объяснение поможет другим разработчикам избежать подобных проблем при фильтрации записей по нескольким критериям.