Welcome to HowToShipIt — practical how-to guides for developers: code, AI tools, and servers, explained step by step.

WordPress Debug.log: How to Enable It and Read What It Tells You (2026)

What the WordPress debug.log actually is

Your WordPress debug.log is a plain-text file that lives at wp-content/debug.log — once you switch it on. It is not a dashboard, not a plugin, and not a report: it is the raw stream of PHP errors your site produces, written line by line as they happen. Every fatal error, warning, notice, deprecated-function call, and database error gets appended to it with a timestamp, the file that caused it, and the exact line number.

Think of it as WordPress finally answering the question “what actually broke?” The white screen of death tells you nothing. The critical-error email gives you a hint. The debug.log gives you the file name, the line number, and the error message — which is usually everything you need to name the culprit plugin or theme in under a minute.

What it does not capture: JavaScript errors (those live in your browser console), 404s and traffic (those are in your server’s access logs), and anything your host’s PHP configuration intercepts before WordPress boots. It is a PHP-side log for a PHP application, and that is exactly what makes it so useful for troubleshooting.

How to enable the WordPress debug.log

Everything below was verified on October 12, 2026 against the official WordPress debugging handbook, the WordPress core source behaviour it documents, and current 2026 guides. There are three ways to switch logging on. Pick the one that matches your access level.

Method 1: wp-config.php (the canonical way)

Open wp-config.php in your site’s root and add these lines above the line that reads /* That's all, stop editing! Happy blogging. */:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );

Three separate switches, three separate jobs:

Constant What it does Default
WP_DEBUG Master switch. Turns WordPress’s debug mode on — without it, the other two do nothing at all. false
WP_DEBUG_LOG Writes every error, warning, and notice to wp-content/debug.log. Accepts a file path instead of true if you want the log elsewhere. false
WP_DEBUG_DISPLAY Prints errors inside the page HTML. Set it to false on any site a visitor can reach — raw PHP errors leak file paths. true

Two details people get wrong constantly. First, the values must be the booleans true/false, not the quoted strings 'true'/'false' — a quoted 'false' is a non-empty string, which PHP treats as true, so you would accidentally enable debugging. Second, if your host enables display_errors at the PHP configuration level, WP_DEBUG_DISPLAY alone cannot suppress it; the @ini_set( 'display_errors', 0 ) line is the belt-and-suspenders fix.

Method 2: WP-CLI (no file editing)

If you have SSH access, you never need to open wp-config.php by hand. These three commands are idempotent — safe to run repeatedly:

wp config set WP_DEBUG true --raw --type=constant
wp config set WP_DEBUG_LOG true --raw --type=constant
wp config set WP_DEBUG_DISPLAY false --raw --type=constant

The --raw flag stores real booleans instead of strings (remember the quoting trap above). Omit --raw when the value is meant to be a string — for example, pointing the log outside the web root:

wp config set WP_DEBUG_LOG /tmp/wp-errors.log --type=constant

Method 3: A plugin (when you can’t touch wp-config)

On managed hosting or client sites where wp-config.php is off-limits, install a debugging plugin such as Query Monitor (free on WordPress.org) — it surfaces PHP errors, database queries, and hooks per page load in the admin bar. It complements the log rather than replacing it: the log is permanent and catches off-screen errors (AJAX, wp-cron); Query Monitor is immediate and visual.

Once any method is active, reload the broken page once. The file wp-content/debug.log is created on the first logged error — if nothing has errored yet, the file simply does not exist, and that is normal.

Anatomy of a debug.log line

Here is what a real entry looks like (format verified against live 2026 guides):

[12-Oct-2026 09:41:07 UTC] PHP Fatal error:  Uncaught Error: Call to undefined function render_checkout_widget() in /var/www/html/wp-content/plugins/my-shop/includes/widgets.php on line 84

Every line has exactly four parts:

  1. Timestamp — [12-Oct-2026 09:41:07 UTC]. Errors are appended chronologically, so the newest entries are always at the bottom of the file. Start reading there.
  2. Severity — PHP Fatal error, PHP Warning, PHP Notice, PHP Deprecated. Fatal means PHP stopped executing — that is your blank page or 500 error. Warnings and notices mean PHP kept going; they rarely break a page on their own, but a notice repeating thousands of times per load usually means a loop or recursion problem.
  3. Message — what went wrong, in PHP’s words. You do not need to understand all of it; you need the next part.
  4. File path and line number — where it happened. This is the part that solves the case.

The money rule, confirmed across every 2026 reading guide: the folder right after /plugins/ or /themes/ names the culprit. In the example above, /wp-content/plugins/my-shop/ means the plugin my-shop is responsible, and line 84 of widgets.php is the exact spot. You do not need to read code — you need the folder name, because that is the thing you will deactivate.

Path segments are a map:

  • /wp-content/plugins/foo/ — the plugin foo caused it.
  • /wp-content/themes/bar/ — the theme bar caused it.
  • /wp-includes/ or /wp-admin/ — core code threw the error. Core rarely breaks itself; usually a plugin or theme called a core function wrongly. Look at the stack trace’s deeper frames to find who called it.
  • WordPress database error ... — not a PHP error at all; a failed SQL query. The log includes the query that failed, which usually names the offending plugin outright.

Fatal errors are often followed by a Stack trace: block listing #0, #1, #2 frames. Read top-down: #0 is where PHP died, and the deeper frames show the chain of function calls that led there. When the top frame points at core but #2 points at a plugin, the plugin is your suspect.

The error signature cheat sheet

You will see the same dozen messages over and over. Here is what each one actually means and what to do about it:

Signature What it means Your move
Call to undefined function foo() Code calls a function that does not exist — almost always a PHP version incompatibility (the function was removed in a newer PHP). Check the plugin’s WordPress.org page for its tested PHP version; update the plugin or align your PHP version.
Cannot redeclare foo() Two plugins (or a plugin and your theme) define the same function name — a namespace collision from poorly coded software. Deactivate one of the two; keep the better-maintained one.
Allowed memory size of X bytes exhausted One request ate all available PHP memory. Raising the limit is temporary relief, not a fix — a faulty loop, huge import, or pathological query will eat the new limit too. Raise WP_MEMORY_LIMIT to restore service, then find the memory hog via the plugin path in the log.
Maximum execution time of N seconds exceeded Something ran too long — an infinite loop, a remote API call hanging, or a pathological database query. Trace the file path; check for loops and external HTTP calls in that code.
Call to a member function bar() on null Code expected an object and got nothing — a missing dependency or wrong initialization order. Look for a recently deactivated companion plugin, or a hook firing too early.
Cannot modify header information - headers already sent by (output started at ...) Something printed output (even a stray space before <?php) before WordPress sent HTTP headers. The log names the exact file and line where output started — remove the stray whitespace or echo.
WordPress database error ... for query ... A SQL query failed — malformed query from a plugin, or a damaged table. Read the included query; if a plugin table is named, repair or reinstall that plugin’s tables.
Deprecated: Function foo() is deprecated Harmless today, fatal tomorrow — the function still works but is slated for removal. Update the plugin or theme; if it is abandoned, replace it before the next major release removes the function.
Parse error: syntax error A PHP file has broken syntax — almost always a botched manual edit. Revert the last edit to the named file; the line number points at the break.

A real debugging session: white screen to culprit in five minutes

Here is the full loop, exactly as you would run it on a broken site:

  1. Enable logging with the three wp-config.php lines (or the WP-CLI commands). Keep WP_DEBUG_DISPLAY off if the site is live.
  2. Reload the broken page once. One clean reproduction beats a log full of stale noise.
  3. Open wp-content/debug.log over SFTP, SSH (tail -n 50 wp-content/debug.log), or your host’s file manager.
  4. Jump to the bottom. Find the newest PHP Fatal error with a timestamp matching your reload.
  5. Read the folder name after /plugins/ or /themes/. That is your culprit.
  6. Deactivate it — wp plugin deactivate culprit-name over SSH, or rename its folder to culprit-name-disabled over SFTP if wp-admin is unreachable. Renaming a plugin folder is WordPress’s built-in “off switch”: WordPress simply stops loading it.
  7. Reload. If the site is back, you have confirmed the diagnosis. Roll the plugin back to its previous version, or leave it off and find a replacement.

If the culprit is your theme, switch to a default theme (wp theme activate twentytwentyfive) the same way. If the log points at core files with no plugin in the trace, you are likely looking at a corrupted core update — re-install WordPress core from Dashboard → Updates, which replaces core files without touching your content.

When the WordPress debug.log stays empty or lies to you

No file at all? Then logging was never actually enabled. The official handbook is explicit: WP_DEBUG_LOG does nothing unless WP_DEBUG is also true. Check both constants, check they sit above the “stop editing” line, and check you used real booleans. Then reload a page — the file only appears after the first error is logged.

File exists, but your error is not in it? Remember the log’s superpower: it catches off-screen errors — AJAX requests, REST calls, and wp-cron runs that never render a page. If the symptom involves scheduled tasks, also check your host’s server-level error_log; some fatal errors die before WordPress’s logger is even registered. (Related reading: why WordPress cron is fake and how to run real cron — cron-spawned errors are a classic “invisible” category.)

Log flooded with thousands of identical notices? That is the signal, not noise: one notice repeating per page load means a loop or recursion. Fix the loop and the flood stops.

Nothing about your JavaScript bug? Correct — PHP never sees browser-side errors. For block editor or admin JS issues, enable SCRIPT_DEBUG to load unminified core scripts, then use the browser console. The two tools cover the two runtimes.

A warning about security: debug.log sits in a web-accessible directory by default, and it contains your server’s file paths. Treat it like a password while debugging is on, and delete it when you are done. If you debug on production regularly, point WP_DEBUG_LOG at a path outside the web root (like /tmp/wp-errors.log) so the file is never URL-reachable.

Going deeper once the basics work

Three official tools take you past “which plugin broke” into “why is it slow”:

  • SAVEQUERIES — define( 'SAVEQUERIES', true ); stores every database query in $wpdb->queries along with its execution time and the function that called it. The handbook warns it has a real performance impact, so use it in short sessions on staging, never as a permanent setting.
  • Query Monitor — the free developer panel that shows database queries (flagging slow, duplicate, and erroneous ones), PHP errors with call stacks, hooks, and HTTP API calls per page load, filterable by plugin. It is the fastest way to answer “which plugin is making 400 queries on every page.”
  • error_log() for your own code — with WP_DEBUG_LOG active, PHP’s built-in error_log() writes straight to debug.log, which makes it the quick way to trace values through AJAX handlers and cron jobs where var_dump would corrupt the response. The official handbook even documents a write_log() wrapper that pretty-prints arrays and objects — but keep it in a custom plugin or snippet manager, not functions.php.

One more constant worth knowing for local development: WordPress 5.2+ ships a fatal error handler that catches fatals and shows the “critical error” screen instead of a white page. Great on production; on your local machine it can mask the real error while you work. define( 'WP_DISABLE_FATAL_ERROR_HANDLER', true ); turns it off so things break loudly and honestly during development.

Turn it off when you’re done

Debugging left on is a liability: slower pages, a growing log file eating disk, and error details one misconfiguration away from public. When the case is closed:

  1. Set define( 'WP_DEBUG', false ); in wp-config.php (or wp config set WP_DEBUG false --raw --type=constant). With the master switch off, the logging and display constants are inert.
  2. Delete wp-content/debug.log. Do not just leave it sitting there with your server paths inside.
  3. Reload the site and confirm no debug output appears anywhere, including in page source.

Further Reading & References

Debugging constants and log-line formats verified against official WordPress developer documentation on October 12, 2026. Internal guides referenced: fixing the white screen of death, fixing the critical error message, and fixing the database connection error.

Leave a Comment