WooCommerce后台的产品检索与前台搜索略有不同。前台是在WordPress默认搜索的基础上修改,后台直接用了一套自己的逻辑,从wc_product_meta_lookup这个表里检索产品,调用函数WC_Product_Data_Store_CPT->search_products()
,这个函数只有一个filter——woocommerce_product_pre_search_products
,允许返回自定义结果,代价是截断了WooCommerce所有的搜索逻辑,显然不适合小修改。后台可以搜sku,但其它自定义字段就不行了,且没有任何位置可以干预。幸运的是我们还能用WordPress自带的filter – request
来完成自定义字段搜索功能。
目录
WordPress Request Filter
它的用法如下:
- 它可以修改WordPress所有主查询的参数,且是在sql被执行之前运行。也就是说,我们可以在WooCommerce搜索的查询参数确定后,修改查询参数,再执行查询,这是我们加入自定义字段查询的关键。
- 它可以用在主题的functions.php里,但不能用在模板文件里,因为模板文件运行时,WordPress的主查询已经运行完了。
- 它会在全站运行,无论前台还是后台,所以要仔细测试,不要弄坏网站其它功能。
简单用法如下,也是本文代码的和心思想。
add_filter( 'request', 'alter_the_query' );
function alter_the_query( $query_vars ) {
$query_vars['post__in'] = array(1,2,3,4,5);
return $request;
}
post___in
参数负责告诉查询,把符合数组里指定的post_id的post全部返回给我们。只要我们用自定义查询找到想要的post_id,加到这个参数里,就会和WooCommerce的其它搜索结果一并返回。
增加自定义字段搜索功能的代码
这段代码来自Extending WooCommerce admin product search to use custom fields,放到主题的functions.php
里即可。假定要搜索的自定义字段的meta_key为“ _your_meta_key
”。
/**
* Alter the query vars to include products which have the meta we are searching for.
*
* @param array $query_vars The current query vars.
*
* @return array
*/
function sola_request_query( $query_vars ) {
global $typenow;
global $wpdb;
global $pagenow;
// 确保仅在后台产品列表页面运行
if ( 'product' === $typenow && isset( $_GET['s'] ) && 'edit.php' === $pagenow ) {
$meta_key = '_your_meta_key'; // 要搜索的meta_key
$search_term = esc_sql( sanitize_text_field( $_GET['s'] ) );
$post_types = array( 'product', 'product_variation' );
$sql = "SELECT DISTINCT posts.ID as product_id, posts.post_parent as parent_id
FROM {$wpdb->posts} posts
LEFT JOIN {$wpdb->postmeta} AS postmeta ON posts.ID = postmeta.post_id
WHERE postmeta.meta_key = '{$meta_key}'
AND postmeta.meta_value LIKE %s
AND posts.post_type IN ('" . implode( "','", $post_types ) . "')
ORDER BY posts.post_parent ASC, posts.post_title ASC";
$search_results = $wpdb->get_results(
$wpdb->prepare( $sql,'%' . $wpdb->esc_like( $search_term ) . '%' )
);
// 将查询到的parent_id和product_id合并,去除重复数据
$product_ids = wp_parse_id_list( array_merge( wp_list_pluck( $search_results, 'product_id' ), wp_list_pluck( $search_results, 'parent_id' ) ) );
// 修改query_vars,将查询到的产品id放到post_in参数里,该参数的作用是直接指定要获取的post
$query_vars['post__in'] = array_merge( $product_ids, $query_vars['post__in'] );
}
return $query_vars;
}
add_filter( 'request', 'sola_request_query', 20 );
给产品列表增加自定义字段
我们来实际测试一下,先在后台的产品列表增加一个自定义字段,meta_key是“ _your_meta_key
”。
add_filter( 'manage_product_posts_columns', 'sola_new_custom_product_columns' );
function sola_new_custom_product_columns( $columns ){
$newColumns = [
'my_custom_column' => '自定义字段',
];
return array_slice( $columns, 0, 2 ) + $newColumns + $columns;
}
add_action( 'manage_product_posts_custom_column', 'sola_show_custom_product_columns', 10, 2 );
function sola_show_custom_product_columns( $column, $post_id ){
switch( $column ){
case 'my_custom_column' :
echo esc_html( get_post_meta( $post_id, '_your_meta_key', true) );
break;
}
}
再增加了自定义字段搜索的代码后,我们就能搜到这个自定义字段了,如下所示:
如何给产品增加自定义字段
你可以用Advanced Custom Fields插件创建字段,也可以用代码,例如在之前文章WooCommerce 后台自定义产品选项中提到的方法。
函数解释
在代码中出现了一些WordPress函数,简单解释一下用法。
wp_list_pluck()
从数组或对象里提取一个字段,类似PHP的array_column()函数。
$foods = array(
array(
'name' => 'Banana',
'color' => 'Yellow',
),
array(
'name' => 'Apple',
'color' => 'Red',
),
array(
'name' => 'Lettuce',
'color' => 'Green',
),
array(
'name' => 'Apple',
'color' => 'Red',
),
);
$food_names = wp_list_pluck( $foods, 'name' );
/*
* 返回值
* array ( 0 => 'Banana', 1 => 'Apple', 2 => 'Lettuce', 3 => 'Apple' )
*/
wp_parse_id_list()
清理一组ID,如果输入是空格或逗号分隔的数组,先转成数组,再去除重复。如果是一个数组,去除重复。
$ids = array(1,1,2,3,4);
$cleaned_ids = wp_parse_id_list( $ids );
/*
* 返回值
* array ( 0 => 1, 2 => 2, 3 => 3, 4 => 4 )
*/
$ids = '1 2 45 67 9 9';
$cleaned_ids = wp_parse_id_list( $ids );
/*
* 返回值
* array ( 0 => 1, 1 => 2, 2 => 45, 3 => 67, 4 => 9 )
*/