如何解决WooCommerce Analytics自定义Weight列无法排序的问题?
问题背景
在WooCommerce Analytics的分类报表中添加了自定义「Weight」列,用于展示对应分类下售出商品的总重量。采用woocommerce_rest_prepare_report_categories钩子编写PHP代码,woocommerce_admin_report_table钩子编写JS代码后,列显示正常,但设置isSortable: true后点击排序触发400错误,提示orderby参数不在允许的枚举值列表中,需要补充处理orderby参数的逻辑。
现有代码
PHP代码
add_filter( 'woocommerce_rest_prepare_report_categories', 'add_category_weight_in_rest', 10, 3 ); function add_category_weight_in_rest ($response, $report, $request ){ $data = $response->get_data(); $category_id = $data['category_id']; $params = $request->get_params(); $after = $params['after']; $before = $params['before']; $data['category_weight'] = get_ordered_weight_by_category($category_id, $after, $before); $response->set_data($data); return $response; }
JS代码
function addWeightToCategories( reportTableData ) { const { endpoint, items } = reportTableData; if ( 'categories' !== endpoint ) { return reportTableData; } reportTableData.headers = [ ...reportTableData.headers, { label: 'Weight', key: 'category_weight', isNumeric: true, //isSortable: true }, ]; reportTableData.rows = reportTableData.rows.map( ( row, index ) => { const item = items.data[ index ]; const newRow = [ ...row, { display: item.category_weight, value: item.category_weight, }, ]; return newRow; } ); return reportTableData; } wp.hooks.addFilter( 'woocommerce_admin_report_table', 'mysupershop', addWeightToCategories );
错误信息
原始错误:
{"code":"rest_invalid_param","message":"Invalid parameters : « orderby »","data":{"status":400,"params":{"orderby":"orderby is not one of category_id, items_sold, net_revenue, orders_count, products_count, et category."},"details":{"orderby":{"code":"rest_not_in_enum","message":"orderby is not one of category_id, items_sold, net_revenue, orders_count, products_count, et category.","data":null}}}}
翻译后:
{"code":"rest_invalid_param","message":"无效参数:« orderby »","data":{"status":400,"params":{"orderby":"orderby 不属于 category_id, items_sold, net_revenue, orders_count, products_count, category 中的任何一个。"},"details":{"orderby":{"code":"rest_not_in_enum","message":"orderby 不属于 category_id, items_sold, net_revenue, orders_count, products_count, category 中的任何一个。","data":null}}}}
解决方案
要解决排序问题,需完成两个核心操作:允许orderby参数包含自定义字段,以及实现该字段的排序逻辑。
1. 扩展orderby参数的合法值
添加过滤器让REST API接受category_weight作为合法的排序字段:
add_filter( 'woocommerce_rest_report_categories_collection_params', 'add_category_weight_orderby_param', 10, 1 ); function add_category_weight_orderby_param( $params ) { if ( isset( $params['orderby']['enum'] ) ) { $params['orderby']['enum'][] = 'category_weight'; } return $params; }
2. 实现自定义字段的排序逻辑
由于category_weight是动态计算的字段,无法直接通过数据库查询排序,需先获取所有分类数据、计算重量后再排序:
add_filter( 'woocommerce_rest_report_categories_query', 'sort_categories_by_weight', 10, 2 ); function sort_categories_by_weight( $query_args, $request ) { $orderby = $request->get_param( 'orderby' ); $order = $request->get_param( 'order' ) ?: 'asc'; if ( 'category_weight' === $orderby ) { // 获取原始报表数据 $report = new WC_Admin_Report_Categories(); $categories_data = $report->get_report_data( $query_args ); // 为每个分类计算总重量 foreach ( $categories_data->data as &$category ) { $category->category_weight = get_ordered_weight_by_category( $category->category_id, $query_args['after'], $query_args['before'] ); } // 根据重量排序 usort( $categories_data->data, function( $a, $b ) use ( $order ) { if ( $a->category_weight == $b->category_weight ) { return 0; } return ( 'asc' === $order ) ? ( $a->category_weight < $b->category_weight ? -1 : 1 ) : ( $a->category_weight > $b->category_weight ? -1 : 1 ); } ); // 替换原始查询结果 add_filter( 'woocommerce_admin_report_get_report_data', function( $data ) use ( $categories_data ) { return $categories_data; }, 10, 2 ); } return $query_args; }
3. 启用JS排序设置
取消JS代码中isSortable: true的注释:
{ label: 'Weight', key: 'category_weight', isNumeric: true, isSortable: true },
注意事项
确保get_ordered_weight_by_category函数能正确计算指定时间范围内,对应分类下所有售出商品的总重量,否则排序结果会不准确。
内容的提问来源于stack exchange,提问作者Tameroski

