返回介绍

WooCommerce 产品搜索支持 SKU

发布于 2022-01-02 19:03:56 字数 5938 浏览 935 评论 2 收藏 0

WooCommerce 前台搜索只会从标题、内容、摘要里搜索,产品 SKU 有时比较重要,但它存储在 custom field 里,默认无法通过 SKU 搜索产品。本文介绍的方法可以让产品搜索支持 SKU。

默认搜索

假设我要搜 SLK3423 这个 SKU,默认搜索的 SQL 语句如下所示,可以看出只搜了标题、摘要和内容。

SELECT SQL_CALC_FOUND_ROWS wp_posts.id
FROM   wp_posts
WHERE  1 = 1
       AND ( wp_posts.id NOT IN (SELECT object_id
                                 FROM   wp_term_relationships
                                 WHERE  term_taxonomy_id IN ( 6 )) )
       AND (( ( wp_posts.post_title LIKE '%SLK3423%' )
               OR ( wp_posts.post_excerpt LIKE '%SLK3423%' )
               OR ( wp_posts.post_content LIKE '%SLK3423%' ) ))
       AND wp_posts.post_type = 'product'
       AND ( wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private' )
GROUP  BY wp_posts.id
ORDER  BY wp_posts.post_title LIKE '%SLK3423%' DESC,
          wp_posts.post_date DESC

让搜索支持 custom field

从 WordPress 角度考虑,只要让搜索支持 custom field,不就能搜 SKU 了吗。Adam J. Balée 在 Search WordPress by Custom Fields without a Plugin 中介绍了让 WordPress 的搜索支持 custom field 的方法。代码如下:

<?php
/**
 * Extend WordPress search to include custom fields
 *
 * https://adambalee.com
 */

/**
 * Join posts and postmeta tables
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_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' );

/**
 * Modify the search query with posts_where
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_where
 */
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->postmeta.".meta_value LIKE $1)", $where );
    }

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

/**
 * Prevent duplicates
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_distinct
 */
function cf_search_distinct( $where ) {
    global $wpdb;

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

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

将这段代码放进主题的 functions.php 中,搜索就支持 custom field 了,sku 也属于 custom field,自然就能通过 sku 查找产品。

只搜索 SKU 字段

产品其它 custom field 可能含有和 sku 类似的字符串,但并不是我们想要的,我们希望只匹配 SKU 而忽略其它 custom field,这时我们可以这样修改一下 posts_where

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->postmeta.".meta_key='_sku' AND ".$wpdb->postmeta.".meta_value LIKE $1)", $where );
    }

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

这样修改后,查询产品的 SQL 语句变成了下面这样:

SELECT SQL_CALC_FOUND_ROWS distinct wp_posts.ID
FROM   wp_posts
       LEFT JOIN wp_postmeta
              ON wp_posts.id = wp_postmeta.post_id
WHERE  1 = 1
       AND ( wp_posts.id NOT IN (SELECT object_id
                                 FROM   wp_term_relationships
                                 WHERE  term_taxonomy_id IN ( 6 )) )
       AND (( ( wp_posts.post_title LIKE '%SLK3423%' )
               OR ( wp_postmeta.meta_key = '_sku' AND wp_postmeta.meta_value LIKE '%SLK3423%' )
               OR ( wp_posts.post_excerpt LIKE '%SLK3423%' )
               OR ( wp_posts.post_content LIKE '%SLK3423%' ) ))
       AND wp_posts.post_type = 'product'
       AND ( wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private' )
GROUP  BY wp_posts.id
ORDER  BY wp_posts.post_title LIKE '%SLK3423%' DESC,
          wp_posts.post_date DESC

注意:这种方法只会搜索 post_type 是 product 的产品,variable product 的 variation 可以有自己的 sku,variation 的 post_type 是 product_variation,所以这种方法是搜不到 variation 的 sku 的。

为什么不能用 WooCommerce Meta Query

WooCommerce 的 product search 有一个 action 叫 woocommerce_product_query ,可以修改 Product Query 参数,搜索 SKU 是 meta query,通过这个 action 添加一个 meta query 不就好了吗?

add_action( 'woocommerce_product_query', 'sola_wc_meta_query', 10, 2 );
function sola_wc_meta_query( $query, $wc_query ){
    if( $query->is_search() ){
        $meta_query[] =  array(
            array(
                'key'=> '_sku',
                'value' => sanitize_text_field( $query->get('s') ),
                'compare'=> 'LIKE'
            )
        );
        $query->set( 'meta_query', $meta_query ); 
    }
}

这样加完后是搜不到 sku 的,为什么?看看它生成的 SQL 就明白了,如下所示,这段 SQL 要找 post_title 和 meta_value 中都含有搜索关键词的产品,除非你把 SKU 写到标题里,否则是找不到的。我们想要 OR 的关系,而不是 AND。而前面的方法用正则表达式把 AND 替换成了 OR。

SELECT SQL_CALC_FOUND_ROWS wp_posts.id
FROM   wp_posts
       INNER JOIN wp_postmeta
               ON ( wp_posts.id = wp_postmeta.post_id )
WHERE  1 = 1
       AND ( wp_posts.id NOT IN (SELECT object_id
                                 FROM   wp_term_relationships
                                 WHERE  term_taxonomy_id IN ( 6 )) )
       AND (( ( wp_posts.post_title LIKE '%SLK3423%' )
               OR ( wp_posts.post_excerpt LIKE '%SLK3423%' )
               OR ( wp_posts.post_content LIKE '%SLK3423%' ) ))
       AND ((( wp_postmeta.meta_key = '_sku'AND wp_postmeta.meta_value LIKE '%SLK3423%' )))
       AND wp_posts.post_type = 'product'
       AND ( wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private' )
GROUP  BY wp_posts.id

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

JSmiles 回复 Suzann 2023-12-29 10:00:12

函数一般加到主题的 functions.php 里面即可!

Suzann 2023-12-26 20:54:43

看了这么多办法,包括装插件,数这个最靠谱。
能具体说下怎么在WORDPRESS里写上这串代码吗

~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文