Columns in WooCommerce
In this in-depth tutorial I am going to guide you through the process of managing columns in order or product tables etc in WooCommerce admin which is very similar to managing columns in any WordPress admin pages but there are some moments you need to keep in mind for sure.
Also we’re going to take a look at different examples, for example we’re going to add a column to the product list with total sales like this:

Which Column Hooks to Use?
Depending on what WooCommerce admin page (orders list, products list etc) you’re going to create a custom column, the process might be slightly different, at least the hooks you’re using are going to be different. And right now I am going to show you what hooks we can use. You can also jump straight to the examples.
There are also different hooks for adding columns and populating columns with data, right now we are about to take a look at each of them step by step.
Adding columns
First things first – we need just to add an empty column to the admin table. Below is the list of hooks intended to help you with that.
Hook | Admin page |
---|---|
manage_edit-shop_order_columns | Orders as CPT |
manage_woocommerce_page_wc-orders_columns | Orders with HPOS |
manage_edit-product_columns | Products |
manage_edit-product_cat_columns | Product categories |
manage_edit-product_tag_columns | Product tags |
manage_users_columns | Users |
I would like to additionally highlight the thing with WooCommerce orders – most likely you’re using the latest WooCommerce version with HPOS enabled by default, which means that WooCommerce orders aren’t a custom post type (CPT) anymore and the hook manage_edit-shop_order_columns
not working for you. Don’t worry, just use manage_woocommerce_page_wc-orders_columns
instead and check the example below where we create a WooCommerce column for orders which works for both HPOS-based and CPT-based orders.
Now let’s take a look at a simple example. No matter what hook you’re using, the code is going to look similar – we just add one more item into the $columns
array which is the associative array of column IDs and titles like this array( 'column_id' => 'column_title' )
.
// that's the hook
add_filter( 'manage_woocommerce_page_wc-orders_columns', 'rudr_new_column' );
function rudr_new_column( $columns ){
// just add a new column here
$columns[ 'rudr_new_column' ] = 'My new column';
// return the modified array
return $columns;
}
That’s it. The column is added. These set of hooks is also useful when you need to remove a specific column.
Oh, yes, if you don’t know where to insert this code, please read this.
Populating columns with data
Once the column is added we need to display some data in it, right? There is also a different set of hooks for that.
Hook | Admin page |
---|---|
manage_posts_custom_column | Products and CPT-based orders |
manage_woocommerce_page_wc-orders_custom_column | HPOS-based orders |
manage_product_cat_custom_column | Product categories |
manage_product_tag_custom_column | Product tags |
manage_users_custom_column | Users |
The callback function for these hooks isn’t the same, for example for products and orders we print the result inside the function, but for users, tags and categories – return the result.
Users, product categories and product tags:
// for Users
// add_filter( 'manage_users_custom_column', 'misha_populate_columns', 10, 3 );
// for product categories
// add_filter( 'manage_product_cat_custom_column', 'misha_populate_columns', 10, 3 );
// for product tags
add_filter( 'manage_product_tag_custom_column', 'misha_populate_columns', 10, 3 );
function misha_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;
}
Products and CPT-based orders:
// products and legacy orders (CPT-based)
add_action( 'manage_posts_custom_column', 'misha_populate_columns' );
function misha_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-based orders:
add_action( 'manage_woocommerce_page_wc-orders_custom_column', 'misha_populate_orders_column', 25, 2 );
function misha_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';
}
}
Now we’ve finished with the theory part and you can definitely jump straight to the examples.
How to Remove Any Column?
Sometimes your admin pages can be overloaded with the columns and you would like to clean up the things a little bit and remove some of the columns you don’t need. But of course you can also hide them in “Screen Options” – don’t forget about that.
Here is step by step:
- Decide on what admin page you would like to remove columns, then go to this chapter of this tutorial and choose an appropriate hook.
- Find out the column ID, in order to do so you can just “Inspect” the column in your browser.
- Finally, the code:
// replace 'manage_edit-product_columns' hook with the hook you need
add_filter( 'manage_edit-product_columns', 'misha_remove_woo_columns' );
function misha_remove_woo_columns( $columns ) {
unset( $columns[ 'column ID here' ] );
// for example unset( $columns[ 'product_cat' ] );
return $columns;
}
You can remove multiple columns at the same time of course.
How to Create a Custom Column (Examples)
Example 1. Add column to order list
I decided to start with this example because the hook manage_edit-shop_order_columns
not working anymore if you’re using the latest WooCommerce version or at least have HPOS turned on in settings.
As an example let’s just print the products purchases near every order like this:

The code below works great for both legacy and HPOS-based orders:
// legacy – for CPT-based orders
add_filter( 'manage_edit-shop_order_columns', 'misha_order_items_column' );
// for HPOS-based orders
add_filter( 'manage_woocommerce_page_wc-orders_columns', 'misha_order_items_column' );
function misha_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', 'misha_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 misha_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
}
}
}
}
Take a look at 24
line, I find it very interesting, because hooks manage_shop_order_posts_custom_column
and manage_woocommerce_page_wc-orders_custom_column
have different second argument – it is either an order ID or an order object accordingly and we’re using $order_or_order_id instanceof WC_Order
condition to check that.
Example 2. Add column to product list
The idea here is that WooCommerce creates a custom meta field total_sales
for each product and stores the number of total sales in it. It allows us to use this value inside pre_get_posts
hook and create a sortable column!
Here is the result what we are going to create:

And here is the code for your functions.php
:
// add
add_filter( 'manage_edit-product_columns', 'rudr_add_product_list_column' );
function rudr_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
);
}
// populate
add_action( 'manage_posts_custom_column', 'rudr_populate_product_column', 25, 2 );
function rudr_populate_product_column( $column_name, $product_id ) {
if( 'total_sales' === $column_name ) {
echo get_post_meta( $product_id, 'total_sales', true );
}
}
// make sortable
add_filter( 'manage_edit-product_sortable_columns', 'rudr_sortable_column' );
function rudr_sortable_column( $sortable_columns ) {
return wp_parse_args(
array(
'total_sales' => 'by_total_sales' // column name => sortable arg
),
$sortable_columns
);
}
// doing to sorting stuff
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;
} );
Also the question here is that can we really use the product meta data as a regular posts meta data? I mean using get_post_meta()
, pre_get_posts
hook etc. Because if you have ever done that to orders, well, now for HPOS-orders your code doesn’t work anymore. And I think – yes, we can do that for now because, in my opinion, using CPT for WooCommerce products is exactly what it is meant for. No doubt maybe one day we will face to “high performance product storage”, but I haven’t heard about it at all.
Example 3. Add a column with WooCommerce billing details to users admin page
The last but not least let’s add one more column to Users > All users page this time. In this column we’re going to display billing addresses. Just like this:

And here is ready to use code:
add_filter( 'manage_users_columns', 'rudr_billing_address_column' );
function rudr_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', 'rudr_populate_address', 10, 3 );
function rudr_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;
}

Misha Rudrastyh
Hey guys and welcome to my website. For more than 10 years I've been doing my best to share with you some superb WordPress guides and tips for free.
Need some developer help? Contact me
Hello Misha,
i am trying to add column order by weight in product list but the weight is not displayed.
echo get_post_meta( $product_id, 'weight', true );
Do you know why is not showed product weight?
Thank you for support :)
Hey Kamil,
Weight is a system hidden custom field, so, you should use key
_weight
instead ofweight
. Make sure also that you made the replacement inpre_get_posts
hook too, I mean:$query->set( 'meta_key', '_weight' );
.Hey Misha, thank you very much for support! It works! Do you know how to sort products if weight is not provided in the product options or equal zero. It is possible?
If you want the products without weight to be displayed in your sorting list, pass 0 weight value to meta_key
_weight
for those products.Awesome! You are my master of WordPress :) Thank you very much for your support!
You are welcome! 🙃
HI Kamil,
could you please provide the code you added? I’m facing the same issue and not able to have it working.
Thank you
hello, i cannot quite get how to populate a custom column on the orders page, with a product’s taxonomy term…
i see in your example1, how this works on the ‘products’ page, would like to get categories displayed on the admin orders page…?
sorry, i am still learning about this
thanks
Hi,
Do you want to get categories of the purchased products in orders, right?
yes, so i can sort sales by a particular category or custom taxonomy
Ok, I see,
Please contact me and I will try to help you with the code.
Hello Misha, thank you for your post!
I try to make custom column sortable in product category list but it doesn’t work.
Can you show me an example more clearly about how to make custom column sortable in product category list ?
Hey 🙂
I could try to help you with the code, just contact me.
Thanks, I have to try
pre_get_posts
action but it can’t query from product category. Which action can I query to make product category custom column sortable?Thank you in advanced.
Thank you ever so much for your snippets, these are invaluable!
hi! I have scoured every blog and worked hard to tweak these codes with no success. i have a custom dropdown field on my checkout page, “Pick Up Location” (Select_delivery) which i am trying to have displayed on the orders page. Can anyone help me please? I feel that this is easy but I just have limited coding skills. thank you, tim https://www.threechimneyfarm.com/checkout/
Hi! I have tried your examples 1 and 2, just copied and pasted them to try things out, Your second example is working out just fine, but the first one (which I think is more suitable for my needs) is not working, nothing extra is showing up in the orders screen. I have also checked the screen options but with no luck. Do you have an idea of what could be wrong? I have copied the text to my child themes functions.php folder. What I am trying to do further on is to implement some meta data from woocommerce bookings right on the orders screen, I am just taking it in small steps right now. :)
Thanks!
Hey Malcom,
Did you register a custom taxonomy
pa_brand
? 🙃Aha, maybe I forgott that, So first I have to make a new taxanomy that is named pa_brand to check if it works? Then i can probably replace that later on with my own preffered taxanomy, Do you have any knowledge of woocommerce bookings? What I would like to do is to get the bookings start and end date showing up as a column in the orders screen. Maybe you have a better solution for that?
Yes, correct.
No, unfortunately I do not have experience with Woo Bookings plugin.
Great job. Tks for these great codes.
Hi Misha, your blog is so inspiring ! Great work.
I tried to figure out how to sort my products to show Featured products on top with your examples but had no luck. Also I’m not sure in fact that the meta key is valid as I didn’t find relevant information about it. Your link sent only to the WP codex but this is specific to WooCommerce.
I’m not sure what the if (empty … ; is ment to do here.
Here is what I tried :
Hi Thibault,
Thank you, I’m glad you like it 🙃
if( empty( ...
means if not set.The interesting thing is that WooCommerce sorts product by featured by default, all you have to do is to set
order=DESC
ororder=ASC
parameter.So, let’s just make the Featured column sortable with the below code:
And that’s all!
You saved my life… Thank you! :D
Google Search on
manage_edit-product_columns
brought me here. Glad I dropped by and bookmarked a very informative blog.Awesome! 🙃
WOWA! Great man!
Any way to add product image inside the purchased items column next to the quantity instead of the name.So i can see thumbnails of all items in the order. Been trying for 3 days to tweak your code but no success. Can you help ?
Hey Ali,
The following code should help you:
woocommerce_get_product_thumbnail()
may not help because we can not pass product ID there, it works with global variable$product
, but it can be not defined in your code.Nice!!! Thank you!!!
Hi Misha. So glad I found this blogpost and your site. Inspiring.
I tried to alter your fifth example – so I can show a checkbox on the order pages by replacing all ‘product’ references by ‘shop_order’. The column is showing up, I can click on it and it will register the meta value, but the AJAX isn’t working. A click will go the admin page of the order.
When I use your code for the products page, everything works as expected. Any tips? Thanks!
Hi Koen,
First things first, could you please give me a screenshot of your browser console after you clicked it but before you’ve been redirected?
Hi Misha, thanks for the follow-up. I ended up setting up things a bit different in the admin so no longer need for the checkbox in the order page.
Hello Misha,
i try to add column order with a custom checkout field called “billing_nom_chantier”.
I try this but it doesn’t work :
echo ( isset( $order[ 'billing_nom_chantier' ] ) ? $order[ 'billing_nom_chantier' ] : '' );
Can you help me?
Thank you for support :)
Hey Laetitia :)
Have you tried
get_post_meta()
function?Excellent, thank you!
Hi, in order type column, when a customer place an order to our website it displays their unique roles (wholesale).
I encountered not a big problem, but may I know if this can be changed?
a customer place an order and order type is ‘wholesale’ but when done manually (admin) from woocommerce>orders>add new, under same customer, the order type changed to retail.
is it possible to get it correct or change into a ‘wholesale’ in order type even I did it manually?
Hi Rowell,
How your order type column is populated? Could you provide a piece of code from there?
Hi Misha. Can you help me? I need to display min variable price in custom column for each product and I don`t get how to do that. Give your advice please.
Hi Yurii,
Have you tried this method?
$price = $product->min_variable_price('min');
Hello Misha, thanks for very useful tuts.
I’d like to ask a question, after adding your Example 2 snippet (which works great) in the Orders admin list, how can I change width of specific columns? As my products are multiple-word strings, multiple item order takes up whole page – and I’d like to increase the width of this specific column and decrease width of some of the previous columns.
Thanks in advance
Matus
Hey Matus,
You just have to inspect in browser and find out the column ID attribute, then just use CSS like this:
Thanks for the quick response!
Super Helpful blog….cheers
Amazing!! Thank you for the code to view the products in the orders page!!
Thanks!!
Adding a column for the products works well!
Can we also add the product meta data to this? Do you perhaps have a code snippet?
Thanks
Hi Eric, isn’t it what you’re asking about?