How to Delete All WooCommerce Orders
In this guide, I’m going to uncover two ways how you can delete all WooCommerce orders at once.
- In the first method, I’m going to show you SQL queries that you can just run in your database,
- In the second method, you will find a plugin (or a code snippet) that you can just install on your site and hit the “Delete All Orders” button.
Why would someone ever need that? I guess if you’re looking for it and reading this post right now, you have a reason. In my case, for example, I usually needed to delete test orders when I’m developing either my Order Sync or Multisite Order Sync plugin.
SQL Queries to Delete All WooCommerce Orders
The first and easiest way to delete all WooCommerce orders at once is to run a couple of SQL queries. If you have no idea how to run them, please continue reading below.
The only thing that you need to keep in mind when using this method is what database structure is used for orders on your WooCommerce store.
- Has your store existed for a long time, and probably you’re still using the legacy database structure for orders (the same as for WordPress custom post types),
- Or maybe you’re using high-performance order storage, which appeared in WooCommerce 8.2?
- Or maybe even both? (compatibility mode).
CPT-based (legacy) orders
Let’s begin with the legacy database structure. Basically, here, we need to remove all items of the shop_order custom post type.
# delete orders and orders data
DELETE FROM wp_postmeta WHERE post_id IN ( SELECT ID FROM wp_posts WHERE post_type = 'shop_order' );
DELETE FROM wp_posts WHERE post_type = 'shop_order';
# delete order notes which are comments
DELETE FROM wp_comments WHERE comment_type = 'order_note';
# delete order items
DELETE FROM wp_woocommerce_order_itemmeta;
DELETE FROM wp_woocommerce_order_items;Should I remind you that you also need to replace wp_ with the database prefix you’re using on your WooCommerce store? You’ve probably changed it for security reasons before.
HPOS orders
From my tutorial about high-performance order storage, you probably know that there are 4 new database tables where orders are stored: wp_wc_orders, wp_wc_order_addresses, wp_wc_order_operational_data, wp_wc_orders_meta also, let’s remember about WooCommerce analytics and include wp_wc_order_stats here.
# delete order data
DELETE FROM wp_wc_orders;
DELETE FROM wp_wc_order_addresses;
DELETE FROM wp_wc_order_operational_data;
DELETE FROM wp_wc_orders_meta;
# don't forget about order placeholders
DELETE FROM wp_posts WHERE post_type = 'shop_order_placehold';
# delete order notes
DELETE FROM wp_comments WHERE comment_type = 'order_note';
# delete order items
DELETE FROM wp_woocommerce_order_itemmeta;
DELETE FROM wp_woocommerce_order_items;
# delete WooCommerce analytics data
DELETE FROM wp_wc_order_stats;If I forgot about some specific SQL queries, please remind me in the comments.
How to run SQL queries?
First of all, I must say that everything depends on the WordPress hosting you’re using for your WooCommerce store.
Sometimes, you can access phpMyAdmin from the cPanel, but this is not always the case:

Once you’re in the phpMyAdmin, you need to switch to the SQL tab and run the queries:

As an alternative solution, you could try to run SQL queries using Adminer plugin.
How to Delete All Orders With a Plugin in WooCommerce?
In case you don’t want to deal with the database or just get stuck trying to access the phpMyAdmin interface, then I have another solution for you.
Here is how it is going to look on the WooCommerce > Orders page:

Here is the complete code:
<?php
/*
* Plugin name: WooCommerce Delete All Orders
* Description: Allows to delete all WooCommerce orders in one click
* Author: Misha Rudrastyh
* Author URI: https://rudrastyh.com
* Plugin URI: https://rudrastyh.com/woocommerce/delete-all-orders.html#wordpress-plugin
* Version: 1.0
*/
// we need this namespace to check whether HPOS is in use
use Automattic\WooCommerce\Utilities\OrderUtil;
// for legacy orders
add_action( 'manage_posts_extra_tablenav', function( $which ) {
$screen = get_current_screen();
if( 'shop_order' !== $screen->post_type || 'top' !== $which ) {
return;
}
rudr_display_delete_all_orders_btn();
}, 25 );
// for HPOS orders
add_action( 'woocommerce_order_list_table_extra_tablenav', function( $post_type, $which ) {
if( 'shop_order' !== $post_type || 'top' !== $which ) {
return;
}
rudr_display_delete_all_orders_btn();
}, 25, 2 );
// display HTML for the "Delete All Orders" link
function rudr_display_delete_all_orders_btn(){
printf(
'<a href="%s" class="button" style="height:32px">%s</a>',
add_query_arg(
array(
'action' => 'delete_all_orders_now',
'_wpnonce' => wp_create_nonce( 'mishatest' ),
),
admin_url( 'admin-post.php' )
),
esc_html__( 'Delete All Orders', 'woocommerce' )
);
}
// process order deletion with the hook admin_post_{$action}
add_action( 'admin_post_delete_all_orders_now', function() {
global $wpdb;
check_admin_referer( 'mishatest' );
if( OrderUtil::custom_orders_table_usage_is_enabled() ) {
$count = $wpdb->get_var(
"
SELECT COUNT(*)
FROM {$wpdb->prefix}wc_orders
"
);
$queries = array(
"DELETE FROM {$wpdb->prefix}wc_orders",
"DELETE FROM {$wpdb->prefix}wc_order_addresses",
"DELETE FROM {$wpdb->prefix}wc_order_operational_data",
"DELETE FROM {$wpdb->prefix}wc_orders_meta",
"DELETE FROM {$wpdb->posts} WHERE post_type = 'shop_order_placehold'",
"DELETE FROM {$wpdb->comments} WHERE comment_type = 'order_note'",
"DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta",
"DELETE FROM {$wpdb->prefix}woocommerce_order_items",
"DELETE FROM {$wpdb->prefix}wc_order_stats",
);
foreach( $queries as $query ) {
$wpdb->query( $query );
}
wp_safe_redirect(
add_query_arg(
array(
'page' => 'wc-orders',
'deleted' => $count,
),
'admin.php'
)
);
} else {
$count = $wpdb->get_var(
"
SELECT COUNT(*)
FROM {$wpdb->posts}
WHERE post_type = 'shop_order'
"
);
$queries = array(
"DELETE FROM {$wpdb->postmeta} WHERE post_id IN ( SELECT ID FROM {$wpdb->posts} WHERE post_type = 'shop_order' )",
"DELETE FROM {$wpdb->posts} WHERE post_type = 'shop_order'",
"DELETE FROM {$wpdb->comments} WHERE comment_type = 'order_note'",
"DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta",
"DELETE FROM {$wpdb->prefix}woocommerce_order_items",
"DELETE FROM {$wpdb->prefix}wc_order_stats",
);
foreach( $queries as $query ) {
$wpdb->query( $query );
}
wp_safe_redirect(
add_query_arg(
array(
'post_type' => 'shop_order',
'deleted' => $count,
),
'edit.php'
)
);
}
exit;
} );A couple of notes for the code above:
- It works for both CPT-based legacy orders and HPOS orders; you can see that I used two hooks
manage_posts_extra_tablenavandwoocommerce_order_list_table_extra_tablenav, and later in the code, I checked whether HPOS was enabled with theOrderUtilclass. - Do we need to clean up the
wp_commentmetatable? I am not sure that order notes have any metadata. - We can not run multiple SQL queries with
$wpdb->query(), that’s why I used theforeach()loop. - I used
deletedURL parameter to display a notice in order to skip an unnecessaryadmin_noticeusage over here.
I think that’s pretty much it. Let me know your thoughts in the comments, guys.
Misha Rudrastyh
Hey guys and welcome to my website. For more than 15 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