When something breaks on your WordPress site and all you see is a white screen or a vague error message, the debug log is your best friend. It records every PHP error, warning, and notice that WordPress generates behind the scenes. Instead of guessing what went wrong, you read the log and know exactly which file, which line, and which function caused the problem.
This guide covers the complete WordPress debugging toolkit: enabling WP_DEBUG, configuring the debug log file, reading and interpreting log entries, writing custom log functions, managing log file size, and using Query Monitor for real-time debugging. Every technique works on any WordPress installation, from local development to production servers. If you are also dealing with database bloat from revisions, see our guide on how to limit and clean up WordPress post revisions.
The WordPress Debug Constants Explained
WordPress has three debug-related constants that you set in wp-config.php. Each controls a different aspect of error reporting. Understanding what each one does prevents common mistakes like displaying PHP errors to your visitors.
WP_DEBUG
This is the master switch. When set to true, WordPress enables PHP error reporting for notices, warnings, and fatal errors. It also activates deprecated function notices, which tell you when your theme or plugins use functions that WordPress plans to remove in future versions.
// Enable WordPress debug mode
define( 'WP_DEBUG', true );
With WP_DEBUG set to false (the default), WordPress suppresses all PHP errors. This is correct for production sites, but it means problems happen silently. You will not know about deprecation warnings, undefined variable notices, or non-fatal errors until something actually breaks.
WP_DEBUG_LOG
This constant tells WordPress to write all debug output to a log file instead of (or in addition to) displaying it on screen. The default log file location is wp-content/debug.log.
// Write errors to wp-content/debug.log
define( 'WP_DEBUG_LOG', true );
You can also specify a custom file path. This is useful when you want to keep the log outside the web root for security, or when you need separate logs for different sites on a multisite installation:
// Custom log file path (outside web root)
define( 'WP_DEBUG_LOG', '/home/username/logs/wordpress-debug.log' );
WP_DEBUG_DISPLAY
This controls whether PHP errors appear on screen in your browser. On production sites, you always want this set to false. Displaying raw PHP errors to visitors exposes file paths, database table names, and other information that attackers can exploit.
// Never show errors on screen
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );
The @ini_set line is a safety net that forces PHP itself to suppress display errors, even if your hosting environment has display_errors enabled in php.ini.
The Production-Safe Debug Configuration
Here is the configuration you should use on live sites. It captures every error in the log file without showing anything to visitors:
// Production-safe debugging — log everything, display nothing
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );
// Optional: log database queries
define( 'SAVEQUERIES', true );
Place these lines in wp-config.php before the line that says /* That's all, stop editing! */. Order matters in wp-config.php — constants defined after WordPress loads will not take effect.
The SAVEQUERIES constant is optional. When enabled, WordPress stores every database query along with execution time and the calling function in the $wpdb->queries array. This is invaluable for identifying slow queries but adds memory overhead, so disable it when you are done debugging.
Reading and Interpreting the Debug Log
The debug log file at wp-content/debug.log is a plain text file. Each entry includes a timestamp, the error severity level, the message, and the file and line number where the error occurred.
Here is what a typical log entry looks like:
[17-Feb-2026 10:23:45 UTC] PHP Notice: Undefined variable $user_meta in /var/www/html/wp-content/plugins/my-plugin/includes/class-user.php on line 142
[17-Feb-2026 10:23:45 UTC] PHP Warning: Invalid argument supplied for foreach() in /var/www/html/wp-content/themes/mytheme/functions.php on line 87
[17-Feb-2026 10:23:46 UTC] PHP Fatal error: Uncaught Error: Call to undefined function custom_function() in /var/www/html/wp-content/plugins/broken-plugin/init.php on line 23
Error Severity Levels
| Level | Meaning | Action Required |
|---|---|---|
| Notice | Non-critical issue like an undefined variable. Code still runs. | Fix when possible — notices often indicate logic errors that cause bugs under certain conditions |
| Warning | Something unexpected happened but execution continues. Common with incorrect function arguments. | Fix promptly — warnings frequently cause incorrect output or data corruption |
| Fatal error | Execution stops completely. The page fails to load. | Fix immediately — your site is broken for visitors |
| Deprecated | A function or feature is scheduled for removal in a future WordPress version. | Plan to update — your code will break after a future WordPress update |
Finding the Source of an Error
Every log entry tells you the exact file and line number. Use this information to trace the problem:
- Note the file path — is it in
wp-content/plugins/,wp-content/themes/, orwp-includes/? - If it is in a plugin or theme, that is where the bug lives. If it is in
wp-includes/, a plugin or theme is likely passing bad data to a WordPress core function - Open the file and go to the exact line number
- Read the error message carefully — “Undefined variable” means a variable was used before being assigned. “Invalid argument supplied for foreach()” means a non-array was passed to a loop
Writing Custom Log Functions
The built-in error_log() function writes to the debug log, but it only handles strings. When you need to log arrays, objects, or complex data structures, you need a helper function.
Add this to your theme’s functions.php or a custom plugin:
/**
* Log any variable to the WordPress debug log.
* Works with strings, arrays, objects, and booleans.
*/
function tweakswp_log( $data, $label = '' ) {
if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
return;
}
$prefix = $label ? "[{$label}] " : '';
if ( is_array( $data ) || is_object( $data ) ) {
error_log( $prefix . print_r( $data, true ) );
} elseif ( is_bool( $data ) ) {
error_log( $prefix . ( $data ? 'true' : 'false' ) );
} else {
error_log( $prefix . $data );
}
}
Usage examples:
// Log a string
tweakswp_log( 'Payment processed for order #1234' );
// Log an array with a label
tweakswp_log( $user_data, 'User Data' );
// Log inside a hook
add_action( 'woocommerce_order_status_completed', function( $order_id ) {
tweakswp_log( "Order completed: #{$order_id}", 'WooCommerce' );
});
The label parameter makes it easy to filter log entries. When you search for [WooCommerce] in the log file, you see only the entries from your WooCommerce debugging hooks.
Managing Debug Log File Size
On active sites, the debug log can grow to hundreds of megabytes or even gigabytes. A bloated log file wastes disk space, slows down file searches, and can eventually fill your server’s storage.
Manual Log Rotation via WP-CLI
The simplest approach is to periodically clear or rotate the log file using WP-CLI or SSH:
# Check the current log file size
ls -lh wp-content/debug.log
# Archive the current log and start fresh
mv wp-content/debug.log wp-content/debug-$(date +%Y%m%d).log
touch wp-content/debug.log
# Delete archived logs older than 30 days
find wp-content/ -name 'debug-*.log' -mtime +30 -delete
Automated Log Rotation with Cron
Add a cron job to rotate the log automatically. This command runs every Sunday at midnight and keeps four weeks of archived logs:
# Edit your crontab
crontab -e
# Add this line for weekly rotation
0 0 * * 0 cd /var/www/html && mv wp-content/debug.log wp-content/debug-$(date +\%Y\%m\%d).log 2>/dev/null; find wp-content/ -name 'debug-*.log' -mtime +28 -delete
Disable Debugging When You Are Done
The most effective way to manage log size is to disable debugging when you do not need it. Set WP_DEBUG back to false in wp-config.php after you have resolved the issue. There is no reason to log PHP notices on a stable production site 24/7.
Query Monitor: Real-Time Debugging in Your Browser
Query Monitor is a free WordPress plugin that adds a developer toolbar to your admin bar. It shows PHP errors, database queries, HTTP API calls, hooks, conditionals, and more — all in real time as you browse your site.
Key features for debugging:
- PHP errors displayed inline with the responsible plugin or theme identified
- Database queries with execution time, caller function, and the ability to sort by slowest query
- HTTP API requests showing response time, status code, and the calling function
- Hooks and actions with the number of callbacks registered to each
- Transients that were set or updated during the page load
- Template parts loaded for the current page, useful for theme debugging
Query Monitor only shows information to administrators, so it is safe to run on production sites temporarily. However, the SAVEQUERIES constant must be enabled for the database query panel to work.
Debugging Specific Scenarios
White Screen of Death (WSOD)
A blank white screen usually means a PHP fatal error. If you cannot access the admin:
- Enable debugging via
wp-config.phpusing FTP or SSH - Reload the broken page
- Check
wp-content/debug.logfor the fatal error — it will tell you exactly which file crashed - If a plugin caused it, rename the plugin’s folder via FTP to deactivate it:
mv wp-content/plugins/broken-plugin wp-content/plugins/broken-plugin.bak
Slow Page Loads
Enable SAVEQUERIES and install Query Monitor. Check for:
- Queries taking more than 0.05 seconds
- Duplicate queries (same query running multiple times per page load)
- Missing indexes — Query Monitor flags queries that could benefit from database indexes
- HTTP API calls to slow external services blocking page rendering
Plugin Conflicts
When two plugins interfere with each other:
- Enable debugging and reproduce the problem
- Check the log for the first error — subsequent errors are often caused by the first one
- If the log does not reveal the conflict, deactivate all plugins and reactivate them one at a time while monitoring the log
Security: Protect Your Debug Log
The debug.log file contains file paths, database table names, function names, and sometimes sensitive data from error contexts. If it is accessible via the web, anyone can read it by navigating to yoursite.com/wp-content/debug.log.
Protect it with an .htaccess rule in your wp-content directory:
# Deny access to debug.log
Require all denied
For Nginx servers, add this to your site configuration:
location ~* /debug\.log$ {
deny all;
return 404;
}
Better yet, use a custom log path outside the web root as shown earlier. If the file is not inside public_html or htdocs, it cannot be accessed via a browser at all.
Quick Reference: Debug Configuration Cheat Sheet
| Scenario | WP_DEBUG | WP_DEBUG_LOG | WP_DEBUG_DISPLAY | SAVEQUERIES |
|---|---|---|---|---|
| Production (stable) | false | false | false | false |
| Production (investigating issue) | true | true | false | false |
| Production (slow query hunt) | true | true | false | true |
| Local development | true | true | true | true |
For sites running outdated plugins, security vulnerabilities can compound debugging issues. Our WPVivid vulnerability fix guide shows how to audit and harden your plugins. Related: if autoloaded options are slowing your site, check our guide on fixing wp_options autoload bloat. The WordPress debug log is the single most useful tool for diagnosing problems on any WordPress site. Enable it, read it carefully, fix the issues it reveals, and disable it when you are done. Combined with Query Monitor for real-time analysis and WP-CLI for log management, you have everything you need to debug WordPress like a professional.
WordPress Debugging WP_DEBUG WP-CLI
Last modified: February 17, 2026