4

So I'm still learning around WordPress and can't seem to figure out how to properly hook a nonce into a AJAX Form that I have created.

Here I am hooking and localizing the js file and defining a update_profile_validation nonce [WORKS]:

function enqueue_scripts()
{
    if (!is_admin()) {
        wp_register_script('profile_edit_submit', content_url() . '/mu-plugins/fleishmanhillard/scripts/frontend-profile-edit.js', ['jquery'], '', true);
        wp_localize_script( 'profile_edit_submit', 'profile_edit', [
            // This will generate the admin URL that we can use on the front-end of our website
            'ajax_url' => admin_url('admin-ajax.php'),
            // Pass in a custom nonce name for JS
            'nonce' => wp_create_nonce('update_profile_validation'),
        ]);
        wp_enqueue_script('profile_edit_submit');
    }
}
add_action('wp_enqueue_scripts', 'enqueue_scripts');

This method is used to update the user content [WORKS]:

function ajax_update_profile_post($args)
{
    check_ajax_referer('update_profile_validation', 'my_nonce');
    update_profile_post($args);
    wp_die();
}
add_action( 'wp_ajax_update_profile_post', 'ajax_update_profile_post' );

function update_profile_post($args  = [])
{
    if (!$args) {
        return;
    }

    // If the server request is POST, proceed to update post
    if (strtolower($_SERVER['REQUEST_METHOD']) === "post") {
        wp_update_post($args);
    }
}

Here is my AJAX form submission [WORKS]:

(function ($) {
    $(function($) {
        $('#profile_update').on('submit', function(e) {
            $.ajax({
                type: 'POST',
                url : profile_edit.ajaxurl,
                data: $('#profile_update').serialize() +
                    '&my_nonce=' + profile_edit.nonce +
                    '&action=update_profile_post'
            });
            return false;
        });
    });
})(jQuery);

Here is the final part of my form:

<?php if ($profile->get_edit_post_link()):

    // Set the post field content field
    $post_content = $_POST['content'];

    ajax_update_profile_post([
        'ID' => $profile->get_id(),
        'post_content' => $post_content,
    ]);

    ?>
    <form action="" id="profile_update" method="POST">
        <input type="text" name="content" id="post_content">
        <button type="submit"><?= 'Update Post' ?></button>
        <?php wp_nonce_field('update_profile_validation', 'my_nonce'); ?>
    </form>
<?php endif;

So the form works and the field submits and all, but I'm having a difficult time understanding how to apply a proper nonce to the form.. All assistance would be appreciated!

1 Answer 1

3

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.

7
  • Wow, @Sally CJ thanks so much! I'm running into a small issue, looks like the check_ajax_referer( 'update_profile_validation', 'my_nonce'); is throwing a -1 output and hiding the form.
    – DevSem
    Mar 31, 2020 at 11:41
  • 1
    Oops, sorry! I meant profile_edit.nonce and not profile_edit.update_profile_validation. I'll correct it in the answer, in 10 mins or so.
    – Sally CJ
    Mar 31, 2020 at 11:55
  • thanks so much! On this part don't forget the action name! am I missing anything or is the action name already included? Do I have to call a action: "lorem ipsum" inside the ajax request?
    – DevSem
    Mar 31, 2020 at 11:57
  • I've updated the whole code with your answer above but for some odd reason all that I'm seeing is a -1 instead of a input box and submit button.
    – DevSem
    Mar 31, 2020 at 12:15
  • I'm editing the answer, but from what I could tell, you changed the nonce action from update_profile_validation to update_profile_post - wp_create_nonce( 'update_profile_post' ). So could you please roll back the edit because that would invalidate my answer. Or (later) append your updates at the bottom, not changing the original texts.
    – Sally CJ
    Mar 31, 2020 at 12:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.