I'm having trouble making an Expresso Store multi-step checkout process work via AJAX. I have the checkout steps working as individual pages, and have attempted to AJAXify the submission of each step via the following pattern of jQuery (replacing "form" below with the correct checkout form):

$('form').on('submit', function(e) {

    type: "POST",
    url: $(this).attr('action'),
    data: $(this).serialize(),
    success: function(data) { console.log(data); }


This AJAX query correctly submits the form variables of the checkout step, however the "data" variable returned is a JavaScript object containing all checkout variables (correctly updated).

What I want is for "data" to return the HTML of the next checkout step page, like what happens when pressing the "Next" button of the un-AJAXified form.

I think the issue is that the AJAX above doesn't tell the server it was the Next button (with name="next" attribute) pressed, and the server bases its response on which form button was pressed… but I'm how sure how I would tell the server which button was "pressed" via AJAX.

Any ideas how I can get this working?

1 Answer 1


It would be ideal if Expresso Store actually just send you a json response, but like you've mentioned, it returns the whole order object, including form errors (if any). You can see this in the module code under Store > src > Action > CheckoutAction.php

It returns this:

if ($this->ee->input->is_ajax_request()) { $this->ee->output->send_ajax_response(array_merge($cart->toTagArray(), static::$form_errors)); }

So, you will need to handle the different steps of your checkout process yourself using multiple ajax calls. What we've done before is have separate ajax templates for the steps like "checkout-step1", "checkout-step2", etc. In these templates you'll have the {exp:store:checkout} tags as per normal.

Then in your javascript files, at a minimum, you'll have an "initialize" and a "submit" function for each step. like "Checkout.initStep1", "Checkout.submitStep1", etc. You can also have an optional "update" function if you don't want the next step to load, but you're only updating something on the same step, like item quantities.

On first load you'll then "Checkout.initStep1", which simply loads in the step 1 template via ajax.

In step 1's "submit" function, on success of your ajax call you will then call the "Checkout.initStep2" function to load in your step 2 template. It can look something like this (just flesh it out a bit):

Checkout.submitStep1 = function() { $.ajax({ url : '/ajax/checkout-step2', success: function(response) { $('#checkout_form2_wrapper').html(response); fl.Checkout.initStep2(); }, error: function(xhr, status, err) { // throw error here } }); };

On your last step, after payment has been made and the order successfully processed, you can simply redirect to your success template with something like:

window.location.href = '/checkout/success/' + order_hash;

If you are using the Google Analytics enchanced ecommerce tracking, make sure to add a hidden input field named "submit" in your last step, so the Expresso Store cookie can be set, that's needed.

Hope this helps set you on the right track.

  • Thanks jpunk for your detailed response! This gives me a much better understanding of how the checkout process is working re returning JSON, and the solution you present looks great. It's a shame there isn't a way to get Store to respond with the HTML from the next template, but this certainly looks like it will work as an alternative.
    – Ross B
    Feb 11, 2015 at 17:24
  • It's a pleasure. If you want to see this implemented on a production site, you can look at the checkout process on www.flook.co.za
    – telliks
    Feb 11, 2015 at 21:07

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.