How to prevent customers from cancelling WooCommerce orders
reduce customer cancellations in WooCommerce orders

If you’re running an eCommerce business, you know that managing customer orders is super important. One crucial step in the customer journey is order cancellation, which may vary depending on your business needs. You might even have specific conditions under which an order can be canceled. By default, WooCommerce allows customers to cancel an order if it’s in a pending payment or failed status. Also, pending orders are canceled based on store settings. However, if you’re looking to customize these default settings, WooCommerce has got you covered. In this article, we’ll explore various case scenarios and recommend different solutions based on our experience working with several clients over the years. Hope it helps!

Completely remove order cancellation

According to the business requirements, customers should not be able to cancel their orders at any stage. However, WooCommerce provides an option for customers to cancel their orders through the “my account” section. To remove this option, we can use the woocommerce_my_account_my_orders_actions filter hook. Using this hook, we can add or remove actions for customer orders under their account. In our case, we need to remove the cancel action.

This can be achieved using the woocommerce_my_account_my_orders_actions filter

add_filter('woocommerce_my_account_my_orders_actions', 'remove_myaccount_orders_cancel_button', 10, 2);
function remove_myaccount_orders_cancel_button( $actions, $order ){
    unset($actions['cancel']);

    return $actions;
}
Code language: PHP (php)

Conditionally prevent order cancellation

The code mentioned above completely removes the cancel action. However, what if we want to remove it based on the order status? Many businesses want to allow their customers to cancel the order, but only until it’s in processing. Once it’s dispatched (custom order status), cancellation is no longer required. This can be easily achieved by accessing the order status.

We can update the code as below:

add_filter('woocommerce_my_account_my_orders_actions', 'remove_myaccount_orders_cancel_button', 10, 2);
    function remove_myaccount_orders_cancel_button( $actions, $order ){
      if ( $order->has_status( 'processing' ) ) {
         unset($actions['cancel']);
      }
      return $actions;
}
Code language: PHP (php)

Preventing cancellation from URL requests

While the above code removes the actions some geek customers may still end up doing that by directly accessing the cancel URL. For someone familiar with WooCommerce internally can craft the URL.
TODO: Add a URL that some geek can use to cancel the order

To handle this, we will need to sniff the incoming request and if it’s an order cancellation we redirect the customer to my account.

add_filter( 'parse_request', 'sniff_cancel_url');
function sniff_cancel_url() {
    global $wp;
    if (
            isset( $_GET['cancel_order'] ) &&
            isset( $_GET['order'] ) &&
            isset( $_GET['order_id'] ) &&
            ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'woocommerce-cancel_order' ) ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
        ) {
            wp_safe_redirect( 'my-account' );
            exit;
    }
}Code language: PHP (php)

Modifying default valid status for cancellation

While the above code solves the problems that’s still too much code. WordPress core philosophy is extensibility which is inherited by Woo. The same can be achieved by leveraging core filters that handle both scenarios. WooCommerce core defines a valid status for cancel action and handles the request accordingly. These default statuses can be customized as needed.

This can be accomplished with woocommerce_valid_order_statuses_for_cancel filter:

apply_filters( 'woocommerce_valid_order_statuses_for_cancel', array( 'pending', 'failed' ), $order);Code language: PHP (php)

Let’s look at code examples to achieve the above solution with less possible code.
To completely disable cancel:

add_filter( 'woocommerce_valid_order_statuses_for_cancel', 'valid_cancel_status');
function valid_cancel_status ($status, $order) {
    return [];
}
Code language: PHP (php)

We are returning an empty array to completely remove the cancel action.

To allow cancellation till it’s in processing

add_filter( 'woocommerce_valid_order_statuses_for_cancel', 'valid_cancel_status');
function valid_cancel_status ($status, $order) {
    $status[] = 'processing';
    return $status;
}
Code language: PHP (php)

We are adding a new array item ‘processing’ to default statuses.

Transform your WooCommerce store to perfectly match your business vision. We are here to help you customize and adapt it to your unique needs. Contact us today and let’s get started!