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.jsonwith WordPress, WooCommerce, and plugin dependencies - Write
phpunit.xmlconfiguration and initial test cases - Create
.phpcs.xml.distfor 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.ymlwith 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
- Read our guide on zero-downtime deployment strategies for ecommerce
- Explore WooCommerce staging best practices
- Learn Docker for WordPress development
- Contact our team to discuss CI/CD implementation for your WordPress or WooCommerce site
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.
