Columns in WooCommerce

0. Intro — Column hooks

Please note, that creating columns on different WordPress admin pages is a slightly different process. So let’s separate the process into two steps.

1. Add columns

The first step is using the hook manage_edit-{post type or taxonomy}_columns to add column titles here:

WooCommerce column titles

The code is pretty simple:


add_filter( 'manage_edit-{post type or taxonomy}_columns', 'mishafunction' );
function mishafunction( $columns ){
	// do something with $columns array
	return $columns;
}

Replace {post type or taxonomy} with:

But for Users page the hook will be just manage_users_columns!

$columns variable is an associative array of column IDs and titles like this array('column_id' => 'column_title'). Below are a lot of examples where we will use this hook to remove columns, to add new ones etc.

2. Populate columns

The second step is to populate our newly created columns with some content. Code for product and product category columns won’t be the same.

For taxonomies and users we use add_filter() and return the result. We pass 3 variables to the function as well:


// for Users
//add_filter( 'manage_users_custom_column', 'misha_populate_columns', 10, 3 );

// for Product categories and Tags
add_filter( 'manage_{taxonomy name}_custom_column', 'misha_populate_columns', 10, 3);

function misha_populate_columns( $output, $column_name, $id ) {
	// $id is the User ID or taxonomy Term ID

	if( $column_name == 'Some ID from Step 1' ) { // you can use switch()
		// do something and write the result into $output
	}
	return $output;
}

For any WordPress custom post type we use add_action() and echo the result. One variable for the function is enough because we get Post ID and another parameters from globals:


// for any post type
add_action( 'manage_posts_custom_column', 'misha_populate_columns' );

function misha_populate_columns( $column_name ){
	
	// define globals like $post_id, $the_order
	
	if( $column_name == 'Some ID from Step 1' ) {
		// do something and ECHO the result
	}

}

And if your new column isn’t displayed, please check Screen Options at the top right part of the page.

This is how to turn on comment columns in Screen Options.

By the way, we created these columns for Comments page in the previous tutorial.

1. How to Display Columns in Desired Order?

Let’s say you would like the Date column to be displayed just after the Product name column.


add_filter( 'manage_edit-product_columns', 'misha_date_column_after_name' );
function misha_date_column_after_name( $product_columns ) {

	// the best way in this case – manually redefine array order
	return array(
		'cb' => '<input type="checkbox" />', // checkbox for bulk actions
 		'thumb' => '<span class="wc-image tips" data-tip="Image">Image</span>',
		'name' => 'Name',
		'date' => 'Date', // it is the last element by default, I inserted it third!
		'sku' => 'SKU',
		'is_in_stock' => 'Stock',
		'price' => 'Price',
		'product_cat' => 'Categories',
		'product_tag' => 'Tags',
		'featured' => '<span class="wc-featured parent-tips" data-tip="Featured">Featured</span>',
		'product_type' => '<span class="wc-type parent-tips" data-tip="Type">Type</span>'
	);
	// Tip: Just "forget" to add some elements to array if you want to remove associated columns

}

2. How to Remove any WooCommerce Admin Columns?

You can remove several columns at the same time of course.

3. How to Create a Custom Column

Actually this chapter is about using both manage_edit-{HOOK}_columns and manage_posts_custom_column – first one is for creating columns, the second one – to populate them.

Example 1. Add a brand Column to WooCommerce Products

In this example “Brand” โ€“ is custom registered taxonomy with pa_brand name.

Custom Taxonomy Brand Column in WooCommerce Products.

All the code in this tutorial can be inserted just in your current (or child) theme functions.php. It is not the only place, but if you’re not sure what you’re doing, insert to functions.php. ๐Ÿ™ƒ


add_filter( 'manage_edit-product_columns', 'misha_brand_column', 20 );
function misha_brand_column( $columns_array ) {

	// I want to display Brand column just after the product name column
	return array_slice( $columns_array, 0, 3, true )
	+ array( 'brand' => 'Brand' )
	+ array_slice( $columns_array, 3, NULL, true );


}

add_action( 'manage_posts_custom_column', 'misha_populate_brands' );
function misha_populate_brands( $column_name ) {

	if( $column_name  == 'brand' ) {
		// if you suppose to display multiple brands, use foreach();
		$x = get_the_terms( get_the_ID(), 'pa_brand'); // taxonomy name
		echo $x[0]->name;
	}

}

Example 2. Add a column to Orders Admin Page with Products Purchased

Below is the code which help you to display the purchased items near each order in WooCommerce admin.

I also added the links to product edit pages, but it is not necessary or you can add the links directly to front end product pages.


add_filter('manage_edit-shop_order_columns', 'misha_order_items_column' );
function misha_order_items_column( $order_columns ) {
    $order_columns['order_products'] = "Purchased products";
    return $order_columns;
}

add_action( 'manage_shop_order_posts_custom_column' , 'misha_order_items_column_cnt' );
function misha_order_items_column_cnt( $colname ) {
	global $the_order; // the global order object

 	if( $colname == 'order_products' ) {

		// get items from the order global object
		$order_items = $the_order->get_items();

		if ( !is_wp_error( $order_items ) ) {
			foreach( $order_items as $order_item ) {

 				echo $order_item['quantity'] .'&nbsp;&times;&nbsp;<a href="' . admin_url('post.php?post=' . $order_item['product_id'] . '&action=edit' ) . '">'. $order_item['name'] .'</a><br />';
				// you can also use $order_item->variation_id parameter
				// by the way, $order_item['name'] will display variation name too

			}
		}
		
	}

}

Example 3. Add a column with WooCommerce Billing Details to Users Admin Page

WooCommerce billing address on Users page

We can easily get WooCommerce users billing information from user meta.


add_filter( 'manage_users_columns', 'misha_billing_address_column', 20 );
function misha_billing_address_column( $user_columns ) {

	return array_slice( $user_columns, 0, 3, true ) // 4 columns before
	+ array( 'billing_address' => 'Billing Address' ) // our column is 5th
	+ array_slice( $user_columns, 3, NULL, true );

}

add_filter( 'manage_users_custom_column', 'misha_populate_with_billing_address', 10, 3 );
function misha_populate_with_billing_address( $row_output, $user_column_name, $user_id ) {

	if( $user_column_name == 'billing_address' ) {

		$address = array();
		if( $billing_address_1 = get_user_meta( $user_id, 'billing_address_1', true ) )
			$address[] = $billing_address_1;
			
		if( $billing_address_2 = get_user_meta( $user_id, 'billing_address_2', true ) )
			$address[] = $billing_address_2;
			
		if( $billing_city = get_user_meta( $user_id, 'billing_city', true ) )
			$address[] = $billing_city;
			
		if( $billing_postcode = get_user_meta( $user_id, 'billing_postcode', true ) )
			$address[] = $billing_postcode;
			
		if( $billing_country = get_user_meta( $user_id, 'billing_country', true ) )
			$address[] = $billing_country;

		return join(', ', $address ); // here we replace and return our custom $row_output

	}

}

Example 4. Add a Membership Plan ID column to WooCommerce Memberships

Sometimes people who have WooCommerce Memberships plugin installed ask me to add a column with Plan ID. To add this column is pretty easy task but keep in mind that you can find out the plan ID just if you hover on the link with the plan name.

Adding columns to WooCommerce Memberships is just similar like adding columns to custom post types.

Code for functions.php:


// we use post type name "wc_user_membership" in the hook below
// it is required to use priority 20 or higher
add_filter( 'manage_edit-wc_user_membership_columns', 'misha_wcm_id_column', 20 );
function misha_wcm_id_column( $membership_columns ) {

	// the first thing to do – to understand the column position
	// let's add it after Plan column (the 4th column)
	return array_slice( $membership_columns, 0, 4, true ) // 4 columns before
	+ array( 'membership_id' => 'ID' ) // our column is 5th
	+ array_slice( $membership_columns, 4, NULL, true ); // the rest of columns

}

add_action( 'manage_posts_custom_column', 'misha_wcm_id' );
function misha_wcm_id( $column ) {
	switch ( $column ) {
		case 'membership_id':
			$membership = wc_memberships_get_user_membership(get_the_ID());
			echo $membership->plan_id;
			// if you want to display Membership ID, you can use just:
			// echo get_the_ID(); // because post ID == $membership->id
			break;
	}
}

Example 5. Add a Checkbox Column and Update Meta Value with AJAX

Sometimes you need to make some fast changes in your Products, Orders or another content. Of course, you can use custom bulk actions or just add your own fields to bulk edit menu.

But another option is to code something in AJAX. In this example it will be an AJAX checkbox, similar to nearby column with a “star” icon.

This column with checkbox for WooCommerce product list can save a product meta value with AJAX.

In the code below I added jQuery script to functions.php as well, but you can move it to an external .js file.


// this part of the code is for creating a column
add_filter( 'manage_edit-product_columns', 'misha_extra_column', 20 );
function misha_extra_column( $columns_array ) {
	$columns_array['extra'] = 'Extra';
	// remember that you can add this column at any place you want with array_slice() function
	return $columns_array;

}

// this part of the code adds checkbox to our newly created column
add_action( 'manage_posts_custom_column', 'misha_populate_columns' );
function misha_populate_columns( $column_name ) {

	if( $column_name  == 'extra' ) {
		echo '<input type="checkbox" data-productid="' . get_the_ID() .'" class="some_checkbox" ' . checked( 'yes', get_post_meta( get_the_ID(), 'some_meta_key', true ), false ) . '/><small style="display:block;color:#7ad03a"></small>';
	}

}

// this code adds jQuery script to website footer that allows to send AJAX request
add_action( 'admin_footer', 'misha_jquery_event' );
function misha_jquery_event(){

	echo "<script>jQuery(function($){
		$('.some_checkbox').click(function(){
			var checkbox = $(this),
			    checkbox_value = (checkbox.is(':checked') ? 'yes' : 'no' );
			$.ajax({
				type: 'POST',
				data: {
					action: 'productmetasave', // wp_ajax_{action} WordPress hook to process AJAX requests
					value: checkbox_value,
					product_id: checkbox.attr('data-productid'),
					myajaxnonce : '" . wp_create_nonce( "activatingcheckbox" ) . "'
				},
				beforeSend: function( xhr ) {
					checkbox.prop('disabled', true );
				},
				url: ajaxurl, // as usual, it is already predefined in /wp-admin
				success: function(data){
					checkbox.prop('disabled', false ).next().html(data).show().fadeOut(400);
				}
			});
		});
	});</script>";

}

// this small piece of code can process our AJAX request
add_action( 'wp_ajax_productmetasave', 'misha_process_ajax' );
function misha_process_ajax(){

	check_ajax_referer( 'activatingcheckbox', 'myajaxnonce' );

	if( update_post_meta( $_POST[ 'product_id'] , 'some_meta_key', $_POST['value'] ) ) {
		echo 'Saved';
	}

	die();
}

4. How to Make any WordPress Admin Column Sortable

Creating sortable columns seems like a difficult task but actually it is not a very big deal. First of all let’s come back and look at WP_Query class, we need its orderby parameter. Here it is in the official codex. We can sort by anything you can see there easily!

If the value we want to sort by is not a meta value, the 5 lines of code will be enough! Small example of sortable columns you can find here.


add_filter('manage_edit-{cpt or taxonomy or users}_sortable_columns', 'misha_sortable');
function misha_sortable( $sortable_columns ){
	// just add your column in array in following format:
	//  array( 'column ID' => '$_GET['orderby'] parameter value' )
	return $sortable_columns
}

If your new array element value matches any core WP_Query, (or WP_User_Query for users) parameters like: date, type, name, title, no additional steps are required!

But if you want to sort by meta value, we should add one more step. Keep in mind too, that your $_GET['orderby'] parameter value should be unique.


add_action( 'pre_get_posts', 'misha_filter' );

function misha_filter( $query ) {
	// if it is not admin area, exit the filter immediately
	if ( ! is_admin() ) return;

	if( empty( $_GET['orderby'] ) || empty( $_GET['order'] ) ) return;

	if( $_GET['orderby'] == 'unique_parameter' ) {
		$query->set('meta_key', 'meta_key_to_sort_by' );
		$query->set('orderby', 'meta_value'); // or meta_value_num
		$query->set('order', $_GET['order'] );
	}

	return $query;

}

No more theory, let’s do something now. ๐Ÿ”ฅ

Add Total Sales Sortable Column

The core idea is that WooCommerce creates a custom meta field total_sales for each product where it stores the number of total sales of the product. Let’s add a column with this custom field and make it sortable!

Here is the result:

Sortable WooCommerce Product Columns

And here is the code for your functions.php:

// add
add_filter( 'manage_edit-product_columns', 'misha_total_sales_1', 20 );
// populate
add_action( 'manage_posts_custom_column', 'misha_total_sales_2' );
// make sortable
add_filter('manage_edit-product_sortable_columns', 'misha_total_sales_3');
// how to sort
add_action( 'pre_get_posts', 'misha_total_sales_4' );

function misha_total_sales_1( $col_th ) {

	// a little different way of adding new columns
	return wp_parse_args( array( 'total_sales' => 'Total Sales' ), $col_th );

}

function misha_total_sales_2( $column_id ) {

	if( $column_id  == 'total_sales' )
		echo get_post_meta( get_the_ID(), 'total_sales', true );

}

function misha_total_sales_3( $a ){
	return wp_parse_args( array( 'total_sales' => 'by_total_sales' ), $a );

}

function misha_total_sales_4( $query ) {

	if( !is_admin() || empty( $_GET['orderby']) || empty( $_GET['order'] ) )
		return;

	if( $_GET['orderby'] == 'by_total_sales' ) {
		$query->set('meta_key', 'total_sales' );
		$query->set('orderby', 'meta_value_num');
		$query->set('order', $_GET['order'] );
	}

	return $query;

}

I tried to make the code in this tutorial as simple and clear as possible. But if something is not still clear for you, welcome to comments. ๐Ÿ™‚

Misha Rudrastyh

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

Follow me on Twitter