在 WooCommerce 中,我们经常用到的数据列表为产品数据列表和订单列表,在本深入教程中,我们将一起学习如何在 WooCommerce 仪表盘中管理订单或产品列表中的数据列,这与在任何 WordPress 仪表盘中文章或页面数据列表非常相似,但是有一些不同。
此外,我们还将看到不同的示例,例如,我们要在产品列表中添加一个「总销售额」数据列,入下图所示:
我们在 WooCommerce 仪表盘的产品列表中添加了一个可排序的 「总销售额 」数据列。您可以直接跳转到这个示例。
使用哪一个钩子?
根据我们要创建自定义数据列的 WooCommerce 管理页面(订单列表、产品列表等)的不同,创建过程可能会略有不同,我们使用的钩子也会有所不同。现在,我们一起来看一下我们可以使用哪些钩子。你也可以直接跳转到示例。
除了管理数据列的钩子,我们还需要用到一些关于的钩子用于向列中填充数据,现在我们将一步一步地逐一介绍。
添加数据列
首先,我们需要在数据列表中添加一个空列。下面是钩子列表,可以帮助你完成这项工作。
钩子 | 管理页面 |
---|---|
manage_edit-shop_order_columns | 在 CPT 数据类型的订单中使用 |
manage_woocommerce_page_wc-orders_columns | 在 HPOS 数据类型的订单中使用 |
manage_edit-product_columns | 产品 |
manage_edit-product_cat_columns | 产品类别 |
manage_edit-product_tag_columns | 产品标签 |
manage_users_columns | 用户 |
我还想强调一下关于WooCommerce订单的问题–很可能你使用的是默认启用了HPOS的最新版WooCommerce,这意味着WooCommerce订单不再是自定义文章类型(CPT),因此manage_edit-shop_order_columns
钩子对你不起作用。别担心,只需使用manage_woocommerce_page_wc-orders_columns
来代替,并查看下面的示例,我们在其中为订单创建了一个 WooCommerce 列,它既适用于基于 HPOS 的订单,也适用于基于 CPT 的订单。
现在让我们来看一个简单的示例。无论您使用哪种钩子,代码看起来都差不多–我们只需在$columns
数组中再添加一项,里面包含数据列 ID 和名称,如下所示array( 'column_id' => 'column_title' )
.
add_filter( 'manage_woocommerce_page_wc-orders_columns', 'wprs_new_column' );
function wprs_new_column( $columns ){
// 在这里添加新数据列
$columns[ 'wprs_new_column' ] = 'My new column';
// return the modified array
return $columns;
}
就这样,数据列已经添加好了。当我们需要移除某个数据列时,这组钩子也很有用。
为自定义数据列添加数据
完成了上一部,我们只是为数据列表添加了一个表头,我们需要在其中显示一些数据,这样才能在数据表格中显示我们需要的内容。
钩子 | 管理页面 |
---|---|
manage_posts_custom_column | 产品和基于 CPT 的订单 |
manage_woocommerce_page_wc-orders_custom_column | 基于 HPOS 的订单 |
manage_product_cat_custom_column | 产品分类 |
manage_product_tag_custom_column | 产品标签 |
manage_users_custom_column | 用户 |
这些钩子的回调函数并不相同,例如,对于产品和订单,我们会在函数内打印结果,但对于用户、标签和类别,则会返回结果。
用户、产品分类和产品标签:
// 用于用户
// add_filter( 'manage_users_custom_column', 'wprs_populate_columns', 10, 3 );
// 用于产品分类
// add_filter( 'manage_product_cat_custom_column', 'wprs_populate_columns', 10, 3 );
// 用于产品标签
add_filter( 'manage_product_tag_custom_column', 'wprs_populate_columns', 10, 3 );
function wprs_populate_columns( $output, $column_name, $object_id ) {
// $object_id is either the user ID or product category/tag ID
if( 'column ID here' === $column_name ) {
// you can use switch()
// do something and write the result into $output
$output .= 'some column data here';
}
return $output;
}
产品和基于 CPT 的订单:
// products and legacy orders (CPT-based)
add_action( 'manage_posts_custom_column', 'wprs_populate_columns' );
function wprs_populate_columns( $column_name ){
global $post, $the_order;
if( 'column ID here' === $column_name ) {
// do something and print the result
echo 'some column data here';
}
}
基于 HPOS 的订单:
add_action( 'manage_woocommerce_page_wc-orders_custom_column', 'wprs_populate_orders_column', 25, 2 );
function wprs_populate_orders_column( $column_name, $order ){ // WC_Order object is available as $order variable here
if( 'column ID here' === $column_name ) {
// do something and print the result
echo 'some column data here';
}
}
现在我们已经完成了理论部分,如果需要查看示例,你可以直接进入示例部分。
如何删除某个数据列?
有时,管理页面中的数据列会比较多,我们可能需要稍微清理一下,删除一些不需要的数据列。当然,我们也可以在 “屏幕选项 “中隐藏它们–别忘了这一点。
下面是具体步骤:
- 决定要在哪个管理页面移除列,然后转到本教程的这一章,选择一个合适的钩子。
- 找出列 ID,为此可以在浏览器中 “检查 “该列。
- 最后是代码:
// replace 'manage_edit-product_columns' hook with the hook you need
add_filter( 'manage_edit-product_columns', 'wprs_remove_woo_columns' );
function wprs_remove_woo_columns( $columns ) {
unset( $columns[ 'column ID here' ] );
// for example unset( $columns[ 'product_cat' ] );
return $columns;
}
当然,如果需要,我们也可以同时删除多个列。
如何创建自定义数据列(示例)
例 1.在订单列表中添加数据列
如果我们使用的是最新版本的 WooCommerce,或者在设置中打开了HPOS,那么manage_edit-shop_order_columns
订单数据列的钩子就不再起作用了,我们通过下来的例子来学习一下怎么解决。
假如,我们需要在订单状态后面显示已该订单中包含的商品列表。
下面的代码对传统订单和基于 HPOS 的订单都非常有效:
// legacy – for CPT-based orders
add_filter( 'manage_edit-shop_order_columns', 'wprs_order_items_column' );
// for HPOS-based orders
add_filter( 'manage_woocommerce_page_wc-orders_columns', 'wprs_order_items_column' );
function wprs_order_items_column( $columns ) {
// let's add our column before "Total"
$columns = array_slice( $columns, 0, 4, true ) // 4 columns before
+ array( 'order_products' => 'Purchased products' ) // our column is going to be 5th
+ array_slice( $columns, 4, NULL, true );
return $columns;
}
// legacy – for CPT-based orders
add_action( 'manage_shop_order_posts_custom_column', 'wprs_populate_order_items_column', 25, 2 );
// for HPOS-based orders
add_action( 'manage_woocommerce_page_wc-orders_custom_column', 'misha_populate_order_items_column', 25, 2 );
function wprs_populate_order_items_column( $column_name, $order_or_order_id ) {
// legacy CPT-based order compatibility
$order = $order_or_order_id instanceof WC_Order ? $order_or_order_id : wc_get_order( $order_or_order_id );
if( 'order_products' === $column_name ) {
$items = $order->get_items();
if( ! is_wp_error( $items ) ) {
foreach( $items as $item ) {
echo $item[ 'quantity' ] .' × <a href="' . get_edit_post_link( $item[ 'product_id' ] ) . '">'. $item[ 'name' ] .'</a><br />';
// you can also use $order_item->variation_id parameter
// by the way, $item[ 'name' ] will display variation name too
}
}
}
}
请看第24
行,我发现它非常有趣,因为钩子manage_shop_order_posts_custom_column
和manage_woocommerce_page_wc-orders_custom_column
的第二个参数不同–它要么是订单 ID,要么是相应的订单对象,我们使用$order_or_order_id instanceof WC_Order
条件来检查这一点。
manage_shop_order_posts_custom_column
就是钩子名称,不像有些钩子一样,需要把 custom_column
替换为数据列ID。例 2.为产品列表添加列
在这个示例中,我们需要为每个产品创建一个自定义字段total_sales
,并在其中存储总销售额。这样,我们就可以在pre_get_posts
钩子中使用该值并创建一个可排序的列!
下面就是我们要创建的结果:
正如您所看到的,”总销售额 “列的标题是可点击的,这意味着这一列数据是可以排序的,下面是实现这个需求的代码。
// 添加数据列
add_filter( 'manage_edit-product_columns', 'wprs_add_product_list_column' );
function wprs_add_product_list_column( $column_name ) {
// a little different way of adding new columns
return wp_parse_args(
array(
'total_sales' => 'Total Sales'
),
$column_name
);
}
// 显示列数据
add_action( 'manage_posts_custom_column', 'wprs_populate_product_column', 25, 2 );
function wprs_populate_product_column( $column_name, $product_id ) {
if( 'total_sales' === $column_name ) {
echo get_post_meta( $product_id, 'total_sales', true );
}
}
// 使这一列数据可排序
add_filter( 'manage_edit-product_sortable_columns', 'wprs_sortable_column' );
function wprs_sortable_column( $sortable_columns ) {
return wp_parse_args(
array(
'total_sales' => 'by_total_sales' // column name => sortable arg
),
$sortable_columns
);
}
// 实现排序逻辑
add_action( 'pre_get_posts', function( $query ) {
if( ! is_admin() || empty( $_GET[ 'orderby' ] ) || empty( $_GET[ 'order' ] ) ) {
return $query;
}
if( 'by_total_sales' === $_GET[ 'orderby' ] ) {
$query->set( 'meta_key', 'total_sales' );
$query->set( 'orderby', 'meta_value_num' );
$query->set( 'order', $_GET[ 'order' ] );
}
return $query;
} );
还有一个问题是,我们真的可以将产品元数据用作普通的文章元数据吗?我的意思是使用get_post_meta()
、pre_get_posts
钩子等。因为如果我们曾经在订单中使用过这种方法,那么现在对于HPOS 订单,我们的代码就不再起作用了。我认为–是的,我们现在可以这样做,因为在我看来,将 CPT 用于 WooCommerce 产品正是它的目的所在。毫无疑问,也许有一天我们会面临 “高性能产品存储 “的问题,但我完全没有听说过。
示例 3.在用户管理页面添加包含 WooCommerce 账单详细信息的列
最后,让我们在 “用户”>”所有用户“页面上再添加一列。在这一栏中,我们将显示账单地址。就像这样
下面是实现这一功能的代码:
add_filter( 'manage_users_columns', 'wprs_billing_address_column' );
function wprs_billing_address_column( $columns ) {
return array_slice( $columns, 0, 3, true ) // 3 columns before
+ array( 'billing_address' => 'Billing Address' ) // our column is 4th
+ array_slice( $columns, 3, NULL, true );
}
add_filter( 'manage_users_custom_column', 'wprs_populate_address', 10, 3 );
function wprs_populate_address( $row_output, $column_name, $id ) {
if( 'billing_address' === $column_name ) {
$address = array();
if( $address_1 = get_user_meta( $id, 'billing_address_1', true ) ) {
$address[] = $address_1;
}
if( $address_2 = get_user_meta( $id, 'billing_address_2', true ) ) {
$address[] = $address_2;
}
if( $city = get_user_meta( $id, 'billing_city', true ) ) {
$address[] = $city;
}
if( $postcode = get_user_meta( $id, 'billing_postcode', true ) ) {
$address[] = $postcode;
}
if( $country = get_user_meta( $id, 'billing_country', true ) ) {
$address[] = $country;
}
$row_output = join( ', ', $address );
}
return $row_output;
}