De WordPress debug log inschakelen en lezen

Een ander KB-artikel zei dat je WP_DEBUG aan moest zetten en debug.log moest lezen. Hier lees je hoe je dat veilig doet, waar het bestand staat, wat elke constante echt doet en hoe je het log afschermt zodat bezoekers je foutmeldingen nooit te zien krijgen.

Je volgde een troubleshooting-artikel. Het zei dat je WP_DEBUG moest aanzetten, WP_DEBUG_LOG op true moest zetten en het log moest lezen om te zien wat er kapot is. Dat is goed advies. Maar het zijn ook vier constanten vol valkuilen als je niet snapt hoe ze samenwerken, en de verkeerde combinatie print elke PHP-fout van je site rechtstreeks in de HTML die je bezoekers zien. Dit artikel loopt het veilige pad: welke constanten je instelt, welke je expliciet uit moet zetten, waar het logbestand belandt, hoe je leest wat erin staat, en hoe je voorkomt dat iemand buiten je team het kan inzien.

Wat de WordPress debug log vastlegt

Goed ingesteld vangt de WordPress debug log elke PHP-fout op die tijdens een request voorkomt: parse errors, fatale fouten, warnings, notices en deprecation messages van PHP zelf, van WordPress core, van je actieve theme en van elke actieve plugin. Elke regel is één entry die door PHP's error_log() functie naar een tekstbestand wordt geschreven, met een UTC-tijdstempel, het foutniveau, de melding en het bestandspad plus regelnummer waar de fout afging.

Het mechanisme staat beschreven in het WordPress debugging handbook en wordt geïmplementeerd in wp_debug_mode(). Die functie draait vroeg in de WordPress-bootstrap en bepaalt wat PHP moet rapporteren en waar die rapporten heen gaan. Als WP_DEBUG true is, roept die functie error_reporting( E_ALL ) aan, dus PHP gaat alles rapporteren. Is WP_DEBUG_LOG daarnaast ook true, dan roept dezelfde functie ini_set( 'log_errors', 1 ) en ini_set( 'error_log', $log_path ) aan, en daarmee belanden al die fouten in een bestand dat je kunt openen en lezen.

Database-fouten zijn een uitzondering: WordPress print SQL-fouten alleen als WP_DEBUG aanstaat, ongeacht wat WP_DEBUG_LOG doet. Dus als je een wpdb-probleem aan het uitzoeken bent, is WP_DEBUG de constante die je nodig hebt, niet alleen het log.

Debugging inschakelen in wp-config.php

De hele configuratie zit in vier constanten in wp-config.php. Ze moeten boven de /* That's all, stop editing! Happy publishing. */ regel staan, want het bestand wordt van boven naar beneden gelezen en alles onder die regel wordt pas verwerkt nadat WordPress al beslissingen heeft genomen over error reporting.

Verbind via SFTP, SSH of je hosting file manager. Open wp-config.php in de WordPress-rootmap. Zoek de regel met define( 'WP_DEBUG', false ); en vervang die door de veilige development-configuratie:

// Zet WordPress debugging aan (E_ALL reporting)
define( 'WP_DEBUG', true );
// Schrijf alle PHP-fouten naar wp-content/debug.log
define( 'WP_DEBUG_LOG', true );
// Verberg fouten in de page output (NIET overslaan)
define( 'WP_DEBUG_DISPLAY', false );
// Voor de zekerheid: zeg ook PHP zelf om niets te tonen
@ini_set( 'display_errors', 0 );

Sla het bestand op en herlaad de kapotte pagina één keer. Je weet dat de configuratie aan staat als het bestand wp-content/debug.log na die reload bestaat (het wordt aangemaakt bij de eerste fout) en regels bevat met een tijdstempel uit het moment dat je de pagina laadde.

De vier constanten doen vier verschillende dingen, en de meeste lezers komen in de problemen door er één in te stellen en aan te nemen dat de rest een veilige default heeft. Dat is niet zo.

  • WP_DEBUG is de hoofdschakelaar. Staat hij uit (dat is de default), dan beperkt WordPress PHP's error reporting tot fatale fouten. Notices en deprecations worden helemaal onderdrukt. Staat hij aan, dan rapporteert PHP E_ALL. Zonder WP_DEBUG = true worden de drie andere constanten hieronder gewoon genegeerd.
  • WP_DEBUG_LOG regelt het loggen naar bestand. Zet hem op true om naar wp-content/debug.log te loggen. Of geef een string-pad mee (bijvoorbeeld '/home/user/private-logs/wp-errors.log') om ergens anders te loggen. Op false laten staan (de default) betekent geen file logging, ook niet als WP_DEBUG aan staat.
  • WP_DEBUG_DISPLAY bepaalt of fouten inline in de HTML-response worden geprint. De default is true. Lees dat nog even: de default is true. Zet je WP_DEBUG = true en vergeet je ook WP_DEBUG_DISPLAY = false neer te zetten, dan wordt elke PHP warning van je site direct in de HTML van je bezoekers gerenderd.
  • @ini_set( 'display_errors', 0 ) is een vangnet. Het zegt PHP zelf om geen fouten te tonen, voor het geval iets tussen WordPress' aanroep van wp_debug_mode() en het moment van de fout de display-instelling overschrijft. Het kost niks en het heeft meer dan één site behoed voor uitlekkende stack traces.

De string-pad-vorm van WP_DEBUG_LOG is in WordPress 5.1 toegevoegd (januari 2019). Daarvoor kon je alleen naar de standaardlocatie loggen. Wil je een eigen pad:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', '/home/user/private-logs/wp-errors.log' );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );

De map die je opgeeft moet al bestaan en schrijfbaar zijn voor de webserver-user. Het bestand zelf wordt bij de eerste fout aangemaakt. Wijs je naar een niet-bestaande map, dan wordt het loggen stilletjes weggeslikt zonder dat je het merkt.

WP_DEBUG_DISPLAY staat standaard op TRUE: bescherm je bezoekers tegen lekken

Dit is het belangrijkste in dit hele artikel. WP_DEBUG_DISPLAY heeft als default true. Niet false. De officiële WordPress-documentatie is daar duidelijk over: "WP_DEBUG_DISPLAY [...] Set this to false to hide errors from being printed. The default is true." Dus je moet hem actief uit zetten, niet actief aan.

Het praktische gevolg: zet je alleen define( 'WP_DEBUG', true ); neer en loop je weg, dan ziet elke bezoeker van je site PHP warnings en notices in de page-HTML staan. Soms midden in de <head>, waardoor de layout breekt. Soms midden in de body, waar bestandspaden, plugin-namen, database table prefixes en af en toe stukjes database-content uit lekken. Zoekmachines crawlen vervolgens die HTML en cachen hem. Niks van dit alles wil je.

De fix is het blok van vier regels hierboven. Zet WP_DEBUG_DISPLAY = false en @ini_set( 'display_errors', 0 ) altijd samen met WP_DEBUG = true neer. Behandel ze als één geheel. Als je maar één snippet uit dit artikel mag onthouden, is het dat blok.

Een handige consequentie: ben je klaar met debuggen, dan is de veiligste opruiming niet om alleen WP_DEBUG weer op false te zetten en de andere drie regels te laten staan. Verwijder alle vier de regels, of laat ze staan en zet de configuratie om naar de productie-veilige vorm onderaan dit artikel.

Waar staat debug.log

Met WP_DEBUG_LOG op true wordt het log geschreven naar wp-content/debug.log. Het exacte pad is WP_CONTENT_DIR . '/debug.log', dat tijdens runtime wordt opgelost. Een eigen WP_CONTENT_DIR constante verplaatst het bestand dus mee. Op een standaard installatie betekent dat:

/pad/naar/jouw/site/wp-content/debug.log

Het bestand wordt aangemaakt bij de eerste fout nadat je logging aanzette. Een ontbrekend bestand betekent niet dat logging stuk is. Het betekent dat er nog geen kwalificerende fout is afgegaan. Herlaad de pagina waarvan je weet dat hij stuk is en kijk nog een keer.

Geef je WP_DEBUG_LOG een string-pad mee, dan wordt dat pad gebruikt. Wat er feitelijk actief is kun je opvragen met WP-CLI of een eenregelige PHP eval:

# Welk error log gebruikt PHP nu daadwerkelijk?
wp eval 'echo ini_get("error_log") . PHP_EOL;'

Dat commando print het absolute pad dat PHP op dit moment gebruikt voor error logging, en dat is het enige antwoord waar je op kunt vertrouwen. Sommige managed hosts overschrijven de error_log ini-directive en sturen alle fouten naar een eigen systeemlog, ongeacht wat WordPress instelt. In dat geval blijft wp-content/debug.log leeg, ook met logging volledig aan. Toont wp eval een pad dat je niet herkent, dan is dat de override van je host en moet je daar aankloppen om het log in te zien.

Andere redenen waarom wp-content/debug.log leeg kan blijven, ook al is er duidelijk iets stuk:

  • WP_DEBUG staat niet op true. Zonder de hoofdschakelaar wordt het hele WP_DEBUG_LOG-mechanisme overgeslagen.
  • De wp-content map is niet schrijfbaar voor de webserver-user.
  • De fatal slaat heel vroeg in de bootstrap toe, voordat wp-settings.php geladen is. Die fouten belanden in het server-niveau PHP error log, niet in het WordPress-log.
  • Quoted booleans: define( 'WP_DEBUG', 'false' ); is truthy, want 'false' is een niet-lege string. Gebruik altijd echte booleans, nooit strings.

Hoe je een PHP-fout in het log leest

Elke regel in debug.log volgt het formaat dat PHP's error_log() functie gebruikt als hij naar een bestand schrijft:

[08-Apr-2026 14:23:11 UTC] PHP Notice:  Undefined variable: foo in /var/www/html/wp-content/plugins/some-plugin/init.php on line 42
[08-Apr-2026 14:23:11 UTC] PHP Warning: include(): Failed opening '/var/www/html/missing.php' for inclusion in /var/www/html/wp-content/themes/my-theme/functions.php on line 17
[08-Apr-2026 14:23:12 UTC] PHP Fatal error:  Uncaught Error: Call to undefined function bar() in /var/www/html/wp-content/plugins/broken-plugin/main.php:15

Lees elke entry van links naar rechts. De tijdstempel tussen de blokhaken is in UTC, niet je lokale tijd. Dan komt het foutniveau, de melding, het bestandspad waar de fout afging en het regelnummer. Het bestandspad is het belangrijkste veld: het vertelt je meteen of het probleem in WordPress core zit (wp-includes/, wp-admin/), in een plugin (wp-content/plugins/<plugin-naam>/), in een theme (wp-content/themes/<theme-naam>/) of in een must-use plugin (wp-content/mu-plugins/).

Het foutniveau zegt je hoe bezorgd je moet zijn:

Niveau Wat het betekent Actie
PHP Notice Niet kritiek: een undefined variable, ontbrekende array key of vergelijkbaar laagdrempelig issue Het oplossen is wel verstandig, vooral bij herhaling. Vaak een plugin-bug.
PHP Warning Er ging iets mis maar de uitvoering ging door Snel oplossen. De code is niet gecrasht maar deed bijna zeker niet wat de bedoeling was.
PHP Deprecated Een functie of feature die in een toekomstige PHP-versie verdwijnt Update de plugin of het theme. PHP 8.x en later breekt uiteindelijk met deze code.
PHP Fatal error De uitvoering stopte Direct oplossen. Dit is wat je white screen of kritieke foutscherm veroorzaakte.
PHP Parse error Syntax error in de broncode Direct oplossen. Bijna altijd een handmatige edit die fout ging in functions.php of wp-config.php.

Heb je meerdere fouten en weet je niet welke ertoe doet, focus dan op de laatste PHP Fatal error of PHP Parse error vlak voor de crash. Notices en warnings kunnen het log wekenlang vullen zonder dat er iets stuk gaat, maar een fatal is wat het request stopzette.

Wil je het log live volgen terwijl je de bug reproduceert, en heb je shell-toegang, dan helpt:

# Stream nieuwe regels zodra ze binnenkomen
tail -f wp-content/debug.log

Druk op Ctrl+C om te stoppen. Dit is de snelste manier om te zien welk bestand precies afgaat als je op een knop klikt of een pagina laadt.

Veelvoorkomende foutpatronen en wat ze betekenen

Een handvol patronen komt zo vaak voor dat herkennen ervan de diagnose flink versnelt.

PHP Fatal error: Allowed memory size of N bytes exhausted. Het script is door zijn geheugen heen. De oorzaak is bijna altijd een plugin of import-actie die te veel werk in één request probeert te doen. Het gerichte fix-pad staat in allowed memory size exhausted in WordPress.

PHP Parse error: syntax error, unexpected token "...". Een .php bestand is malformed, bijna altijd door een handmatige edit. PHP weigert het bestand uit te voeren. De diagnose staat in syntax error, unexpected: een PHP parse error in WordPress oplossen.

PHP Fatal error: Uncaught Error: Call to undefined function .... De genoemde functie bestaat niet op het moment dat hij wordt aangeroepen. Meestal omdat een plugin of theme verwacht dat een andere plugin eerst geladen is, omdat de autoloader stuk is, of omdat een functie tussen versies hernoemd is.

PHP Fatal error: Maximum execution time of N seconds exceeded. Het script draaide langer dan de ingestelde tijdslimiet. Vaak een trage database query of een loop die niet meer stopt. Combineer dit met maximum execution time exceeded in WordPress.

PHP Warning: Cannot modify header information - headers already sent by .... Iets heeft output geprint voordat WordPress een HTTP-header probeerde te sturen. Het bestandspad in de melding noemt waar die ongewilde output vandaan kwam, en dat is bijna altijd een verdwaalde spatie voor <?php of na ?> in een theme- of plugin-bestand.

PHP Deprecated: Function X is deprecated. De genoemde functie verdwijnt in een toekomstige PHP-versie. Update de plugin of het theme dat hem gebruikt. Vandaag breekt het je site nog niet, maar na de volgende PHP-upgrade wel.

Wat al deze patronen gemeen hebben: het bestandspad in de melding is het antwoord. WordPress core laat de fout afgaan, maar wp-content/plugins/<naam>/... in dat pad is de plugin die je moet updaten, uitschakelen of vervangen.

Publieke toegang tot debug.log blokkeren

wp-content/debug.log zit standaard binnen je webroot. Dat betekent dat het bestand bereikbaar is op https://jouwsite.nl/wp-content/debug.log vanaf elk willekeurig adres op het internet. Iedereen die de URL kent of raadt kan het bestand downloaden, je bestandspaden lezen, je database-tabelnamen, fragmenten van database-content uit foutmeldingen, je plugin-lijst, en soms gebruikersnamen of sessiedetails. Dit is een echt datalek en zoekmachines hebben dit soort bestanden in het verleden gewoon geïndexeerd.

Blokkeer publieke toegang altijd voordat je logging aanzet, niet erna.

De simpelste fix op Apache is een Files-regel in het .htaccess-bestand in je site-root:


    Require all denied

Dat gebruikt de moderne Require-syntax uit Apache 2.4. Zit je op een veel oudere Apache, dan werkt de oude vorm ook nog:


    Order Allow,Deny
    Deny from all

Op Nginx voeg je een location-block toe aan je server config (je hebt server-toegang nodig of een hosting-paneel waar je Nginx-config in kunt zetten):

location = /wp-content/debug.log {
    deny all;
}

De netste fix, als je host het toelaat, is om het log helemaal buiten de webroot te plaatsen via de string-pad-vorm van WP_DEBUG_LOG:

define( 'WP_DEBUG_LOG', '/home/user/private-logs/wp-errors.log' );

Een pad buiten de docroot kan überhaupt niet via HTTP opgevraagd worden, dus een .htaccess-regel is dan niet nodig. Dit is de aanpak die ik op elke site die ik beheer gebruik, juist omdat het de faalmodus wegneemt waarin iemand de .htaccess-regel vergeet of een plugin-update hem overschrijft.

Verifieer de bescherming door https://jouwsite.nl/wp-content/debug.log in een incognito-tab te openen nadat je logging hebt ingeschakeld. Je weet dat het werkt als je een 403 Forbidden of 404 Not Found krijgt in plaats van de bestandsinhoud. Doe dit elke keer, voordat je een debug-sessie afsluit en wegloopt.

Debug logging uit op productie

Debug logging is een development- en incident-response-tool. Het hoort niet permanent aan te staan op een live site. Het schrijft een bestand bij elk request waarin een fout optreedt. Het onthult informatie over je stack aan iedereen die het log kan lezen. En het kan je site zelfs trager maken als een drukke plugin het log volpompt met notices op elke page load.

Ben je klaar met debuggen, zet wp-config.php dan om naar de productie-veilige configuratie:

// Productie: expliciete, veilige defaults
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_LOG', false );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'log_errors', 'On' );
@ini_set( 'display_errors', 'Off' );

De twee ini_set-aanroepen onderaan horen bij de productieconfiguratie, niet bij de development-versie. Ze vertellen PHP zelf om fouten te loggen naar het log-target dat de host heeft geconfigureerd (meestal een server-niveau error log) en om nooit fouten in de HTML-response te printen. Ook al zet een plugin ergens anders een setting om, deze regels zorgen dat fouten netjes in het server-log belanden, waar jij of je host ze achteraf kunt lezen.

Alle andere constanten die wp-config.php accepteert, naast deze vier, staan in mijn wp-config.php settings reference. Ga je voor het eerst aan dat bestand zitten? Dan is dat het artikel om eerst te lezen.

Blokkeert je host .htaccess-edits, blokkeert hij SFTP, of maakt hij het bewerken van wp-config.php onpraktisch (sommige "drag and drop" hosting-omgevingen doen dit), dan moet je eerst bij je host aankloppen voor directe bestandstoegang voordat je iets uit dit artikel kunt toepassen.

Alternatief: Query Monitor voor development

Ben je aan het debuggen op een staging-omgeving en zie je foutmeldingen liever in de admin-toolbar dan dat je een logbestand zit te tail-en, dan is Query Monitor van John Blackbourn de standaard-tool. Versie 4.0.1, uitgebracht op 2026-04-07, draait op WordPress 6.9.4 en PHP 7.4 tot en met 8.5, en heeft meer dan 200.000 actieve installaties.

Query Monitor haakt direct in PHP's error handler, dus het vangt fouten realtime op bij elke page load en toont ze in de admin-toolbar mét call stack en de plugin of het theme die ervoor verantwoordelijk is. En heel belangrijk: hij doet dat zonder dat WP_DEBUG = true nodig is en zonder dat je WP_DEBUG_DISPLAY überhaupt nodig hebt. Foutmeldingen zijn alleen zichtbaar voor ingelogde administrators, nooit voor bezoekers. Daarmee is hij veiliger dan WP_DEBUG_DISPLAY op een staging-site die anonieme gebruikers kunnen bereiken, en sneller in het gebruik dan een logbestand tail-en terwijl je door admin-pagina's klikt.

Query Monitor en WP_DEBUG_LOG sluiten elkaar niet uit. Ik draai ze allebei tegelijk als ik een lastige bug aan het opsporen ben: Query Monitor voor het live overzicht van wat er gebeurt terwijl ik klik, het debug-log voor het historische overzicht waar ik achteraf doorheen kan grep-pen.

Een paar waarschuwingen. Installeer Query Monitor niet op een productie-site. Het voegt meetbare overhead toe op elke request, en hoewel het probeert zijn data te verbergen voor niet-admins, is de veiligste positie om hem helemaal buiten productie te houden. Het is een development-tool. Schakel hem uit (of liever: deïnstalleer hem) zodra je klaar bent. Datzelfde geldt voor SAVEQUERIES, de WordPress-constante die elke database query in $wpdb->queries opslaat voor inspectie: handig in development, duur in productie.

Wijst het debug-log uit dat het probleem eigenlijk een fatal in wp-config.php of een must-use plugin is die crasht voordat WordPress het kritieke foutscherm kan tonen, dan staat het diagnose-pad in White Screen of Death in WordPress. Toont het log dat het kritieke foutscherm netjes afgaat zoals bedoeld maar wil je de recovery-flow uitgelegd hebben, dan is er heeft zich een kritieke fout voorgedaan op deze site de juiste volgende stop.

WordPress onderhoud zonder omkijken?

Ik regel updates, backups en beveiliging, en houd performance strak—zodat storingen en traagheid niet terugkomen.

Bekijk WordPress onderhoud

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.