← All posts

Orchestrating WordPress Deployments with WP-CLI and GitHub Actions

Orchestrating WordPress Deployments with WP-CLI and GitHub Actions

I've spent countless hours navigating FTP clients, manually sifting through plugin updates, and holding my breath during database migrations. It's a rite of passage for many WordPress developers, but an unnecessary one in the era of robust CI/CD. When we talk about advanced WordPress development from an infrastructure perspective, automating these critical, repetitive tasks is foundational. Today, I want to share how I've leveraged WP-CLI alongside GitHub Actions to build reliable, automated deployment pipelines, turning hours of manual work into seconds of execution.

At its core, WP-CLI is an indispensable tool for anyone serious about WordPress development. It allows you to manage almost every aspect of a WordPress installation directly from the command line. From updating core, themes, and plugins to managing users, clearing caches, or even importing/exporting database snapshots, WP-CLI makes programmatic control over WordPress possible. This power is exactly what we need when building an automated deployment. Imagine needing to update a custom plugin, run its database migration script, and then flush the site cache — all with a single command on your server. WP-CLI enables this through simple commands like `wp plugin update my-custom-plugin`, `wp db update`, or `wp cache flush`.

Our goal is to execute these WP-CLI commands automatically whenever specific conditions are met, such as pushing new code to a `main` branch. This is where GitHub Actions steps in. GitHub Actions provides a flexible platform for automating workflows directly within your repository. We can define a YAML file that specifies a series of steps to be executed on a virtual machine, including SSHing into our staging or production server and running our WP-CLI commands.

Here’s a simplified GitHub Actions workflow I use for deploying to a staging environment. This example assumes your entire WordPress project, including custom plugins and themes, is version-controlled and pushed to a `main` branch.

name: Deploy WordPress Site to Staging

on: push: branches: - main

jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v3

- name: Deploy to Staging Server via SSH uses: appleboy/ssh-action@master with: host: ${{ secrets.SSH_HOST_STAGING }} username: ${{ secrets.SSH_USERNAME_STAGING }} key: ${{ secrets.SSH_PRIVATE_KEY_STAGING }} script: | cd /var/www/html/staging.mysite.com # Adjust to your WordPress root git pull origin main composer install --no-dev --prefer-dist # Run if your project uses Composer wp db update --allow-root # Runs any pending database updates wp cache flush --allow-root # Clears all caches echo "Deployment to staging complete!"

Let’s break down what's happening here. The workflow is triggered by a `push` to the `main` branch. The `deploy` job runs on an `ubuntu-latest` virtual machine. First, `actions/checkout@v3` clones your repository onto the runner. Then, the `appleboy/ssh-action@master` action is used to establish an SSH connection to your staging server. Crucially, sensitive information like `host`, `username`, and `key` are stored securely as GitHub Secrets, preventing them from being exposed in your repository.

Once connected via SSH, the script navigates to the WordPress root directory on the server. `git pull origin main` fetches the latest code changes. If your custom plugins or theme dependencies are managed via Composer, `composer install` ensures they are up-to-date. The WP-CLI commands `wp db update` and `wp cache flush` are then executed. The `--allow-root` flag here is used because the SSH connection might be established as a user that is not the web server user; in a production environment, you'd typically configure `sudoers` for the deploy user to run `wp` commands without needing `--allow-root` or direct root access for enhanced security. This ensures any database schema changes from your custom code are applied and all persistent caches are cleared, preventing stale content or functional issues.

This setup transforms the deployment process. A simple `git push` to your main branch initiates a robust, repeatable series of actions, drastically reducing the chance of human error and freeing up valuable development time. You can extend this further with pre-deployment checks, post-deployment notifications, or even multi-stage deployments. This level of automation isn't just a convenience; it's a cornerstone of professional, scalable WordPress engineering.