Debug in WordPress
In development, you need to be able to see where the error is when something suddenly breaks. WordPress has a special debug mode for this. In this post, let's take it apart and see what this WP_DEBUG constant is.
Base knowledge
Debug mode is enabled by the WP_DEBUG
constant. It is disabled by default - the file wp-config.php
has the constant:
define( 'WP_DEBUG', false );
It can be enabled by setting the value of the constant to true:
define( 'WP_DEBUG', true );
true in this case enables processing of absolutely all PHP errors and displaying them on the screen. Also enabling the WP_DEBUG constant activates additional logic in the kernel, plugins and themes code, where the value of this constant is checked and something is done if it is enabled.
Read more about WP_DEBUG below.
See also video on WP learn portal: https://learn.wordpress.org/tutorial/debugging-in-wordpress/
Need to know
All debug mode constants are defined in file wp-config.php.
By default, the debug constants have the following values:
WP_DEBUG = false
(true when'development' === wp_get_environment_type()
)WP_DEBUG_DISPLAY = true
(it only works when WP_DEBUG is enabled)WP_DEBUG_LOG = false
WP_DEBUG_DISPLAY
and WP_DEBUG_LOG
are activated only if the WP_DEBUG
constant is enabled.
Enabling WP_DEBUG
does not change the value of other constants. That is, when WP_DEBUG = true
WP_DEBUG_DISPLAY
and WP_DEBUG_LOG
will retain their default values and PHP settings for error display and logging will be set based on these values.
However, if WP_DEBUG = false
, the error display and logging will work based on the settings in the php.ini file.
Use wp_get_environment_type(), to control the development environment.
It is important to disable "debugging" on the working (production) site.
Error display is always disabled for AJAX requests, you can only see errors there through the log file. This is set in wp_debug_mode():
if ( defined( 'XMLRPC_REQUEST' ) || defined( 'REST_REQUEST' ) || ( defined( 'WP_INSTALLING' ) && WP_INSTALLING ) || wp_doing_ajax() ) { @ini_set( 'display_errors', 0 ); }
How to enable error display in an AJAX request, see article about AJAX.
Why do we need "debug mode"?
Let's say you changed the functions.php file of the theme and the site stopped working. In its place is a white screen - nothing is clear. "Debug" will help to understand, it will show you the error and tell you in which line of what file it is.
"Debug" displays not only the errors that cause the site to stop working, but also the notes and warnings. Notes can be created by PHP itself (for example, when a variable is used incorrectly) or by PHP script code (for example, WP creates such notes if the site uses a deprecated WordPress function, or an deprecated function parameter).
Examples of enabling Debug mode
Basic enabling
Open the wp-config.php file at the root of your site and change false
to true
on the line:
define( `WP_DEBUG`, true ); // false - turn off error display
When you turn it on like this:
- All error levels will be reported in the error report.
- All errors will be displayed on the screen, because WP_DEBUG_DISPLAY = true by default.
- Errors will be logged to the log file specified in php.ini, because WP_DEBUG_LOG = false by default.
Enable debug mode and log file, and disable displaying errors
The code below will enable all levels of errors (notice, warning, error) to be written to the wp-content/debug.log
file and disable the notice, warning output to the screen.
define( 'WP_DEBUG', true ); // debug mode define( 'WP_DEBUG_LOG', true ); // error logging to a file /wp-content/debug.log define( 'WP_DEBUG_DISPLAY', false ); // disables error display
Thanks to the code above, error logging to a file has been enabled. This can be used to write the contents of the variables to log file:
error_log( $value ); // Scalar values error_log( print_r( $value, 1) ); // Any data
Debug mode for production site
For a production site, it is recommended to specify the following in the wp-config.php file:
define( 'WP_DEBUG', false ); @ini_set( 'display_errors', 0 ); @ini_set( 'log_errors', 1 );
In this setting we force change values from php.ini file for log_errors
and display_errors
directives, because WP will not set it when WP_DEBUG = false, and we do not trust what is set in php.ini. If we need to leave the values from php.ini, then these ini_set() directives can be omitted.
You can see on the internet that the values of constants are also set:
define( 'WP_DEBUG_DISPLAY', false ); define( 'WP_DEBUG_LOG', false );
However, this setting just doesn't make sense, because WP_DEBUG_DISPLAY simply doesn't work without WP_DEBUG enabled, and WP_DEBUG_LOG already defaults to false.
Dynamically turn on/off errors display
This code helps to quickly enable the WP_DEBUG constant, which on a working site should be turned off. The code also allows you to enable error logging in the /wp-content/debug.log file, and disable error display on the screen.
Why this code is handy? Let's say we made the site and it works, but we periodically fix it's code. While editing of course appear different errors, including fatal ones. To see what the cause, we need to enable debug, to do this, open wp-config.php and change the constant, after completion it is necessary to return everything back. This is inconvenient, it's more convenient to enable debug via URL and see errors when needed.
Enabling errors is saved in the cookie of your site so it will works only for you.
To get things working, replace line define( WP_DEBUG, false );
in file wp-config.php with this code:
<?php /** * Dynamically enable/disable the display of PHP errors in WordPress. * * Installation: * replace line 'define( WP_DEBUG, false );' in 'wp-config.php' file with this code. * * Enabling debug mode: * NOTE: Strongly recommended to changing the 'debug' word to something more unique! * add the 'debug' query parameter to the URL. Examples: * https://site.com/?debug - default enabling of WP_DEBUG constant * https://site.com/?debug=1 - logging of errors into file 'DOCUMENT_ROOT/../php-errors-{HOST}.log'. * https://site.com/?debug=2 - linking uncompressed scripts and saving all SQL queries to $wpdb->queries * https://site.com/?debug=3 - saving all SQL queries in $wpdb->queries * https://site.com/?debug=4 - disable displaying errors (enabled by default) * https://site.com/?debug=14 - combining * * Disabling debug mode: * https://site.com/?debug=anything * * @author Kama (http://wp-kama.ru) * @version 2.5 */ // IMPORTANT: change from `debug` to your unique key! kama_define_wp_debug( 'debug' ); function kama_define_wp_debug( $key ){ $val = isset( $_GET[ $key ] ) ? ( $_GET[ $key ] ?: 'yes' ) : false; // set/delete cookie if( $val !== false ){ $cookie = preg_match( '/^(yes|[1234])$/', $val ) ? $val : null; $host = str_replace( 'www.', '', $_SERVER['HTTP_HOST'] ); // cirilic domains: .сайт, .онлайн, .дети, .ком, .орг, .рус, .укр, .москва, .испытание, .бг false !== strpos( $host, 'xn--' ) ? preg_match( '~xn--[^.]+.xn--[^.]+$~', $host, $mm ) : preg_match( '~[a-z0-9][a-z0-9-]{1,63}.[a-z.]{2,6}$~', $host, $mm ); $host = $mm[0]; $_COOKIE[ $key ] = $cookie; setcookie( $key, $cookie, time() + ( $cookie ? 3600 * 24 * 365 : -3600 ), '/', ".$host" ); } // enable the debug based on the cookie if( ! empty( $_COOKIE[ $key ] ) ){ define( 'WP_DEBUG', true ); $set = array_flip( preg_split( '/(\d)/', $_COOKIE[ $key ], -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY ) ); isset( $set[1] ) && define( 'WP_DEBUG_LOG', dirname( $_SERVER['DOCUMENT_ROOT'] ) . "/php-errors-{$_SERVER['HTTP_HOST']}.log" ); isset( $set[2] ) && define( 'SCRIPT_DEBUG', true ); isset( $set[3] ) && define( 'SAVEQUERIES', true ); isset( $set[4] ) && define( 'WP_DEBUG_DISPLAY', false ); } else { define( 'WP_DEBUG', false ); } }
Now, to enable WP_DEBUG mode, you need to add ?debugquery parameter to any URL, for example:
http://example.com/?debug
- enables debug.http://example.com/?debug=1
- forced output to screen if such output is disabled.http://example.com/?debug=2
- logging to file.
For protection, the debug
key should be changed to your own key, which only you will know, because you will use it to enable/disable the debug mode.
When enabling error logging (?debug=2
) the site parent folder (DOCUMENT_ROOT/..
) must be writable, otherwise PHP will not be able to create the log file. Or you can manually create a log file DOCUMENT_ROOT/../php-errors-example.com.log
. It must have write permissions (CHMOD 660 or higher).
WP_DEBUG
Default: false.
The WP_DEBUG constant enables or disables debug mode in WordPress.
When debug mode is enabled, absolutely all error levels will be included in the error report. When disabled, only important error levels will be included in the report.
-
When
WP_DEBUG = true
:- for
display_errors
is responsible the value of the constant WP_DEBUG_DISPLAY. - for
log_errors
anderror_log
is responsible the value of the constant WP_DEBUG_LOG. - And
error_reporting
is set toE_ALL
- to include absolutely all error levels in the report.
- for
- When
WP_DEBUG = false
:display_errors
,log_errors
anderror_log
, remain as they are specified in thephp.ini
file.- And
error_reporting
is set toE_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR
The WP_DEBUG constant should be set in wp-config.php file.
define( 'WP_DEBUG', false ); // debug is disabled. Default. // or define( 'WP_DEBUG', true ); // debug enabled
If the WP_DEBUG constant is not set at all in wp-config.php, it defaults to false
. However, if the development
environment is specified, it defaults to true
:
if ( wp_get_development_mode() || 'development' === wp_get_environment_type() ) { define( 'WP_DEBUG', true ); } else { define( 'WP_DEBUG', false ); }
Note: do not set false in quotes - 'false'
. In this case the debug will be enabled because the value of string 'false' is logical true.
PHP errors, warnings and notices
There are different levels of errors in PHP. Without going into details, the significance levels are:
errors
- a serious error which leads to a halt of the script. Aborts PHP.warnings
- not an error, but a warning about something. PHP does not interrupt.notices
- not an error, but a note about something. PHP does not interrupt. Notes may indicate possible bugs in the code. Fixing them will usually make the code more stable.
"Debug mode" includes all levels of errors. This is not like PHP's usual behavior: usually only errors at the 'errors' level are included, and warnings and notices are not shown. See error_reporting() for more details.
Deprecated functions, hooks and deprecated function parameters
WP_DEBUG also includes internal WordPress noties. WordPress has special functions like _deprecated_function(), which show a notices level error when an deprecated function or hook or parameter of a hook, function, etc. is used. These notices warn that the WP function is considered deprecated and should be replaced because it can be removed at any time. Such notes most often suggest an alternative function to replace it.
WP_DEBUG_DISPLAY
Default: true
Another WP_DEBUG component, which controls the display of errors.
Depends on WP_DEBUG
! Only works if debug is enabled WP_DEBUG = true
. Otherwise it just uses the global value of the PHP display_errors
option.
If you specify in wp-config.php:
-
define( 'WP_DEBUG_DISPLAY', true )
- (by default) WP will display errors. -
define( 'WP_DEBUG_DISPLAY', false )
- The errors will not be displayed. This is needed when errors are written to a log file (see WP_DEBUG_LOG) and you can see them later. define( 'WP_DEBUG_DISPLAY', null )
- WP will not specify a value for PHP option display_errors at all, i.e. it will use the global PHP (server) setting.
Error display is always turned off for REST, AJAX or XML-RPC requests. Such code ini_set('display_errors', 0 ) works for those requests forcibly. The value of WP_DEBUG_DISPLAY constant does not change!
WP_DEBUG_LOG
Default: false.
Enables writing errors to a file. Overwrites the following directives specified in the php.ini file:
ini_set( 'log_errors', 1 ); ini_set( 'error_log', WP_CONTENT_DIR . '/debug.log' );
Only works if WP_DEBUG = true
. Otherwise directives from php.ini will be used.
Writing errors in the log file can be useful when you want catch errors, which does not display anything on the screen. For example, when AJAX request or when testing CRON or REST.
Example of including error recording in the default log file /wp-content/debug.log
:
define( 'WP_DEBUG_LOG', true );
In this case, the default path to the file is used, which is located in the folder accessed via HTTP: https://example.com/wp-content/debug.log
. This is not a secure location because anyone can access it.
Ideally, the log file should be located above the root directory to which there is no HTTP access. If for some reason you can't put it above the root directory, then, set 600 permissions on the file and add such an entry to the .htaccess
file in the root directory of your WordPress installation:
<Files debug.log> Order allow,deny Deny from all </Files>
Example of including error recording in a custom log file
Via WP
With WordPress 5.1, in WP_DEBUG_LOG you can specify a file path where errors will be stored. For example, let's place it one level above the current WORDPRESS installation:
define( 'WP_DEBUG_LOG', dirname( __DIR__ ) . '/errors.log' );
Via PHP
Changing the path via PHP can be useful when WP_DEBUG = false
and when you want to change the path specified in the php.ini file.
ini_set( 'error_log', dirname( __DIR__ ) . '/errors.log' );
- The end folder in the specified path must exist and be writable for PHP.
- The file inside may not exist, it will be created as soon as the first error occurs.
WP_DISABLE_FATAL_ERROR_HANDLER
По умолчанию: false
Allows you to disable fatal error handling built into WordPress since version 5.2.
When a fatal error occurs on a WordPress site, it sends an email to the administrator.
If for some reason you don't want to send such emails, add this line of code to the wp-config.php file:
define( 'WP_DISABLE_FATAL_ERROR_HANDLER', true );
Since WP 5.2, a class WP_Fatal_Error_Handler{} has been added to the core to handle Fatal Errors. For this purpose, the WP_Fatal_Error_Handler::handle() method is hung on the shutdown event.
The fatal error handler class can be overridden!
To do this, you need to create a file wp-content/fatal-error-handler.php
where you need to return the handler object:
<?php /** * File: wp-content/fatal-error-handler.php * Substitute for the class: WP_Fatal_Error_Handler() */ class My_Fatal_Error_Handler { public function handle() { // your code here } } return new My_Fatal_Error_Handler();
As a basis for creating such a class you should take the class WP_Fatal_Error_Handler{}.
See the function code for how this works:
- wp_is_fatal_error_handler_enabled() — Checks whether the fatal error handler is enabled.
- wp_register_fatal_error_handler() — Registers the shutdown handler for fatal errors.
- WP_Fatal_Error_Handler() — Core class used as the default shutdown handler for fatal errors.
SAVEQUERIES
Default: not set.
Related to debug constant. When enabled, all SQL queries will be saved in the $wpdb->queries
property as an array. In this array you can see all SQL queries and if necessary find the right one and make sure it is correct, etc.
In addition to the query itself, also recorded data about how much time the query took and what function it was called.
// save SQL queries and their data in `$wpdb->queries` define( 'SAVEQUERIES', true );
Important! this option requires additional memory and PHP operations. Therefore, for performance reasons, this constant should be used only while site development.
An example of how you can see all the SQL requests:
if ( current_user_can( 'administrator' ) ) { global $wpdb; print_r( $wpdb->queries ); }
SCRIPT_DEBUG
Default: false.
A debug-related constant. Controls which JS and CSS files to use: compressed or full. When enabled, WordPress will use uncompressed versions (dev versions) of JS and CSS files. The default is to use min
versions of the files. This is necessary for testing when modifying embedded js or css files.
// use full versions of WP `.css` and `.js` files define( 'SCRIPT_DEBUG', true );
CONCATENATE_SCRIPTS
Default: true.
Allows you to disable script concatenation in the admin. See. script_concat_settings().
To speed up the admin area, all JavaScript files are merged into a single URL. If you work with admin scripts, it is advisable to disable this function:
define( 'CONCATENATE_SCRIPTS', false );
How does Debug mode work?
When generating a page, at the very beginning of WordPress loading (see. wp-settings.php), among others, two functions are triggered:
-
wp_initial_constants() - sets default values of constants if they were not set in the wp-config.php file.
- wp_debug_mode() - overrides php.ini directive values based on the specified debug constants. Using PHP functions, the following are sets:
- Which error levels to handle.
- Whether to display them on the screen or not.
- Whether to log errors to a file or not.
- Which file to log errors to.
WP_DEBUG does not work?
Sometimes you may have a situation when you enable WP_DEBUG
in wp-config, but the error is still not visible. This behavior can occur when somewhere after the error display settings by WordPress itself, these settings are changed. For example in MU plugin, a regular plugin or in the theme, the errors are turned off by reinstalling the ini directives PHP, something like this code:
error_reporting( 0 ); // turn off error messages ini_set( 'display_errors', 0 ); // disables displaying errors
In this case WP's debug settings get interrupted and it stops working.
To solve this, it is best to find where the settings are changed and delete such lines, so that from now on you can work only with WP_DEBUG constant.
As another solution, you can try to re-build the error output settings by specifying them again:
error_reporting( E_ALL ); // enable error messages ini_set( 'display_errors', 1 ); // show errors on the screen
WP functions for debugging
- wp_debug_backtrace_summary() — Return a comma-separated string of functions that have been called to get to the current point in code.
- wp_get_environment_type() — Retrieves the current environment type.
System data
For debugging, WP has a class WP_Debug_Data. For example, using the following method we can get a bunch of data about the system:
require_once ABSPATH . '/wp-admin/includes/class-wp-debug-data.php'; require_once ABSPATH . '/wp-admin/includes/update.php'; require_once ABSPATH . '/wp-admin/includes/misc.php'; $data = WP_Debug_Data::debug_data(); print_r( $data );
We get a big data set:
Customizing php.ini
First of all, the default logging and error display settings are specified in the PHP configuration file php.ini
, which you may or may not have access to. If you do have access, you should set them there. It is strongly recommended that you do not display error messages on the working site, but redirect them to the error log file. Also, error log files should not be accessible by URL.
Example of recommended settings for php.ini
:
error_reporting = 4339 display_errors = Off display_startup_errors = Off log_errors = On error_log = /home/example.com/logs/php_error.log log_errors_max_len = 1024 ignore_repeated_errors = On ignore_repeated_source = Off html_errors = Off
error_reporting = 4339
is a custom value. 4339 is the decimal representation of the binary number 100001111110011
. Each 1 of the binary value corresponds to an enabled error level, and 0 to a disabled error level.
In the error_reporting
value it is more convenient to specify constants rather than numbers, for example:
# Include all types of errors in the report error_reporting = E_ALL # Include all error types except E_NOTICE E_STRICT E_DEPRECATED in the report error_reporting = E_ALL & ~E_NOTICE & ~E_STRICT & ~E_DEPRECATED # Include only the specified error types in the report error_reporting = E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR
PHP error level table (see [PHP Error Constants](). PHP Error Constants):
Constant | decimal | binary | Description |
---|---|---|---|
E_ERROR | 1 | 1 | Fatal errors that cannot be fixed by means of the script itself, such as memory allocation error, etc. |
E_WARNING | 2 | 10 | Warnings. The script is not interrupted. |
E_PARSE | 4 | 100 | Errors at the compilation stage. Should be generated only by the parser. |
E_NOTICE | 8 | 1000 | Notices. Potential error in the script. The script is not interrupted. |
E_CORE_ERROR | 16 | 10000 | Fatal errors. Occurs during PHP startup. Similar to E_ERROR, but generated by the PHP kernel. |
E_CORE_WARNING | 32 | 100000 | Warnings. Occurs during the initial startup of PHP. Similar to E_WARNING, but generated by the PHP kernel. |
E_COMPILE_ERROR | 64 | 1000000 | Fatal errors at the compilation stage. Similar to E_ERROR, but generated by Zend engine. |
E_COMPILE_WARNING | 128 | 10000000 | Warnings at compile time. Similar to E_WARNING, but generated by Zend engine. |
E_USER_ERROR | 256 | 100000000 | Similar to E_ERROR, only generated by the user in the script code via trigger_error(). |
E_USER_WARNING | 512 | 1000000000 | Similar to E_WARNING, but generated by the user in the script code via trigger_error(). |
E_USER_NOTICE | 1024 | 10000000000 | Similar to E_NOTICE, only generated by the user in the script code via trigger_error(). |
E_STRICT | 2048 | 100000000000 | Included to allow PHP to suggest code changes that will ensure better code interoperability and compatibility. |
E_RECOVERABLE_ERROR | 4096 | 1000000000000 | Fatal errors with possibility of handling. Indicates that a dangerous situation has occurred, but the script engine is stable. If not handled by a custom function (see set_error_handler()), execution is aborted as for E_ERROR. |
E_DEPRECATED | 8192 | 10000000000000 | Notices about the use of deprecated constructs. Enabled when you need to warn about code that will not work in future versions of PHP. |
E_USER_DEPRECATED | 16384 | 100000000000000 | Similar to E_DEPRECATED, only generated by the user via trigger_error(). |
E_ALL | 32767 | 111111111111111 | All supported bugs, warnings, and comments. |
The bit representation of a constant can be viewed like this:
$err_lvl = E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE; var_dump( $err_lvl ); // int(119) var_dump( decbin( $err_lvl ) ); // string(7) "1110111"
IMPORTANT: WordPress always changes the error_reporting
value specified in the php.ini
file via the error_reporting() function. This is done in the wp_debug_mode() function.
If WP_DEBUG = true
, absolutely all error levels are included in the report:
error_reporting( E_ALL );
When WP_DEBUG = false
, the report includes this list of errors:
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 );
Plugins for debugging and profiling in WordPress
There are several plugins in the WP catalog that extend the "debugging" capabilities and provide additional information to identify code weaknesses. Popular ones are:
-
Query Monitor - displays a bunch of useful information about the current page query. How much time was spent, how many SQL queries, what queries, how long each query took, how much memory was spent, what hooks were used, etc.
- Query Monitor Addons