Вопрос или проблема
У меня есть интернет-магазин на 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, чтобы убедиться, что он работает должным образом и отображает ожидаемые результаты.
Если у вас будут дополнительные вопросы или проблемы, не стесняйтесь задавать!