If you’ve ever forgotten to tag a version, shipped dev files in your ZIP, or spent 20 minutes on a deployment that should take 20 seconds — this guide is for you.
In this post, I’ll walk you through the exact GitHub Actions workflow I use to automate deployments for my plugin Bitly URL Shortener. Every time I publish a GitHub release, the entire pipeline runs automatically: dependencies are installed, assets are built, the plugin is deployed to WordPress.org SVN, and a clean production ZIP is attached to the release — without me touching a thing.
No manual SVN commits. No accidental dev files in production. No version mismatches. Just a reliable, repeatable deployment pipeline that scales with your plugin.
Whether you’re maintaining your first plugin or managing multiple on WordPress.org, this setup will save you time and eliminate the human error that comes with manual releases.
Why Automate WordPress Plugin Deployment?
Manual WordPress.org deployment usually means:
- Building assets locally
- Cleaning dev files
- Committing to SVN
- Tagging versions manually
- Creating ZIP files
This process is:
- Error-prone
- Inconsistent
- Hard to scale
Using GitHub Actions solves this by making your deployment:
- Release-driven
- Reproducible
- Secure
- Fully automated
How the GitHub Action Works
The workflow runs only when a release is published
on:
release:
types: [published]This ensures:
- Deployment happens only for production versions
- GitHub release version matches WordPress.org version
- No accidental deployments
This is clean release management.
What Happens During Deployment?
Setup Environment
The workflow prepares:
- PHP 8.1 + Composer
- Node.js 20
- Fresh Ubuntu runner
Every build starts from scratch, ensuring consistency.
Install Production Dependencies
composer install --no-dev --optimize-autoloader
npm ci
npm run buildWhy this matters:
--no-devkeeps the plugin lightweightnpm ciensures deterministic installsnpm run buildgenerates production-ready assets
Your plugin is now optimized for release.
Deploy to WordPress.org SVN
The workflow uses: 10up / action-wordpress-plugin-deploy
10up/action-wordpress-plugin-deployThis automatically:
- Pushes code to WordPress.org SVN
- Creates the correct tag
- Syncs trunk
- Generates a ZIP file
SVN credentials are stored securely in GitHub Secrets.
This means no credentials in your codebase.

Using .distignore for Clean Release ZIP
One of the most important optimizations in this setup is the .distignore file:
.distignore works like .gitignore, but for deployment.
It excludes:
.github/node_modules/- Tests
- Dev configs
- Unnecessary local files
Why this is important:
- Smaller ZIP size
- Cleaner production package
- No accidental dev files in release
- Faster downloads
This small step dramatically improves release quality.
Automatic GitHub Release ZIP Upload
After deployment:
- A production ZIP is generated
- The ZIP is automatically attached to the GitHub Release
This gives you dual distribution:
- Install via WordPress.org
- Download directly from GitHub
Professional workflow.
How do I deploy a WordPress plugin using GitHub Actions?
Trigger deployment on GitHub release and use
10up/action-wordpress-plugin-deployto automatically push to WordPress.org SVN.What is
.distignorein WordPress plugin development?.distignoreexcludes development files from your production ZIP, ensuring only necessary files are shipped.Why use
npm ciinstead ofnpm installin CI?npm ciensures consistent, lock-file-based installs and prevents version mismatch issues.Is this method secure?
Yes. SVN credentials are stored in GitHub Secrets and never exposed in your repository.
Workflow Code
Codehaveli Bitly URL Shortener Repo reference: https://github.com/royrakesh/codehaveli-bitly-url-shortener/blob/main/.github/workflows/deploy-wordpress.yml
name: Deploy to WordPress.org
on:
release:
types: [published]
permissions:
contents: write
jobs:
deploy:
name: Deploy on Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
tools: composer
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install Composer dependencies
run: composer install --no-dev --optimize-autoloader
- name: Install npm dependencies
run: npm ci
- name: Build blocks and assets
run: npm run build
- name: WordPress Plugin Deploy
uses: 10up/action-wordpress-plugin-deploy@stable
with:
generate-zip: true
env:
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SLUG: codehaveli-bitly-url-shortener
- name: Upload release asset
uses: softprops/action-gh-release@v2
env:
# Note, this is an exception to action secrets: GH_TOKEN is always available and provides access to
# the current repository this action runs in.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
# Provide what the file should be named when attached to the release (plugin-name.zip)
files: ${{ github.workspace }}/codehaveli-bitly-url-shortener.zip
