Using WordPress Debug Constants

Here are some constants you can define in your wp-config.php file to assist with debugging.

Note that debugging should not be enabled on a production site, or if it is, it should be “silent” (i.e. writing to the log, but not displaying on the screen). Also for production use, keep in mind that debugging should be temporary. Constantly writing debug messages to the log will eventually slow your site down as the log grows larger. Leaving this on indefinitely could eventually crash the site when the log grows too large to handle.

WP_DEBUG

This is the core WP constant that enables debugging. Setting this to true (see the example code at the end) will allow PHP error messages to be printed to the screen and/or the log. Used alone, without any of the additional constants will display errors, warnings, and notices to the screen but not to the error log file.

WP_DEBUG_LOG

This constant is a companion to WP_DEBUG and it causes all errors to be written to a log file. By default, this log file will by located in /wp-content/debug.log.

WP_DEBUG_DISPLAY

This constant is a companion to WP_DEBUG and it causes all errors to be displayed on screen in the browser.

SCRIPT_DEBUG

This little known constant is an important one for testing and debugging WordPress sites. When set to TRUE, it causes WP to load non-minified versions of CSS and JS files. If plugins or themes are properly constructed to WP standards, it will load non-minified versions of those assets as well.

SAVEQUERIES

This constant saves database queries to an array and that array can be displayed to help analyze them. It’s important to note that this constant has a definite performance impact and should only be used when actually debugging.

Save WordPress debug log by date

It’s not recommended to keep debugging enabled on a production site. But sometimes you may need to in order to gain the data you need.

The danger is that error logging writes to a text file, and the larger that file becomes, the more it degrades your system performance. If you ignore it completely, it can crash your site.

This article outlines a way to automatically save the debug log by date so you can maintain smaller file size for the log, which will help avoid performance issues. This also makes it easier to find logs for specific dates, since the date is part of the file name (at least in this example).

It’s important to note that the error_log() function used to log errors is not a WordPress function. People mislabel this all the time and spend time looking for the WP function; but it’s actually a PHP function.

The primary action that WP enacts when the debug log is enabled is to write the log file to /wp-content/debug.log. Adding the following somewhere in your site (can be in your wp-config.php, in a plugin, or in your theme’s functions.php file) will set a filename for the debug.log file in the format of debug-2020-01-01.log.

ini_set( 'error_log', WP_CONTENT_DIR . '/debug-' . date('Y-m-d') . '.log' );

Note that this is not really a secure process. Your log files are still openly available if someone knows the naming convention being used. To protect your log files from prying eyes, I recommend adding a hash to the filename. This way, the file name has some randomness to it. In order to work successfully, you’ll need to store the hash for the day, so you create one hash for the day and use it for all writes to the log file.

// Get stored hashes.
$error_log_hashes = get_option( 'error_log_hashes' );
// Get today's date.
$date = date('Y-m-d');
// Check if there is a hash for today. If not, create one.
if ( isset( $error_log_hashes[ $date ] ) ) {
    $hash = $error_log_hashes[ $date ];
} else {
    // Generate a random value with NO special characters.
    $hash = wp_generate_password( 12, false, false );
    // Update the hashes so we use this on subsequent requests this day.
    $error_log_hash[ $date ] = $hash;
    update_option( 'error_log_hashes', $error_log_hashes );
}

$log_file = 'debug-' . $hash . '-' . $date . '.log';
$error_log_file = WP_CONTENT_DIR . '/debug-' . $date . '.log';

ini_set( 'error_log', $error_log_file );

Utility function for the WordPress error log

There is function for writing information to the WP error log file – error_log().

The problem is that the function doesn’t handle arrays or objects directly. For those, you need to format the data before writing to the log (if you want to be able to read the result in the log).

Here’s a simple utility you can use to pass a string, array, or object and write it to the log without having to worry about pre-formatting the value.

/**
 * Writes string, array, and object data to the WP error log.
 * 
 * To use, pass the result to write to the log as follows:
 * write_log( $value_to_write );
 *
 * @param string|array|object $log
 */
function write_log( $log )  {
    if ( is_array( $log ) || is_object( $log ) ) {
        error_log( print_r( $log, true ) );
    } else {
        error_log( $log );
    }
}

To use this function, just add it to your theme’s functions.php file. Or better yet, add it to your site specific plugin.

You’ll need to make sure that debugging is turned on in your wp-config.php file and that you’ve enabled error logging.

/**
 * The WP debug constants.
 * 
 * These are used in wp-config.php to enable debugging.
 * 
 * NOTE all of these MUST be inserted in wp-config.php
 * before the following line:
 * /* That's all, stop editing! Happy blogging.
 */

// Turns on general debugging
define( 'WP_DEBUG', true );

/*
 * WP_DEBUG_DISPLAY is optional. If WP_DEBUG is true
 * and WP_DEBUG_DISPLAY is not defined, debugging messages
 * will be output to the screen. So for general debugging
 * it is not needed. But if you need to debug in production
 * and write to the log without displaying to the screen,
 * use the following:
 */
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );

// Enables error logging to /wp-content/debug.log
define( 'WP_DEBUG_LOG', true );

// Use dev versions of core JS and CSS files (only needed if you are modifying these core files)
define( 'SCRIPT_DEBUG', true );

// Saves the database queries to an array that can help analyze those queries.
define( 'SAVEQUERIES', true );

How to Create a Site Specific Plugin

A common question I get when supporting WordPress users is “where to I put this custom code snippet.”

A frequent and simple answer to that question is, “In your theme’s functions.php file.”

While that’s not necessarily a wrong answer, it’s not the best answer. Putting custom code snippets in your theme’s functions.php means that if you change themes, you have to migrate all that code.

A much simpler solution is to create a site specific plugin to store your custom code. That way, all of your customizations stay with you.

But how do you do that?

I have a simple site specific plugin framework available on github that you can use for any and all of your custom code snippets. You can use it as-is, or you can add additional files if you want to separate custom code by different groupings (such as customizations for multiple plugins). You could also copy and rename the plugin to create separate plugins within a single site.

How to get started

To get started, copy the entire package from github. Rename files as needed.

The core file structure consists of the following:

|– site-specific-plugin.php – The plugin initialization file.
|– readme.txt – A standard WP plugin readme file.
|– license – The GPL license.
|– custom/
|– functions.php – A file to contain your custom PHP functions.
|– custom.js – A file to contain your custom JS.
|– style.css – A file to contain your custom CSS.

Install the folder as you would a regular plugin. Once activated, you can edit locally and upload changes via FTP or you can edit using the WordPress plugin editor. Use caution if editing live on the site – if you make a code error, this could crash your site.

Don’t Use do_shortcode()

The Internet abounds with examples of bad practices in WordPress development. Using do_shortcode() unnecessarily is one of the most pervasive.

do_shortcode() runs a fairly extensive regex (regular expression) that has to go through every possible shortcode. Konstantin Kovshenin has a good explanation of this:

That regex looks for all registered shortcodes within a string. For each match, it runs a replacement with a callback function, which also take the time to parse the shortcode attributes, before finally calling the actual callback function that’s been registered with add_shortcode.

Searching for the callback (function) and using it directly is preferable to using do_shortcode(). But what if you can’t? What if it’s in an object class?

Here is a simple utility function you can use to run a shortcode’s callback function, even if it’s in a class. It supports passing attributes and content.

/**
 * Call a shortcode function by its tag name.
 * 
 * Directly executes a shortcode's callback function using the shortcode's
 * tag name. Can execute a function even if it's in an object class.
 * Simply pass the shortcode's tag and an array of any attributes.
 *
 * @global array  $shortcode_tags
 * @param  string $tag            The shortcode tag name.
 * @param  array  $atts           The attributes (optional).
 * @param  array  $content        The shortcode content (null by default).
 *
 * @return string|bool False on failure, the result of the shortcode on success.
 */
function do_shortcode_func( $tag, array $atts = array(), $content = null ) {
 
    global $shortcode_tags;
 
    if ( ! isset( $shortcode_tags[ $tag ] ) ) {
        return false;
    }
 
    return call_user_func( $shortcode_tags[ $tag ], $atts, $content, $tag );
}