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" 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 ></div>
<!-- Fist & Last Name Field -->
<div >
<div >
<label for="account_first_name">Nome *</label>
<input type="text" placeholder="Inserisci il tuo nome" name="account_first_name" id="account_first_name" value="<?php echo esc_attr( $user->first_name ); ?>" />
</div>
<div >
<label for="account_last_name">Cognome *</label>
<input type="text" placeholder="Inserisci il tuo cognome" 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" 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);
}
});
});
});
CodePudding user response:
You're missing a lot of this here.
- You're working with WordPress ajax so you need the
admin-ajax.php
based url that will be used inurl
args, which is missing. - WordPress ajax needs the
action
key and value in form data, that is missing in your code. - WordPress also required nonce, if you're handing nonce in your code and making nonce validation, that is also missing in your code.
- 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 thendataType: 'html'
will be used if you're sending json then you need to changehtml(data)
tohtml(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' );
CodePudding user response:
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
},
...,