WordPress debugging snippets
Turn on WordPress debug logging safely, list the scripts and styles a page loads, and silence the zlib ob_end_flush() shutdown notice.
On this page
These are small tools for finding out why a WordPress site misbehaves: switching on error output, seeing exactly which assets a page loads, and silencing a common shutdown notice. Remove them once you're done.
Turn On Debug Mode
In wp-config.php
Add these above the /* That's all, stop editing! */ line in wp-config.php:
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true ); // Write to wp-content/debug.log.
define( 'WP_DEBUG_DISPLAY', false ); // Don't print errors into pages.
define( 'SCRIPT_DEBUG', true ); // Load unminified core JS and CSS.On a local or staging site where you want errors on screen, set WP_DEBUG_DISPLAY to true and add @ini_set( 'display_errors', 1 ); in case the server's php.ini turns display off.
With WP-CLI
From the WordPress directory:
wp config set WP_DEBUG true --raw
wp config set WP_DEBUG_LOG true --raw
wp config set WP_DEBUG_DISPLAY false --raw
wp config set SCRIPT_DEBUG true --raw--raw writes the value as a PHP boolean instead of the string 'true'. Turn everything off again with the same commands using false, or remove the constants with wp config delete WP_DEBUG.
Warning
Never leave WP_DEBUG_DISPLAY on in production. Error output reveals file paths, plugin names, and sometimes query details to every visitor. Also, wp-content/debug.log is publicly downloadable on most servers. On a live site, point the log somewhere outside the web root:
define( 'WP_DEBUG_LOG', '/var/log/php/example.com-debug.log' );Make sure the PHP user can write to that path.
Follow the log while you reproduce the problem:
tail -f wp-content/debug.logList the Scripts and Styles a Page Loads
Use this when you need the handle of an asset so you can dequeue it, or want to see what a plugin adds to a page. It prints the handles of every script and style that was output as an HTML comment at the bottom of the page, and only for logged-in administrators.
Put it in a must-use plugin (for example wp-content/mu-plugins/asset-debug.php) while you investigate, then delete the file:
<?php
/**
* Print enqueued script and style handles as an HTML comment (admins only).
*/
add_action( 'wp_footer', function () {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
printf(
"\n<!-- Styles: %s -->\n<!-- Scripts: %s -->\n",
esc_html( implode( ', ', wp_styles()->done ) ),
esc_html( implode( ', ', wp_scripts()->done ) )
);
}, PHP_INT_MAX );done holds everything already printed, including dependencies pulled in automatically. Use queue instead to see only what was explicitly enqueued. View the page source and search for Styles:.
Tip
The Query Monitor plugin shows the same information, plus where each asset was enqueued, slow queries, hooks, and HTTP calls. Reach for it first on any site where you can install plugins.
Older versions of this snippet called wp_print_styles() and wp_print_scripts() inside wp_enqueue_scripts. Those functions actually print the tags early in the page and change the output you're trying to inspect, so don't use them for debugging.
Silence the ob_end_flush() Shutdown Notice
On servers with zlib.output_compression turned on, every request can log:
Notice: ob_end_flush(): Failed to send buffer of zlib output compression (1) in .../wp-includes/functions.phpWordPress calls wp_ob_end_flush_all() on shutdown, which tries to close every output buffer, including the one zlib owns and won't release. The notice is harmless but fills logs. The cleanest fix is to turn off zlib.output_compression and let the web server compress responses. When you can't change PHP settings, replace the core shutdown handler with one that stops quietly at the first buffer it can't close.
Put this in a must-use plugin or site plugin:
<?php
/**
* Flush output buffers on shutdown without the zlib notice.
*/
remove_action( 'shutdown', 'wp_ob_end_flush_all', 1 );
add_action( 'shutdown', function () {
while ( ob_get_level() > 0 && @ob_end_flush() ) {
// Keep flushing until a buffer refuses to close.
}
}, 1 );The @ only hides the notice for the one buffer that can't be flushed; the loop still flushes every other level like core does.
Sources
This article is in the public domain (CC0 1.0), code samples included. Use it however helps you.