3

I want to validate user entries on a WordPress post upon hitting the submit button, display an error message is there are problems, and submit the form if everything is OK. I have a PHP function that does the checking, returning true if data in form_data is OK, some error code otherwise. The following JavaScript issues the AJAX request, and was supposed to continue submitting the form upon successful checking, but it doesn't:

        jQuery(document).ready(function() {
            jQuery('#post').submit(function() {

                var form_data = jQuery('#post').serializeArray();
                var data = {
                    action: 'ep_pre_submit_validation',
                    security: '<?php echo wp_create_nonce( 'pre_publish_validation' ); ?>',
                    form_data: jQuery.param(form_data),
                };
                var proceed = false;
                jQuery.post(ajaxurl, data, function(response) {
                    if (response.indexOf('true') > -1 || response == true) {
                        proceed = true;
                    } else {
                        alert("Error: " + response);
                        proceed = false;
                    }
                });
                jQuery('#ajax-loading').hide();
                jQuery('#publish').removeClass('button-primary-disabled');
                return proceed; //breakpoint here makes the code run
            });
        });

The code is adapted from a WPSE question, which originally didn't work for me as the form didn't get submitted. I found out that if the jQuery function bound to .submit() returns true, the form should be submitted, so that's what I tried to implement. With the code above, it doesn't seem to work at first (form doesn't get submitted when there are no errors), but upon close inspection with Firebug proceed seems to get the right result if a breakpoint is inserted at the return proceed line. It works as intended with valid data only if I wait it out a bit upon hitting the breakpoint, and then continue execution. If there are errors, the alert is issued without a problem.

What is the best way to handle this?

EDIT

Based on @Linus answer below, the following code works with both valid and invalid data:

        jQuery(document).ready(function() {
            jQuery('#post').submit(function() {
                if(jQuery(this).data("valid")) {
                    return true;
                }

                var form_data = jQuery('#post').serializeArray();
                var data = {
                    action: 'ep_pre_submit_validation',
                    security: '<?php echo wp_create_nonce( 'pre_publish_validation' ); ?>',
                    form_data: jQuery.param(form_data),
                };
                jQuery.post(ajaxurl, data, function(response) {
                    if (response.indexOf('true') > -1 || response == true) {
                        jQuery("#post").data("valid", true).submit();
                    } else {
                        alert("Error: " + response);
                        jQuery("#post").data("valid", false);

                    }
                    //hide loading icon, return Publish button to normal
                    jQuery('#ajax-loading').hide();
                    jQuery('#publish').removeClass('button-primary-disabled');
                });
                return false;
            });
        });
Community
  • 1
  • 1
englebip
  • 955
  • 1
  • 11
  • 17

4 Answers4

6

Bind your button to a validation function instead of submit. If it passes validation, call submit().

Diodeus - James MacFarlane
  • 112,730
  • 33
  • 157
  • 176
  • You mean to do the validation with JQuery Validate or something like that? Can I do an Ajax call with it? – englebip Feb 17 '12 at 15:40
  • Instead of a submit button, use a regular button to make your AJAX call. Submit the form in-code when you want to submit it. – Diodeus - James MacFarlane Feb 17 '12 at 15:46
  • Gotcha. I ended up doing that as well, and it actually solved the handling of saving drafts but not publishing posts as well. Thanks! – englebip Feb 17 '12 at 17:39
  • I think this is the easiest and best way after trying for 3 days, change your submit button to normal "a href" button and control your form with $(document).ajaxComplete(function() { //to do }); call $(#your-form-id).submit(); to submit – Eddy Goh Oct 12 '16 at 10:47
6

Short answer: You can't - not in this manner.

Some background: The callbacks you supply as arguments to functions such as $.post are executed asynchronously. This means that you will return proceed before your success callback has been executed, and proceed will always be false. With your breakpoint, if you wait until the success callback has executed, proceed will be true and all will be well.

So, if you want to submit the form after your ajax request has finished, you must submit it using javascript. This is pretty easy with jQuery, just do a jQuery $.post with data: $("yourForm").serialize() and url: yourForm.action.

This is basically what you already are doing, you just have to repeat that call to the URL to which you actually want to post the data.

EDIT:

Another way would be to set an attribute on your form, say valid, and in your submit handler check that:

jQuery("#post").submit(function() {
    if($(this).data("valid")) {
        return true;
    }
    // Rest of your code
});

And in the success callback for your validation ajax request you would set/clear that attribute, and then submit:

$("#post").data("valid", true).submit();

EDIT:

You also want to do your "ajax-loading"/button enabling inside the callback for $.post for the same reasons stated above - as it is, they will happen immediately, before your ajax call returns.

Linus Thiel
  • 38,647
  • 9
  • 109
  • 104
  • Brilliant solution! I struggled a bit at first, but I realized afterwards that it wasn't working because within WordPress jQuery has to be called as `jQuery` and not `$`... – englebip Feb 17 '12 at 16:29
  • 1
    Wow, you just saved my living room window, my computer and my last shred of patience. I couldn't understand (and still don't) why an ajax event can't block and then signal completion and allow regular form processing to occur. This worked, but I can't fathom why this scenario didn't crop up when the powers that be tested this. – eggmatters Feb 02 '13 at 08:36
2

Wordpress has its own mechanism to process Ajax requests, using wp-admin/wp-ajax.php. This allows you to run arbitrary code on either side of the Ajax boundary without having to write the back and forth status-checking code and all that. Set up your callbacks and go....

1

The real question is - why are you doing validation server-side? Why can't you load in the validation criteria before - as the post is being written? Then your validation can happen real-time and not on-submit.

jquery.post is performed asynchronously, which means the JS will continue before it gets the reply. You're stuck with Diodeus's answer - bind the button to validtion which then submits the form (which makes it not degrade well), or change your $.post to ajax and turn off async, which will force it to wait for response before proceeding...possibly locking up JS on your page until it times out.

$.ajax({
    type: 'POST',
    url: ajaxurl,
    async:false,
    data: data,
    timeout:3000,
    success: function(){

    }
});
Will Stern
  • 17,181
  • 5
  • 36
  • 22
  • Good point about the server-side validation; I was just thinking about this now. I needed to make sure that a post with invalid/incomplete data does not get published, that's why I thought server-side was the way to go. Perhaps disable the submit (Publish) button while there are unmet requirements? What about if JavaScript is disabled by the user? Would this add a lot of overhead? – englebip Feb 17 '12 at 16:01
  • Front-side validation is very light on overhead. if ($('your field').val().length < xxx){ $('#error').html('too short');return false;} Since a VERY low percentage of users have js disabled anymore, the good practice is to do all validation front-side, then, run back-end checks on the page that processes the post as a fallback. If it gets past front end, you can still bounce them back to the page with an error message. – Will Stern Feb 17 '12 at 16:40