2
votes

I get several orders where a customer selects "Direct Bank Transfer" and then they change their mind and want to pay by Credit Card. This is quite annoying because I have to manually change the order from "On Hold" to "Pending Payment" so they can pay by card via the "order-pay" endpoint which is found in "My Account" under "Orders".

I've been using the WooCommerce change order status BACS processing to automatically change the order status from "On Hold" to "Pending Payment".

// WooCommerce Change Order Status BACS Pending

add_action( 'woocommerce_thankyou', 'bacs_order_payment_pending_order_status', 10, 1 );

function bacs_order_payment_pending_order_status( $order_id ) {
    if ( ! $order_id ) {
        return;
    }

    // Get an instance of the WC_Order object
    $order = new WC_Order( $order_id );

    if ( ( get_post_meta($order->id, '_payment_method', true) == 'bacs' ) && ('on-hold' == $order->status ) ) {
        $order->update_status('pending');
    } else {
        return;
    }
}

But since I have several user profiles (I sell B2B as well), this is not practical for my shop. I'm trying to expand this snippet to also check for the user role. I've used the following in my other snippets. Is it possible to add the below logic to the snippet above?

    $user = wp_get_current_user();
    $roles = (array) $user->roles;
    $roles_to_check = array('administrator', 'customer', 'shop_manager');
    $compare = array_diff($roles, $roles_to_check);

    if (empty($compare)){

This is my attempt.

// WooCommerce Change Order Status BACS Pending

add_action( 'woocommerce_thankyou', 'bacs_order_payment_pending_order_status', 10, 1 );

function bacs_order_payment_pending_order_status( $order_id ) {
    if ( ! $order_id ) {
        return;
    }

    // Get an instance of the WC_Order object
    $order = new WC_Order( $order_id );

    $user = wp_get_current_user();
    $roles = (array) $user->roles;
    $roles_to_check = array('administrator', 'customer', 'shop_manager');
    $compare = array_diff($roles, $roles_to_check);

    if (empty($compare)){

    if ( ( get_post_meta($order->id, '_payment_method', true) == 'bacs' ) && ('on-hold' == $order->status ) ) {
        $order->update_status('pending');
    } else {
        return;
    }
}
2
Since Woocommerce version 3.4, there is a much better dedicated hook to be use than general woocommerce_thankyou hook… Please have a look to the answer below.LoicTheAztec

2 Answers

2
votes

You can use this as follows, comment with explanation added in the code

function bacs_order_payment_pending_order_status( $order_id ) {
    // Get $order object
    $order = wc_get_order( $order_id );
    
    // Is a WC_Order
    if ( is_a( $order, 'WC_Order' ) ) {
        // Get user
        $user = $order->get_user();
        
        // Roles
        $roles = (array) $user->roles;
        
        // Roles to check
        $roles_to_check = array( 'administrator', 'customer', 'shop_manager' );
        
        // Compare
        $compare = array_diff( $roles, $roles_to_check );
        
        // Result is empty
        if ( empty ( $compare ) ) {
            if ( $order->get_payment_method() == 'bacs' && $order->has_status( 'on-hold' ) ) {
                $order->update_status( 'pending' );
            }
        }
    }
}
add_action( 'woocommerce_thankyou', 'bacs_order_payment_pending_order_status', 10, 1 );

Might Come in handy: WooCommerce: Get Order Info (total, items, etc) From $order Object

2
votes

Woocommerce version 3.4.0 has introduced a much better hook that allows to change the default status for BACS payment gateway which is set to "on-hold".

Using this hook will:

  • Lighten your code,
  • Avoid "on-hold" notification to the customer when a BACS order is placed.

Here is that code:

add_filter( 'woocommerce_bacs_process_payment_order_status','filter_process_payment_order_status_callback', 10, 2 );
function filter_process_payment_order_status_callback( $status, $order ) {
    // Here set the user roles to check
    $roles_to_check = array( 'administrator', 'customer', 'shop_manager' ); 
    
    $user = $order->get_user(); // Get the WP_User Object
        
    $compare = array_diff( $user->roles, $roles_to_check ); // compare
        
    if ( empty ( $compare ) ) {
        return 'pending';
    }
    return $status;
}

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

Since WooCommerce 5+: Allow re-sending New Order Notification in WooCommerce 5+


Enabling New Order email notification (sent to the admin) for BACS payments:

As pending Orders doesn't send email notifications, you can enable that with the following

add_action( 'woocommerce_checkout_order_processed', 'pending_new_order_notification', 20, 1 );
function pending_new_order_notification( $order_id ) {
    // Get an instance of the WC_Order object
    $order = wc_get_order( $order_id );

    // Only for "pending" order status and BACS payments
    if( $order->has_status( 'pending' ) && $order->get_payment_method() === 'bacs' ) 
    {
        // Send "New Email" notification (to admin)
        WC()->mailer()->get_emails()['WC_Email_New_Order']->trigger( $order_id );
    }
}

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

Related: Send an Email notification to the admin for pending order status in WooCommerce


Useful: How to get WooCommerce order details

Related: Change default WooCommerce order status to processing for cheque and bacs payments

Freshly updated answer thread: WooCommerce change order status BACS processing