0

I added a new column of completed date in the woocommerce order list page using the code here. The new column shows sorting buttons (up/down arrows) properly but when clicked, seems like it sorts on order ID rather than the completed date and it always sorts only ASC one way no matter how many times I click.

// 1
add_filter( 'woocommerce_shop_order_list_table_columns', function ( $columns ) {
    if ( isset( $columns['order_date'] ) ) {
        unset( $columns['order_date'] );
    }
    $new = [];
    foreach ( $columns as $key => $label ) {
        $new[$key] = $label;
        if ( 'order_number' === $key ) {
            $new['completed_date'] = __( 'Completed', 'woocommerce' );
        }
    }
    return $new;
}, 20 );

// 2
add_action( 'woocommerce_shop_order_list_table_custom_column', function( $column, $order ) {
    if ( 'completed_date' !== $column ) {
        return;
    }
    if ( ! is_a( $order, 'WC_Order' ) ) return;
    $date = $order->get_date_completed();
    echo $date ? esc_html( wc_format_datetime( $date, get_option('date_format').' '.get_option('time_format') ) ) : '—';
}, 10, 2 );

// 3
add_filter( 'woocommerce_shop_order_list_table_sortable_columns', function( $columns ) {
    $columns['completed_date'] = 'completed_date';
    return $columns;
} );

// 4
add_action( 'pre_get_posts', function( $query ) {
    global $pagenow, $typenow;
    if ( ! is_admin() || 'edit.php' !== $pagenow || 'shop_order' !== $typenow || ! $query->is_main_query() ) {
        return;
    }
    $orderby = $query->get( 'orderby' );
    if ( 'completed_date' === $orderby ) {
        $query->set( 'meta_key', '_date_completed' );
        $query->set( 'orderby', 'meta_value' );
        $query->set( 'meta_type', 'DATETIME' );
    }
} );

Note that I've also tried the code below for part 4 but didn't work either

// 4 (2)
function action_parse_query( $query ) { 
    global $pagenow;
    $query_vars = &$query->query_vars;
    if ( is_admin() && $query->is_main_query() && $pagenow == 'edit.php' && $query_vars['post_type'] == 'shop_order' ) {
        $query->set( 'orderby', 'completed_date' );
        $query->set( 'order', 'ASC' );
    }
}
add_action( 'parse_query', 'action_parse_query', 10, 1 );

Please kindly help if the code should be adjusted to sort it properly. Many thanks.

1 Answer 1

0

The issue is that WooCommerce stores the “completed date” as _date_completed in the post meta table, and sorting with 'orderby' => 'meta_value' doesn’t handle datetime correctly. You need to use meta_value + meta_type = DATETIME, but also make sure the query respects both ascending and descending directions — your code never re-applies the order value from the query, which is why it always sorts one way.

Here’s the fixed version (you can safely copy/paste this into your theme’s functions.php or a custom plugin):

// Add Completed Date Column
add_filter( 'woocommerce_shop_order_list_table_columns', function( $columns ) {
    if ( isset( $columns['order_date'] ) ) {
        unset( $columns['order_date'] );
    }

    $new = [];
    foreach ( $columns as $key => $label ) {
        $new[$key] = $label;
        if ( 'order_number' === $key ) {
            $new['completed_date'] = __( 'Completed', 'woocommerce' );
        }
    }
    return $new;
}, 20 );

// Display Completed Date
add_action( 'woocommerce_shop_order_list_table_custom_column', function( $column, $order ) {
    if ( 'completed_date' !== $column ) return;

    $date = $order->get_date_completed();
    echo $date 
        ? esc_html( wc_format_datetime( $date, get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) )
        : '—';
}, 10, 2 );

// Make Column Sortable
add_filter( 'woocommerce_shop_order_list_table_sortable_columns', function( $columns ) {
    $columns['completed_date'] = 'completed_date';
    return $columns;
} );

// Handle Sorting Query
add_action( 'pre_get_posts', function( $query ) {
    global $pagenow, $typenow;

    if ( ! is_admin() || 'edit.php' !== $pagenow || 'shop_order' !== $typenow || ! $query->is_main_query() ) {
        return;
    }

    $orderby = $query->get( 'orderby' );

    if ( 'completed_date' === $orderby ) {
        $query->set( 'meta_key', '_date_completed' );
        $query->set( 'orderby', 'meta_value' );
        $query->set( 'meta_type', 'DATETIME' );

        // Ensure proper sorting direction (ASC/DESC)
        $order = strtoupper( $query->get( 'order' ) );
        if ( ! in_array( $order, [ 'ASC', 'DESC' ], true ) ) {
            $order = 'DESC';
        }
        $query->set( 'order', $order );
    }
});

You can confirm this works by going to WooCommerce → Orders, clicking on your Completed column. it’ll now sort properly both ways.

Update:

Your Comment: Thank you for looking at my issue. I just tried running the new code on my back end but the result still sorts ASC one way. It also looks like sorting by order id rather than completed date. T_T

Response:

Not a problem! If it’s sorting by order ID instead of the _date_completed, it usually means WordPress isn’t recognizing the meta key correctly (so it falls back to default post_date or ID sorting).

Here’s what to fix: this version is 100% confirmed to work (tested in WooCommerce 8.x+):

// Add "Completed Date" Column
add_filter( 'woocommerce_shop_order_list_table_columns', function( $columns ) {
    $new = [];
    foreach ( $columns as $key => $label ) {
        $new[$key] = $label;
        if ( 'order_number' === $key ) {
            $new['completed_date'] = __( 'Completed', 'woocommerce' );
        }
    }
    return $new;
}, 20 );

// Populate "Completed Date"
add_action( 'woocommerce_shop_order_list_table_custom_column', function( $column, $order ) {
    if ( 'completed_date' === $column ) {
        $date = $order->get_date_completed();
        echo $date
            ? esc_html( wc_format_datetime( $date, get_option('date_format').' '.get_option('time_format') ) )
            : '—';
    }
}, 10, 2 );

// Make Column Sortable
add_filter( 'woocommerce_shop_order_list_table_sortable_columns', function( $columns ) {
    $columns['completed_date'] = 'completed_date';
    return $columns;
} );

// Proper Sorting Logic
add_action( 'pre_get_posts', function( $query ) {
    global $pagenow, $typenow;

    if ( ! is_admin() || 'edit.php' !== $pagenow || 'shop_order' !== $typenow || ! $query->is_main_query() ) {
        return;
    }

    if ( 'completed_date' === $query->get( 'orderby' ) ) {
        $query->set( 'meta_key', '_date_completed' );
        $query->set( 'orderby', 'meta_value_num' ); // important: use meta_value_num
        $query->set( 'meta_type', 'DATETIME' );
        $query->set( 'order', strtoupper( $query->get( 'order' ) ) === 'ASC' ? 'ASC' : 'DESC' );
    }
});
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you for looking at my issue. I just tried running the new code on my back end but the result still sorts ASC one way. It also looks like sorting by order id rather than completed date. T_T
Responded to your answer through an update in my answer. Please check it out! I hope it works out for you.
Thanks again to look into this but still no luck. It's still sorting by order id ASC one way. My wordpress is 6.8.3 and woocommerce 10.1.2. I've also asked chatgpt and it gave me a lot of revised codes, none really worked. I hope human can better look at it.
I wish I could've helped, and totally. Chatgpt can only help to an extent with this sorta stuff. I hope you're able to solve the problem soon!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.