Black Friday & Cyber Monday SUPER SALE ALL WEEK:
Grab 40% OFF on plugins
Days
Hours
Minutes
Seconds

How to Refund Multiple Orders (via Bulk Actions) in WooCommerce (Compatible with HPOS Order Tables)?

In WooCommerce, the default refund status available on the edit order page works well for changing a single order to refund status. But you might also be required to change the status of multiple orders to refund status. Currently, the bulk actions dropdown on the WooCommerce > Orders page which provides several bulk actions but doesn’t include actions, such as changing multiple orders to the “Refunded” status.

In this post, we’ll cover how to change multiple orders to refunded status using the Bulk Actions dropdown, with two distinct approaches: one for automatically restocking the refunded items and another for processing the refund without restocking.

Solution 1: Bulk Refund Orders with Restocking

This WooCommerce customization will add a custom bulk action that helps you to refund multiple orders simultaneously. When you refund multiple orders, it’s important to also restock the items if they were returned. Thus this code snippet adds a custom bulk action ‘Refund with Restocking’ which will refund bulk orders and also restock the items in those refunded orders.

// Add custom bulk action: Refund with Restock
$add_custom_bulk_actions = function ( array $bulk_actions ) {
    $bulk_actions['refund-with-restock'] = 'Refund with Restock';
    return $bulk_actions;
};

// Handle the custom bulk action: Refund with Restock
$custom_bulk_action_handler = function ( string $redirect_to, string $action, array $ids ) {
    if ( 'refund-with-restock' === $action ) {
        $changed = false;

        // Iterate over each selected order
        foreach ( $ids as $order_id ) {
            $order = wc_get_order( $order_id );

            if ( ! $order ) {
                continue;
            }

            // Process refund with restocking
            $refund = wc_create_refund( [
                'order_id'     => $order_id,
                'amount'       => $order->get_total(),
                'reason'       => 'Bulk Refund with Restock',
                'restock_items'=> true, // Restock the items
                'refund_method'=> 'refund' // This will apply the actual refund action
            ] );

            if ( $refund && is_a( $refund, 'WC_Order_Refund' ) ) {
                // Update the order status to 'refunded'
                $order->update_status( 'refunded' );
                $changed = true;

                // Custom restocking logic if "Refund with Restock" is selected
                foreach ( $order->get_items() as $item ) {
                    if ( $item->get_product_id() > 0 ) {
                        $product = $item->get_product();

                        if ( $product && $product->exists() && $product->managing_stock() ) {
                            $qty = $item->get_quantity(); // Get the item quantity
                            $product->increase_stock( $qty ); // Restock the quantity

                            do_action( 'woocommerce_auto_stock_restored', $product, $item ); // Optional custom action
                            
                            // Optionally, send stock notifications if necessary
                            $order->send_stock_notifications( $product, $product->get_stock_quantity(), $qty );
                        }
                    }
                }

                // Optionally add an order note for tracking
                $order->add_order_note( 'Stock levels increased for refunded items with restock.' );
            }
        }

        // Set redirect notice
        if ( $changed ) {
            $redirect_to = add_query_arg( 'bulk_action', 'refund-with-restock-notice', $redirect_to );
        }
    }

    return $redirect_to;
};

// Display a notice after the bulk action has been executed
$custom_bulk_action_notice = function () {
    if ( isset( $_GET['bulk_action'] ) ) {
        $action = sanitize_text_field( $_GET['bulk_action'] );
        if ( 'refund-with-restock-notice' === $action ) {
            echo '<div class="updated" style="border-left-color: #d7f"><p>Refund with Restock has been successfully applied to selected orders and stock levels have been adjusted.</p></div>';
        }
    }
};

// Register the custom bulk action
add_filter( 'bulk_actions-woocommerce_page_wc-orders', $add_custom_bulk_actions );

// Handle the custom bulk action
add_filter( 'handle_bulk_actions-woocommerce_page_wc-orders', $custom_bulk_action_handler, 10, 3 );

// Show a notice after the action is performed
add_action( 'admin_notices', $custom_bulk_action_notice );

flexi bogo cta banner image


This to the shop owners who are running or planning to run BOGO offers on their WooCommerce store…

BOGO deals are great for increasing your sales, but have you thought about which offers are bringing you more revenue and which offers are not performing that great?

Don’t just set a BOGO deal, track the revenue generated by your deals in real-time with the Flexi BOGO for WooCommerce plugin.

Output

Let’s take an example product called ‘Beast Earbuds’ with an initial stock quantity of 10 which is set in the quantity field of the product settings.

How to Refund Multiple Orders (via Bulk Actions) in WooCommerce (Compatible with HPOS Order Tables)? - Tyche Softwares

If the customer places 5 units of this product, the stock quantity will be reduced to 5 which is automatically updated by WooCommerce.

How to Refund Multiple Orders (via Bulk Actions) in WooCommerce (Compatible with HPOS Order Tables)? - Tyche Softwares



When the refund action is applied to multiple orders, the code also triggers the default “Refunded” process that happens on the edit orders page and adjusts the total costs accordingly. The code to change multiple orders to refund status is also compatible with HPOS Order Tables.

How to Refund Multiple Orders (via Bulk Actions) in WooCommerce (Compatible with HPOS Order Tables)? - Tyche Softwares

Once the orders are refunded using the bulk actions, the stock count for the product ‘beast earbuds’ is restored to 10 because the refunded 5 units is added back to the inventory.

Solution 2: Bulk Refund Orders without Restocking

The above solution works well when a store owner wants to refund multiple orders and simultaneously restock items for all refunded orders. However, in cases of lost or damaged packages, the refunded items shouldn’t be restocked to inventory, as these products were not actually returned by the customer. Restocking in such cases would result in inaccurate stock levels.


If you want to do multiple refunds without restocking then you can simply use the code snippet given below. The code will add a custom bulk action named as ‘Refund without restocking’  which will only do refunding multiple orders but not restock the items in the orders.

// Updating label in admin order list bulk actions dropdown
function ts_update_custom_dropdown_bulk_actions_shop_order( $actions ) {

// Add default WooCommerce 'mark_refunded' action
$actions['mark_refunded'] = __( 'Refund without restocking', 'woocommerce' );

return $actions;
}
add_action('bulk_actions-edit-shop_order', 'ts_update_custom_dropdown_bulk_actions_shop_order');
add_filter( 'bulk_actions-woocommerce_page_wc-orders', 'ts_update_custom_dropdown_bulk_actions_shop_order', 20, 1 );
add_filter( 'handle_bulk_actions-woocommerce_page_wc-orders', 'ts_update_custom_dropdown_bulk_actions_shop_order', 20, 1 );


Selecting the option ‘ Refund without restocking’ from the bulk actions dropdown will let you to refund multiple orders at once without restocking the inventory.

How to Refund Multiple Orders (via Bulk Actions) in WooCommerce (Compatible with HPOS Order Tables)? - Tyche Softwares

Combined snippet for adding both option: Refund Orders with Restocking & Refund Orders without Restocking

// Add custom bulk actions: Refund with Restock and Refund without Restock
$ts_add_custom_bulk_actions = function ( array $bulk_actions ) {
    return array_merge( $bulk_actions, [
        'refund-with-restock' => 'Refund with Restock',
        'refund-without-restock' => 'Refund without Restock',
    ] );
};

// Handle the custom bulk actions
$ts_custom_bulk_action_handler = function ( string $redirect_to, string $action, array $ids ) {
    if ( 'refund-with-restock' === $action || 'refund-without-restock' === $action ) {
        $changed = false;

        // Iterate over each selected order
        foreach ( $ids as $order_id ) {
            $order = wc_get_order( $order_id );

            if ( ! $order ) {
                continue;
            }

            // Process refund
            $refund = wc_create_refund( [
                'order_id'     => $order_id,
                'amount'       => $order->get_total(),
                'reason'       => 'Bulk Refund',
                'restock_items'=> $action === 'refund-with-restock', // Restock if Refund with Restock
                'refund_method'=> 'refund' // This will apply the actual refund action
            ] );

            if ( $refund && is_a( $refund, 'WC_Order_Refund' ) ) {
                // Update the order status to 'refunded'
                $order->update_status( 'refunded' );
                $changed = true;

                // Custom restocking logic if "Refund with Restock" is selected
                if ( 'refund-with-restock' === $action ) {
                    foreach ( $order->get_items() as $item ) {
                        if ( $item->get_product_id() > 0 ) {
                            $product = $item->get_product();

                            if ( $product && $product->exists() && $product->managing_stock() ) {
                                $qty = $item->get_quantity(); // Get the item quantity
                                $new_quantity = $product->increase_stock( $qty ); // Restock the quantity

                                do_action( 'woocommerce_auto_stock_restored', $product, $item ); // Optional custom action
                                
                                // Optionally, send stock notifications if necessary
                                $order->send_stock_notifications( $product, $new_quantity, $qty );
                            }
                        }
                    }
                    
                    // Optionally add an order note for tracking
                    $order->add_order_note( 'Stock levels increased for refunded items with restock.' );
                }
            }
        }

        // Set redirect notice
        if ( $changed ) {
            $redirect_to = add_query_arg( 'bulk_action', $action . '-notice', $redirect_to );
        }
    }

    return $redirect_to;
};

// Display a notice after the bulk action has been executed
$ts_custom_bulk_action_notice = function () {
    if ( isset( $_GET['bulk_action'] ) ) {
        $action = sanitize_text_field( $_GET['bulk_action'] );
        if ( 'refund-with-restock-notice' === $action ) {
            echo '<div class="updated" style="border-left-color: #d7f"><p>Refund with Restock has been successfully applied to selected orders and stock levels have been adjusted.</p></div>';
        } elseif ( 'refund-without-restock-notice' === $action ) {
            echo '<div class="updated" style="border-left-color: #d7f"><p>Refund without Restock has been successfully applied to selected orders.</p></div>';
        }
    }
};

// Register the custom bulk actions
add_filter( 'bulk_actions-woocommerce_page_wc-orders', $ts_add_custom_bulk_actions );

// Handle the custom bulk actions
add_filter( 'handle_bulk_actions-woocommerce_page_wc-orders', $ts_custom_bulk_action_handler, 10, 3 );

// Show a notice after the action is performed
add_action( 'admin_notices', $ts_custom_bulk_action_notice );

Solution 3: Automatically Refund Multiple WooCommerce Orders when Using PayPal Payment Gateway

Most WordPress site owners prefer to use the most popular payment gateways like PayPal to streamline transactions into their woocommerce site. When such payment options are set up on your site then you might need customizations to automate tasks, such as refunding bulk orders.

For instance, if you need to refund multiple orders paid via PayPal, doing it manually from the WooCommerce edit order page is a daunting task. So in this WooCommerce customization, we will provide a solution that will automate the refund for multiple orders in PayPal transactions. Also, the provided code snippet ensures that it works in both WordPress posts table and HPOS orders Tables.

use function WooCommerce\PayPalCommerce\Api\ppcp_refund_order;

// Updating label in admin order list bulk actions dropdown
function ts_update_custom_dropdown_bulk_actions_shop_order( $actions ) {
    // Add default WooCommerce 'mark_refunded' action
    $actions['mark_refunded'] = __( 'Change status to Refunded', 'woocommerce' );
    return $actions;
}
add_action('bulk_actions-edit-shop_order', 'ts_update_custom_dropdown_bulk_actions_shop_order');
add_filter( 'bulk_actions-woocommerce_page_wc-orders', 'ts_update_custom_dropdown_bulk_actions_shop_order', 20, 1 );

// Handling the custom bulk action
function ts_handle_custom_bulk_actions_shop_order( $redirect_to, $doaction, $order_ids ) {
    if ( $doaction === 'mark_refunded' && ! empty( $order_ids ) ) {
        foreach ( $order_ids as $order_id ) {
            $order = wc_get_order( $order_id );
            if ( $order && $order->get_status() !== 'refunded' ) {
                // Update the order status to "refunded"
                $order->update_status( 'refunded' );
            }
        }
    }
    return $redirect_to;
}
add_filter( 'handle_bulk_actions-edit-shop_order', 'ts_handle_custom_bulk_actions_shop_order', 20, 3 );

// Hook to handle automatic refunds when status changes to "refunded"
add_action( 'woocommerce_order_status_changed', 'ts_auto_refund_on_status_change', 10, 4 );

function ts_auto_refund_on_status_change( $order_id, $old_status, $new_status, $order ) {
    if ( $new_status === 'refunded' ) {
        if ( $order->get_payment_method() === 'ppcp-gateway' ) {
            $refund_amount = $order->get_total();
            $refund_response = ppcp_refund_order( $order, $refund_amount );
           
        }
    }
}

Output

Let’s consider that you need to refund some bulk  WooCommerce orders paid via the PayPal payment gateway. The below image shows a list of orders currently in ‘Processing’ status, indicating they’ve been completed using real payment methods like PayPal.

How to Refund Multiple Orders (via Bulk Actions) in WooCommerce (Compatible with HPOS Order Tables)? - Tyche Softwares

At this point, when an order is completed in WooCommerce, the payment transaction status of these orders in the PayPal test store will be in ‘completed’ status.

How to Refund Multiple Orders (via Bulk Actions) in WooCommerce (Compatible with HPOS Order Tables)? - Tyche Softwares

Let’s change the status of the WooCommerce orders to ‘refunded’ status using the bulk action ‘Change status to Refunded’ option in WooCommerce > Orders page.

How to Refund Multiple Orders (via Bulk Actions) in WooCommerce (Compatible with HPOS Order Tables)? - Tyche Softwares
Once the status is set to ‘refunded’ on the WooCommerce orders page, the refund process will automatically be initiated and applies a full refund in the PayPal’s transaction activity.

How to Refund Multiple Orders (via Bulk Actions) in WooCommerce (Compatible with HPOS Order Tables)? - Tyche Softwares
Here is the detailed walk-through of the video of how to handle bulk refunds in WooCommerce.

Interested in exploring another useful feature that most admins prefer? You can filter WooCommerce orders by multiple statuses, which could be a game-changer for managing your daily tasks!

Browse more in: Code Snippets, WooCommerce How Tos, WooCommerce Tutorials

Share It:

Subscribe
Notify of
15 Comments
Newest
Oldest
Inline Feedbacks
View all comments
14 days ago

Hi, does this also restock the refunded items?

13 days ago
Reply to  Saranya

Thanks for this! If you have any more time to spare on this, I wonder if you could suggest how this could be done as two separate bulk order actions, therefore “refund with restock” and “refund without restock”. This is to cater for the two very common scenarios for mail order stores: Package lost/damaged –> no restock Package returned –> restock The specific problem I’m trying to solve is where we forget to untick the refund=yes check box when refunding a lost order. This frequently results in another refund being required shortly afterwards, sometimes to the exact same customer that… Read more »

Philip
4 months ago

Thank you very much, this code snippet helped me with my bulk refunding through paypal gateway in Woocommerce. I just added it by using the “Code Snippets”-Plugin under the “functions” section. super easy 🙂

conhe
4 months ago

Hello and thank you for this snippet, will it refund the full amount of the order (all the products + shipping + taxes) for the selected orders ?

Edit : sorry, I’ve added the code and nothing appears in the dropdown. WOP is up to date as all plugins

Last edited 4 months ago by conhe
conhe
4 months ago
Reply to  Saranya

Hi Saranya and thank you for your answer. I tried but nothing works.. So, I took the code from ( https://www.tychesoftwares.com/how-to-add-custom-bulk-actions-to-woocommerce-admin-order-list/ ) and modified it with mark_refunded and it works great though

conhe
4 months ago
Reply to  Saranya

Update : it doesn’t “really” work as it didn’t refunded the customer. I have to go on paypal and do it myself. This is a manual refund and not an automatic. Any idea how to turn it automatic ?

conhe
4 months ago
Reply to  Saranya

Hello Saranya, sure thing. Since, this wasn’t working (nothing was appearing in the bulk action menu) : // Updating label in admin order list bulk actions dropdown function ts_update_custom_dropdown_bulk_actions_shop_order( $actions ) {   // Add default WooCommerce 'mark_refunded' action   $actions['mark_refunded'] = __( 'Change status to Refunded', 'woocommerce' );   return $actions; } add_filter( 'bulk_actions-woocommerce_page_wc-orders', 'ts_update_custom_dropdown_bulk_actions_shop_order', 20, 1 ); add_filter( 'handle_bulk_actions-woocommerce_page_wc-orders', 'ts_update_custom_dropdown_bulk_actions_shop_order', 20, 1 ); I’ve added this : function ts_custom_bulk_action_mark_refunded() {   ?>   <script type="text/javascript">     jQuery(document).ready(function($) {       if ($('select[name="action"]').length > 0) {         $('<option>')           .val('mark_refunded')           .text('<?php _e('Change status to Refunded', 'snippet'); ?>')           .appendTo('select[name="action"]');       }       if ($('select[name="action2"]').length > 0) {         $('<option>')           .val('mark_refunded')           .text('<?php _e('Change status… Read more »

conhe
4 months ago
Reply to  Saranya

Hello Saranya and thank you for your time. I’ll have a look at HPOS since we deactivated it because of some other stuff. I’ll see if I can reactivate it.

Thank you !

15
0
Would love your thoughts, please comment.x
()
x