Confused on AJAX submit form through page template

I think I’ve been looking at too much code and have confused myself while trying to get a better understanding of forms in WordPress with AJAX. I set out this week to learn how to create a form for a page and submit it through AJAX.

The page is a template and the action I’ve looked into two solutions of the handling. One through a redirect to a PHP, such as:

<form action="<?php echo get_template_directory_uri() . "/validation.php"; ?>" id="contactForm">
</form>

after reading several posts on the topic that a separate validation of the form should be made. Is this correct and why? Then the other issue is if I do want to process the form on the template-page the form action should look like:

<form action="#" id="contactForm">
</form>

but outside of WordPress I’ve seen:

<form action="" id="contactForm">
</form>

why is this? On the AJAX portion I’ve seen a difference of:

jQuery.ajax({
    type :"post",
    url: ajaxurl,
    }
});

then a different URL of:

jQuery.ajax({
    type :"post",
    dataType:"json",
    url: MBAjax.admin_url,
    }
});

and lastly:

jQuery.ajax({
    type :"post",
    dataType:"json",
    url: /wp-admin/admin-ajax.php?action=contactForm",
    }
});

So what is the proper way to write the action in WordPress if:

  • If the form is processed on the same page?
  • If a separate PHP file validates the form?

Then what is the proper AJAX call in WordPress?

Reference points:

  • Form submission using AJAX and handling response in WordPress Website
  • Submitting HTML form using Jquery AJAX
  • Handling an Ajax form submit
  • Custom Form with Ajax
  • Submitting a form with ajax in WordPress
  • submitting a form in wordpress using ajax
  • Ajax Form Post Submission Using WordPress
  • How To Build Your Own WordPress Contact Form and Why

Edit:

After further reading decided to step into RESTful submissions. I referenced “REST APIs for Absolute Beginners” but I’m not getting the return I’m hoping for:

HTML:

<form id="contactForm" action="" method="POST">
    <div class="form-group">
        <label for="form_email"><span class="asterisk">*</span>Email address:</label>
        <input type="email" class="form-control" id="form_email">
    </div>
    <div class="form-group">
        <button id="form_submit" class="supportbutton" type="submit">Submit</button>
    </div>
</form>
<div id="testForm"></div>

jQuery:

$(document).ready(function() {
    $('#contactForm').submit(function(e) {
        e.preventDefault(); 
        jQuery.ajax({
            url: '<?php echo home_url(); ?>/wp-json/darthvader/v1/contact',
            type: 'post',
            dataType: 'json',
            data: $('#contactForm').serialize(),
            success: function(data) {
                $("#testForm").html(data);
            },
             error: function() {
                alert("There was an issue");
             },
        });
    });
});

functions.php:

add_action('rest_api_init', function() {
    register_rest_route('darthvader/v1', '/contact/', array(
        'methods'   => 'POST',
        'callback'  => 'darth_contact_form'
    ));
});
function darth_contact_form(\WP_REST_Request $request) {
    $email = $request['form_email'];
    return "Your contact request had the title " . $email;
}

Why do I only get Your contact request had the title on the return and not the email too?

2 Answers
2

<form action="<?php echo get_template_directory_uri() . "/validation.php"; ?>" id="contactForm">

😱

So I’ll outline the basic fundamentals, so you have a framework to move forwards with

Fixing Admin AJAX

So I’ll cover this very briefly as it’s not the crux of my answer, but would be useful:

  • Add a hidden input field named action rather than adding it to the URL
  • validation.php and any other standalone files should burn with the fire of a thousand suns, do this validation in JS, and again in the form handler. Handling the form and validating it are the same step, else someone could skip validation and go straight to handling

Finally, use a standard form handler for when JS isn’t used/possible, check for the existence of something in the form that would only happen if it’s been submitted, and submit the form to the same page, by having an empty action attribute e.g.:

if ( !empty( $_POST['form_page'] ) ) {
    $valid = false;

    // do validation
    // 
    if ( true === $valid ) {
        // yay do whatever submitting the form is meant to do
        // if it's a multipage form, handle that here
    } else {
        get_template_part( 'form' ); // show the form again, but with warnings for validation
    }
} else {
    get_template_part( 'form' );
}

RESTful Form Submissions

Change your form submission jQuery to use a REST endpoint, lets call this darthvader/v1/contact, I used some code from a stackoverflow answer here:

jQuery('input#submitButton').click( function() {
    jQuery.ajax({
        url: '/wp-json/darthvader/v1/contact',
        type: 'post',
        dataType: 'json',
        data: jQuery('form#contactForm').serialize(),
        success: function(data) {
            //... do something with the data...
        }
    });
});

That’s pretty much every form submission via REST API you’ll ever need, but you still need that endpoint to exist, ‘/wp-json/darthvader/v1/form’ needs creating, so lets tell WP we want an endpoint, that accepts POST’s:

add_action( 'rest_api_init', function () {
        register_rest_route( 'darthvader/v1', '/contact/', array(
                'methods' => 'POST',
                'callback' => 'darth_contact_form'
        ) );
} );

Then define what will happen when it’s called:

function darth_contact_form( \WP_REST_Request $request ) {
    //
}

That’s where we’ll handle our form, e.g.:

function darth_contact_form( \WP_REST_Request $request ) {
    $title = $request['title'];
    $message = $request['message'];
    // send an email or create a post, or whatever
    // the contact form does when its submitted
    return "Your contact request had the title ".$title;
}

The return value gets turned into JSON and sent back to the browser, so that you can handle it in the success function in javascript that you saw earlier in this answer. You can also return other responses, e.g.:

return \WP_REST_Response( "Bad request, X Y and Z are empty", 400);

and you can return a WP_Error object to indicate something going wrong or incorrect:

return new WP_Error( 'awesome_no_author', 'Invalid author', array( 'status' => 404 ) );

You can do your validation inside the endpoint, but you can also make the endpoint do the validation for you by specifying what fields to expect, and a function to validate them, but I leave that as an exercise ( or new question ) for you

Leave a Comment