Categories
Developer Resources

How The Checkout Block Processes An Order

Have you ever wondered, what happens after a user hits the “Place Order” button in the Checkout Block? In this post, we will go through a step by step deep-dive on the inner workings of the Checkout Block order flow.

Structure

First, let’s take a look at the main areas associated with processing the checkout for a user

The Payment Registry github

We have a payment registry that stores all the configuration information for each payment method. We can register a new payment method here with the registerPaymentMethod and registerExpressPaymentMethod functions, also available to third parties.

Data Stores

We use data stores to keep track of data that is likely to change during a user’s session, such as the active payment method, whether the checkout has an error, etc. We split these data stores by areas of concern, so we have 2 data stores related to the checkout: wc/store/checkout github and wc/store/payment github . Data stores live in the assets/js/data folder.

Contexts

We use several contexts that make data available to the Checkout block. Each of these provide data and functions related to a specific area of concern, via the use of a hook. For example, if we wanted to the onPaymentProcessing handler from the PaymentEventsContext context, we can do it like this:

const { onPaymentProcessing } = usePaymentEventsContext();

The other job of contexts is to run side effects for our Checkout block. What typically happens is that the CheckoutEvents and PaymentEvents will listen for changes in the checkout and payment data stores, and dispatch actions on those stores based on some logic.

For example, in the CheckoutEvents context, we dispatch the emitValidateEvent action when the checkout status is before_processing. There is a lot of similar logic that reacts to changes in status and other state data from these two stores.

The Checkout contexts are:

  • CheckoutEvents github– provides some checkout related event handlers
  • PaymentEvents github– provides event handlers related to payments
  • CustomerData github– provides data related to the current customer
  • ShippingData github– provides data and actions related to shipping errors

The Checkout Processor (checkout-processor.js)

This is a component that, much like some of the contexts, subscribes to changes in the checkout or payment data stores, packages up some of this data and calls the StoreApi /checkout endpoint when the conditions are right.

The Checkout Provider

This lives here, and wraps all the contexts mentioned above around the CheckoutProcessor component.


Checkout User Flow

Now that we have a better understanding of the structure, let’s look at what happens when a user places an order:

1. Click the “Place Order” button

The checkout process starts when a user clicks the button

2. Checkout status is set to before_processing github

As soon as the user clicks the “Place Order” button, we change the checkout status to “before_processing”. This is where we handle the validation of the checkout information.

3. Emit the checkout_validation_before_processing event github

This is where our own app, as well as third party plugins can register event listeners for dealing with validation. The event listeners for this event will run and if there are errors, we set checkout status to idle and display the errors to the user.

If there are no errors, we move to (4) below.

4. Checkout status is set to processing github

This is purely so that we know we are processing the checkout. It’s used by step (5) below to change the payment status

5. Payment status is set to processing github

Once all the checkout processing is done and if there are no errors, the payment processing begins

6. Emit the payment_processing event github

We send out the payment_processing event. Third party plugins can register event listeners for this event and run their own code.

For example, the Stripe plugin checks the address and payment details here, and uses the stripe APIs to create a customer and payment reference within Stripe.

Important to note the actual payment is not taken here. It’s more of a pre-payment hook to run any third party code before the actual payment is attempted.

7. Process the payment_processing event listeners and set the payment and checkout states accordingly github

If the registered event listeners return errors, we will display this to the user

If the event listeners are considered successful, we sync up the address of the checkout with the payment address, store the paymentResult in the payment store, and set the payment status property { isProcessing: true }

8. POST to /wc/store/v1/checkout (assuming no errors present) github

If everything is looking good, there are no payment errors, we call the /checkout StoreApi endpoint. This will take the final customer addresses and chosen payment method, and any additional payment data, then attempts payment and returns the result.

Important: payment is attempted through the StoreApi, NOT through the payment_processing event that is sent from the client

9. The processCheckoutResponse action is triggered on the checkout store github

Once the fetch to the StoreApi /checkout endpoint returns a response, we pass this to the processCheckoutResponse action on the checkout data store.

This does 3 things:

  • sets the redirect URL to redirect to once the order is complete
  • stores the payment result in the checkout data store.
  • Change the checkout status to after_processing (step 10)

10. Checkout status is set to after_processing github

This indicates that we’ve finished the main checkout processing step. We run cleanup actions and display any errors that have been triggered during the last step here.

11. The checkout_after_processing_with_success event is emitted github

If there are no errors, the checkout_after_processing_with_success event is triggered. This is where third party plugins can run some code after the checkout process has been successful.

Any event listeners are run here. If there are no errors from the event listeners, we call the setComplete action on the checkout data store to set the status to complete (step 13). An event listener can return an error here for whatever reason, which will be displayed to the user.

12. The checkout_after_processing_with_error event is emitted github

If there has been an error from step 5, the checkout_after_processing_with_error event will be emitted. Again, third party plugins can register event listeners to run here to display an error to the user. We process the event listeners and display any errors to the user.

13. Set checkout status to complete github

If there are no errors, we change the status property in the checkout data store to complete.

14. Redirect github

Once the checkout status is set to complete and if there is a redirectUrl in the checkout data store, then we redirect the user to the URL.

Other notable things

Checking a payment method can pay

A payment method is registered with a configuration object, which looks like this. It must include a function named canMakePayment. This function should return true if the payment method can be used to pay for the current cart. The current cart (items, addresses, shipping methods etc.) is passed to this function, and each payment method is responsible for reporting whether it can be used.

There is a helper function checkPaymentMethodsCanPay() github that goes through all the registered payment methods, checks if they can pay, and if so, adds them to the availablePaymentMethods property on the payment data store.

This must be called in a few places in order to validate the payment methods before they can be displayed to the user as viable options.

  • Here, once the cart loads, we want to be able to display express payment methods, so we need to validate them first.
  • Here, once the cart changes, we may want to enable/disable certain payment methods
  • Here, once the checkout loads, we want to verify all registered payment methods

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.