Perché serve CI/CD per progetti WordPress
La gestione manuale dei deploy WordPress è ancora troppo diffusa nelle agenzie web. Ogni deploy via FTP o cPanel introduce rischio di errore umano, downtime non pianificato e difficoltà nel tracciare le modifiche in produzione.
Una pipeline CI/CD (Continuous Integration/Continuous Deployment) automatizza l’intero flusso: dal push del codice su Git fino al deploy in produzione, passando per test automatici e validazioni. Per agenzie che gestiscono decine di siti client, questo si traduce in:
- Riduzione degli errori di deploy del 90% circa (dato interno da team che hanno fatto la transizione)
- Tempo di deploy ridotto da 15-30 minuti manuali a 3-5 minuti automatici
- Rollback immediato in caso di problemi
- Tracciabilità completa di ogni modifica in produzione
- Possibilità di deployare più volte al giorno senza stress
GitHub Actions è la scelta naturale per questo workflow: integrato nativamente con i repository, gratuito per repository privati (2000 minuti/mese sul piano free), e con una sintassi YAML relativamente semplice da apprendere.
Architettura della pipeline WordPress
Prima di scrivere codice, è fondamentale definire l’architettura della pipeline. Un workflow CI/CD WordPress maturo prevede questi stage:
Stage di Continuous Integration
Ogni push o pull request verso branch protetti (sviluppo, staging, main) deve passare attraverso:
- Linting e code quality: PHP_CodeSniffer con WordPress Coding Standards, PHPStan per analisi statica
- Security scanning: controllo dipendenze vulnerabili con Composer audit
- Unit testing: test PHP con PHPUnit per plugin/temi custom
- Build assets: compilazione CSS/JS con npm, ottimizzazione immagini
Stage di Continuous Deployment
Se i test passano, il deploy procede automaticamente verso l’ambiente target:
- Staging: deploy automatico da branch develop/staging
- Production: deploy da branch main, con approvazione manuale opzionale
- Post-deploy checks: verifica che il sito risponda correttamente, controllo status HTTP
Questa separazione garantisce che solo codice validato arrivi in produzione, riducendo drasticamente i bug post-deploy.
Setup iniziale del repository
La struttura del repository WordPress deve essere pensata per il CI/CD. Ecco la configurazione consigliata:
Struttura file system
Consigliamo una struttura che tracci solo codice custom, escludendo WordPress core e plugin di terze parti gestiti via Composer:
repository-root/
├── .github/
│ └── workflows/
│ ├── ci.yml
│ └── deploy-production.yml
├── wp-content/
│ ├── themes/
│ │ └── tema-custom/
│ └── plugins/
│ └── plugin-custom/
├── composer.json
├── package.json
└── .gitignore
File .gitignore critico
Il file .gitignore deve escludere tutto ciò che viene generato o gestito esternamente:
# WordPress core
/wp-admin/
/wp-includes/
# Plugin e temi di terze parti
/wp-content/plugins/*
!/wp-content/plugins/plugin-custom/
/wp-content/themes/*
!/wp-content/themes/tema-custom/
# Upload e cache
/wp-content/uploads/
/wp-content/cache/
# Dipendenze
/vendor/
/node_modules/
# Build artifacts
*.map
.DS_Store
Composer per gestione dipendenze
Utilizzare Composer per gestire WordPress stesso e i plugin di terze parti garantisce versioning e riproducibilità:
{
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org"
}
],
"require": {
"php": ">=8.1",
"johnpbloch/wordpress": "6.5.*",
"wpackagist-plugin/wordpress-seo": "^22.0",
"wpackagist-plugin/wordfence": "^7.11"
},
"require-dev": {
"phpunit/phpunit": "^10.0",
"squizlabs/php_codesniffer": "^3.7",
"wp-coding-standards/wpcs": "^3.0"
}
}
Workflow GitHub Actions: Continuous Integration
Creiamo il primo workflow per la fase CI, che si attiva su ogni push e pull request. File .github/workflows/ci.yml:
name: CI WordPress
on:
push:
branches: [ develop, staging, main ]
pull_request:
branches: [ develop, staging, main ]
jobs:
code-quality:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mysqli, mbstring, xml, gd
tools: composer:v2
- name: Cache Composer dependencies
uses: actions/cache@v4
with:
path: vendor
key: composer-${{ hashFiles('composer.lock') }}
- name: Install dependencies
run: |
composer install --no-interaction --prefer-dist
composer global require wp-coding-standards/wpcs
- name: PHP CodeSniffer
run: |
vendor/bin/phpcs --standard=WordPress \
--extensions=php \
--ignore=vendor,node_modules \
wp-content/themes/tema-custom/ \
wp-content/plugins/plugin-custom/
- name: PHPStan Static Analysis
run: |
composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse --level=5 \
wp-content/themes/tema-custom/ \
wp-content/plugins/plugin-custom/
security-scan:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Composer Audit
run: composer audit
frontend-build:
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build assets
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: frontend-build
path: |
wp-content/themes/tema-custom/dist/
wp-content/plugins/plugin-custom/assets/dist/
Questo workflow esegue tre job in parallelo: code quality, security scan e build frontend. Ogni job gira in un container Ubuntu isolato.
Ottimizzazioni per velocità
Alcuni accorgimenti per ridurre i tempi di esecuzione:
- Cache aggressive: usiamo
actions/cache@v4per vendor e node_modules, riducendo i tempi da 2-3 minuti a 20-30 secondi - Job paralleli: code quality, security e build girano simultaneamente
- Matrix strategy: se dovete testare su più versioni PHP, usate la strategia matrix per parallelizzare
Workflow di Deploy Production
Il workflow di deploy verso produzione richiede più attenzione. File .github/workflows/deploy-production.yml:
name: Deploy Production
on:
push:
branches: [ main ]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-22.04
environment:
name: production
url: https://sitoclient.com
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
- name: Install Composer dependencies
run: composer install --no-dev --optimize-autoloader
- name: Download frontend artifacts
uses: actions/download-artifact@v4
with:
name: frontend-build
- name: Setup SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Deploy via rsync
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
run: |
rsync -avz --delete \
--exclude='.git' \
--exclude='node_modules' \
--exclude='.github' \
--exclude='wp-content/uploads' \
--exclude='wp-config.php' \
./ $DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/
- name: Run remote commands
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
run: |
ssh $DEPLOY_USER@$DEPLOY_HOST << 'EOF'
cd $DEPLOY_PATH
wp cache flush --allow-root
wp rewrite flush --allow-root
EOF
- name: Health check
run: |
sleep 10
STATUS=$(curl -o /dev/null -s -w "%{http_code}" https://sitoclient.com)
if [ $STATUS -ne 200 ]; then
echo "Health check failed: $STATUS"
exit 1
fi
- name: Notify deployment
if: always()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
Gestione secrets
I secrets vanno configurati in Settings → Secrets and variables → Actions del repository:
- SSH_PRIVATE_KEY: chiave privata SSH per accesso server (generare coppia ed-25519 dedicata)
- DEPLOY_HOST: hostname o IP del server
- DEPLOY_USER: username SSH
- DEPLOY_PATH: percorso assoluto della document root WordPress
- SLACK_WEBHOOK: webhook per notifiche (opzionale)
Environment protection rules
GitHub permette di configurare regole di protezione per environment production:
- Required reviewers: almeno un'approvazione prima del deploy
- Wait timer: attesa di N minuti prima del deploy (utile per ripensamenti)
- Deployment branches: solo branch main può deployare in production
Queste regole si configurano in Settings → Environments → production del repository.
Strategie avanzate di deployment
Blue-Green Deployment
Per siti ad alto traffico, il blue-green deployment elimina downtime. Richiede:
- Due installazioni WordPress identiche (blue e green)
- Load balancer o reverse proxy (nginx) che switcha tra le due
- Script di sync del database prima dello switch
Il workflow GitHub Actions deploya sulla versione inattiva, esegue test, poi switcha il traffico. In caso di problemi, lo switch-back è istantaneo.
Database migrations automatizzate
Per plugin custom con modifiche database, integrare WP-CLI migrations:
- name: Run database migrations
run: |
ssh $DEPLOY_USER@$DEPLOY_HOST << 'EOF'
cd $DEPLOY_PATH
wp plugin-custom migrate --allow-root
EOF
Implementare un sistema di versioning delle migration (simile a Laravel Migrations) per tracciare modifiche schema.
Rollback automatico
Aggiungere logica di rollback in caso di health check fallito:
- name: Rollback on failure
if: failure()
run: |
ssh $DEPLOY_USER@$DEPLOY_HOST << 'EOF'
cd $DEPLOY_PATH
git reset --hard HEAD~1
wp cache flush --allow-root
EOF
Testing automatizzato WordPress
Una pipeline CI/CD seria include test automatici. Per WordPress, distinguiamo tre livelli:
Unit testing con PHPUnit
Test isolati di funzioni e classi custom. Setup test environment:
tests:
runs-on: ubuntu-22.04
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wordpress_test
ports:
- 3306:3306
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup WordPress test suite
run: |
bash bin/install-wp-tests.sh \
wordpress_test root root 127.0.0.1:3306 latest
- name: Run PHPUnit
run: vendor/bin/phpunit
Integration testing
Test che verificano interazioni tra componenti, incluse query database e hook WordPress. Usare WP_UnitTestCase come base class.
End-to-end testing con Playwright
Test che simulano utente reale nel browser. Utili per verificare funzionalità critiche post-deploy:
e2e-tests:
runs-on: ubuntu-22.04
steps:
- name: Install Playwright
run: npm install @playwright/test
- name: Run E2E tests
run: npx playwright test
env:
BASE_URL: https://staging.sitoclient.com
Monitoring e observability
Una pipeline CI/CD production-ready include monitoring dei deploy:
Metriche da tracciare
- Deploy frequency: quanti deploy/giorno o settimana
- Lead time: tempo da commit a produzione
- Failure rate: percentuale deploy falliti
- MTTR: tempo medio di recovery da fallimento
GitHub Actions fornisce nativamente molte di queste metriche nella tab Actions del repository.
Integrazione con strumenti esterni
Consigliamo integrazioni con:
- Sentry: error tracking automatico, creazione release su deploy
- New Relic/DataDog: APM per monitoraggio performance post-deploy
- Slack/Discord: notifiche real-time su deploy e fallimenti
Gestione multi-cliente per agenzie
Quando gestite decine di siti client, alcune best practice aggiuntive:
Template workflow riutilizzabili
Creare workflow template in un repository centrale, referenziabili da tutti i progetti client:
jobs:
deploy:
uses: agenzia/.github/.github/workflows/deploy-wordpress.yml@main
with:
environment: production
php-version: '8.2'
secrets:
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
Questo centralizza la logica di deploy, semplificando manutenzione e update.
Secrets management centralizzato
Per agenzie con molti progetti, considerare:
- GitHub Organization secrets: secrets condivisi tra repository
- HashiCorp Vault: gestione centralizzata secrets con rotazione automatica
- AWS Secrets Manager: se infrastructure su AWS
Dashboard centralizzata
Strumenti come AgencyPilot permettono di monitorare lo stato di tutti i deploy client da un'unica dashboard, integrando webhook di GitHub Actions per aggiornamenti real-time.
Costi e performance reali
Dati reali da un'agenzia media (20-30 siti gestiti) dopo 12 mesi di CI/CD:
Costi GitHub Actions
- Piano GitHub Team: €4/utente/mese
- Minuti Actions inclusi: 3000/mese per repository privato
- Costo medio minuti extra: €20-40/mese per agenzia media
- Totale mensile: circa €60-80 per team di 5 persone
ROI in tempo
- Tempo deploy manuale medio pre-CI/CD: 25 minuti
- Tempo deploy automatizzato: 4 minuti (non presidiato)
- Deploy settimanali medi per sito: 3-4
- Risparmio settimanale per 25 siti: circa 80 ore/mese di lavoro umano
Il ROI è evidente già dal primo mese per agenzie con più di 10 siti attivi.
Troubleshooting comuni
Deploy falliti per timeout SSH
Se rsync fallisce con timeout, verificare:
- Firewall server permette connessioni SSH da IP GitHub Actions
- File
~/.ssh/known_hostssu runner contiene host key server - Aggiungere
StrictHostKeyChecking=noper primo deploy (poi rimuovere)
Permessi file dopo deploy
Rsync può alterare owner/permissions. Aggiungere post-deploy:
ssh $DEPLOY_USER@$DEPLOY_HOST << 'EOF'
cd $DEPLOY_PATH
chown -R www-data:www-data wp-content/
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
EOF
Cache persistente post-deploy
Se modifiche non appaiono, flushare tutte le cache:
- WordPress object cache (wp cache flush)
- CDN/reverse proxy (Cloudflare, Varnish)
- Browser cache (versioning asset con hash)
- OpCache PHP (riavvio PHP-FPM o toccare file config)
FAQ
Quanto tempo serve per implementare CI/CD su un progetto WordPress esistente?
Per un singolo sito WordPress con tema e plugin custom, circa 4-8 ore di lavoro per setup iniziale completo: configurazione repository, creazione workflow GitHub Actions, setup secrets, test deploy su staging e produzione. Per agenzie che replicano su più siti, il tempo scende a 1-2 ore per sito successivo usando template riutilizzabili.
È possibile usare GitHub Actions con hosting condiviso economico?
Sì, ma con limitazioni. L'hosting deve supportare accesso SSH e avere Git installato. Molti hosting condivisi bloccano SSH o hanno restrizioni firewall che impediscono connessioni da IP GitHub Actions. In questi casi, alternative sono: deploy via FTP (meno affidabile), webhook che triggera script sul server, o upgrade a VPS/hosting managed che supporta pienamente SSH.
Come gestire il database in una pipeline CI/CD WordPress?
Il database non va mai sovrascritto automaticamente in produzione. Le strategie corrette sono: mantenere database separati per ambiente (locale, staging, production) sincronizzando solo struttura/schema via migration script, usare WP-CLI per export/import selettivo di configurazioni (con wp option get/set), escludere sempre wp-content/uploads e database dump dal repository Git. Per modifiche schema (nuove tabelle plugin custom), usare migration versionate eseguite post-deploy.
Quale strategia usare per siti WordPress ad alto traffico con zero downtime?
Per siti critici consigliamo blue-green deployment: due installazioni WordPress identiche dietro load balancer, deploy sulla versione inattiva, switch atomico del traffico solo dopo verifica successo. Alternativa più semplice: mettere sito in maintenance mode durante deploy (plugin WP Maintenance Mode attivabile via WP-CLI), deploy veloce, rimozione maintenance mode. Con pipeline ottimizzata, il downtime è sotto i 30 secondi.
GitHub Actions è la scelta migliore o esistono alternative valide?
GitHub Actions è ideale per team già su GitHub per semplicità di integrazione. Alternative valide: GitLab CI/CD (ottimo se usate GitLab, più potente ma curva apprendimento maggiore), Bitbucket Pipelines (se usate Bitbucket), Jenkins (self-hosted, massima flessibilità ma richiede manutenzione server), Buddy Works (UI più friendly, pricing a consumo). Per agenzie, GitHub Actions o GitLab CI/CD sono le scelte più bilanciate tra funzionalità e costi.