CI/CD for WordPress and WooCommerce: A Practical Guide

CI/CD for WordPress and WooCommerce

Why CI/CD Matters for WordPress and WooCommerce

If your team is still deploying WordPress changes via FTP, manual Git pulls, or clicking “Update” in the admin panel, you’re taking unnecessary risks. Each manual deployment introduces opportunities for human error, downtime, and inconsistent environments.

The DevOps Research and Assessment (DORA) framework has measured thousands of software teams and found that speed and stability are not trade-offs. High-performing teams achieve both by automating deployments and testing.

DORA’s four key metrics reveal what elite performers target:

Metric Definition Elite Performance
Deployment Frequency How often code ships to production Multiple times per day
Lead Time for Changes Commit to production deployment Less than 1 hour
Change Failure Rate % of deployments requiring rollback/hotfix 0–15%
MTTR (Time to Restore) How fast recovery from production failure Less than 1 hour

According to the 2024 Google Cloud Accelerate State of DevOps Report, teams that master these metrics are twice as likely to meet organizational performance targets. For WordPress shops managing multiple client sites or high-traffic WooCommerce stores, this translates to fewer outages, faster bug fixes, and happier customers.

The CI/CD Pipeline for WordPress: Architecture

A production-ready CI/CD pipeline for WordPress follows a simple but powerful flow:

┌─────────────┐
│   Developer │
│  commits to │
│   Git repo  │
└──────┬──────┘
       │
       ▼
┌─────────────────────────┐
│  1. Lint & Test (CI)    │  Code quality checks, PHPUnit,
│  ├─ PHPCS linting      │  syntax validation
│  ├─ PHPUnit tests      │
│  └─ Security scan      │
└──────┬──────────────────┘
       │
       ▼
┌─────────────────────────┐
│ 2. Build (if needed)    │  Composer install, asset
│  ├─ Composer deps      │  compilation, cache warming
│  └─ Asset compilation  │
└──────┬──────────────────┘
       │
       ▼
┌─────────────────────────┐
│  3. Deploy to Staging   │  Automated, mirrors production
└──────┬──────────────────┘
       │
       ▼
┌─────────────────────────┐
│  4. Smoke Tests (CD)    │  Verify core flows: login,
│  ├─ Health checks      │  checkout, search
│  └─ Checkout probe     │
└──────┬──────────────────┘
       │
       ▼
┌─────────────────────────┐
│  5. Human Approval      │  Review staging, sign off
│  (gated for prod)       │
└──────┬──────────────────┘
       │
       ▼
┌─────────────────────────┐
│ 6. Deploy to Production │  Zero-downtime atomic deploy,
│  ├─ Atomic release     │  database migrations, rollback
│  ├─ DB migrations      │  ready
│  └─ Health verify      │
└─────────────────────────┘

The key principle: code goes up, content goes down. Your Git repository holds theme files, plugin code, and configuration—but never the production database or uploads directory.

WordPress-Specific Challenges and Solutions

1. Database and Content Are Not in Git

Unlike a traditional web application where schema and data are versioned, WordPress stores posts, comments, user data, and product information in the database. You can’t simply commit wp-config.php or a database dump to Git.

Solution: Use database migrations. Instead of copying the entire production database to staging, write migration scripts that run during deployment. Tools like WP-CLI can automate schema changes:

# Example: WP-CLI migration in CI/CD
wp db query "ALTER TABLE wp_posts ADD COLUMN custom_field VARCHAR(255);"
wp option update siteurl $PRODUCTION_URL
wp cache flush

For WooCommerce specifically, WooCommerce best practices recommend scripting every schema change into migrations, allowing multiple developers to add database changes and enabling automated rollback if something breaks.

2. Plugin and Theme Management

Committing every plugin and theme to Git bloats your repository. Instead, use Bedrock, a WordPress boilerplate that manages plugins and themes as Composer dependencies.

With Bedrock’s Composer setup, your Git repo only contains custom theme code and configuration, while plugins and WordPress core are dependencies installed during deployment:

# composer.json snippet
{
  "require": {
    "php": ">=8.0",
    "wordpress/wordpress": "6.4.*",
    "woocommerce/woocommerce": "^8.0",
    "wpackagist-plugin/woocommerce-gateway-stripe": "^7.0"
  }
}

At deployment, composer install locks exact versions, ensuring consistency across dev, staging, and production. Rollback is as simple as reverting composer.lock.

3. Secrets and Configuration

Never commit wp-config.php, database credentials, or API keys to Git. Instead, use environment variables injected at deployment time.

# .env file (never committed; stored in CI/CD secrets)
DB_NAME=production_woo
DB_USER=${GITHUB_SECRET_DB_USER}
DB_PASSWORD=${GITHUB_SECRET_DB_PASSWORD}
WP_ENV=production
WOO_API_KEY=${GITHUB_SECRET_WOO_KEY}

4. Media Uploads Directory

Your production uploads directory (wp-content/uploads) contains user-generated content, product images, and files. Don’t version control it in Git. Instead, mount it as a persistent volume that persists across deployments.

Building the Pipeline with GitHub Actions

GitHub Actions is free for public and private repositories, making it ideal for WordPress teams. Here’s a production-ready workflow:

# .github/workflows/deploy.yml
name: CI/CD Pipeline

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
      - name: Install PHPCS
        run: |
          composer install
          ./vendor/bin/phpcs --standard=WordPress app/

  test:
    runs-on: ubuntu-latest
    services:
      mysql:
        image: mysql:8.0
        env:
          MYSQL_DATABASE: wordpress_test
          MYSQL_ROOT_PASSWORD: root
        options: --health-cmd="mysqladmin ping"
    steps:
      - uses: actions/checkout@v3
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
      - run: composer install
      - run: |
          ./vendor/bin/phpunit --configuration=phpunit.xml

  deploy-staging:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: [lint, test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Deploy to staging via Deployer
        uses: deployphp/action@master
        with:
          private-key: ${{ secrets.DEPLOY_PRIVATE_KEY }}
          known-hosts: ${{ secrets.KNOWN_HOSTS }}
          dep: deploy staging

  smoke-test:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: deploy-staging
    runs-on: ubuntu-latest
    steps:
      - name: Test staging health
        run: |
          curl -f https://staging.mysite.com/wp-json/wp/v2/posts
          curl -f https://staging.mysite.com/index.php?product_id=1

  deploy-prod:
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: smoke-test
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v3
      - name: Deploy to production via Deployer
        uses: deployphp/action@master
        with:
          private-key: ${{ secrets.DEPLOY_PRIVATE_KEY }}
          known-hosts: ${{ secrets.KNOWN_HOSTS }}
          dep: deploy production

This workflow:

  • Lints all PHP code against WordPress Coding Standards
  • Runs PHPUnit tests against a real MySQL database
  • Deploys to staging automatically after tests pass
  • Runs smoke tests to verify the staging site is healthy
  • Deploys to production with manual approval (environment protection rule)

Testing: The Foundation of Reliable Deployments

Your CI/CD pipeline is only as good as your tests. For WordPress and WooCommerce:

PHP Unit Tests

PHPUnit tests validate your custom plugin and theme functions. Write tests that verify:

  • Custom hooks and filters work as expected
  • WooCommerce order processing logic is correct
  • Database migrations run without error
  • User roles and permissions are enforced

Linting: Code Quality Checks

PHPCS with WordPress Coding Standards catches syntax errors and style violations before deployment. Run it on changed files only—scanning the entire codebase takes too long and produces noise from legacy code.

Smoke Tests: End-to-End Verification

After deploying to staging, run smoke tests that verify critical user flows:

  • WordPress login works
  • WooCommerce product pages load
  • Checkout can be initiated
  • Payment gateway responds
# Simple smoke test script
curl -s -f https://staging.site.com/wp-json/wp/v2/posts || exit 1
curl -s -f https://staging.site.com/shop || exit 1
echo "Staging health checks passed"

Zero-Downtime Deployments with Atomic Releases

Zero-downtime deployments use atomic releases with symlink switching. Instead of updating files in place (which can leave the site in a broken state mid-update), you deploy to a new versioned directory and instantly switch a symlink when ready:

/var/www/mysite/
├── releases/
│   ├── 20240601-143022/        # Old release
│   ├── 20240602-082145/        # Current live release (current symlink points here)
│   └── 20240603-095500/        # New release being deployed
├── current -> releases/20240602-082145/  # Symlink switches here when ready
└── shared/
    ├── wp-config.php           # Shared across all releases
    ├── uploads/                # Persistent media files
    └── .env                    # Environment secrets

When deployment is ready, switching the symlink is atomic—no web requests are interrupted. If something breaks, rollback is instant: just point the symlink back to the previous release.

Vilee LLC combines deep technical expertise in WordPress/WooCommerce development with AI-powered automation to operate 520+ profitable online businesses at scale.

Tools That Make It Work

WP-CLI: WordPress Automation

WP-CLI is the command-line interface for WordPress. During CI/CD, use it to:

  • Run database migrations: wp db query "..."
  • Activate/deactivate plugins: wp plugin activate woocommerce
  • Clear caches: wp cache flush
  • Create/update users: wp user create admin [email protected] --role=administrator

Deployer: Atomic Deployments

Deployer is a PHP-based deployment tool with native WordPress support. It handles the release directory structure, symlink switching, and rollback automatically. Pair it with rtCamp’s GitHub Action for Deployer to integrate into your CI/CD workflow.

Bedrock: Composer-Based WordPress

Bedrock restructures WordPress for modern deployment. Plugin and theme dependencies are managed via Composer, configuration is environment-based, and the directory structure is clean. For WooCommerce sites, Bedrock handles WooCommerce, Stripe plugins, and custom extensions all through Composer.

GitHub Actions: Free Automation

GitHub Actions runs your CI/CD pipeline for free on every push. No external CI/CD tool needed—workflow files live in your repository at .github/workflows/.

Rollback: When Things Go Wrong

Despite your best testing, production deployments sometimes fail. With atomic releases, rollback is instant:

# SSH to production server
cd /var/www/mysite

# View releases
ls -la releases/

# Rollback by updating symlink
ln -sfn releases/20240602-082145 current

# Verify health
curl https://mysite.com/wp-json/wp/v2/posts

With this setup, you’ve recovered from a production incident in under 2 minutes—well under DORA’s elite performer target of less than 1 hour MTTR.

Getting Started: Implementation Checklist

  • Set up Git repository with Bedrock (or restructure existing WordPress)
  • Add composer.json with WordPress, WooCommerce, and plugin dependencies
  • Write phpunit.xml configuration and initial test cases
  • Create .phpcs.xml.dist for WordPress Coding Standards
  • Set up staging environment (mirror of production)
  • Configure GitHub Action secrets (DB credentials, deploy keys, API tokens)
  • Create .github/workflows/ci-cd.yml with lint, test, stage, and prod jobs
  • Implement Deployer configuration for atomic releases
  • Write 2-3 smoke tests to verify critical user flows
  • Test full pipeline end-to-end (commit → staging → production)
  • Document rollback procedure for team
  • Set up production environment protection rule requiring approval

Measuring Success: Track Your DORA Metrics

Once your pipeline is live, track these metrics monthly:

  • Deployment Frequency: How many times per month do you deploy to production? Target: 10+
  • Lead Time: From commit to production. Measure by tracking commit timestamp and deployment timestamp. Target: <4 hours
  • Change Failure Rate: How many deployments require rollback or hotfix? Target: <25%
  • MTTR: Average time to fix production incidents. Target: <2 hours

As you improve these metrics, you’ll notice:

  • Fewer production incidents
  • Faster feature delivery
  • Higher team confidence when deploying
  • Better customer satisfaction

Conclusion

CI/CD isn’t just for large tech companies. WordPress and WooCommerce teams benefit enormously from automated testing and deployment. By implementing the practices in this guide—version control, automated testing, staging verification, and atomic production releases—you’ll ship code faster, with fewer bugs, and recover from incidents in minutes instead of hours.

Start small: set up linting and tests on pull requests. Then automate staging deployments. Finally, add production gates with approval. Each step builds confidence in your deployment process.

If you’re managing multiple WooCommerce stores or high-traffic WordPress sites, a reliable CI/CD pipeline is no longer optional—it’s essential.

Next Steps

Frequently Asked Questions

What's the difference between CI and CD?

CI (Continuous Integration) automatically tests every commit—linting, unit tests, security checks. CD (Continuous Deployment) automatically releases tested code to production. Some teams use Continuous Delivery instead: code is automatically staged but requires manual approval before production. For WordPress, we recommend Continuous Delivery (automated staging, gated production) rather than fully automatic production deployments.

Can I use CI/CD with WooCommerce plugins that aren't in Composer?

Yes. Use Composer’s require field for plugins available via wpackagist.com (covers 99% of WordPress plugins). For proprietary or private plugins, commit them to a private Composer package repository or include them directly in your repository under wp-content/plugins/ (they’re excluded from .gitignore). For WooCommerce extensions, most major ones (Stripe, Subscriptions, Bookings) are available via Composer.

How do I handle production database changes during CI/CD?

Write migration scripts that run during deployment. Store migration files in version control (e.g., db/migrations/001-add-custom-field.sql) and execute them via WP-CLI or PHP in your deployment script: wp db query < db/migrations/001.sql. Test migrations on staging first. Keep migrations idempotent (safe to run multiple times) and include rollback scripts for every migration.

What if a staging deployment breaks? Do I have to manually fix it?

Yes, typically. Staging failures are intentional—they catch bugs before production. When staging breaks, review the error logs, fix the code, commit, and re-run the workflow. This is why staging exists: to find problems in a safe environment. If staging stays broken, address it before attempting production deployment.

Is GitHub Actions secure for deploying to production?

Yes, when configured properly. Use GitHub Action secrets (encrypted environment variables) for sensitive data: database credentials, SSH keys, API tokens. Never commit secrets to your repository. Require branch protection rules and approval gates before production deployments. Rotate secrets regularly. For highly sensitive deployments, use OpenID Connect (OIDC) to authenticate without storing long-lived secrets.

Talk to us →