skip to Main Content

I have a form that allows the user to change their account info. I added ajax requests to save changes without page refresh. My problem is that I don’t want to submit all the fields on the form because some are disabled. So I just want to send some fields. To do this I wrote the code below which is not working, can someone help me figure out what am I wrong ?

Functions.php

// Validate - my account
add_action( 'woocommerce_save_account_details_errors', array( &$errors, &$user ), 1, 10 );
add_action( 'wp_ajax_save_account_details', 'save_account_details' );
function save_account_details( $user_id ) {
  if (trim($_POST['account_first_name']) == '') {
    $response = wc_print_notices();
  } else if ( isset( $_POST['account_first_name'] ) ) {
    $response = wc_print_notices();
  }
  echo json_encode($response);
  exit();
}

My form

<form name="Form" class="mts-edit-account" action="<?php echo admin_url('admin-ajax.php'); ?>" method="post" enctype="multipart/form-data" <?php add_action( 'woocommerce_edit_account_form_tag', 'action_woocommerce_edit_account_form_tag' );?> > 
  
  <!-- Message section -->
  <div class="msg_box"></div>

  <!-- Fist & Last Name Field -->
  <div class="row name_surname">
    <div class="form-row">
      <label class="t3" for="account_first_name">Nome *</label>
      <input type="text" placeholder="Inserisci il tuo nome" class="field-settings" name="account_first_name" id="account_first_name" value="<?php echo esc_attr( $user->first_name ); ?>" />
    </div>

    <div class="form-row">
      <label class="t3" for="account_last_name">Cognome *</label>
      <input type="text" placeholder="Inserisci il tuo cognome" class="field-settings" name="account_last_name" id="account_last_name" value="<?php echo esc_attr( $user->last_name ); ?>" />
    </div> 

    <!-- Save Settings -->
    <p style="margin-bottom: 0px!important;">
      <?php wp_nonce_field( 'save_account_details', 'save-account-details-nonce' ); ?>
      <button type="submit" class="edit-account-button" name="save_account_details" value="<?php esc_attr_e( 'Save changes', 'woocommerce' ); ?>"><?php esc_html_e( 'Salva modifiche', 'woocommerce' ); ?></button>
      <input type="hidden" name="action" value="save_account_details" />
    </p>
  </div>
</form>

Js Code
This is what I am doing to send only specific fields but it doesn’t work. When click on submit button nothing happens, there is no ajax request.

jQuery(document).ready(function($) {
    
    $('.mts-edit-account').on('submit', function(e) {
        e.preventDefault();

    // Specific form field
    var $formData = {
      name: $("#account_first_name").val(),
      lastName: $("#account_last_name").val()
    };

    //Ajax Save settings
    jQuery.ajax({
      dataType: "json",
      type: "POST",
      data: formData,
      success: function(data) {
        jQuery('.newdiv').html(data);
      }
    });

    });

});

This instead is Js code that sends all fields of the form and works correctly.

jQuery(document).ready(function($) {
    
    $('.mts-edit-account').on('submit', function(e) {
        e.preventDefault();

    //Ajax Save settings
    jQuery.ajax({
      type: "POST",
      data: jQuery(".mts-edit-account").serialize(),
      success: function(data) {
        jQuery('.newdiv').html(data);
      }
    });

    });

});

3

Answers


  1. You’re missing a lot of this here.

    1. You’re working with WordPress ajax so you need the admin-ajax.php based url that will be used in url args, which is missing.
    2. WordPress ajax needs the action key and value in form data, that is missing in your code.
    3. WordPress also required nonce, if you’re handing nonce in your code and making nonce validation, that is also missing in your code.
    4. you’ve defined dataType: 'json' which means you’re expecting json from your ajax response but in the success function, you’re trying to write json object into html div, so it’s unclear what you’re actually sending in your response. you need to work here, if you’re sending html code in response then dataType: 'html' will be used if you’re sending json then you need to change html(data) to html(JSON.stringify(data)

    So after correcting all those things your code should be like this, I have provided all the possible explanations so that you could understand what I have done and changed in the code.

    NOTE: I have not tested the code so if you see any error in console, please let me know so that I could update and fix the code

    jQuery(document).ready(function ($) {
        $(document).on('submit', '.mts-edit-account', function (e) {
            // prevent default event.
            e.preventDefault();
    
            // define form element.
            const form = $(this);
    
            // get the wordpress ajax submission url from the form action attribute.
            const ajax_url = form.attr('action');
    
            // get specific form field using form.find().
            var formData = {
                first_name: form.find('#account_first_name').val(), // get first name.
                last_name: form.find('#account_last_name').val(), // get last name.
                action: form.find('input[name=action]').val(), // get the action value from the hidden field.
                _wpnonce: form.find('input[name=save-account-details-nonce]'), // get the nonce value define by name save-account-details-nonce
    
                /**
                 * NOTE: we're passing nonce by with key name _wpnonce
                 * so in you php code when you check for nonce validation
                 * use this key name not the save-account-details-nonce
                 * while the nonce action value is still save_account_details
                 *
                 * otherwise your nonce verification will show failed because you're not using correct key.
                 */
            };
    
            $.ajax({
                type: 'POST', // Request type is post
                url: ajax_url, // set admin_url('admin-ajax.php') url here.
                data: formData, // pass the form data with first_name, last_name, action, _wpnonce
                dataType: 'json', // pass the return data type.
                success: function (res) {
                    // if we have success in response.
                    if (res.success) {
                        const success_msg = res.data.message;
                        // now display this success message in your html element.
                    } else {
                        // when we get an error response.
                        // not our ajax is not failed here but we're error in success function
                        // because we're getting a response from ajax but error is in our php code.
                        // wp_send_json_error && wp_send_json_success do this thing
                        // you'll have to read about those functions
                        const error_msg = res.data.error;
                        // Now show this error message in your html element.
                    }
                },
                error: function () {
                    // catch the error.
                    console.log('Something not working!');
                },
            });
        });
    });
    

    Coming to your PHP code for handling ajax.
    add_action( 'woocommerce_save_account_details_errors', array( &$errors, &$user ), 1, 10 );
    I am not sure what you’re added to this line, doesn’t make any sense when you have your own ajax handling function. remove this line.

    Then you can’t use wc_print_notices() you’ll have to write your own validation and error handling. In able to use wc_print_notices(), you need a deep understanding of WooCommerce.

    Also, you’re missing validation, nonce checking, sanitization, and many more things. You need to learn so much about these things. Below I have prepared the php code and tried to explain basics, but if you want to learn about those function and their usage you need to search each function on the internet or in WordPress documentation and learn about those. it’s hard to explain and teach all those functions and how they work, in detail.

    Note: You should always use a prefix for your global function names to avoid conflict and keep the function name unique. I have changed save_account_details to vh_sto_wc_custom_save_account_details to make it unique. However, your nonce action name is still save_account_details you can change it and make it unique in all the required places later

    Here is the php code for handling the ajax callback.

    /**
     * Ajax callback for saving account details.
     */
    function vh_sto_wc_custom_save_account_details() {
        // We are using try catch to handle the error and send in response.
        // when validation fails.
        try {
    
            // Check if the nonce is available in post data.
            if ( ! isset( $_POST['_wpnonce'] ){
                throw new Exception( __( 'Nonce is missing.', 'your-text-domain' ) );
            }
    
            // validate the nonce.
            if ( wp_verify_nonce( sanitize_key( $_POST['_wpnonce'] ), 'save_account_details' ) ) {
                throw new Exception( __( 'Nonce is invalid.', 'your-text-domain' ) );
            }
    
            // Check if the first name is available and not empty.
            if ( ! isset( $_POST['first_name'] ) || empty( $_POST['first_name'] ) ) {
                throw new Exception( __( 'First name should not be empty.', 'your-text-domain' ) );
            }
    
            // Check if the last name is available and not empty.
            if ( ! isset( $_POST['last_name'] ) || empty( $_POST['last_name'] ) ) {
                throw new Exception( __( 'Last name should not be empty.', 'your-text-domain' ) );
            }
    
            // Store values in array.
            $first_name = sanitize_text_field( wp_unslash( $_POST['first_name'] ) );
            $last_name  = sanitize_text_field( wp_unslash( $_POST['last_name'] ) );
    
            // Get current user id.
            $user_id = get_current_user_id();
    
            // Check if the user id is a valid id.
            if ( $user_id <= 0 ) {
                throw new Exception( __( 'You are not allowed to perform this action.', 'your-text-domain' ) );
            }
    
            // update user data.
            $user_data = wp_update_user(
                array(
                    'ID'         => $user_id,
                    'first_name' => $first_name,
                    'last_name'  => $last_name,
                )
            );
    
            // Check if there is any error on the update.
            if ( is_wp_error( $user_data ) ) {
                throw new Exception( __( 'Sorry, could not update your account details.', 'your-text-domain' ) );
            } else {
                // send success response when there is no error and the update was successful.
                wp_send_json_success( array( 'message' => __( 'Your account details has been updated.', 'your-text-domain' ) ) );
            }
        } catch ( Exception $e ) {
            // Send the error response with error message.
            // in jquery you'll access by response.data.error
            wp_send_json_error( array( 'error' => $e->getMessage() ) );
        }
    }
    add_action( 'wp_ajax_save_account_details', 'vh_sto_wc_custom_save_account_details' );
    
    Login or Signup to reply.
  2. Well, to submit some fields and not the others you simply select them and send them in the ajax body, something like this.

    let id = $("SOMETHING").val();
    let name =$("SomethingElse").val();
    ...etc
    

    and inside the ajax you do this

    ...,
    data: {
        id: id,
        name: name,
        ...etc
    },
    ...,
    
    Login or Signup to reply.
  3. You are pulling the data in your PHP function differently to what is being submitted.

    You have defined in javascript that name = account_first_name. So your php function is looking for the $POST 'account_first_name' field and you are giving it name.

    So change your ajax request to:

    jQuery(document).ready(function($) {
        
        $('.mts-edit-account').on('submit', function(e) {
            e.preventDefault();
    
        // Specific form field
        var formData = {
          account_first_name: $("#account_first_name").val(),
          account_last_name: $("#account_last_name").val()
        };
    
        //Ajax Save settings
        jQuery.ajax({
          type: "POST",
          data: formData,
          success: function(data) {
            jQuery('.newdiv').html(data);
          }
        });
    
        });
    
    });
    

    and now the PHP function is getting the correct field.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search