Add Columns to Admin Orders List in Woocommerce

Add columns to admin orders list in WooCommerce

Updated: 2018-03-30 - added positioning feature to the new columns

So you if you want to add some columns in the orders Admin list page (in backend):

ADDING COLUMNS IN WOOCOMMERCE ADMIN ORDERS LIST

In the example below, we add 2 new custom columns, before existing "Total" and "Actions" columns.

// ADDING 2 NEW COLUMNS WITH THEIR TITLES (keeping "Total" and "Actions" columns at the end)
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 20 );
function custom_shop_order_column($columns)
{
$reordered_columns = array();

// Inserting columns to a specific location
foreach( $columns as $key => $column){
$reordered_columns[$key] = $column;
if( $key == 'order_status' ){
// Inserting after "Status" column
$reordered_columns['my-column1'] = __( 'Title1','theme_domain');
$reordered_columns['my-column2'] = __( 'Title2','theme_domain');
}
}
return $reordered_columns;
}

// Adding custom fields meta data for each new column (example)
add_action( 'manage_shop_order_posts_custom_column' , 'custom_orders_list_column_content', 20, 2 );
function custom_orders_list_column_content( $column, $post_id )
{
switch ( $column )
{
case 'my-column1' :
// Get custom post meta data
$my_var_one = get_post_meta( $post_id, '_the_meta_key1', true );
if(!empty($my_var_one))
echo $my_var_one;

// Testing (to be removed) - Empty value case
else
echo '<small>(<em>no value</em>)</small>';

break;

case 'my-column2' :
// Get custom post meta data
$my_var_two = get_post_meta( $post_id, '_the_meta_key2', true );
if(!empty($my_var_two))
echo $my_var_two;

// Testing (to be removed) - Empty value case
else
echo '<small>(<em>no value</em>)</small>';

break;
}
}

Code goes in function.php file of your active child theme (or active theme). Tested and works.

Sample Image


Related answer (for products): Add custom columns to admin producs list in WooCommerce backend

Add a sortable custom column in Woocommerce Admin Orders list

I figured it out. Will leave this up here for anyone else trying to add a sorted zip code column. Just add this additional action.


// Make sorting by custom column work properly
add_action('pre_get_posts', 'custom_zipcode_orderby');
function custom_zipcode_orderby($query)
{
if (!is_admin()) return;

$orderby = $query->get('orderby');
if ('_shipping_postcode' == $orderby) {
$query->set('meta_key', '_shipping_postcode');
$query->set('orderby', 'meta_value_num');
}
}

WooCommerce admin orders list custom column with order notes sent to customer

First the rule on stackOverFlow is one question at the time.

To only display public order notes send to customer in a custom column on admin orders list, use the following revisited code:

// Add custom column on admin orders list page
add_filter( 'manage_edit-shop_order_columns', 'add_order_notes_column' );
function add_order_notes_column( $columns ) {
$columns['order_notes'] = 'Order Notes';
return $columns;
}

// CSS styles
add_action( 'admin_print_styles', 'add_order_notes_column_style' );
function add_order_notes_column_style() {
$css = '.post-type-shop_order table.widefat.fixed { table-layout: auto; width: 100%; }';
$css .= 'table.wp-list-table .column-order_notes { min-width: 280px; text-align: left; }';
$css .= '.column-order_notes ul { margin: 0 0 0 18px; list-style-type: disc; }';
// $css .= '.order_customer_note { color: #ee0000; }'; // red
// $css .= '.order_private_note { color: #0000ee; }'; // blue
wp_add_inline_style( 'woocommerce_admin_styles', $css );
}

// Admin orders list custom column displayed content
add_action( 'manage_shop_order_posts_custom_column', 'add_order_notes_content' );
function add_order_notes_content( $column ) {
global $post, $the_order;

if( 'order_notes' !== $column )
return;

$order = is_a($the_order, 'WC_Order') ? $the_order : wc_get_order( $post->ID );

$notes = wc_get_order_notes( array(
'order_id' => $order->get_id(),
'order_by' => 'date_created',
'order' => 'ASC',
) );

if( ! empty($notes) ) {
echo '<ul>';

foreach( $notes as $note ) {
if( $note->customer_note && 'system' !== $note->added_by ) {
echo '<li class="order_customer_note">' . sprintf( __('%s by %s <br> %s:'),
date_i18n( 'm/d/y H:i', strtotime( $note->date_created ) ),
$note->added_by,
$note->content
) . '</li>';
}
}
echo '</ul>';
}
}

Code goes in functions.php file of the active child theme (or active theme). Tested and works.

Add multiple custom columns (notes and VAT) on WooCommerce admin orders list

To add 2 columns versus 1 you can actually apply the same as you already did for adding 1 column

Adding the VAT number to the order can be done in different ways, from your question I understand that this is a custom checkout field with the meta key: billing_piva

Note: the use of add_action( 'wp_enqueue_scripts', 'mini_enqueue_scripts' ); is not necessary

So you get:

// Display on order admin list (header)
function filter_manage_edit_shop_order_columns( $columns ) {
// Add columns
$columns['order_notes'] = __( 'Customer note', 'woocommerce' );
$columns['order_vat'] = __( 'VAT number', 'woocommerce' );

return $columns;
}
add_filter( 'manage_edit-shop_order_columns', 'filter_manage_edit_shop_order_columns', 10, 1 );

// Display on order admin list (populate the column)
function action_manage_shop_order_posts_custom_column( $column, $post_id ) {
// Get order
$order = wc_get_order( $post_id );

// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Compare
switch ( $column ) {
case 'order_notes':
// Get customer note
$note = $order->get_customer_note();

// NOT empty
if ( ! empty( $note ) ) {
echo '<span class="note-on tips" data-tip="' . wc_sanitize_tooltip( $note ) . '">' . __( 'Yes', 'woocommerce' ) . '</span>';
} else {
echo '<span class="na">–</span>';
}

break;
case 'order_vat':
// Get VAT (if necessary, adjust to the correct meta key)
$vat_number = $order->get_meta( 'billing_piva' );

// NOT empty
if ( ! empty( $vat_number ) ) {
// Output
$output = '<span>' . sprintf( __( 'VAT Number: %s', 'woocommerce' ), $vat_number ) . '</span>';

// Get CID number
$cid_number = $order->get_meta( 'billing_cid' );

// NOT empty
if ( ! empty ( $cid_number ) ) {
// Concatenation
$output .= '<br><span>' . sprintf( __( 'CID Number: %s', 'woocommerce' ), $cid_number ) . '</span>';
}

// Print
echo $output;
} else {
echo '<span class="na">–</span>';
}
}
}
}
add_action( 'manage_shop_order_posts_custom_column' , 'action_manage_shop_order_posts_custom_column', 10, 2 );

Add columns in admin order list on woocommerce 3.3

Updated - It can be done this way:

// ADDING 1 NEW COLUMNS WITH THEIR TITLES
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column',11);
function custom_shop_order_column($columns)
{
$reordered_columns = array();

foreach( $columns as $key => $column){
$reordered_columns[$key] = $column;
if( $key == 'order_number' ){
$reordered_columns['my-column1'] = __( 'Title1','theme_slug');
}
}
return $reordered_columns;
}

// Adding the data for the additional column (example)
add_action( 'manage_shop_order_posts_custom_column' , 'custom_orders_list_column_content', 10, 2 );
function custom_orders_list_column_content( $column, $post_id )
{
if( 'my-column1' == $column )
{
// Get custom post meta data 1
$my_var_one = get_post_meta( $post_id, '_the_meta_key1', true );
if(!empty($my_var_one))
echo $my_var_one;

// Get custom post meta data 2
$my_var_two = get_post_meta( $post_id, '_the_meta_key2', true );
if(!empty($my_var_two))
echo $my_var_two;

// Testing (to be removed) - Empty value case
if( empty($my_var_one) && empty($my_var_two) )
echo '<small>(<em>no value</em>)</small>';
}
}

The other function stays unchanged…

Code goes in function.php file of your active child theme (or active theme). Tested and works.

Add a sortable and searchable customer country column in WooCommerce admin order list

To make it sortable you can use the manage_edit-shop_order_sortable_columns
in combination with the pre_get_posts hook.

To make it searchable you can use the woocommerce_shop_order_search_fields hook.

So you get:

// Get geolocated country code by IP
function get_user_geo_country( $user_ip ) {
// Get WC_Geolocation instance object
$geo = new WC_Geolocation();

// Get geolocated user data
$user_geo = $geo->geolocate_ip( $user_ip );

// Get the country code
$country = $user_geo['country'];

// Return the country code
return $country;
}

// Display new column on WooCommerce admin orders list (header)
function filter_manage_edit_shop_order_columns( $columns ) {
$columns['customer_country'] = __( 'Customer Country', 'woocommerce' );

return $columns;
}
add_filter( 'manage_edit-shop_order_columns', 'filter_manage_edit_shop_order_columns', 10, 1 );

// Display details after order status column, on order admin list (populate the column)
function action_manage_shop_order_posts_custom_column( $column, $post_id ) {
// Compare
if ( $column == 'customer_country' ) {
// Get order
$order = wc_get_order( $post_id );

// Get shipping country code
$user_geo_country = get_user_geo_country( $order->get_customer_ip_address() );

// NOT empty
if ( ! empty ( $user_geo_country ) ) {
echo $user_geo_country;
} else {
echo __( 'N/A', 'woocommerce' );
}
}
}
add_action( 'manage_shop_order_posts_custom_column' , 'action_manage_shop_order_posts_custom_column', 10, 2 );

// Make custom column sortable
function filter_manage_edit_shop_order_sortable_columns( $sortable_columns ) {
return wp_parse_args( array( 'customer_country' => '_shipping_country' ), $sortable_columns );
}
add_filter( 'manage_edit-shop_order_sortable_columns', 'filter_manage_edit_shop_order_sortable_columns', 10, 1 );

// Orderby for custom sortable column
function action_pre_get_posts( $query ) {
// If it is not admin area, exit
if ( ! is_admin() ) return;

global $pagenow;

// Compare
if ( $pagenow === 'edit.php' && isset( $_GET['post_type'] ) && $_GET['post_type'] === 'shop_order' ) {
// Get orderby
$orderby = $query->get( 'orderby' );

// Set query
if ( $orderby == '_shipping_country' ) {
$query->set( 'meta_key', '_shipping_country' );
$query->set( 'orderby', 'meta_value' );
}
}
}
add_action( 'pre_get_posts', 'action_pre_get_posts', 10, 1 );

// Make searchable
function filter_woocommerce_shop_order_search_fields( $meta_keys ) {
$meta_keys[] = '_shipping_country';
return $meta_keys;
}
add_filter( 'woocommerce_shop_order_search_fields', 'filter_woocommerce_shop_order_search_fields', 10, 1 );

This works relatively easily. The only drawback is that you will not see the full country name, but only the country code. This is because the search and sort hook require a metakey. WooCommerce only stores the country code, as metadata for each order, and the full name of the country is not stored in the database and therefore cannot be used.


If you really want to go for the full country name. Then, in addition to the country code, you can also add the full country name as metadata for every new order, via the woocommerce_thankyou hook and $order->update_meta_data()

So then you get:

// Get geolocated country name by IP
function get_user_geo_country( $user_ip ) {
// Get WC_Geolocation instance object
$geo = new WC_Geolocation();

// Get geolocated user data
$user_geo = $geo->geolocate_ip( $user_ip );

// Get the country code
$country = $user_geo['country'];

// Return the country name
return WC()->countries->countries[ $country ];
}

function action_woocommerce_thankyou( $order_id ) {
// Get $order object
$order = wc_get_order( $order_id );

// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Get full shipping country name
$user_geo_country = get_user_geo_country( $order->get_customer_ip_address() );

// NOT empty
if ( ! empty( $user_geo_country ) ) {
// Update meta data
$order->update_meta_data( '_shipping_country_full_name', $user_geo_country );
} else {
// NOT available
$na = __( 'N/A', 'woocommerce' );

// Update meta data
$order->update_meta_data( '_shipping_country_full_name', $na );
}

// Save
$order->save();
}
}
add_action( 'woocommerce_thankyou', 'action_woocommerce_thankyou', 10, 1 );

// Display new column on WooCommerce admin orders list (header)
function filter_manage_edit_shop_order_columns( $columns ) {
$columns['customer_country'] = __( 'Customer Country', 'woocommerce' );

return $columns;
}
add_filter( 'manage_edit-shop_order_columns', 'filter_manage_edit_shop_order_columns', 10, 1 );

// Display details after order status column, on order admin list (populate the column)
function action_manage_shop_order_posts_custom_column( $column, $post_id ) {
// Compare
if ( $column == 'customer_country' ) {
// Get order
$order = wc_get_order( $post_id );

// Get meta
$shipping_country_full_name = $order->get_meta( '_shipping_country_full_name' );

// NOT empty
if ( ! empty ( $shipping_country_full_name ) ) {
echo $shipping_country_full_name;
} else {
echo __( 'N/A', 'woocommerce' );
}
}
}
add_action( 'manage_shop_order_posts_custom_column' , 'action_manage_shop_order_posts_custom_column', 10, 2 );

// Make custom column sortable
function filter_manage_edit_shop_order_sortable_columns( $sortable_columns ) {
return wp_parse_args( array( 'customer_country' => '_shipping_country_full_name' ), $sortable_columns );
}
add_filter( 'manage_edit-shop_order_sortable_columns', 'filter_manage_edit_shop_order_sortable_columns', 10, 1 );

// Orderby for custom sortable column
function action_pre_get_posts( $query ) {
// If it is not admin area, exit
if ( ! is_admin() ) return;

global $pagenow;

// Compare
if ( $pagenow === 'edit.php' && isset( $_GET['post_type'] ) && $_GET['post_type'] === 'shop_order' ) {
// Get orderby
$orderby = $query->get( 'orderby' );

// Set query
if ( $orderby == '_shipping_country_full_name' ) {
$query->set( 'meta_key', '_shipping_country_full_name' );
$query->set( 'orderby', 'meta_value' );
}
}
}
add_action( 'pre_get_posts', 'action_pre_get_posts', 10, 1 );

// Make searchable
function filter_woocommerce_shop_order_search_fields( $meta_keys ) {
$meta_keys[] = '_shipping_country_full_name';
return $meta_keys;
}
add_filter( 'woocommerce_shop_order_search_fields', 'filter_woocommerce_shop_order_search_fields', 10, 1 );

The disadvantage of this is that the existing orders would not have that data, so you would have to add this for all those orders as well,
which can then be added again with the following function:

function action_wp_footer() {
$limit = 50;

// Args
$args = array(
'limit' => $limit,
'meta_key' => '_shipping_country_full_name',
'meta_compare' => 'NOT EXISTS',
);

// Get orders
$orders = wc_get_orders( $args );

// NOT empty
if ( ! empty ( $orders ) ) {
// Loop through orders
foreach ( $orders as $order ) {
// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Get full shipping country name
$user_geo_country = get_user_geo_country( $order->get_customer_ip_address() );

// NOT empty
if ( ! empty( $user_geo_country ) ) {
// Update meta data
$order->update_meta_data( '_shipping_country_full_name', $user_geo_country );
} else {
// NOT available
$na = __( 'N/A', 'woocommerce' );

// Update meta data
$order->update_meta_data( '_shipping_country_full_name', $na );
}

// Save
$order->save();
}
}
}
}
add_action( 'wp_footer', 'action_wp_footer' );

Each time you/a visitor will browse a front end page of your site the function will be triggered. Processing orders by 50 (limit) is just more secure and will avoid a timeout or errors. When all existing orders are updated, this function can be removed

Add multiple custom columns to WooCommerce My account orders table

The woocommerce_account_orders_columns filter hook allows us to add 1 or more columns

// Add new column(s) to the "My Orders" table in the account.
function filter_woocommerce_account_orders_columns( $columns ) {
$columns['custom-column'] = __( 'New Column 1', 'woocommerce' );
$columns['custom-column2'] = __( 'New Column 2', 'woocommerce' );

return $columns;
}
add_filter( 'woocommerce_account_orders_columns', 'filter_woocommerce_account_orders_columns', 10, 1 );

However, adding content per column is done via the woocommerce_my_account_my_orders_column_{$column_id} action hook.

So {$column_id} need to be replaced by the column key slug (custom-column or custom-column2) in this particular case.
It is therefore not necessary to determine the correct column in the callback function via an if condition

So you get:

// Adds data to the custom column in "My Account > Orders"
function filter_woocommerce_my_account_my_orders_column_custom_column( $order ) {
echo 'New Column 1';
}
add_action( 'woocommerce_my_account_my_orders_column_custom-column', 'filter_woocommerce_my_account_my_orders_column_custom_column', 10, 1 );

// Adds data to the custom column in "My Account > Orders"
function filter_woocommerce_my_account_my_orders_column_custom_column2( $order ) {
echo 'New Column 2';
}
add_action( 'woocommerce_my_account_my_orders_column_custom-column2', 'filter_woocommerce_my_account_my_orders_column_custom_column2', 10, 1 );

Issue when adding a new column in WooCommerce admin order list displaying product names

Your code has some minor bugs, for example:

  • You indicate that the products_column_show_products() callback function expects 3 arguments, while the manage_{$post->post_type}_posts_custom_column WordPress hook contains 2 parameters. The $column_name and the $post_id
  • There is no need to use global $order;, via the $post_id,
    you can access the order with wc_get_order( $post_id );

So this should suffice:

// Add a Header
function filter_manage_edit_shop_order_columns( $columns ) {
// Loop trough existing columns
foreach ( $columns as $key => $name ) {

$new_columns[ $key ] = $name;

// Add after order status column
if ( $key === 'order_number' ) {
$new_columns['order_products'] = __( 'Products', 'woocommerce' );
}
}

return $new_columns;
}
add_filter( 'manage_edit-shop_order_columns', 'filter_manage_edit_shop_order_columns', 10, 1 );

// Populate the Column
function action_manage_shop_order_posts_custom_column( $column, $post_id ) {
// Compare
if ( $column == 'order_products' ) {
// Get order
$order = wc_get_order( $post_id );

echo '<ul>';

// Going through order items
foreach ( $order->get_items() as $item ) {
// Get product object
$product = $item->get_product();

echo '<li><a href="' . $product->get_permalink() . '">' . $item->get_name() . '</a> × ' . $item->get_quantity() . '</li>';
}

echo '</ul>';
}
}
add_action( 'manage_shop_order_posts_custom_column' , 'action_manage_shop_order_posts_custom_column', 10, 2 );


Related Topics



Leave a reply



Submit