WordPress Cron per Agenzie: Sostituire WP-Cron con Cron Server per Affidabilità [2026]

6 settembre 202614 minPerformance

Il sistema WordPress Cron (WP-Cron) è il motore di pianificazione delle attività automatizzate che gestisce pubblicazione di post, controllo aggiornamenti, backup programmati e pulizia del database. Per le agenzie che gestiscono decine di siti clienti, affidarsi al WP-Cron nativo significa accettare un rischio silenzioso: task saltati, backup non eseguiti, pubblicazioni in ritardo. In questa guida spieghiamo come sostituire WP-Cron con cron di server reale per ottenere affidabilità prevedibile, ridurre il carico su ogni page load e proteggere wp-cron.php da abusi esterni.

TL;DR: WP-Cron esegue i task programmati ad ogni page load, non su un orologio reale. Su siti con poco traffico i task vengono saltati; su siti con molto traffico rallentano le pagine. La soluzione è disabilitare WP-Cron via wp-config.php (define('DISABLE_WP_CRON', true);) e configurare un cron job di sistema che richiama wp-cron.php ogni 5-15 minuti. Per le agenzie multi-sito, uno script bash centralizzato può gestire 50+ siti con un’unione configurazione.

Come Funziona WP-Cron: Il Pseudo-Cron di WordPress

WP-Cron non è un vero cron job. È un meccanismo PHP che WordPress ha creato per simulare il comportamento di cron sui sistemi Unix, perché molti hosting condivisi non offrono accesso al sistema scheduler. Secondo la documentazione ufficiale WordPress, WP-Cron funziona controllando, ad ogni page load, una lista di task programmati per vedere cosa deve essere eseguito. Qualsiasi task in scadenza viene lanciato durante quel page load.

Questo significa che WP-Cron non gira continuamente come un cron di sistema: viene attivato solo quando un visitatore carica una pagina. Se programmiamo un task per le 14:00 e nessuno visita il sito fino alle 17:00, il task non verrà eseguito fino alle 17:00. Al contrario, su un sito ad alto traffico, WP-Cron viene lanciato ad ogni singola richiesta, moltiplicando il carico sul server.

Per le agenzie che gestiscono siti WordPress per clienti, questo comporta due problemi opposti:

  • Siti a basso traffico: task critici (backup, pubblicazioni programmate, scadenze coupon) vengono saltati silenziosamente
  • Siti ad alto traffico: WP-Cron compete per le risorse PHP con le richieste reali degli utenti, rallentando TTFB e Core Web Vitals

Perché Disabilitare WP-Cron: I 3 Problemi Principali

Nella nostra esperienza di gestione di oltre 200 siti WordPress per agenzie, abbiamo identificato tre problemi ricorrenti con WP-Cron nativo:

1. Task Saltati su Siti a Basso Traffico

Un sito aziendale con 50 visite al giorno potrebbe non caricare una pagina per ore. Se un backup è programmato per le 3:00 di notte e il primo visitatore arriva alle 8:30, il backup partirà alle 8:30 — con 5 ore e mezza di ritardo. Abbiamo visto casi di backup giornalieri effettivamente eseguiti ogni 2-3 giorni perché il traffico notturno era insufficiente.

2. Carico su Ogni Page Load

Ogni volta che un utente carica una pagina, WordPress esegue wp-cron.php per controllare se ci sono task in coda. Su un sito con 100.000 page view al mese, significa 100.000 esecuzioni di controllo, la maggior parte delle quali non fa nulla ma consuma comunque risorse PHP. Questo impatta il Core Web Vitals, in particolare il TTFB (Time To First Byte).

3. Vulnerabilità di Sicurezza

Il file wp-cron.php è pubblicamente accessibile. Qualsiasi persona può inviare una richiesta a https://tuodominio.it/wp-cron.php e forzare l’esecuzione del cron. Su un sito bersagliato, questo può essere usato per saturare le risorse del server con richieste ripetute — un attacco di tipo DoS semplice ma efficace. Disabilitando WP-Cron si chiude completamente questa porta, come spiegato anche da Kinsta nella loro guida sulla disabilitazione di WP-Cron.

Disabilitare WP-Cron: Procedura Step-by-Step

La procedura richiede due passaggi in ordine preciso: prima configurare il cron di server, poi disabilitare WP-Cron. Se inverti l’ordine, i task smettono di funzionare silenziosamente.

Step 1: Configurare il Cron Job di Server

Accedi al server via SSH e modifica il crontab:

# Modifica il crontab dell'utente web
crontab -e

# Aggiungi questa riga per eseguire wp-cron.php ogni 5 minuti
*/5 * * * * wget -q -O - https://tuodominio.it/wp-cron.php?doing_wp_cron >/dev/null 2>&1

In alternativa, usando PHP CLI (più efficiente perché non genera traffico HTTP):

# Usa il path assoluto del tuo sito
*/5 * * * * /usr/bin/php /var/www/tuodominio.it/wp-cron.php?doing_wp_cron >/dev/null 2>&1

# Oppure con WP-CLI (consigliato per agenzie)
*/5 * * * * cd /var/www/tuodominio.it && wp cron event run --due-now --allow-root >/dev/null 2>&1

La variante con WP-CLI è preferibile per le agenzie perché:

  • Non genera traffico HTTP interno
  • Permette di eseguire solo i task effettivamente in scadenza (--due-now)
  • Mostra output leggibile per il debugging
  • Funziona anche se il sito ha restrizioni su wp-cron.php a livello di firewall

Step 2: Disabilitare WP-Cron in wp-config.php

Modifica il file wp-config.php nella root del sito e aggiungi questa riga prima della riga /* That's all, stop editing! */:

/** Disabilita WP-Cron nativo - usa cron di server */
define( 'DISABLE_WP_CRON', true );

Da questo momento, WordPress non eseguirà più wp-cron.php ad ogni page load. Tutti i task pianificati verranno eseguiti esclusivamente dal cron job di sistema configurato allo Step 1.

Configurazione Cron per Agenzie Multi-Sito

Per un’agenzia che gestisce 50+ siti WordPress, configurare un cron job per ogni sito è inefficiente. Ecco uno script bash che centralizza la gestione:

#!/bin/bash
# /root/scripts/wp-cron-runner.sh
# Esegue wp-cron per tutti i siti gestiti dall'agenzia

SITES_FILE="/root/scripts/sites-list.txt"
LOG_FILE="/var/log/wp-cron-runner.log"
WP_CLI="/usr/local/bin/wp"

# Legge la lista dei siti (un dominio per riga)
while IFS= read -r site_path; do
    # Salta righe vuote e commenti
    [[ -z "$site_path" || "$site_path" == \#* ]] && continue

    if [ -d "$site_path" ]; then
        # Verifica che WP-Cron sia disabilitato
        if grep -q "DISABLE_WP_CRON" "$site_path/wp-config.php" 2>/dev/null; then
            cd "$site_path"
            $WP_CLI cron event run --due-now --allow-root --quiet 2>&1 | \
                while read -r line; do
                    echo "$(date '+%Y-%m-%d %H:%M:%S') [$site_path] $line" >> "$LOG_FILE"
                done
        else
            echo "$(date '+%Y-%m-%d %H:%M:%S') [$site_path] WARNING: DISABLE_WP_CRON non impostato" >> "$LOG_FILE"
        fi
    else
        echo "$(date '+%Y-%m-%d %H:%M:%S') [$site_path] ERROR: directory non trovata" >> "$LOG_FILE"
    fi
done < "$SITES_FILE"

# Rotazione log automatica (mantieni 30 giorni)
find /var/log/ -name "wp-cron-runner.log" -mtime +30 -delete

Il file sites-list.txt contiene i path assoluti dei siti:

# Lista siti gestiti - un path per riga
/var/www/cliente1.it
/var/www/cliente2.com
/var/www/cliente3.it
/var/www/staging.cliente4.it

Crontab per l’esecuzione ogni 5 minuti:

# Cron multi-sito per agenia - ogni 5 minuti
*/5 * * * * /root/scripts/wp-cron-runner.sh

Verificare che il Cron Funzioni: WP-CLI e Debug

Dopo aver configurato il cron di server, è fondamentale verificare che i task vengano eseguiti correttamente. WP-CLI offre comandi specifici per ispezionare e testare il sistema cron:

# Lista tutti i task programmati con prossimo esecuzione
wp cron event list --allow-root

# Esempio output:
# +-------------------+---------------------+-----------------+----------+
# | hook              | next_run_relative   | next_run        | schedule |
# +-------------------+---------------------+-----------------+----------+
# | wp_version_check  | now                 | 2026-08-10 12:00 | 12 hours |
# | wp_update_plugins | now                 | 2026-08-10 12:00 | 12 hours |
# | wp_update_themes  | now                 | 2026-08-10 12:00 | 12 hours |
# | publish_future    | 1 min               | 2026-08-10 12:01 | 5 min    |
# +-------------------+---------------------+-----------------+----------+

# Esegui manualmente tutti i task in scadenza
wp cron event run --due-now --allow-root

# Esegui uno specifico hook
wp cron event run wp_version_check --allow-root

# Elimina un task programmato
wp cron event delete wp_update_themes --allow-root

Per il debug avanzato, puoi abilitare il log di WP-Cron aggiungendo questo snippet in wp-config.php:

/** Log di debug per WP-Cron */
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG', true );

// In functions.php del theme o mu-plugin:
add_action( 'wp_cron_triggered', function() {
    error_log( 'WP-Cron eseguito: ' . date( 'Y-m-d H:i:s' ) );
    $events = _get_cron_array();
    error_log( 'Task in coda: ' . count( $events ) );
} );

WP-Cron vs Cron Server: Tabella Comparativa

Caratteristica WP-Cron Nativo Cron di Server
Attivazione Ad ogni page load Su orologio reale (es. ogni 5 min)
Affidabilità (basso traffico) ❌ Task saltati ✅ Esecuzione garantita
Performance (alto traffico) ❌ Carico ad ogni visita ✅ Zero impatto su page load
Sicurezza ❌ wp-cron.php pubblico ✅ Endpoint non accessibile
Precisione temporale Dipende dal traffico ±1 minuto dal schedule
Configurazione Nessuna richiesta Accesso SSH + crontab
Scaling multi-sito ❌ Manuale per ogni sito ✅ Script bash centralizzato
Recupero task falliti ✅ Esegue al prossimo page load ⚠️ Richiede monitoraggio

Action Scheduler: L’Alternativa per Task Pesanti

Per task che richiedono molto tempo (importazioni dati, generazione report, sincronizzazione ERP), né WP-Cron né un cron di server semplice sono sufficienti. WP-Cron ha un timeout di esecuzione legato al limite PHP (max_execution_time, tipicamente 30-60 secondi), e i task lunghi vengono interrotti.

Action Scheduler è una libreria sviluppata da WooCommerce/SkyVerge che gestisce code di task asincroni con retry automatico, parallelismo controllato e logging strutturato. È usata da plugin come WooCommerce per gestire ordini ricorrenti, email di abbandono carrello e sincronizzazioni.

// Registra uno schedule personalizzato con Action Scheduler
// Nel file functions.php o mu-plugin

add_action( 'init', function() {
    if ( ! class_exists( 'ActionScheduler' ) ) {
        return;
    }

    // Schedule ricorrente ogni ora
    if ( ! as_has_scheduled_action( 'agencypilot_daily_report' ) ) {
        as_schedule_recurring_action(
            time(),
            HOUR_IN_SECONDS,
            'agencypilot_daily_report'
        );
    }
} );

// Handler del task
add_action( 'agencypilot_daily_report', function() {
    // Genera report per tutti i clienti
    $clients = get_option( 'agencypilot_clients', array() );
    foreach ( $clients as $client_id ) {
        // Task pesante: può richiedere minuti
        agencypilot_generate_client_report( $client_id );
    }
    
    // Log esecuzione
    error_log( 'Report generati per ' . count( $clients ) . ' clienti' );
} );

Action Scheduler gestisce automaticamente:

  • Retry: se un task fallisce, viene ritentato fino a 5 volte con backoff esponenziale
  • Concurrency: esegue un task per volta di default, con configurazione per parallelismo
  • Logging: ogni esecuzione viene registrata con status, durata e eventuali errori
  • Timeout: non ha il limite max_execution_time perché usa la coda del database

Intervalli Cron Personalizzati per Agenzie

WordPress supporta nativamente intervalli di hourly, twicedaily e daily. Per le agenzie possono servire intervalli personalizzati (es. ogni 5 minuti, ogni 15 minuti). Ecco come registrarli:

// In functions.php o mu-plugin
add_filter( 'cron_schedules', function( $schedules ) {
    // Aggiunge intervallo ogni 5 minuti
    $schedules['every_five_minutes'] = array(
        'interval' => 5 * MINUTE_IN_SECONDS,
        'display'  => 'Ogni 5 minuti',
    );
    
    // Aggiunge intervallo ogni 15 minuti
    $schedules['every_fifteen_minutes'] = array(
        'interval' => 15 * MINUTE_IN_SECONDS,
        'display'  => 'Ogni 15 minuti',
    );
    
    // Aggiunge intervallo ogni settimana
    $schedules['weekly'] = array(
        'interval' => 7 * DAY_IN_SECONDS,
        'display'  => 'Ogni settimana',
    );
    
    return $schedules;
} );

// Registra un evento ricorrente con intervallo personalizzato
register_activation_hook( __FILE__, function() {
    if ( ! wp_next_scheduled( 'agencypilot_health_check' ) ) {
        wp_schedule_event( time(), 'every_five_minutes', 'agencypilot_health_check' );
    }
} );

// Handler dell'evento
add_action( 'agencypilot_health_check', function() {
    // Controlla uptime dei siti clienti
    $sites = get_option( 'agencypilot_monitored_sites', array() );
    foreach ( $sites as $site_url ) {
        $response = wp_remote_get( $site_url, array(
            'timeout' => 10,
        ) );
        
        if ( is_wp_error( $response ) ) {
            // Invia alert a Discord/Slack
            agencypilot_send_alert( $site_url, 'DOWN', $response->get_error_message() );
        } elseif ( wp_remote_retrieve_response_code( $response ) !== 200 ) {
            agencypilot_send_alert( $site_url, 'ERROR', 'HTTP ' . wp_remote_retrieve_response_code( $response ) );
        }
    }
} );

// Pulizia alla disattivazione
register_deactivation_hook( __FILE__, function() {
    $timestamp = wp_next_scheduled( 'agencypilot_health_check' );
    if ( $timestamp ) {
        wp_unschedule_event( $timestamp, 'agencypilot_health_check' );
    }
} );

Monitoring del Cron: Come Rilevare Task Falliti

Quando si disabilita WP-Cron nativo, diventa cruciale monitorare che il cron di server stia effettivamente eseguendo i task. Ecco uno script di monitoring che invia un alert se il cron non ha girato negli ultimi 15 minuti:

#!/bin/bash
# /root/scripts/cron-monitor.sh
# Monitora che wp-cron venga eseguito regolarmente

SITES_FILE="/root/scripts/sites-list.txt"
ALERT_WEBHOOK="https://discord.com/api/webhooks/YOUR_WEBHOOK"
MAX_MINUTES=15

while IFS= read -r site_path; do
    [[ -z "$site_path" || "$site_path" == \#* ]] && continue
    
    if [ -d "$site_path" ]; then
        cd "$site_path"
        
        # Controlla l'ultimo esecuzione del cron via WP-CLI
        LAST_RUN=$(/usr/local/bin/wp option get _transient_last_cron_run --allow-root 2>/dev/null)
        
        if [ -z "$LAST_RUN" ]; then
            # Fallback: controlla la data dell'ultimo transient
            LAST_RUN=$(/usr/local/bin/wp option get cron_last_run --allow-root --format=json 2>/dev/null)
        fi
        
        if [ -n "$LAST_RUN" ]; then
            MINUTES_AGO=$(( ($(date +%s) - $LAST_RUN) / 60 ))
            if [ $MINUTES_AGE -gt $MAX_MINUTES ]; then
                # Invia alert Discord
                curl -s -X POST "$ALERT_WEBHOOK" \
                    -H "Content-Type: application/json" \
                    -d "{\"content\": \"⚠️ CRON ALERT: $site_path non eseguito da $MINUTES_AGO minuti (limite: $MAX_MINUTES)\"}"
            fi
        fi
    fi
done < "$SITES_FILE"

Aggiungi il monitoraggio al crontab ogni 15 minuti:

# Monitoraggio cron - ogni 15 minuti
*/15 * * * * /root/scripts/cron-monitor.sh

Proteggere wp-cron.php con .htaccess e Nginx

Anche dopo aver disabilitato WP-Cron, è buona pratica bloccare l’accesso pubblico a wp-cron.php. Se il cron di server usa WP-CLI (consigliato), il file non deve essere raggiungibile da esterno.

Apache (.htaccess)

# Blocca accesso pubblico a wp-cron.php
<Files "wp-cron.php">
    # Permetti solo richieste locali
    Require ip 127.0.0.1
    # Permetti IP del server se diverso
    Require ip 192.168.1.100
</Files>

Nginx

# Nel server block del sito
location = /wp-cron.php {
    # Permetti solo richieste locali
    allow 127.0.0.1;
    allow 192.168.1.100;
    deny all;
    
    # Passa a PHP-FPM
    fastcgi_pass unix:/var/run/php/php8.3-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    include fastcgi_params;
}

Questo chiude completamente la superficie di attacco: nessuno dall’esterno può forzare l’esecuzione del cron, e il hardening di sicurezza del sito ne risulta rinforzato.

Hosting Managed WordPress: Cosa Cambia

Molti provider di hosting managed WordPress (Kinsta, WP Engine, Cloudways) offrono cron di server preconfigurato. Secondo Kinsta, ad esempio, un server cron job gira su tutti i siti ogni 15 minuti, quindi i task continueranno a essere eseguiti anche dopo la disabilitazione di WP-Cron.

Tuttavia, 15 minuti possono non essere sufficienti per tutte le esigenze. Per pubblicazioni programmate con precisione al minuto, backup più frequenti o integrazioni API real-time, configura il tuo cron job personalizzato:

Hosting Provider Cron Predefinito Custom Cron Metodo
Kinsta Ogni 15 min ✅ Su richiesta MyKinsta dashboard
WP Engine Ogni 5 min (alternativo) ✅ Via supporto Support ticket
Cloudways Ogni 5 min ✅ Self-service Cron Job Manager
VPS/Dedicated Configurabile ✅ Completo SSH + crontab
Hosting condiviso Spesso limitato ⚠️ Variabile cPanel cron

Errori Comuni nella Configurazione del Cron

Nella nostra esperienza abbiamo visto ripetersi gli stessi errori nelle agenzie che si approcciano per la prima volta alla sostituzione di WP-Cron:

  1. Disabilitare WP-Cron prima di configurare il cron di server — i task smettono immediatamente di funzionare senza errori visibili. Configura sempre il cron di server per primo.
  2. Dimenticare doing_wp_cron nella URL — senza il parametro ?doing_wp_cron, alcune configurazioni di WordPress rifiutano l’esecuzione del cron.
  3. Usare wget senza -q — il cron job salva l’output HTML in un file, riempiendo il disco nel tempo. Sempre redirigere output a /dev/null.
  4. Non impostare DISABLE_WP_CRON prima di /* That's all, stop editing! */ — WordPress ignora le costanti definite dopo questa riga.
  5. Eseguire il cron ogni minuto — eccessivo per la maggior parte dei siti. Ogni 5 minuti è il compromesso ideale tra reattività e carico server.

FAQ — Domande Frequenti su WordPress Cron per Agenzie

Disabilitare WP-Cron rompe i plugin che usano task programmati?

No. I plugin utilizzano l’API di WP-Cron (wp_schedule_event) per registrare i task nel database. Quando disabiliti WP-Cron nativo, i task rimangono registrati ma vengono eseguiti dal cron di server invece che ad ogni page load. Il plugin non nota alcuna differenza — l’esecuzione diventa solo più affidabile.

Ogni quanto dovrei eseguire il cron job di server?

Ogni 5 minuti è il valore consigliato per la maggior parte dei siti WordPress. Per siti con task time-sensitive (pubblicazioni programmate al minuto, e-commerce con ordini ricorrenti), puoi usare ogni 1-2 minuti. Per siti statici o portfolio, ogni 15 minuti è sufficiente.

Come verifico che il cron di server stia funzionando?

Usa wp cron event list --allow-root per vedere i task e la loro prossima esecuzione programmata. Confronta next_run con l’ora attuale: se c’è un ritardo superiore all’intervallo del cron, qualcosa non funziona. In alternativa, installa un plugin come WP Crontrol per un’interfaccia visiva nel dashboard WordPress.

Posso usare cron di server su hosting condiviso?

Dipende dal provider. La maggior parte offre accesso a cron job tramite cPanel o Plesk, ma con limitazioni (es. intervallo minimo di 5 o 15 minuti, limite di numero di cron job). Per agenzie che gestiscono molti siti, un VPS o hosting dedicato è fortemente consigliato per avere pieno controllo.

Action Scheduler sostituisce completamente WP-Cron?

No, Action Scheduler è complementare. WP-Cron gestisce i task leggeri e frequenti (controllo aggiornamenti, pubblicazione post). Action Scheduler è indicato per task pesanti (>30 secondi), task con retry complessi e code parallele. Molti siti usano entrambi: cron di server per WP-Cron e Action Scheduler per i task intensivi.

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