Il debug log di WordPress è spento di default. Quando un sito cliente va in bianco, il tuo primo istinto è aprire wp-config.php e inserire define('WP_DEBUG', true);. Il problema? Su 50 siti, farlo a mano ogni volta ti costa ore. E se lo lasci acceso, il file debug.log cresce fino a riempire il disco. In questa guida vediamo come configurare il logging WordPress in modo professionale: errori separati dalle notice, rotazione automatica dei log, invio a un servizio centralizzato, e come leggere quello che WordPress ti sta dicendo.
Questo articolo si integra con la nostra guida alla sicurezza WordPress per agenzie e con il monitoraggio log WordPress per agenzie — il logging è il primo passo per un monitoraggio serio.
TL;DR
WP_DEBUG,WP_DEBUG_LOGeWP_DEBUG_DISPLAYsono tre costanti indipendenti — non una sola- Imposta
WP_DEBUG_LOGatruesu tutti i siti di produzione, ma con rotazione automatica del file - Usa
error_reporting(E_ERROR | E_WARNING | E_PARSE)per filtrare le notice infinite dei plugin scadenti - Per agenzie con 10+ siti: invia i log a un servizio centralizzato (Graylog, Papertrail, o anche solo un file per sito con
WP_DEBUG_LOGpersonalizzato) - Non lasciare mai
WP_DEBUG_DISPLAYattivo in produzione — mostra errori HTML agli utenti
Come Funziona il Debug WordPress (e Perché Quasi Tutti Sbagliano)
WordPress ha tre costanti per il debug, e il 90% degli sviluppatori ne usa una sola. Ecco cosa fanno davvero:
| Costante | Default | Cosa fa | Produzione |
|---|---|---|---|
WP_DEBUG |
false |
Attiva il debug mode di WordPress. Controlla anche SCRIPT_DEBUG e WP_DEBUG_DISPLAY indirettamente |
true (sempre) |
WP_DEBUG_LOG |
false |
Scrive gli errori in wp-content/debug.log |
true (con rotazione) |
WP_DEBUG_DISPLAY |
true |
Mostra gli errori a schermo (HTML). Disabilitato quando WP_DEBUG è false |
false (sempre) |
SCRIPT_DEBUG |
false |
Carica i file JS/CSS non minimizzati. Utile solo per debug frontend | false |
L’errore più comune: impostare WP_DEBUG a true senza toccare WP_DEBUG_DISPLAY. Risultato: gli errori PHP compaiono nell’HTML del sito. I clienti lo notano. A volte sono errori innocui (notice PHP 8.2 su plugin non aggiornati), ma l’impatto visivo è disastroso.
La configurazione corretta per produzione:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
@ini_set('display_errors', 0);
Sì, WP_DEBUG a true in produzione. Non è pericoloso finché WP_DEBUG_DISPLAY è false. WordPress scriverà tutto nel file debug.log senza mostrare nulla all’utente. Questo ti dà visibilità su problemi che altrimenti scopriresti solo quando un cliente si lamenta.
Configurazione Avanzata: Separare Errori da Notice
Il problema di WP_DEBUG è che scrive TUTTO nel log. Su un sito con 30 plugin, il file debug.log si riempie di notice inutili (“Undefined index: foo in /var/www/wp-content/plugins/some-plugin/functions.php on line 42”). Risultato: gli errori veri (fatal error, warning su query SQL) si perdono nel rumore.
La soluzione è filtrare il livello di error_reporting direttamente nel wp-config.php:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
@ini_set('display_errors', 0);
// Filtra: solo errori, warning e parse errors — no notice, no deprecated
error_reporting(E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING);
Se stai facendo un audit di un sito nuovo e vuoi vedere tutto (incluso notice e deprecated), temporaneamente alza il livello:
error_reporting(E_ALL);
Ma non lasciarlo così in produzione. Le notice di WordPress 6.x su PHP 8.2+ sono decine per ogni pagina load, anche su installazioni pulite.
Come Personalizzare il Percorso del File debug.log
Di default WordPress scrive in wp-content/debug.log. Su un server con 50 siti, vuoi i log in un posto solo, non sparsi in 50 cartelle wp-content. Puoi cambiare il percorso definendo WP_DEBUG_LOG come path assoluto invece che boolean:
// Tutti i log di questo sito in /var/log/wordpress/sito-nomecliente.log
define('WP_DEBUG_LOG', '/var/log/wordpress/' . basename(ABSPATH) . '.log');
In questo modo ogni sito ha il suo file di log in /var/log/wordpress/. Facile da grep, facile da ruotare con logrotate.
Assicurati che l’utente del web server (di solito www-data su Debian/Ubuntu) abbia i permessi di scrittura:
sudo mkdir -p /var/log/wordpress
sudo chown www-data:www-data /var/log/wordpress
sudo chmod 755 /var/log/wordpress
Rotazione Automatica dei Log con logrotate
Il debug.log non ha rotazione nativa. Su un sito con molto traffico, un file da 500MB in una settimana è normale. Un file di 5GB rallenta il server quando PHP cerca di scrivere alla fine. La soluzione è logrotate:
# /etc/logrotate.d/wordpress-debug
/var/log/wordpress/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
copytruncate
size 50M
maxsize 500M
}
Cosa fa questa configurazione:
daily: controlla ogni giornorotate 14: tiene 14 giorni di logsize 50M: ruota anche se il file supera 50MB (indipendentemente dal giorno)copytruncate: copia il file e tronca quello originale — non serve riavviare PHP o Nginxcompress: comprime i log vecchi con gzip
Testa la configurazione:
sudo logrotate -d /etc/logrotate.d/wordpress-debug
Se vedi errori di permessi, controlla che logrotate giri come root (di default nel cron di sistema) o che l’utente www-data possa scrivere nella cartella di destinazione.
Catturare gli Errori Fatali Prima che il Cliente Li Noti
Il debug.log passivo è meglio di niente, ma non ti avvisa quando qualcosa si rompe. Per un’agenzia con 50+ siti, serve un monitoraggio attivo.
L’approccio più semplice: uno script bash che legge i log ogni 5 minuti e invia un alert se trova errori nuovi. Se usi già un sistema di monitoring come Uptime Kuma o Pingdom (di cui abbiamo parlato nel nostro articolo sul monitoraggio uptime con AI), puoi integrarlo.
#!/bin/bash
# /usr/local/bin/wp-debug-check.sh
# Controlla i debug.log di tutti i siti e invia alert su nuovi errori fatali
LOG_DIR="/var/log/wordpress"
STATE_FILE="/var/lib/wp-debug-check/last-seen"
ALERT_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
mkdir -p "$(dirname "$STATE_FILE")"
for logfile in "$LOG_DIR"/*.log; do
[ -f "$logfile" ] || continue
sitename=$(basename "$logfile" .log)
last_line=$(wc -l < "$logfile" 2>/dev/null || echo 0)
prev_line=$(cat "$STATE_FILE/$sitename" 2>/dev/null || echo 0)
if [ "$last_line" -gt "$prev_line" ]; then
new_errors=$(tail -n +$((prev_line + 1)) "$logfile" | grep -i "fatal\|parse error\|warning" | head -5)
if [ -n "$new_errors" ]; then
payload=$(jq -n --arg text "🔴 $sitename: nuovi errori in debug.log\n\`\`\`\n$new_errors\n\`\`\`" '{text: $text}')
curl -s -X POST "$ALERT_WEBHOOK" -H "Content-Type: application/json" -d "$payload"
fi
fi
echo "$last_line" > "$STATE_FILE/$sitename"
done
Metti questo script in crontab ogni 5 minuti:
# crontab -e
*/5 * * * * /usr/local/bin/wp-debug-check.sh
Usare WP-CLI per Leggere i Log Velocemente
Se hai accesso SSH, wp-cli può aiutarti a leggere i log senza aprire il file. Non esiste un comando nativo, ma puoi crearne uno breve. Leggi il nostro articolo su WP-CLI per agenzie per la configurazione completa.
Comandi utili per leggere i log da terminale:
# Ultimi 20 errori del sito
tail -20 /var/log/wordpress/sito-cliente.log
# Cerca tutti i fatal error in tutti i siti
grep -ri "fatal" /var/log/wordpress/ | tail -20
# Conta gli errori per sito nell'ultima settimana
for f in /var/log/wordpress/*.log; do
count=$(grep -c "$(date +%Y-%m-%d | sed 's/-/\\-/g')" "$f" 2>/dev/null || echo 0)
echo "$(basename $f): $count errori"
done | sort -t: -k2 -rn
# Usa wp-cli per vedere se WP_DEBUG è attivo su un sito
wp config get WP_DEBUG --path=/var/www/sito-cliente
wp config get WP_DEBUG_LOG --path=/var/www/sito-cliente
Logging Strutturato: Oltre il debug.log Nativo
Il debug.log di WordPress è plain text. Va bene per debug veloce, ma per un’agenzia con 50+ siti serve qualcosa di più strutturato. Due opzioni pratiche:
Opzione 1: Monolog via mu-plugin
Se i tuoi siti usano Composer (e dovrebbero), installa monolog/monolog e crea un mu-plugin che logga a un file strutturato:
<?php
// wp-content/mu-plugins/structured-logging.php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Formatter\JsonFormatter;
if (!class_exists('Monolog\Logger')) {
return; // Monolog non installato, fallback al debug.log nativo
}
add_action('init', function() {
$logger = new Logger('wordpress');
$handler = new StreamHandler('/var/log/wordpress/' . basename(ABSPATH) . '.json.log');
$handler->setFormatter(new JsonFormatter());
$logger->pushHandler($handler);
// Registra handler per errori PHP
set_error_handler(function($errno, $errstr, $errfile, $errline) use ($logger) {
$logger->warning($errstr, [
'errno' => $errno,
'file' => $errfile,
'line' => $errline,
'url' => $_SERVER['REQUEST_URI'] ?? '',
'ip' => $_SERVER['REMOTE_ADDR'] ?? '',
]);
return false; // Lascia che il handler nativo continui
});
// Registra handler per fatal error
register_shutdown_function(function() use ($logger) {
$error = error_get_last();
if ($error && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR])) {
$logger->critical('Fatal error: ' . $error['message'], [
'file' => $error['file'],
'line' => $error['line'],
]);
}
});
});
I log in JSON possono essere inviati a Graylog, ELK, o qualsiasi sistema di log aggregation. Ogni entry ha timestamp, livello, messaggio e contesto strutturato.
Opzione 2: Invio a un servizio esterno
Se non vuoi gestire un server di log, servizi come Papertrail o Better Stack offrono log management gratuito (o economico) per piccoli volumi. Configura syslog sul server e invia i log via UDP:
# /etc/rsyslog.d/30-wordpress.conf
# Invia i log WordPress a Papertrail
*.* @logsX.papertrailapp.com:XXXXX
Papertrail ti dà ricerca full-text, alert, e dashboard in 5 minuti di setup. Per un’agenzia con 50 siti, il piano gratuito (50MB/mese) basta per iniziare.
Errori Comuni nel Debug WordPress (e Come Evitarli)
1. Lasciare WP_DEBUG_DISPLAY attivo in produzione
Questo è l’errore #1. Gli errori PHP compaiono nell’HTML del sito. Non solo è brutto per il cliente, ma può esporre percorsi del server e informazioni sensibili. WP_DEBUG_DISPLAY deve SEMPRE essere false in produzione.
2. Non ruotare il file debug.log
Abbiamo visto file debug.log da 12GB. PHP diventa lento a scrivere, il disco si riempie, il sito va in 502. Configura logrotate il giorno uno, non dopo il primo incidente.
3. Attivare WP_DEBUG solo quando c’è un problema
Se WP_DEBUG è spento, non logghi niente. Quando il cliente chiama dicendo “il sito era bianco ieri alle 15:00”, non hai nessun log da guardare. Attiva il logging il primo giorno, non quando serve. Il costo è zero (un file di testo che ruota), il beneficio è enorme.
4. Ignorare i warning dei plugin
I warning PHP non rompono il sito, ma indicano problemi. “Undefined index” su un plugin significa che il plugin non gestisce i casi limite. “Deprecated” significa che alla prossima major release di PHP, il sito si rompe. Monitora i warning per programmare gli aggiornamenti prima che diventano emergenze.
5. Usare plugin di error logging invece della configurazione nativa
Esistono plugin come “Error Log Monitor” o “WP Debugging” che aggiungono UI per il debug. Per un’agenzia sono una dipendenza in più da mantenere, un altro plugin da aggiornare, un altro punto di fallimento. La configurazione nativa in wp-config.php + logrotate è più robusta e non richiede accesso admin al sito.
Checklist Configurazione Logging per 50+ Siti
Se stai configurando il logging su molti siti, ecco la sequenza operativa che usiamo noi:
- Crea la cartella centralizzata:
/var/log/wordpress/con permessiwww-data - Configura logrotate: crea
/etc/logrotate.d/wordpress-debugcon la configurazione sopra - Modifica wp-config.php di ogni sito: imposta
WP_DEBUG,WP_DEBUG_LOG(con path personalizzato),WP_DEBUG_DISPLAY - Aggiungi error_reporting filter:
E_ERROR | E_WARNING | E_PARSEper non annegare nelle notice - Verifica con un test: genera un errore volontario (es.
trigger_error('test', E_USER_WARNING);) e controlla che appaia nel log - Configura alert: script cron o integrazione con sistema di monitoring esistente
- Documenta il setup: per ogni sito, annota dove si trova il log e come accedervi
Per applicare la configurazione su 50 siti in batch, usa uno script bash con WP-CLI:
#!/bin/bash
# /usr/local/bin/wp-enable-logging.sh
# Applica la configurazione di debug a tutti i siti in un server
SITES=$(find /var/www -maxdepth 2 -name "wp-config.php" -exec dirname {} \;)
for site_dir in $SITES; do
site_name=$(basename "$site_dir")
log_path="/var/log/wordpress/${site_name}.log"
# Usa wp-cli per modificare wp-config.php
wp config set WP_DEBUG true --raw --path="$site_dir" --quiet
wp config set WP_DEBUG_LOG "$log_path" --path="$site_dir" --quiet
wp config set WP_DEBUG_DISPLAY false --raw --path="$site_dir" --quiet
# Aggiungi error_reporting se non presente
if ! grep -q "error_reporting" "$site_dir/wp-config.php"; then
sed -i "/define('WP_DEBUG_DISPLAY'/a error_reporting(E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING);" "$site_dir/wp-config.php"
fi
echo "✓ $site_name → $log_path"
done
echo "Done. Verifica con: tail -f /var/log/wordpress/*.log"
FAQ — Debug WordPress per Agenzie
WP_DEBUG rallenta il sito?
No, se WP_DEBUG_DISPLAY è false. Il costo di scrivere una riga in un file di log è trascurabile (meno di 1ms). Il vero rallentamento arriva quando WP_DEBUG_DISPLAY è true e PHP inlinea gli errori nell’HTML, aumentando il tempo di render e rovinando il layout.
Dove si trova il file debug.log?
Di default in wp-content/debug.log. Puoi cambiarlo definendo WP_DEBUG_LOG come stringa (path assoluto) invece che boolean. Per agenzie conviene centralizzare in /var/log/wordpress/nome-sito.log.
Come leggo il debug.log senza accesso SSH?
Se non hai SSH, scarica il file via SFTP o usa un plugin come “Debug Log Manager” che mostra il log nell’admin di WordPress. Per un’agenzia, però, SSH è non-opzionale. Senza SSH non puoi configurare logrotate, grep, o inviare log a un servizio esterno.
Qual è la differenza tra WP_DEBUG e error_reporting?
WP_DEBUG controlla il sistema di debug di WordPress (constant checks nel codice core, SCRIPT_DEBUG). error_reporting controlla il livello di errori PHP che vengono loggati. Sono indipendenti: puoi avere WP_DEBUG true ma error_reporting a solo E_ERROR per loggare solo i fatal.
Devo preoccuparmi che il debug.log contenga informazioni sensibili?
Sì. Il debug.log può contenere query SQL, variabili di sessione, e a volte password in chiaro se un plugin fa var_dump di dati sensibili. Per questo motivo, il file deve avere permessi 600 (solo l’utente del web server) e non deve mai essere accessibile via web. Se usi Nginx, aggiungi un blocco:
location ~* /debug\.log$ {
deny all;
return 404;
}