WP-Cron vs Cron Reale: Come Automatizzare WordPress in Produzione [2026]

25 agosto 202614 minPerformance

Introduzione

Il WP-Cron è il sistema di pianificazione integrato in WordPress, ma non è un vero cron job. Nella nostra esperienza di gestione di oltre 50 siti WordPress per agenzie, abbiamo visto che il WP-Cron nativo causa problemi reali: post programmati non pubblicati, backup saltati, processi WooCommerce bloccati. In questa guida spieghiamo la differenza tra WP-Cron e cron reale, perché disabilitare WP-Cron in produzione è una best practice, e come configurare correttamente un cron server per WordPress.

Se gestisci siti WordPress per clienti, questa ottimizzazione rientra nella ottimizzazione delle performance WordPress e nella gestione multi-sito di agenzie. È una delle modifiche che applichiamo per primi su ogni nuovo sito client.

Sommario (TL;DR)

  • WP-Cron non è un vero cron: si attiva solo quando un visitatore carica una pagina
  • Questo significa che siti a basso traffico perdono task programmati
  • Siti ad alto traffico sprecano risorse eseguendo WP-Cron troppo spesso
  • La soluzione: disabilitare WP-Cron e usare un cron job server-side
  • Per task pesanti, usare Action Scheduler invece di WP-Cron diretto
  • Configurazione completa per Nginx, Apache, WP-CLI e multi-sito

Cos’è WP-Cron e Come Funziona

WP-Cron è il sistema di pianificazione delle attività integrato in WordPress. Il nome è fuorviante: non è un cron job nel senso Unix del termine. È invece un sistema di “pseudo-cron” che funziona in questo modo:

  1. Ogni volta che un visitatore carica una pagina, WordPress controlla se ci sono task pianificati in scadenza
  2. Se ci sono task in coda, WordPress esegue una richiesta HTTP interna a wp-cron.php
  3. Il file wp-cron.php esegue tutti i task in scadenza
  4. L’esecuzione avviene in modo asincrono, senza bloccare il caricamento della pagina per il visitatore

Questo approccio ha un vantaggio evidente: non richiede configurazione server. WordPress “funziona e basta”. Ma ha anche limiti significativi che diventano problemi reali in produzione.

Il meccanismo interno di WP-Cron

Quando WordPress riceve una richiesta, durante l’hook init, controlla la tabella options per il valore cron. Questo valore contiene un array serializzato di tutti i task pianificati con i rispettivi timestamp. Se un task ha un timestamp passato o uguale al momento corrente, viene eseguito.

Il controllo avviene tramite la funzione wp_cron(), definita in wp-includes/cron.php. Questa funzione invia una richiesta HTTP non bloccante a wp-cron.php?doing_wp_cron=TIMESTAMP utilizzando wp_remote_post().

WP-Cron vs Cron Reale: Differenze Chiave

Caratteristica WP-Cron Cron Server (Unix)
Attivazione Basata sul traffico (page load) Basata sul tempo (daemon cron)
Affidabilità Dipende dal traffico: niente visite = niente cron Indipendente dal traffico
Precisione temporale Approssimativa (dipende quando arriva un visitatore) Precisione al minuto
Impatto sulle performance Aggiunge overhead a ogni page load Zero overhead sul traffico web
Siti a basso traffico Task persi frequentemente Esecuzione garantita
Siti ad alto traffico Esecuzioni multiple contemporanee Esecuzione singola e controllata
Configurazione richiesta Nessuna (automatico) Configurazione server necessaria
Controllo sui task Limitato alla API WordPress Controllo completo a livello sistema
Timeout Eredita i limiti PHP di esecuzione Configurabile indipendentemente
Logging Non disponibile nativamente Log di sistema completi

Perché Disabilitare WP-Cron in Produzione

1. Siti a basso traffico: task persi

Se un sito riceve poche visite, WP-Cron potrebbe non attivarsi mai. Un post programmato per le 9:00 del mattino potrebbe essere pubblicato alle 14:00, quando finalmente arriva un visitatore. Per agenzie che gestiscono siti aziendali o siti per studi legali con traffico modesto, questo è un problema ricorrente.

2. Siti ad alto traffico: overhead sulle performance

Su siti con molto traffico, WP-Cron viene controllato a ogni page load. Anche se WordPress utilizza un transient per evitare esecuzioni troppo frequenti (di default, un controllo ogni 60 secondi), il controllo stesso aggiunge overhead al database. Su un sito che riceve 1000 visite contemporanee, il sistema esegue comunque centinaia di controlli inutili.

3. Esecuzioni sovrapposte

WP-Cron utilizza un lock basato su transient, ma in condizioni di alto traffico o con cache aggressiva, le richieste sovrapposte a wp-cron.php possono causare esecuzioni duplicate degli stessi task. Questo può portare a backup doppi, post pubblicati due volte, o email inviate multipli volte.

4. Timeout e memory limit

WP-Cron eredita i limiti PHP della richiesta web. Se un task richiede più memoria o tempo del limite configurato, viene interrotto senza completare. Con un cron server, puoi configurare limiti di memoria e timeout indipendenti.

5. Sicurezza: attacchi DDoS su wp-cron.php

wp-cron.php è un endpoint pubblico accessibile da chiunque. Gli attaccanti possono inviare migliaia di richieste a questo file per sovraccaricare il server, causando un denial of service. Questo vettore di attacco è documentato e reale: nella nostra esperienza, è uno dei primi endpoint che proteggiamo con strategie di protezione DDoS.

Come Disabilitare WP-Cron

Disabilitare WP-Cron è semplice. Modifica il file wp-config.php aggiungendo questa riga prima di /* That's all, stop editing! */:

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

Questa costante dice a WordPress di non eseguire il controllo dei task pianificati durante il caricamento delle pagine. I task rimangono nella coda, ma non vengono eseguiti automaticamente. Sarà il cron server a eseguirli chiamando wp-cron.php a intervalli regolari.

⚠️ Attenzione: Disabilitare WP-Cron senza configurare un cron server significa che nessun task pianificato verrà mai eseguito. Post programmati, backup automatici, aggiornamenti pianificati e notifiche email smetteranno di funzionare. Disabilita WP-Cron SOLO dopo aver configurato il cron server.

Configurare il Cron Server per WordPress

Configurazione base con crontab

La configurazione minima consiste nell’eseguire wp-cron.php ogni 5 minuti tramite crontab di sistema:

# Modifica crontab dell'utente web
crontab -e -u www-data

# Aggiungi questa riga per eseguire WP-Cron ogni 5 minuti
*/5 * * * * php /var/www/sito-wordpress/wp-cron.php >/dev/null 2>&1

Questo metodo funziona, ma ha uno svantaggio: esegue wp-cron.php direttamente con PHP CLI, che potrebbe non avere lo stesso ambiente della richiesta web.

Configurazione con WP-CLI (consigliata)

Il metodo più affidabile è usare WP-CLI per eseguire i cron event:

# Crontab: esegue tutti i task WP-Cron ogni 5 minuti
*/5 * * * * cd /var/www/sito-wordpress && wp cron event run --due --allow-root >/dev/null 2>&1

Vantaggi dell’approccio WP-CLI:

  • Esegue nell’ambiente corretto di WordPress
  • Permette di eseguire solo i task in scadenza (--due)
  • Supporta il debug con --debug
  • Non richiede accesso HTTP a wp-cron.php

Configurazione con curl (per ambienti isolati)

In alcuni setup (es. container Docker), potrebbe essere necessario eseguire WP-Cron via HTTP:

# Esegui wp-cron.php via HTTP ogni 5 minuti
*/5 * * * * curl -s -o /dev/null "https://sito-esempio.it/wp-cron.php?doing_wp_cron" >/dev/null 2>&1

Configurazione avanzata con timeout e memory limit

Per task pesanti (backup, sincronizzazioni), imposta limiti personalizzati:

# Cron con memory limit e timeout personalizzati
*/5 * * * * php -d memory_limit=512M -d max_execution_time=300 /var/www/sito-wordpress/wp-cron.php >/dev/null 2>&1

Configurazione Multi-Sito per Agenzie

Per le agenzie che gestiscono multipli siti WordPress, la configurazione manuale di cron per ogni sito non è scalabile. Ecco due approcci che usiamo in produzione.

Script bash per multi-sito

#!/bin/bash
# /usr/local/bin/wp-cron-multi.sh
# Esegue WP-Cron per tutti i siti WordPress nell'array

SITES=(
  "/var/www/cliente1.it"
  "/var/www/cliente2.it"
  "/var/www/cliente3.it"
  "/var/www/cliente4.it"
)

for SITE in "${SITES[@]}"; do
  if [ -f "$SITE/wp-load.php" ]; then
    cd "$SITE"
    /usr/local/bin/wp cron event run --due --allow-root --quiet 2>/dev/null
    echo "$(date): Cron eseguito per $SITE" >> /var/log/wp-cron-multi.log
  fi
done

Configura il crontab per eseguire lo script:

# Esegui cron multi-sito ogni 5 minuti
*/5 * * * * /usr/local/bin/wp-cron-multi.sh

Approccio con file di configurazione

Per gestire 50+ siti, un file di configurazione è più manutenibile:

#!/bin/bash
# /usr/local/bin/wp-cron-runner.sh
# Legge la lista siti da un file e esegue cron per ognuno

SITES_FILE="/etc/wp-cron-sites.conf"

while IFS= read -r site_path; do
  # Salta commenti e righe vuote
  [[ "$site_path" =~ ^#.*$ ]] && continue
  [[ -z "$site_path" ]] && continue

  if [ -f "$site_path/wp-load.php" ]; then
    cd "$site_path"
    /usr/local/bin/wp cron event run --due --allow-root --quiet 2>&1 | \
      while read -r line; do
        echo "$(date '+%Y-%m-%d %H:%M:%S') [$site_path] $line"
      done >> /var/log/wp-cron-runner.log
  fi
done < "$SITES_FILE"

File /etc/wp-cron-sites.conf:

# Lista siti WordPress per cron runner
# Un percorso per riga, commenti con #
/var/www/cliente1.it
/var/www/cliente2.it
/var/www/cliente3.it
/var/www/cliente4.it
/var/www/cliente5.it

Proteggere wp-cron.php

Anche dopo aver disabilitato WP-Cron nativo, il file wp-cron.php rimane accessibile pubblicamente. È buona pratica bloccare l’accesso diretto.

Nginx

# Blocca accesso diretto a wp-cron.php
location = /wp-cron.php {
  # Permetti solo localhost
  allow 127.0.0.1;
  allow ::1;
  deny all;

  fastcgi_pass unix:/run/php/php8.3-fpm.sock;
  fastcgi_index wp-cron.php;
  include fastcgi_params;
  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}

Apache (.htaccess)

# Blocca accesso diretto a wp-cron.php
<Files "wp-cron.php">
  Require ip 127.0.0.1
  Require ip ::1
</Files>

Per maggiori configurazioni server, consulta la nostra guida su WordPress su Nginx e Nginx + PHP-FPM avanzato.

Action Scheduler: Alternativa per Task Pesanti

Per task che richiedono molto tempo (backup completi, importazioni massicce, sincronizzazioni), né WP-Cron né cron server sono ideali. La soluzione è Action Scheduler, una libreria sviluppata da WooCommerce e utilizzata da plugin come WP Rocket, Yoast SEO e AutomateWoo.

Cos’è Action Scheduler

Action Scheduler è un sistema di code asincrone per WordPress. Invece di eseguire un task immediatamente, lo mette in una coda e lo processa in batch tramite richieste HTTP in background. Questo evita i timeout PHP perché ogni batch ha un limite di tempo proprio.

Vantaggi rispetto a WP-Cron

  • Nessun timeout: i task vengono eseguiti in batch, non in una singola esecuzione
  • Retry automatico: se un task fallisce, viene riprogrammato
  • Logging integrato: ogni azione ha uno stato (pending, running, complete, failed)
  • Interfaccia admin: pagina di amministrazione per monitorare le code
  • API semplice: as_enqueue_async_action()

Esempio: schedulare un backup con Action Scheduler

// Registra un'azione personalizzata
add_action('agencypilot_backup_client', 'agencypilot_run_backup');

function agencypilot_run_backup($site_id) {
  // Logica di backup
  $backup = new AgencyPilot_Backup($site_id);
  $backup->run();

  if ($backup->failed) {
    // Il fallimento viene gestito automaticamente da Action Scheduler
    throw new Exception('Backup fallito: ' . $backup->error);
  }
}

// Schedula il backup ogni giorno alle 3:00
if (!as_next_scheduled_action('agencypilot_backup_client', ['site_id' => 42])) {
  as_schedule_recurring_action(
    strtotime('tomorrow 3:00 AM'),
    DAY_IN_SECONDS,
    'agencypilot_backup_client',
    ['site_id' => 42],
    'agencypilot-backups'
  );
}

Debug di WP-Cron: Strumenti e Tecniche

Listare tutti i task pianificati

# WP-CLI: lista tutti i cron event
wp cron event list

# Output esempio:
# +----------------------+--------+----------+----+-----+-------------+
# | hook                 | status | time     | rn | rec | schedule    |
# +----------------------+--------+----------+----+-----+-------------+
# | wp_version_check     | due    | 0        | 0  | 1   | twicedaily  |
# | wp_update_plugins    | due    | 0        | 0  | 1   | twicedaily  |
# | wp_update_themes     | due    | 0        | 0  | 1   | twicedaily  |
# | agencypilot_backup   | due    | 0        | 0  | 1  | daily       |
# | wp_scheduled_delete  | due    | 0        | 0  | 1  | daily       |
# +----------------------+--------+----------+----+-----+-------------+

Eseguire un singolo task

# Esegui un singolo cron event
wp cron event run wp_version_check

# Esegui tutti i task in scadenza
wp cron event run --due

Verificare la configurazione

# Testa se WP-Cron è disabilitato
wp config get DISABLE_WP_CRON

# Verifica le schedule disponibili
wp cron schedule list

# Controlla i task falliti con Action Scheduler
wp action-scheduler list --status=failed

Plugin per debug

Se preferisci un’interfaccia visiva, il plugin WP Crontrol permette di visualizzare, modificare ed eseguire tutti i cron event direttamente dalla dashboard admin. È uno strumento utile per diagnosticare task persi o programmati incorrectly.

Configurazione Production-Ready: Checklist Completa

Step 1: Disabilita WP-Cron nativo

// wp-config.php
define('DISABLE_WP_CRON', true);

Step 2: Configura cron server

# crontab -e -u www-data
# Esegui WP-Cron ogni 5 minuti con WP-CLI
*/5 * * * * cd /var/www/sito-wordpress && wp cron event run --due --allow-root --quiet >/dev/null 2>&1

Step 3: Blocca accesso pubblico a wp-cron.php

Configura Nginx o Apache per bloccare l’accesso esterno a wp-cron.php (vedi sezioni sopra).

Step 4: Migra task pesanti ad Action Scheduler

Identifica i task che richiedono più di 30 secondi e migra ad Action Scheduler per evitare timeout.

Step 5: Configura logging

# Aggiungi al crontab: log degli errori
*/5 * * * * cd /var/www/sito-wordpress && wp cron event run --due --allow-root 2>> /var/log/wp-cron-errors.log

Step 6: Monitora

Controlla regolarmente i log e usa wp cron event list per verificare che non ci siano task bloccati o falliti.

Configurazione per Docker e Container

Se usi WordPress con Docker, la configurazione del cron richiede un approccio diverso perché i container Docker non hanno un demone cron nativo.

Soluzione 1: Sidecar container

# docker-compose.yml
services:
  wordpress:
    image: wordpress:php8.3-fpm
    volumes:
      - wordpress_data:/var/www/html
    environment:
      - DISABLE_WP_CRON=true

  cron:
    image: wordpress:cli
    depends_on:
      - wordpress
    volumes:
      - wordpress_data:/var/www/html
    entrypoint: |
      sh -c '
        while true; do
          sleep 300
          wp cron event run --due --allow-root --path=/var/www/html
        done
      '

volumes:
  wordpress_data:

Soluzione 2: Host cron con curl

# Sul host, esegui cron verso il container
*/5 * * * * docker exec wordpress-container wp cron event run --due --allow-root --quiet

Problemi Comuni e Soluzioni

Post programmati non vengono pubblicati

Se i post programmati rimangono in stato “pianificato”, il problema è quasi sempre WP-Cron non funzionante. Verifica:

  1. Se DISABLE_WP_CRON è true, controlla che il cron server sia configurato
  2. Esegui wp cron event list per verificare se publish_future_post è in coda
  3. Esegui manualmente: wp cron event run publish_future_post
  4. Verifica i permessi del file wp-cron.php

Task WooCommerce bloccati

WooCommerce utilizza Action Scheduler per processare ordini, email e sincronizzazioni. Se i task sono bloccati:

  1. Vai su WooCommerce > Status > Scheduled Actions
  2. Filtra per status “failed”
  3. Esegui wp action-scheduler run --group=woocommerce
  4. Se il problema persiste, svuota la tabella actionscheduler_logs

Backup che non partono

Se usi plugin come UpdraftPlus o BackWPup, il scheduling dipende da WP-Cron. Dopo aver disabilitato WP-Cron nativo, assicurati che il cron server esegua abbastanza frequentemente. Per backup, raccomandiamo di usare una strategia di backup 3-2-1 con cron dedicato.

Best Practices per Agenzie

Frequenza del cron

La frequenza consigliata è ogni 5 minuti. Più frequente non porta vantaggi (WordPress interno ha un transient di 60 secondi). Meno frequente può causare ritardi nei task.

Separazione dei task

Per agenzie con multipli siti, separa i task per priorità:

# Task critici ogni 5 minuti
*/5 * * * * /usr/local/bin/wp-cron-critical.sh

# Task di manutenzione ogni ora
0 * * * * /usr/local/bin/wp-cron-maintenance.sh

# Backup ogni giorno alle 3:00
0 3 * * * /usr/local/bin/wp-cron-backup.sh

Monitoraggio proattivo

Usa strumenti di automazione WordPress per monitorare lo stato del cron. Un check semplice:

#!/bin/bash
# Controlla se ci sono task in coda da più di 1 ora
WARN=$(wp cron event list --due --format=count --allow-root 2>/dev/null)
if [ "$WARN" -gt 10 ]; then
  # Invia alert via webhook
  curl -s -X POST "$DISCORD_WEBHOOK" \
    -H "Content-Type: application/json" \
    -d "{\"content\": \"⚠️ WP-Cron backlog: $WARN task in coda su $(hostname)\"}"
fi

FAQ

Disabilitare WP-Cron rallenta WordPress?

No, al contrario. Disabilitare WP-Cron rimuove l’overhead del controllo dei task ad ogni page load, migliorando leggermente le performance. Il tempo di risposta del server (TTFB) migliora perché WordPress non deve controllare la coda dei task durante ogni richiesta.

Posso usare WP-Cron e cron server insieme?

Non è consigliato. Se entrambi i sistemi sono attivi, rischi esecuzioni duplicate che possono causare problemi come backup doppi o post pubblicati due volte. Disabilita sempre WP-Cron nativo quando configuri un cron server.

Quanto spesso devo eseguire il cron server?

Ogni 5 minuti è la frequenza ottimale. WordPress utilizza un transient di 60 secondi per evitare esecuzioni troppo ravvicinate, quindi eseguire il cron ogni minuto è inutile. Ogni 5 minuti garantisce che i task vengano eseguiti con un ritardo massimo di 5 minuti, che è accettabile per qualsiasi caso d’uso.

WP-Cron funziona con cache plugin?

I plugin di cache a pagina intera (WP Rocket, W3 Total Cache, etc.) possono interferire con WP-Cron. Se la pagina è servita dalla cache, WordPress non viene caricato e WP-Cron non viene controllato. Questo è un altro motivo per disabilitare WP-Cron nativo e usare un cron server.

Come verifico che il cron server funzioni?

Esegui wp cron event list e controlla che i timestamp dei task non siano troppo vecchi. Se i task hanno timestamp nel passato remoto (più di 1 ora), il cron non sta funzionando. Puoi anche installare il plugin WP Crontrol per un monitoraggio visivo.

Su hosting condiviso posso disabilitare WP-Cron?

Sui hosting condivisi (es. Aruba, Hostinger) potresti non avere accesso al crontab di sistema. In questo caso, verifica se il pannello di controllo offre un’opzione cron. Se non è disponibile, mantieni WP-Cron nativo attivo. Su VPS dedicati o managed hosting come Kinsta o Cloudways, il cron server è sempre disponibile.

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