Properly applying nonce to a form using AJAX

You just need to send the nonce along with your AJAX data:

$.ajax({
    type: 'POST',
    url : profile_edit.ajaxurl,
    data: $('#profile_update').serialize() +
        '&my_nonce=" + profile_edit.nonce +
        "&action=update_profile_post', // don't forget the action name!
});

Alternatively, since you’re using jQuery’s serialize() function, you could just add the nonce directly in the form:

<?php wp_nonce_field( 'update_profile_validation', 'my_nonce' ); ?>

Then since you’re doing AJAX, you’d use check_ajax_referer() to verify the submitted nonce:

function update_profile_post() {
    check_ajax_referer( 'update_profile_validation', 'my_nonce' );
    // ... the rest of your code.
    wp_die();
}

Check the WordPress developer site here for more details.

Additionally, I’d use two functions instead of calling the same update_profile_post() from the form and the AJAX callback. Something like this would do:

function ajax_update_profile_post() {
    check_ajax_referer( 'update_profile_validation', 'my_nonce' );

    // call update_profile_post() with submitted parameters
    // or call wp_update_post() directly

    wp_die();
}
add_action( 'wp_ajax_update_profile_post', 'ajax_update_profile_post' );

function update_profile_post( $args ) {
    // call wp_update_post( $args ) here
    // or just call wp_update_post() directly in your form
}

Also, the REST API offers a more structured and predictable way to interact with your site, so you should consider using the API to handle your AJAX actions. In fact, there’s an existing endpoint for updating a post. 🙂

UPDATE

  1. If you haven’t, check out the AJAX guide on the WordPress’ plugin handbook. You’ll get more information there that I didn’t include in this answer. 🙂

  2. About that // don't forget the action name!, it just means that you need to send the action name along with the AJAX data so that WordPress knows which function should be called, which is the above ajax_update_profile_post() or the update_profile_post() as in the question. And if you didn’t send the action name, then you’d likely get the famous 400 Bad Request error with the output 0 (which is why the REST API is better since it can tell you the exact error).

    And by action name, I’m referring to the <action> part as in wp_ajax_<action>, which in the question is update_profile_post.

  3. Are we missing a wp_ajax_no_priv action?” — Yes, if you’re allowing non-authenticated users (or those who’re not logged in) to use the form.