Search code examples
javascriptphpwordpresswoocommerceorders

Capture payment method change when an order is updated via WooCommerce admin


I'm currently working on a WooCommerce project, and I'm trying to implement a feature where an order note is added when a user changes the payment method during the order editing process in the WooCommerce admin panel. However, I'm facing an issue in capturing the new payment method.

Here's an example:

Order notes

Here's the code I'm using:

add_action('woocommerce_admin_order_data_after_billing_address', 'order_update_note');
function order_update_note()
{
    global $post;
    $order_id = get_the_ID();
    $order = wc_get_order($order_id);
    $current_user = wp_get_current_user();
    $user_now = $current_user->display_name;
    $current_payment_method = $order->get_payment_method();
    ?>

    <script>
    jQuery(document).ready(function($) {
        $('.save_order').on('click', function() {
            var orderid = <?php echo $order_id; ?>;
            var user_now = '<?php echo $user_now; ?>';
            var payment_method = $('#order_data .wc-order-data-row .order_data_column .order_data_column-inner select[name="_payment_method"]').val();

            console.log(orderid);
            console.log(user_now);
            console.log(payment_method);

            $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                type: 'POST',
                data: {
                    action: 'update_order_add_note',
                    orderid: orderid,
                    user_now: user_now,
                    payment_method: payment_method
                },
                success: function( response ) {
                    console.log( 'Custom field updated successfully.' );
                },
                error: function( response ) {
                    console.log( 'Failed to Submit Expense.' );
                }
            });
        });
    });
    </script>
    <?php
}

add_action('wp_ajax_update_order_add_note', 'update_order_add_note');
add_action('wp_ajax_nopriv_update_order_add_note', 'update_order_add_note');

function update_order_add_note()
{
    $orderid = $_POST['orderid'];
    $user_now = $_POST['user_now'];

    $order = wc_get_order($orderid);
    $payment_method = $_POST['payment_method'];
    $current_payment_method = $order->get_payment_method();

    if ($payment_method !== $current_payment_method) {
        $note = "Order details updated by ".$user_now . " Payment method changed from ".$current_payment_method." to ".$payment_method."\n";
        $order->add_order_note($note);
        $order->save();
        wp_send_json_success();
    } else {
        wp_send_json_error();
    }
}


Here's a breakdown of my code:

I have added a custom JavaScript function that runs when the "Save Order" button is clicked in the WooCommerce order edit screen. This function captures the order ID, the user making the change, and the payment method selected by the user.

On the PHP side, I have set up an AJAX callback function that receives the data sent by the JavaScript function. In this callback function, I attempt to capture the new payment method and compare it with the existing payment method for the order.

The issue is that I'm not successfully fetching the new payment method. The variable $payment_method

I would greatly appreciate any insights or suggestions on how to correctly capture the new payment method when it's changed by the user during the order editing process


Solution

  • updated

    You can use the following different and most effective way:

    • When an order is submitted via checkout (or created manually in admin), a custom field with the current payment method is added.
    • If someone edit the order changing the payment method, an order note is added with this change (and the user who did the change).
    
    // When order is created after checkout, add a custom field
    add_action( 'woocommerce_checkout_order_created', 'save_payment_method_origin', 20 );
    function save_payment_method_origin( $order) {
        if( $payment_method = $order->get_payment_method() ) {
            $order->add_meta_data('_payment_origin', $payment_method );
            $order->save();
        }
    }
    
    // Add 2 hidden fields on admin single order
    add_action( 'woocommerce_admin_order_data_after_shipping_address', 'admin_order_custom_hidden_input_fields' );
    function admin_order_custom_hidden_input_fields( $order ) {
        global $current_user;
        echo '<input type="hidden" name="user_name" value="'.$current_user->display_name.'" />
        <input type="hidden" name="user_id" value="'.$current_user->ID.'" />';
    }
    
    // Adding an order note when payment method is changed
    add_action( 'woocommerce_process_shop_order_meta', 'admin_order_payment_method_change' );
    function admin_order_payment_method_change( $order_id ) {
        $order = wc_get_order( $order_id );
        $payment_method = $order->get_payment_method();
        $payment_origin = $order->get_meta('_payment_origin');
    
        if ( ! empty($payment_origin) && $payment_method != $payment_origin
        && isset($_POST['user_name']) && isset($_POST['user_id']) ) {
            $order->update_meta_data('_payment_origin', $payment_method);
            $order->add_order_note( sprintf( __('Payment method changed from %s to %s by %s (Id %d)'), 
                $payment_origin, $payment_method, esc_attr($_POST['user_name']), intval($_POST['user_id']) ) . "\n" );
            $order->save();
        } elseif ( empty($payment_origin) && ! empty($payment_method) ) {
            $order->update_meta_data('_payment_origin', $payment_method);
            $order->save();
        }
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and works.