Search code examples
javascriptphpajaxwoocommerceorders

Validating current user in custom Ajax form updating Woocommerce order


I'm currently working on a form that allows users to update specific order details, including expense and the reason for the expense. The form displays a JavaScript alert upon successful update of the order, and the updated data is reflected in the order's metadata. However, I'm encountering an issue with user ownership validation.

Here's the problem I'm facing:

Ownership Validation: I want to ensure that users can only update orders associated with their user ID and not those belonging to others. Currently, when a user enters an order ID that isn't associated with their account the order metadata doesn't get updated but JavaScript alert for a successful update is still triggered.

I've included my code below for reference:


<form id="expense_form" class="expense_form" action="" method="post">
    <label for="order-id">Order ID:</label>
    <input class="exp_order_no" id="exp_order_no" type="text" pattern="[0-9]*" placeholder="Enter the Order Number" required>
    
    <label for="expense">Expense:</label>
    <input class="expense_amt" id="expense_amt" type="text"  pattern="[0-9]*" placeholder="Enter the expense amount" required>
    
    <label for="reason">Reason for Expense:</label>
    <textarea class="expense_reason" id="expense_reason" id="reason" name="reason" rows="4" placeholder="Enter Message" required></textarea>

    <input type="submit" class="exp_but" id="exp_but" value="Submit">
</form> 
<script>
    jQuery(document).ready(function($) {
            $('#expense_form').on('submit', function(e) {
                e.preventDefault();
                var orderid  = $('#exp_order_no').val();
                var expense  = $('#expense_amt').val();
                var expense_reason  = $('#expense_reason').val();
                    //  console.log (orderid);
                    //  console.log (expense);
                    //  console.log (expense_reason);
             $.ajax({
                    url: '<?php echo admin_url('admin-ajax.php'); ?>',
                    type: 'POST',
                    data: {
                        action:'update_custom_field_order_expense_php',
                        orderid: orderid,
                        expense: expense,
                        expense_reason:expense_reason
                    },
                    success: function( response ) {
                        console.log( 'Custom field updated successfully.' );
                        alert('Expense Submitted Successfully !!');
                        location.reload();
                    },
                    error: function( response ) {
                        console.log( 'Failed to Submit Expense.' );
                        alert('Expense Not Submitted !! Please enter correct order id.');
                        location.reload();
                    }
                });
             });
        });         
</script>

<?php

add_action( 'wp_ajax_update_custom_field_order_expense_php', 'update_custom_field_order_expense_php' );
add_action('wp_ajax_nopriv_update_custom_field_order_expense_php', 'update_custom_field_order_expense_php');

function update_custom_field_order_expense_php() {
    $order_id = $_POST['orderid'];
    $order_expense = $_POST['expense'];
    $order_expense_reason = $_POST['expense_reason'];
    $order = wc_get_order( $order_id );
    if ( is_user_logged_in()) {
        $current_user = wp_get_current_user();
        $current_user_id = $current_user->ID;
    
        $driver_id = get_post_meta($order_id, 'lddfw_driverid', true);
        //$current_date = date_i18n( 'j F, Y', strtotime( $current_date_time ) );
        if($current_user_id == $driver_id  ){
            $order->update_meta_data( 'Driver Expense', $order_expense );
            $order->update_meta_data( 'Driver Expense Reason',$order_expense_reason);
            $order->save();
            wp_send_json_success();
            exit;
        }else{
            wp_send_json_error();
            exit;
        }
    }
}

?>


Solution

  • Try the following revisited and enhanced code version, checking that the current user ID matches with registered Driver ID order metadata for the requested Order ID.

    I have added a hidden input field for the user ID and a hidden message box where processing messages are displayed.

    The form:

    <?php if ( is_user_logged_in()) : ?>
    <form id="expense_form" class="expense_form" action="" method="post">
        <label for="order-id"><?php _e('Order ID'); ?>:</label>
        <input class="exp_order_no" id="exp_order_no" type="text" pattern="[0-9]*" placeholder="Enter the Order Number" required>
        
        <label for="expense"><?php _e('Expense'); ?>:</label>
        <input class="expense_amt" id="expense_amt" type="text"  pattern="[0-9]*" placeholder="Enter the expense amount" required>
        
        <label for="reason"><?php _e('Reason for Expense'); ?>:</label>
        <textarea class="expense_reason" id="expense_reason" id="reason" name="reason" rows="4" placeholder="<?php _e('Enter Message'); ?>" required></textarea>
    
        <p id="message-response" style="display:none;"></p>
        <input type="submit" class="exp_but" id="exp_but" value="<?php _e('Submit'); ?>">
        <input type="hidden" id="user_id" name="user_id" value="<?php echo get_current_user_id(); ?>">
    </form>
    <?php endif; ?>
    

    The jQuery code

    jQuery(function($) {
        $('#expense_form').on('submit', function(e) {
            e.preventDefault();
            $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                type: 'POST',
                data: {
                    action:   'add_order_expense_cf',
                    order_id: $('#exp_order_no').val(),
                    user_id:  $('#user_id').val(),
                    expense:  $('#expense_amt').val(),
                    reason:   $('#expense_reason').val()
                },
                success: function( response ) {
                    const color   = response.success ? 'green' : 'red',
                          message = response.data;
                    $('#message-response').html(response.data).css('color',color).fadeIn().delay(2000).fadeOut();
                    console.log(response);
                },
                error: function( error ) {
                    $('#message-response').html('Something went wrong, try later please.').css('color','red').fadeIn().delay(2000).fadeOut();
                    console.log(error);
                }
            });
        });
    }); 
    

    The PHP:

    add_action( 'wp_ajax_add_order_expense_cf', 'add_order_expense_custom_fields' );
    add_action('wp_ajax_nopriv_add_order_expense_cf', 'add_order_expense_custom_fields');
    
    function add_order_expense_custom_fields() {
        if( isset($_POST['order_id']) && isset($_POST['user_id']) ) {
            $order = wc_get_order( intval($_POST['order_id']) );
    
            if( ! is_a($order, 'WC_Order') ) {
                wp_send_json_error( __('Wrong order number, please retry.') );
            }
            $driver_id = (int) $order->get_meta('lddfw_driverid');
    
            if( $driver_id === 0 || intval($_POST['user_id']) !== $driver_id ) {
                wp_send_json_error( __('Sorry you are not allowed to request expenses on that order number.') );
            }
            
            $order->update_meta_data( 'Driver Expense', floatval($_POST['expense']) );
            $order->update_meta_data( 'Driver Expense Reason', sanitize_textarea_field($_POST['reason']) );
            $order->save();
            wp_send_json_success( __('Data has been successfully sent and saved.') );
        }
        wp_send_json_error( __('Something went wrong, please try later.') );
    }
    

    Tested and works.