WordPress CI/CD: Ultimate CI/CD pipeline for WordPress
In this tutorial, I’ll show you how to create a CI/CD pipeline for your WordPress site. And that’s not all: I’ll also provide you with my complete CI/CD WordPress workflow including the WordPress CI/CD pipeline!
Continuous Integration and Continuous Deployment (CI/CD) in WordPress is somewhat special compared to other types of web applications. This is because we do not want to deploy the entire application, i.e. not the complete WordPress core including plugins, etc., but only the theme to which customisations are made.
In this tutorial, I will introduce you to my complete WordPress workflow. In addition
- Complete local development environment (including web server, database and phpmyadmin)
- Code quality and CI tools (including linting, code formatting for HTML, CSS, JS, TS and PHP)
- CI & CD (Continuous Integration & Continuous Delivery/Deployment) pipeline for GitHub Actions
- Automated code formatting before each commit
- Installation of recommended VSCode extensions
- Script to integrate a live website into the workflow
- Git workflow with code reviews and PRs (pull requests)
- Optional JS & CSS Minify for delivery/deployment
- Rollback to last successful build if deployment fails
Nice, isn’t it? Many functions are only possible with containers and a great way to share the same environment with several developers. But before we start with the set-up, let’s get to the basics.
Why should I use Continuous Integration and Deployment in WordPress?
Why should you use CI/CD in WordPress? CI/CD relieves you of tedious tasks and ensures that your code is always in top form. This allows you to concentrate on the creative side of things and worry less about technical problems. Here is a summary of the most important factors:
- Save time with workflow automation: Your assistant takes care of all the routine stuff for you – leaving more time for coding.
- Recognise bugs early: Find errors before they become big and problematic.
- Avoid errors: Automatic tests ensure that you don’t accidentally sabotage your own website.
- Faster releases: Your changes go online faster and you can react more quickly to feedback.
- Continuous improvements: Constant updates keep your website up to date.
Install Requirements
As already mentioned, some functions are based on Docker containers and some features for the IDE also require a few packages. You will therefore need the following programmes:
- Visual Studio Code as IDE
- Docker
- Install Node.js (> version 18) on your system (helpful tutorial to update your Node.js version)
- WSL2 mit Ubuntu strongly recommended!
- Installation of some global npm packages:
- Linux/macOS:
sudo npm i -g eslint prettier eslint-config-airbnb eslint-plugin-prettier eslint-config-prettier
- Windows:
npm i -g eslint prettier eslint-config-airbnb eslint-plugin-prettier eslint-config-prettier
- Linux/macOS:
WordPress CI/CD Pipeline
I have implemented the WordPress CI/CD pipeline in GitHub Actions. You should be able to manage with the free quota for a while. The pipeline executes the linter and prettier on a push to the develop branch. This always ensures good code quality in terms of formatting. If you then want to make the status live, open a PR on the main branch. After confirmation, your theme will be loaded into your production environment. This is done via an FTP sync.
The system then checks whether the website is accessible or whether it returns a 200 OK. If not, something went wrong during deployment and the last commit is reinstalled.
For the pipeline to work, the following variables must be created in the GitHub repo:
- Variables:
- FTP_SERVER: The host name of your FTP connection.
- FTP_USER: The user name of your FTP connection.
- THEME_NAME: The name of your WordPress theme (e.g. oceanwp-child).
- LIVE_URL: The URL of your live website.
- Secrets:
- FTP_PASSWORD: The password of your FTP connection.
- PAT: A Personal Access Token from GitHub, which has write access to your repository.
Here is the WordPress CI part, if you only want to use this part for your project:
name: Continuous Integration on: push: branches: ['develop'] jobs: run: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 - name: Set up Node.js uses: actions/setup-node@v2 with: node-version: '20' - name: Install dependencies run: npm ci - name: Run linter run: npm run lint - name: Run prettier run: npm run format
And here is the WordPress CD part:
name: Continuous Deployment on: push: branches: ['main'] jobs: cd: runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v2 with: ref: main # Remove the comments from line 18-27 to enable minification # - name: Set up Node.js # uses: actions/setup-node@v2 # with: # node-version: '20' # - name: Install dependencies # run: npm ci # - name: Run minifier # run: npm run minify - name: Sync files uses: SamKirkland/FTP-Deploy-Action@v4.3.4 with: server: ${{ vars.FTP_SERVER }} username: ${{ vars.FTP_USER }} password: ${{ secrets.FTP_PASSWORD }} local-dir: ./wordpress/wp-content/themes/${{ vars.THEME_NAME }}/ server-dir: ${{ vars.FTP_SERVER_DIR }} - name: Check Website Reachability run: | sudo apt-get update sudo apt-get install -y curl URL="${{ vars.LIVE_URL }}" # Perform a cURL request to fetch the HTTP response code. echo "Checking if $URL is reachable..." HTTP_STATUS=$(curl -sS -o /dev/null -w "%{http_code}" "$URL") # Check if the HTTP status code is not 200 (OK). if [ "$HTTP_STATUS" != "200" ]; then echo "Webpage is reachable but returns an unexpected status code: $HTTP_STATUS" exit 1 else echo "Webpage is reachable and returns a 200 (OK) status code." fi - name: Push uses: s0/git-publish-subdir-action@develop env: REPO: self BRANCH: theme FOLDER: ./wordpress/wp-content/themes/${{ vars.THEME_NAME }}/ GITHUB_TOKEN: ${{ secrets.PAT }} MESSAGE: 'Build: ({sha}) {msg}' rollback: runs-on: ubuntu-latest needs: cd if: failure() steps: - name: Checkout theme branch uses: actions/checkout@v2 with: ref: theme - name: Rollback files uses: SamKirkland/FTP-Deploy-Action@v4.3.4 with: server: ${{ vars.FTP_SERVER }} username: ${{ vars.FTP_USER }} password: ${{ secrets.FTP_PASSWORD }} local-dir: ./ server-dir: ${{ vars.FTP_SERVER_DIR }} - name: Check Website Reachability after Rollback run: | sudo apt-get update sudo apt-get install -y curl URL="${{ vars.LIVE_URL }}" # Perform a cURL request to fetch the HTTP response code. echo "Checking if $URL is reachable..." HTTP_STATUS=$(curl -sS -o /dev/null -w "%{http_code}" "$URL") # Check if the HTTP status code is not 200 (OK). echo "" echo "Rollback result:" if [ "$HTTP_STATUS" != "200" ]; then echo "Webpage is reachable but returns an unexpected status code: $HTTP_STATUS" exit 1 else echo "Webpage is reachable and returns a 200 (OK) status code." fi
Set up WordPress in Git Repo
Thanks to my boilerplate code in the repo, setting it up is very easy and can be done in just a few steps. However, a few adjustments are necessary:
- Create a folder and clone this repository with
git clone https://github.com/lorenzhohmann/wp-workflow-template .
inside the empty folder. - Run the setup-repo.sh script (run
chmod +x setup-repo.sh
and./setup-repo.sh
) - Create a Personal access token under Settings > Developer settings > Personal access tokens > Generate new token (classic) and create a new variable PAT in your repository settings under Secrets and variables > ‘Secrets’ tab > New repository secret
Here is the link to the repo:
To use a website with the repo template, you can now use the import.sh
script. To do this, create a complete export (tgz file) of your website (incl. SQL dump) in the root directory and execute the script (./import.sh
). This script will ask you a few questions and should then completely set up the repo for you.
If you want to create a completely new website, I still recommend installing it in a different folder and using the tgz file. Otherwise you will have to set som
Understanding WordPress workflow
As announced at the beginning, the repo contains more than just a WordPress CI/CD pipeline. I have configured the pipelines so that they work according to the Git workflow.
Here is a brief summary of the most important facts for you:
- Make sure to checkout the develop branch by using
git checkout develop
. Rungit branch develop
before, if the branch doesn’t exist. - Run
git pull
every time before you make changes. - Make your changes, commit them and push them to the remote repository.
- Once the changes are pushed, GitHub executes Code Linting and Formatting in the Background.
- Create a PR (pull request) and have a code review done by another developer.
- After the other developer accepts the change, the theme is automatically deployed to your production system.
WordPress CI/CD: Conclusion
I hope I haven’t promised too much. In my opinion, this WordPress CI/CD workflow is great if you develop WordPress websites yourself and want to save yourself a bit of work and value code quality and clear work structures. Have fun with the workflow! 🙂 Suggestions for improvement and errors can be created as issues.
What did you think of this post?