search ]

You Better use WP_DEBUG_LOG in WordPress Development

In this short post, we’ll see what the correct way is to monitor PHP errors on WordPress sites using WP_DEBUG_LOG.

Like most things related to WordPress development, the best way to understand a specific function is to search for it in WordPress core files and look at the code.

Here is the code for the wp_debug_mode function. The important and relevant part appears in wp-include/load.php:

function wp_debug_mode() {
    if ( WP_DEBUG ) {
        error_reporting( E_ALL );

        if ( WP_DEBUG_DISPLAY )
            ini_set( 'display_errors', 1 );
        elseif ( null !== WP_DEBUG_DISPLAY )
            ini_set( 'display_errors', 0 );

        if ( in_array( strtolower( (string) WP_DEBUG_LOG ), array( 'true', '1' ), true ) ) {
            $log_path = WP_CONTENT_DIR . '/debug.log';
        } elseif ( is_string( WP_DEBUG_LOG ) ) {
            $log_path = WP_DEBUG_LOG;
        }

        if ( isset( $log_path ) ) {
            ini_set( 'log_errors', 1 );
            ini_set( 'error_log', $log_path );
        }
    } else {
        error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
    }

    if ( defined( 'XMLRPC_REQUEST' ) || defined( 'REST_REQUEST' ) || ( defined( 'WP_INSTALLING' ) && WP_INSTALLING ) || wp_doing_ajax() || wp_is_json_request() ) {
        ini_set( 'display_errors', 0 );
    }
}	

In essence, if you set WP_DEBUG_LOG to true, WP_DEBUG_DISPLAY to false, and WP_DEBUG is also true, all PHP errors will be recorded in the debug.log file created in the wp-content directory but will not be displayed in the browser.

Since WordPress 5.1, you can also pass a custom file path to WP_DEBUG_LOG instead of just true. This lets you store the log file outside the web root for better security.

To configure this, use the following code:

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

Make sure to place these constants in your wp-config.php file above the line that says /* That's all, stop editing! */. Never enable WP_DEBUG on production sites.

But why do this? Here are three reasons why it’s preferable to use WP_DEBUG_LOG over WP_DEBUG:

Hidden Error Messages

You’re used to seeing PHP error messages in the browser, but are you sure you see all of them? What about elements hidden in CSS and AJAX calls?

The user interface is not a reliable place to catch all error messages. The PHP log file, on the other hand, shows all of them, and you won’t miss any.

Missing Error Messages

Maybe you like to use plugins like Debug Bar or Query Monitor to monitor and receive error messages, and you’re very satisfied with them.

They are great plugins. However, I’ve encountered situations where they miss errors.

This may happen because these plugins are ultimately plugins and can be affected by other plugins loading before them.

You can change the order of plugin loading using Plugin Organizer, but what about plugins in the MU plugins directory or errors in WordPress core files themselves?

As convenient as these plugins are, relying on them alone to detect all PHP errors on your WordPress site is a mistake.

PHP itself is the most reliable source for error reporting, and you’ll receive it through the debug.log file.

Third-Party Plugins

If your code is problematic and throws errors, you can fix that. But what if external plugins you installed throw errors and comments on your entire interface?

When WP_DEBUG is active, it displays all errors without exception.

It can be very difficult to work when error messages and comments flood your entire screen, especially when certain plugins are active.

At this point, you’ve added those lines to wp-config.php and you’re monitoring errors through the debug.log file. Here’s an example of how errors look in this file:


[18-Dec-2017 09:18:08 UTC] PHP Fatal error:  Call to undefined function get_slocale() in /Users/roeeyossef/Sites/startapp/wp-content/themes/thesis/includes/home.php on line 9
[18-Dec-2017 09:18:08 UTC] PHP Stack trace:
[18-Dec-2017 09:18:08 UTC] PHP   1. {main}() /Users/roeeyossef/Sites/startapp/index.php:0
[18-Dec-2017 09:18:08 UTC] PHP   2. require() /Users/roeeyossef/Sites/startapp/index.php:17
[18-Dec-2017 09:18:08 UTC] PHP   3. require_once() /Users/roeeyossef/Sites/startapp/wp-blog-header.php:19
[18-Dec-2017 09:18:08 UTC] PHP   4. apply_filters() /Users/roeeyossef/Sites/startapp/wp-includes/template-loader.php:73
[18-Dec-2017 09:18:08 UTC] PHP   5. WP_Hook->apply_filters() /Users/roeeyossef/Sites/startapp/wp-includes/plugin.php:203
[18-Dec-2017 09:18:08 UTC] PHP   6. call_user_func_array:{/Users/roeeyossef/Sites/startapp/wp-includes/class-wp-hook.php:286}() /Users/roeeyossef/Sites/startapp/wp-includes/class-wp-hook.php:286
[18-Dec-2017 09:18:08 UTC] PHP   7. thesis_skin->_skin() /Users/roeeyossef/Sites/startapp/wp-includes/class-wp-hook.php:286
[18-Dec-2017 09:18:08 UTC] PHP   8. thesis_skin->_template() /Users/roeeyossef/Sites/startapp/wp-content/themes/thesis/lib/core/skin.php:1003
[18-Dec-2017 09:18:08 UTC] PHP   9. thesis_html_body->html() /Users/roeeyossef/Sites/startapp/wp-content/themes/thesis/lib/core/skin.php:1065
[18-Dec-2017 09:18:08 UTC] PHP  10. thesis_box->rotator() /Users/roeeyossef/Sites/startapp/wp-content/themes/thesis/lib/core/skin/boxes.php:604
[18-Dec-2017 09:18:08 UTC] PHP  11. call_user_func_array:{/Users/roeeyossef/Sites/startapp/wp-content/themes/thesis/lib/core/box.php:389}() /Users/roeeyossef/Sites/startapp/wp-content/themes/thesis/lib/core/box.php:389

The strange file path is due to the use of a local WordPress environment.

Custom Log File Path

Since WordPress 5.1, you can pass a custom file path to WP_DEBUG_LOG instead of just true:

define( 'WP_DEBUG_LOG', '/path/outside/webroot/debug.log' );

This is useful for storing the log file outside the publicly accessible web root, which is a security best practice.

Additional Debug Constants

Beyond the three core constants, WordPress offers two more that are useful during development:

SCRIPT_DEBUG forces WordPress to use the development (non-minified) versions of core CSS and JavaScript files:

define( 'SCRIPT_DEBUG', true );

This is helpful when you need to debug or modify core scripts and styles.

SAVEQUERIES saves all database queries, along with execution time and the calling function, into a global array:

define( 'SAVEQUERIES', true );

You can then inspect the queries using $wpdb->queries. Note that this has a performance impact and should only be used during development.

Securing the debug.log File

By default, the debug.log file is created inside the wp-content directory and is publicly accessible. Anyone who knows the URL can read it, potentially exposing sensitive information like file paths, database queries, and plugin details.

Always protect your debug.log file. Either store it outside the web root using a custom path, or block access to it via your .htaccess file or server configuration.

To block access via .htaccess, add the following rule to the .htaccess file in your wp-content directory:

<Files debug.log>
    Order allow,deny
    Deny from all
</Files>

For more WordPress security tips, check out our dedicated guide.

You can also prevent PHP errors from displaying entirely on your production site.

FAQs

Common questions about WP_DEBUG_LOG:

What is the difference between WP_DEBUG and WP_DEBUG_LOG?
WP_DEBUG enables WordPress debug mode and error reporting. WP_DEBUG_LOG takes it a step further by writing those errors to a log file (debug.log) instead of displaying them on screen. For development, it is best to enable both WP_DEBUG and WP_DEBUG_LOG while setting WP_DEBUG_DISPLAY to false.
Where is the debug.log file located?
By default, the debug.log file is created in the wp-content directory of your WordPress installation. Since WordPress 5.1, you can specify a custom path by passing a string to WP_DEBUG_LOG instead of true, for example: define('WP_DEBUG_LOG', '/path/to/custom/debug.log').
Is it safe to enable WP_DEBUG on a production site?
No. Enabling WP_DEBUG on a production site can expose sensitive information to visitors, including file paths and database details. If you need to debug a production issue, enable WP_DEBUG_LOG with a custom path outside the web root and set WP_DEBUG_DISPLAY to false. Remove the debug constants as soon as you are done.
What does SCRIPT_DEBUG do?
SCRIPT_DEBUG forces WordPress to load the development (non-minified) versions of core CSS and JavaScript files. This is useful when debugging issues related to core scripts or styles, as the unminified code is easier to read and step through.
How do I protect the debug.log file from public access?
You can protect debug.log by storing it outside the web root using a custom path in WP_DEBUG_LOG, or by adding a deny rule in the .htaccess file inside your wp-content directory. Both methods prevent unauthorized users from accessing the file via a browser.
Can I use WP_DEBUG_LOG with Query Monitor?
Yes. WP_DEBUG_LOG and Query Monitor complement each other. Query Monitor provides a convenient in-browser interface for inspecting queries, hooks, and errors, while WP_DEBUG_LOG captures everything to a file, including errors that Query Monitor might miss from AJAX calls, REST API requests, or early-loading plugins.

Summary

Using WP_DEBUG_LOG instead of relying on WP_DEBUG alone is a best practice for WordPress development. It captures all PHP errors – including those hidden in AJAX calls, REST API responses, and early plugin loading – without cluttering your browser.

Combine it with WP_DEBUG_DISPLAY set to false, and you get a clean development experience with a complete error record. Remember to protect the log file from public access and never leave debug mode enabled on production sites.

This post was translated from a post on deliciousbrains.com

Join the Discussion
0 Comments  ]

Leave a Comment

To add code, use the buttons below. For instance, click the PHP button to insert PHP code within the shortcode. If you notice any typos, please let us know!

Savvy WordPress Development official logo