CI/CD WordPress con GitHub Actions: Guida Completa

1 giugno 20265 minGuide
In breveAI

Guida completa per implementare pipeline CI/CD WordPress con GitHub Actions: setup repository, workflow automatizzati, deploy production-ready, testing e best practice per agenzie.

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@v4 per 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_hosts su runner contiene host key server
  • Aggiungere StrictHostKeyChecking=no per 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.

Gestisci i siti WordPress dei tuoi clienti?

AgencyPilot ti dà report AI, uptime monitoring, backup e portale clienti in un’unica dashboard. Gratis per 3 siti.

Prova gratis
Leggi anche
Tutti gli articoli
Tutti gli articoli