Asked  7 Months ago    Answers:  5   Viewed   41 times

I am using WooCommerce plugin for one of my ecommerce WordPress websites. I want to add some columns to my order listing page in the WooCommerce admin area. I am not able to find out where to add that.

Can anyone advise which template page I need to amend in order to meet my requirement?



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):


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 );
                echo $my_var_one;

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


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

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


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

enter image description here

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

Wednesday, March 31, 2021
answered 7 Months ago

Here is the complete way to make your functionality work on bulk order list action selection, instead of date range:

// Adding to admin order list bulk dropdown a custom action 'custom_downloads'
add_filter( 'bulk_actions-edit-shop_order', 'downloads_bulk_actions_edit_product', 20, 1 );
function downloads_bulk_actions_edit_product( $actions ) {
    $actions['write_downloads'] = __( 'Download orders', 'woocommerce' );
    return $actions;

// Make the action from selected orders
add_filter( 'handle_bulk_actions-edit-shop_order', 'downloads_handle_bulk_action_edit_shop_order', 10, 3 );
function downloads_handle_bulk_action_edit_shop_order( $redirect_to, $action, $post_ids ) {
    if ( $action !== 'write_downloads' )
        return $redirect_to; // Exit

    global $attach_download_dir, $attach_download_file; // ???

    $processed_ids = array();

    foreach ( $post_ids as $post_id ) {
        $order = wc_get_order( $post_id );
        $order_data = $order->get_data();

        // Your code to be executed on each selected order
            $order_data['date_created']->date('d/M/Y') . '; ' .
            '#' . ( ( $order->get_type() === 'shop_order' ) ? $order->get_id() : $order->get_parent_id() ) . '; ' .
            '#' . $order->get_id()
        $processed_ids[] = $post_id;

    return $redirect_to = add_query_arg( array(
        'write_downloads' => '1',
        'processed_count' => count( $processed_ids ),
        'processed_ids' => implode( ',', $processed_ids ),
    ), $redirect_to );

// The results notice from bulk action on orders
add_action( 'admin_notices', 'downloads_bulk_action_admin_notice' );
function downloads_bulk_action_admin_notice() {
    if ( empty( $_REQUEST['write_downloads'] ) ) return; // Exit

    $count = intval( $_REQUEST['processed_count'] );

    printf( '<div id="message" class="updated fade"><p>' .
        _n( 'Processed %s Order for downloads.',
        'Processed %s Orders for downloads.',
    ) . '</p></div>', $count );

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

enter image description here

enter image description here

In the returned url I have something like (for 2 selected / processed orders): wp-admin/edit.php?post_type=shop_order&paged=1&write_downloads=1&processed_count=2&processed_ids=847%2C846

I can't test your included script but it's the way to do it on Woocommerce Orders Admin list.


The available variables are set by add_query_arg() function as you will see. When the action is triggered, you get those variables in the URL through GET method…

You can set any variable yourself too…

In this example you can use $_GET or $_REQUEST with:

  • $_GET['write_downloads'] (the name action: true or false)
  • $_GET['processed_count'] (the number of selected orders)
  • $_GET['processed_ids'] (the Order Ids separated by an url-encoded coma %2C)

So you can either execute your script:

  • inside my code function (like in my code) … or …
  • outside it, using the available variables once the action is triggered…

To remove a specific action from the dropdown orders bulk actions

For example we want to remove "On hold" status change:

add_filter( 'bulk_actions-edit-shop_order', 'remove_a_bulk_order_action', 20, 1 );
function remove_a_bulk_order_action( $actions ) {

    return $actions;

All statuses change keys start with mark_ + the status slug (without wc-).

Wednesday, March 31, 2021
answered 7 Months ago

It's possible to get the total items count bought by the current customer in the past 30 days.

Here is the code of this function based on this answer:

function current_customer_month_count( $user_id=null ) {
    if ( empty($user_id) ){
        $user_id = get_current_user_id();
    // Date calculations to limit the query
    $today_year = date( 'Y' );
    $today_month = date( 'm' );
    $day = date( 'd' );
    if ($today_month == '01') {
        $month = '12';
        $year = $today_year - 1;
    } else{
        $month = $today_month - 1;
        $month = sprintf("%02d", $month);
        $year = $today_year - 1;

    // ORDERS FOR LAST 30 DAYS (Time calculations)
    $now = strtotime('now');
    // Set the gap time (here 30 days)
    $gap_days = 30;
    $gap_days_in_seconds = 60*60*24*$gap_days;
    $gap_time = $now - $gap_days_in_seconds;

    // The query arguments
    $args = array(
        // WC orders post type
        'post_type'   => 'shop_order',
        // Only orders with status "completed" (others common status: 'wc-on-hold' or 'wc-processing')
        'post_status' => 'wc-completed', 
        // all posts
        'numberposts' => -1,
        // for current user id
        'meta_key'    => '_customer_user',
        'meta_value'  => $user_id,
        'date_query' => array(
            //orders published on last 30 days
            'relation' => 'OR',
                'year' => $today_year,
                'month' => $today_month,
                'year' => $year,
                'month' => $month,

    // Get all customer orders
    $customer_orders = get_posts( $args );
    $count = 0;
    if (!empty($customer_orders)) {
        $customer_orders_date = array();
        // Going through each current customer orders
        foreach ( $customer_orders as $customer_order ){
            // Conveting order dates in seconds
            $customer_order_date = strtotime($customer_order->post_date);
            // Only past 30 days orders
            if ( $customer_order_date > $gap_time ) {
                $order = new WC_Order( $customer_order->ID );
                $order_items = $order->get_items();
                // Going through each current customer items in the order
                foreach ( $order_items as $order_item ){
        return $count;

This code goes in function.php file of your active child theme (or theme) or also in any plugin file.

The function accept an optional user_id argument (if needed). For example for a user_id with 56 value, you will use the function, this way:

// For user ID: "56".
$number_of_items_in_last_month = current_customer_month_count('56');

The function will get the current user ID in $user_id = get_current_user_id();, if you dont set an argument user_id value, this way:

// For current logged user.
$number_of_items_in_last_month = current_customer_month_count();

You can use this function in a conditional if statement to hide or replace the add-to-cart button through somme WooCommerce hooks or related templates.
You could get helped in that task, asking a new question including this code, and providing more details about how you want to do it.

This code is tested and works.

References: Checking if customer has already bought something in WooCommerce

Saturday, May 29, 2021
answered 5 Months ago

You can remove Free order it by using parse_query filter with $pagenow global variable.

add_filter('parse_query', 'wh_alterAdminPostList');

function wh_alterAdminPostList($query)
    global $pagenow;
    if (is_admin() && $pagenow == 'edit.php' && isset($_GET['post_type']) && $_GET['post_type'] == 'shop_order')
        $query->query_vars['meta_query'] = [
                'key' => '_order_total',
                'value' => 0.00,
                'compare' => '>',
                'type' => 'DECIMAL',

Code goes in function.php file of your active child theme (or theme). Or also in any plugin php files.
Code is tested and works.

Hope this helps!

Saturday, May 29, 2021
answered 5 Months ago

Here is the way to do it with that 2 custom functions hooked. The first one create the column with the title, the second one populate the column with the products data. But you will need to set in that second function, the correct corresponding meta_key to get the data.

Here is that code:

add_filter( 'manage_edit-product_columns', 'custom_product_column',11);
function custom_product_column($columns)
   //add columns
   $columns['delivery'] = __( 'Delivery time','woocommerce'); // title
   return $columns;

add_action( 'manage_product_posts_custom_column' , 'custom_product_list_column_content', 10, 2 );
function custom_product_list_column_content( $column, $product_id )
    global $post;

    // HERE get the data from your custom field (set the correct meta key below)
    $delivery_time = get_post_meta( $product_id, '_delivery_time', true );

    switch ( $column )
        case 'delivery' :
            echo $delivery_time; // display the data

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

Tested and works.

How to get the correct meta_key slug:

To find the correct meta_key slug corresponding to the "delivery time", you should need to make search in your database using PhpMyAdmin. You will have to search for delivery term in wp_postmeta table this way:

enter image description here

Then you will get this kind of results (here there is just 1 line with a fake slug):

enter image description here

So now you should be able to get the correct slug name (like this fake "_delivery_date" one)

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

Friday, July 30, 2021
answered 3 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :