For too long, deploying changes to WordPress projects has been a manual, often nerve-wracking affair. FTP clients, copying files, remembering to flush caches, and praying no one is actively using the site during an update – it’s a recipe for sleepless nights and lost productivity. As engineers focused on robust infrastructure, we know there’s a better way: automation. Today, I want to dive into how we can leverage WP-CLI and GitHub Actions to build a reliable, repeatable deployment pipeline for our custom WordPress plugins.
Imagine pushing a commit to your main branch, and within minutes, those changes are live on your production server, complete with database migrations and cache flushes, all without you touching an SSH client directly. This isn’t just wishful thinking; it’s a standard practice we can implement using two powerful tools. WP-CLI provides the command-line interface to interact with WordPress itself, enabling us to manage plugins, themes, options, and even trigger custom code execution. GitHub Actions, on the other hand, gives us the workflow automation to define a series of steps that execute automatically upon specific Git events.
Let’s walk through a concrete example: deploying a custom plugin that includes database schema changes. We’ll assume our plugin, my-custom-plugin, lives in wp-content/plugins/my-custom-plugin on our server and has a method, My_Custom_Plugin_Updater::run_migrations(), designed to handle its database updates programmatically. Our goal is to update the plugin code and execute these migrations safely whenever new code is pushed to our main branch. This ensures that any new tables or schema modifications required by the plugin are applied before the new code runs, preventing errors.
First, we need to set up our GitHub Actions workflow. In your plugin’s repository, create a file at .github/workflows/deploy.yml. Here’s a simplified version of what it might look like. Note that secrets.SSH_HOST, secrets.SSH_USER, and secrets.SSH_PRIVATE_KEY are GitHub Secrets you’ll configure in your repository settings; this keeps sensitive information out of your version-controlled code. The appleboy/ssh-action allows us to securely connect to our production server and execute commands.
name: Deploy My Custom Plugin
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Deploy to Production
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /var/www/html/wp-content/plugins/my-custom-plugin
git pull origin main
/usr/local/bin/composer install --no-dev # If your plugin uses Composer for dependencies
/usr/local/bin/wp cli eval 'My_Custom_Plugin_Updater::run_migrations();' # Execute database migrations
/usr/local/bin/wp cache flush # Clear WordPress object cache
Inside the script block, the magic happens. We cd into our plugin’s directory on the server, perform a git pull origin main to fetch the latest code, and then, crucially, we use WP-CLI. /usr/local/bin/wp cli eval 'My_Custom_Plugin_Updater::run_migrations();' executes our custom PHP code directly within the WordPress environment, ensuring our database schema is up-to-date. Finally, a wp cache flush clears any stale object cache entries, preventing potential display issues from old data. Using absolute paths for composer and wp is a good practice in non-interactive shell scripts to ensure the correct binaries are executed, especially if your $PATH isn’t fully configured in the SSH environment.
The benefits of this approach are immense. You gain consistency; every deployment follows the exact same steps, eliminating human error. It’s faster and more efficient, freeing up your time for development instead of manual labor. Most importantly, it builds confidence. Knowing that your deployments are automated and reliable allows you to focus on building great features, rather than dreading the next release. This is just one angle of what advanced WordPress development truly means – not just building features, but building robust systems around them to ensure stability and efficiency.