Как добавить артикул (SKU) WooCommerce в поисковый запрос?

2 сент. 2020 г., 17:15:14
Просмотры: 20K
Голосов: 4

У меня возникла проблема с добавлением meta_value в поисковый запрос для артикула (SKU) WooCommerce. По умолчанию поиск по SKU работает только в админ-панели.

Я хочу сделать так, чтобы фронтенд-поиск принимал SKU при поиске.

Примечание: SKU нет в заголовке товара. Поэтому мне нужно создать пользовательский запрос.

function SearchFilter($query) {
  
  if ($query->is_search) {
    
    $meta_query_args = array(
      'relation' => 'OR',
      array(
        'key' => '_sku',
        'value' => $query->query_vars['s'],
        'compare' => '=',
      )
    );

    $query->set('post_type', array('post','page', 'product'));
    $query->set('post_status', array('publish'));
    $query->set('meta_query', $meta_query_args);
  }
  
  return $query;

}
add_filter('pre_get_posts','SearchFilter');

Проблема: Когда я размещаю этот код и вывожу текущий SQL-запрос, он выглядит примерно так.

    SELECT SQL_CALC_FOUND_ROWS  bhd_posts.ID FROM bhd_posts  INNER JOIN bhd_postmeta ON ( bhd_posts.ID = bhd_postmeta.post_id ) WHERE 1=1  AND (((bhd_posts.post_title LIKE '%96242-20VH%') OR (bhd_posts.post_excerpt LIKE '%96242-20VH%') OR (bhd_posts.post_content LIKE '%96242-20VH%')))  AND (bhd_posts.post_password = '')  AND ( 
      ( bhd_postmeta.meta_key = '_sku' AND bhd_postmeta.meta_value = '96242-20VH' )
    ) AND bhd_posts.post_type IN ('post', 'page', 'product') AND ((bhd_posts.post_status = 'publish')) GROUP BY bhd_posts.ID ORDER BY bhd_posts.post_title LIKE '%96242-20VH%' DESC, bhd_posts.post_date DESC LIMIT 0, 10

Как видите, он пытается искать "классическую часть" в таблице x_posts для post_title ИЛИ post_excerpt ИЛИ post_content И должен иметь meta_value моего SKU.

Как сказано выше, в заголовках моих товаров нет артикула.

Цель: Иметь возможность искать в заголовках, кратком описании, содержимом или в meta_value ИЛИ искать исключительно по meta_value.

12
Комментарии

Почему вы используете фильтр и me_replace_and_with_or для вашего meta query, вместо того чтобы использовать параметр relation со значением OR? Это крайне необычно. Учтите, что вложения по умолчанию не отображаются в поиске WordPress, их нужно явно добавлять в поиск каким-то образом.

Tom J Nowell Tom J Nowell
2 сент. 2020 г. 18:03:43

Я просто пытаюсь понять, почему OR все равно возвращает AND в запросе.

Patrice Poliquin Patrice Poliquin
2 сент. 2020 г. 18:16:59

Я вижу это из вашего вопроса, но наличие SQL-фильтра — это важная часть, которую нельзя игнорировать или упускать, и она критически важна. Это напрямую связано с проблемой и является наиболее подозрительной частью вашего кода, а также наиболее вероятной причиной вашей проблемы. Нам нужно знать, что он делает и зачем он там, чтобы ответить на вопрос.

Tom J Nowell Tom J Nowell
2 сент. 2020 г. 18:18:32

По умолчанию SKU WooCommerce не включены в поисковый запрос на фронтенде (только в бэкенде). Я хочу, чтобы пользователи на фронтенде могли искать по SKU (meta_key _sku). Но когда я вызываю "стандартный" поисковый запрос, он выдает указанный выше код. Сейчас я пытаюсь изменить поисковый запрос, чтобы добавить в него meta значение. Также мне неинтересно использовать плагин для этого.

Patrice Poliquin Patrice Poliquin
2 сент. 2020 г. 18:20:36

Я понял, вам не нужен SQL фильтр для этого, так как meta_query уже это делает. Также учтите, что рекомендации плагинов здесь не по теме - запрос плагина приведет к закрытию вашего вопроса как оффтопика.

Tom J Nowell Tom J Nowell
2 сент. 2020 г. 18:22:16

Не совсем понимаю, что вы имеете в виду. Если я выполняю простой поисковый запрос, он ищет только в таблице x_posts по полям post_title ИЛИ post_excerpt ИЛИ post_content.

Patrice Poliquin Patrice Poliquin
2 сент. 2020 г. 18:24:37

Но для этого и существует pre_get_posts, и поэтому вы добавляете meta_query. Вам следовало спросить, как включить в результаты поиска посты с мета-значением, а не как исключить вложения из поиска. Большинство увидит заголовок и придумает решение, убрав attachment из массива post_type, что не соответствует вашей задаче.

Tom J Nowell Tom J Nowell
2 сент. 2020 г. 18:27:01

Я понимаю! В любом случае, использование meta_query в pre_get_posts всё равно не работает, потому что условие AND всё ломает. Похоже, что мой relation => 'OR' не срабатывает.

Patrice Poliquin Patrice Poliquin
2 сент. 2020 г. 18:29:15

Однако я сильно подозреваю, что то, что вы буквально хотите, и то, что вам на самом деле нужно — это не одно и то же. Вы буквально спросили, как искать по мета-полям поста. Но это означает, что если пост упоминает SKU в заголовке, но не в мета-полях, он не появится в результатах поиска. Я подозреваю, что вам на самом деле нужно, чтобы он появлялся, так?

Tom J Nowell Tom J Nowell
2 сент. 2020 г. 18:29:18

Также, relation относится к различным условиям мета-запроса, но у вас только одно условие, поэтому параметр relation в данной ситуации бессмысленен. Можете пояснить, что именно вы имели в виду под relation? Это (ключ метаданных поста равен SKU) ИЛИ (????)

Tom J Nowell Tom J Nowell
2 сент. 2020 г. 18:30:34

Если цель состоит в том, чтобы иметь возможность искать посты, которые не упоминают SKU, но имеют этот SKU в своих метаданных, И посты, которые упоминают SKU, но не имеют этого SKU в своих метаданных, то ответ - это невозможно сделать с помощью WP_Query. Для такой функциональности вам нужно пользовательское решение для поиска, скорее всего что-то вроде Elastic Search. Также вам нужно быть очень, очень четким и конкретным в том, что вы хотите, когда задаете вопрос. А пока обновите свой вопрос, чтобы спрашивать о том, что вам нужно, а не о том, как исправить сломанное исправление.

Tom J Nowell Tom J Nowell
2 сент. 2020 г. 18:36:41

Попытался обновить вопрос и описать свой процесс. Надеюсь, теперь будет понятнее.

Patrice Poliquin Patrice Poliquin
2 сент. 2020 г. 18:38:10
Показать остальные 7 комментариев
Все ответы на вопрос 3
3

Если вы используете поиск в WordPress, вы можете добавить этот код, чтобы он работал по артикулам (SKU)

function search_by_sku( $search, &$query_vars ) {
    global $wpdb;
    if(isset($query_vars->query['s']) && !empty($query_vars->query['s'])){
        $args = array(
            'posts_per_page'  => -1,
            'post_type'       => 'product',
            'meta_query' => array(
                array(
                    'key' => '_sku',
                    'value' => $query_vars->query['s'],
                    'compare' => 'LIKE'
                )
            )
        );
        $posts = get_posts($args);
        if(empty($posts)) return $search;
        $get_post_ids = array();
        foreach($posts as $post){
            $get_post_ids[] = $post->ID;
        }
        if(sizeof( $get_post_ids ) > 0 ) {
                $search = str_replace( 'AND (((', "AND ((({$wpdb->posts}.ID IN (" . implode( ',', $get_post_ids ) . ")) OR (", $search);
        }
    }
    return $search;
    
}
    add_filter( 'posts_search', 'search_by_sku', 999, 2 );
20 нояб. 2020 г. 13:57:47
Комментарии

Спасибо за код. Хочу сообщить, что я попробовал его, но он вызывает PHP предупреждение: "Parameter 2 to search_by_sku() expected to be a reference, value given"

JulienVan JulienVan
4 февр. 2022 г. 09:33:38

@JulienVan как вы его вызываете?

AHSAN KHAN AHSAN KHAN
10 авг. 2022 г. 13:46:22

Лучше поздно, чем никогда: если убрать "&" в "&$query_vars", вы избавитесь от предупреждения "expected to be a reference, value given"

TIIUNDER TIIUNDER
16 окт. 2024 г. 20:16:25
0

Не хватает репутации, поэтому не смог оставить комментарий, но вот исправление:

Код от @ahsankhan вроде бы работает, но, как сообщалось, выдавал ошибку "parameter 2".

Если убрать "&" из первой строки, где "&$query_vars", и заменить на просто "$query_vars", то код начинает работать без ошибок.

function search_by_sku( $search, $query_vars ) {
global $wpdb;
if(isset($query_vars->query['s']) && !empty($query_vars->query['s'])){
    $args = array(
        'posts_per_page'  => -1,
        'post_type'       => 'product',
        'meta_query' => array(
            array(
                'key' => '_sku',
                'value' => $query_vars->query['s'],
                'compare' => 'LIKE'
            )
        )
    );
    $posts = get_posts($args);
    if(empty($posts)) return $search;
    $get_post_ids = array();
    foreach($posts as $post){
        $get_post_ids[] = $post->ID;
    }
    if(sizeof( $get_post_ids ) > 0 ) {
            $search = str_replace( 'AND (((', "AND ((({$wpdb->posts}.ID IN (" . implode( ',', $get_post_ids ) . ")) OR (", $search);
    }
}
return $search;
}
  add_filter( 'posts_search', 'search_by_sku', 999, 2 );
15 дек. 2022 г. 03:18:57
0
// модифицировано для поиска по артикулу в вариациях товаров ;)

function search_by_sku($search, &$query_vars)
{
    global $wpdb;
    if (isset($query_vars->query['s']) && !empty($query_vars->query['s'])) {
        // простые товары
        $args = array(
            'posts_per_page' => -1,
            'post_type' => 'product',
            'meta_query' => array(
                array(
                    'key' => '_sku',
                    'value' => $query_vars->query['s'],
                    'compare' => 'LIKE'
                )
            )
        );

        $posts = get_posts($args);
        $get_post_ids = array();

        foreach ($posts as $post) {
            $get_post_ids[] = $post->ID;
        }


        // вариации товаров
        $args = array(
            'posts_per_page' => -1,
            'post_type' => 'product_variation',
            'meta_query' => array(
                array(
                    'key' => '_sku',
                    'value' => $query_vars->query['s'],
                    'compare' => 'LIKE'
                )
            )
        );

        $posts_variation = get_posts($args);
        
        if (empty($posts_variation) && empty($posts)) return $search;

        foreach ($posts_variation as $post) {
            $get_post_ids[] = $post->post_parent;
        }

        if (sizeof($get_post_ids) > 0) {
            $search = str_replace('AND (((', "AND ((({$wpdb->posts}.ID IN (" . implode(',', $get_post_ids) . ")) OR (", $search);
        }
    }
    return $search;

}

add_filter('posts_search', 'search_by_sku', 999, 2);
18 авг. 2023 г. 15:08:05