The Lockdown Coder: Headless WordPress, WooCommerce and Stripe

Photo by Richard Pennystan on Unsplash

My projects had moved on from the UI challenges I had set myself—they were excellent for practising HTML and CSS — but I became more interested in apps that could have a real-world impact. By now, some friends of mine were showing a keen interest in what I was doing and I had shifted my focus to creating websites that they could use. I previously mentioned creating a website for a medical consultancy (essentially an SPA with a back-end to send emails for a contact form) and there was a project for another friend with a professional services business that had a blog.

It was the first time I had encountered implementing a blog into an app and I immediately think of WordPress when I think of blogs. Indeed, my friend’s co-worker, who manages the blog, said they would prefer to use WordPress compared to their existing setup and so the decision was made.

Locally developing a headless WordPress site

WordPress has its own REST API and a set of URL endpoints that you can use to fetch data into your app. For example, if you go to a WordPress site and append /wp/v2/posts to the base URL (e.g. ) then you should have access to all blog posts in JSON format if no authentication is needed. Using this end point and others I was able to access blog data I needed to show in my app whilst my friend could use the familiar WordPress back-end to write new blogs.

It is this separation between the front-end (my React app) and the back-end (WordPress) that defines a headless CMS setup. Now we can use WordPress as a Content Management System but instead of relying on WordPress templates to generate the website we take full control of the front-end through our React app.

This method has many advantages and the two that appeal most to me are:

  1. You can separate the back-end and front-end cleanly and provide users a familiar CMS platform with which to make changes
  2. You can use the WordPress back-end with any front-end solution so this means I could just as easily create a Flutter mobile app using the data from my WordPress site AND have a web app created with React using the same data

I was still in development mode and didn’t want to spend money to have a WordPress site hosted simply so I could test things. The solution to that was to create a local development site so WordPress effectively runs on your own computer. I use Windows so I went ahead and installed XAMPP with MySQL and phpMyAdmin (an article at was the one that helped me). Whilst I am still no expert on this my understanding is XAMPP allows you to run a server on your local machine and MySQL is the database it will use and phpMyAdmin allows you to manage your databases. With your local server up-and-running you can then follow the instructions to create a new folder in XAMPP’s htdocs directory (e.g. /mywordpress ) in which to install WordPress. After setting up a MySQL database for WordPress you will be able to access your new site at http://localhost/mywordpress . The API endpoints I mentioned before will be available to you with this base URL and you can get testing.

One thing I want to mention is how confused I was with and I had understood that WordPress was open source and free and so I went to as that URL seemed official and the best place to begin. You can get a free website going easily but you get charged for using plugins. I was confused because WordPress without plugins has limited use and it was supposed to be free! It turns out that is the commercial arm of WordPress and they exist to make a profit. is where you can find the install files to create your own local development site and install plugins. The alternative to a local development site is to look at paid-for web hosting solutions and get your own live WordPress site.

Web hosts like, and offer fairly competitive prices. I have used before and thought their customer service was excellent and they were quick to respond either by phone or webchat. I currently use and they are good but their customer service, whilst adequate, is not as good as When you purchase a plan from these web hosts they generally make it pretty easy to get WordPress set up with one-click installs which they can guide you through.

Photo by freestocks on Unsplash

WooCommerce for online shopping

Now that I could create local Wordpress sites for development I wanted to stretch myself and start a new project dealing with e-commerce. A local restaurant was interested in getting their business online and I was excited to see if I could get something working for them.

WooCommerce was the obvious choice as it is owned by Automattic (who owns and is a contributor to and it is a free plugin to install. Once I had completed the install, set up the API keys and added a few sample products I was able to fetch data using WooCommerce’s own REST API end points and get a feel for what I needed to do. Postman was incredibly handy at this early stage as I didn’t need to worry about coding yet and could simply test the API to see what data I would be working with.

The documentation for WooCommerce is very good and they also have separate detailed developer documentation for their REST API too. One thing to mention is GraphQL. Whilst I used REST API to get my data you can also use GraphQL to do the same thing if you prefer. Instead of relying on set end points you can create queries to only get data you need — this makes it more efficient and faster. I tried it and it was very good but the reason I didn’t persevere with it was because I couldn’t figure out how to add authentication. I haven’t tried but I think you can use something like JWT AUTH for authentication.

It took me the best part of a month to get a site together where you could browse a menu, add items to a cart and go through a checkout process to gather all the necessary details. However, unlike other online shops, the restaurant had set opening hours and there was a limit to how far they would deliver orders. These were challenges that needed to be dealt with and they tested my logic and Javascript skills to get the app into shape. Now I had created various checks to make sure the restaurant is currently taking orders, the minimum amount has been met, delivery distance is within range, postcodes are valid and all required checkout fields are complete. I even configured a function in the back-end to send orders directly to the restaurant where software had been configured to automatically print orders using the receipt printer.

The app was taking shape but it still wasn’t ready to handle payments.

Photo by Pixabay on Pexels

Stripe to handle online payments

One popular way of handling online payments is to use Stripe. It has a competitive pricing structure compared to other payment gateways and very good developer documentation. It allows you to capture payment details you need and send to Stripe’s own secure servers to be processed, saving you a big headache.

You will need to setup a Stripe account and, helpfully, they provide you with test API keys you can use to make test payments and make sure everything is working in development. Stripe has many client libraries to make it easier to interact with the platform and there is one for React too along with guidelines on how to use it.

As we were working with sensitive data I wanted to make sure the Stripe functions were happening on the server-side and far away from the corruptible client-side. With Next.js it was as simple as creating a file in the /pages/api directory and working with this end point. For example /pages/api/create-stripe would now be an end point I could access at . I could pass data to this end point with a POST request or fetch data with GET.

There is a process to follow when working with Stripe payments and I fundamentally break it down as follows:

  1. Create a Stripe payment intent (pass the amount and currency)
  2. Update the payment intent (pass new amount and currency, if necessary, and add any other additional information you may have collected about the customer)
  3. Confirm the payment intent (creating or updating a payment intent will return a client_secret which you will need to confirm the payment)

Stripe recommends creating exactly one payment intent for each order so you can view it later in Stripe’s dashboard and see the history of payment attempts.

One important thing to note is the amount you pass to Stripe must be an integer. That means £1.00 must be entered as 100. It’s actually good practice to work with money values as whole numbers because Javascript has a hard time handling calculations with float numbers (numbers with a decimal point).

The common example is 0.1 + 0.2 !== 0.3 . More precisely, 0.1 + 0.2 === 0.30000000000000004 . How does this affect us? The short of it is rounding errors can creep in so some money calculations are a penny or a cent out from what we expected. It’s best to avoid this and working with integers or whole numbers is one way to overcome this.

Accounting for testing and refactoring it was now December 2020 and this particular project had consumed me for the best part of two months. I was ready to get this app live but there was only one problem: I didn’t know how to deploy it.

Lockdown coder: transformation from non-coder to coder in under 12 months…complete-ish.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store