Поиск продуктов Woocommerce с использованием пользовательских полей

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

У меня есть интернет-магазин на WooCommerce. Мой поиск ищет только в заголовке товара, кратком описании и полях SKU. Я хочу, чтобы поиск также осуществлялся по некоторым пользовательским полям (таким как “_barcode” и “_mpn”). Я хочу искать на страницах продуктов, а не в административной панели.

У меня есть этот скрипт, но когда я использую его в functions.php, я не могу искать по заголовку товара или краткому описанию.

function search_filter( $query ) {

    $key_fields = array ( '_barcode', '_mpn', '_sku' );
    $value_field = $query->query_vars['s'];
    $query->query_vars['s'] = '';

    if ( !is_admin() && $value_field != '' ) {

        $filter_query = array( 'relation' => 'OR' );

        foreach ( $key_fields as $one_field ) {
            array_push ( $filter_query , array (
                'key' => $one_field,
                'value' => $value_field,
                'compare' => 'LIKE'
            ) );
        }
        $query->set( 'meta_query' , $filter_query );
    }
}
add_filter( 'pre_get_posts' , 'search_filter');

Почему я не могу искать по заголовку товара или краткому описанию, используя этот скрипт? Есть идеи?

Спасибо.

Обычно я ввожу штрих-код или номер SKU. В результате я получаю 1 результат. Когда я не использую этот скрипт, результаты поиска появляются примерно за 2-3 секунды. Вот мой скрипт:

function cf_search_join( $join ) {
    global $wpdb;

    if ( is_search() ) {    
        $join .=' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    }
    return $join;
}
add_filter('posts_join', 'cf_search_join');

function cf_search_where( $where ) {
    global $pagenow, $wpdb;

    if ( is_search() ) {
        $where = preg_replace(
          "/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
          "(".$wpdb->posts.".post_title LIKE $1 OR ".$wpdb->posts.".post_excerpt LIKE $1) OR (".$wpdb->postmeta. ".meta_value LIKE $1 AND ".$wpdb->postmeta. ".meta_key IN ('_barcode','_sku') )", $where );
    }

    return $where;
}
add_filter('posts_where', 'cf_search_where');

function cf_search_distinct( $where ) {
    global $wpdb;

    if ( is_search() ) {
        return "DISTINCT";
    }

    return $where;
}
add_filter( 'posts_distinct', 'cf_search_distinct' );

Ответ или решение

Для того чтобы настроить поиск по продуктам WooCommerce с учетом индивидуальных пользовательских полей (например, "_barcode" и "_mpn") и при этом не ограничивать поиск заголовком и кратким описанием продукта, вам необходимо модифицировать свой код. Давайте решим вашу проблему по шагам.

Шаг 1: Обновление функции search_filter

Ваш первоначальный код фильтра поиска не учитывает поля заголовка и краткого описания при выполнении поиска. Предлагаю немного его изменить, чтобы он включал заголовок (post_title) и краткое описание (post_excerpt) в запрос.

Вот улучшенный код:

function search_filter( $query ) {
    if (!is_admin() && $query->is_main_query() && $query->is_search()) {
        $meta_query = array('relation' => 'OR');

        // Добавление метаполей для поиска
        $meta_query[] = array(
            'key'     => '_barcode',
            'value'   => $query->query_vars['s'],
            'compare' => 'LIKE'
        );
        $meta_query[] = array(
            'key'     => '_mpn',
            'value'   => $query->query_vars['s'],
            'compare' => 'LIKE'
        );

        // Изменяем условие поискового запроса
        $query->set('meta_query', $meta_query);

        // Добавляем поиск по заголовку и краткому описанию
        $query->set('s', $query->query_vars['s']);
    }
}
add_filter( 'pre_get_posts', 'search_filter' );

Шаг 2: Функция соединения cf_search_join

Функция соединения нужна для того, чтобы связать записи на основе метаполей. Убедитесь, что у вас есть:

function cf_search_join( $join ) {
    global $wpdb;

    if ( is_search() ) {
        $join .= ' LEFT JOIN ' . $wpdb->postmeta . ' ON ' . $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    }
    return $join;
}
add_filter('posts_join', 'cf_search_join');

Шаг 3: Функция фильтрации cf_search_where

Функция cf_search_where должна быть изменена следующим образом:

function cf_search_where( $where ) {
    global $wpdb;

    if ( is_search() ) {
        $search_value = esc_sql($_GET['s']);
        $where = preg_replace(
            "/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
            "($wpdb->posts.post_title LIKE '$search_value' OR $wpdb->posts.post_excerpt LIKE '$search_value')", $where );

        // Добавляем проверки для метаполей
        $where .= " OR (".$wpdb->postmeta.".meta_value LIKE '%$search_value%' AND ".$wpdb->postmeta.".meta_key IN ('_barcode', '_mpn'))";
    }

    return $where;
}
add_filter('posts_where', 'cf_search_where');

Шаг 4: Убедитесь, что используется DISTINCT

Функция cf_search_distinct гарантирует, что дублирующиеся результаты не будут возвращены:

function cf_search_distinct( $where ) {
    global $wpdb;

    if ( is_search() ) {
        return "DISTINCT";
    }

    return $where;
}
add_filter( 'posts_distinct', 'cf_search_distinct' );

Заключение

Собрав все функции вместе, вы обеспечите возможность поиска не только по заголовкам и кратким описаниям, но и по пользовательским полям _barcode и _mpn. Убедитесь, что все эти функции добавлены в файл functions.php вашей темы. После внесения изменений проверьте поиск на своем сайте WooCommerce, чтобы убедиться, что он работает должным образом и отображает ожидаемые результаты.

Если у вас будут дополнительные вопросы или проблемы, не стесняйтесь задавать!

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

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