Как отфильтровать мой поиск в посте, если он содержит слово в заголовке, содержимом или отрывке?

Вопрос или проблема

Я пытаюсь отфильтровать один поиск, и мне интересно знать, находится ли слово в заголовке, содержимом или аннотации, но без успеха, и в конце концов я застрял.

$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;
}

Почему ваш подход работает

  1. Упрощение логики: Объединение запроса в одну функцию снижает вероятность ошибок и повышает читаемость кода.
  2. Использование LIKE: Правильное применение оператора LIKE позволяет искать подстроки в базе данных, что соответствует вашей цели.
  3. Экранирование данных: Использование esc_sql() защищает от SQL-инъекций, что повышает безопасность вашего приложения.

Заключение

Ваше решение демонстрирует, как важно использовать единую стратегию для фильтрации запросов в WordPress. Объединив логику в одну функцию, вы не только упростили процесс, но и улучшили производительность вашего запроса. Надеюсь, это объяснение поможет другим разработчикам избежать подобных проблем при фильтрации записей по нескольким критериям.

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

Капча загружается...