How to Deploy a WordPress Plugin Using GitHub Actions (Complete CI/CD Guide)

How to Deploy a WordPress Plugin Using GitHub Actions

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 build

Why this matters:

  • --no-dev keeps the plugin lightweight
  • npm ci ensures deterministic installs
  • npm run build generates 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-deploy

This 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.

codehaveli bitly url shortener royrakesh

Using .distignore for Clean Release ZIP

One of the most important optimizations in this setup is the .distignore file:

https://raw.githubusercontent.com/royrakesh/codehaveli-bitly-url-shortener/refs/heads/main/.distignore

.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-deploy to automatically push to WordPress.org SVN.

  • What is .distignore in WordPress plugin development?

    .distignore excludes development files from your production ZIP, ensuring only necessary files are shipped.

  • Why use npm ci instead of npm install in CI?

    npm ci ensures 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