How to debug with WP_DEBUG and WP_DEBUG_LOG in PHP in WordPress

Contents

Introduction

This article explains everything about using WP_DEBUG and WP_DEBUG_LOG to debug WordPress sites in PHP. It covers what the constants do, how to enable them safely, example usage, advanced logging techniques, reading and rotating logs, permissions, common pitfalls, and best practices for development and production environments.

What these constants do (at a glance)

WP_DEBUG Master switch. When true, WordPress will display PHP notices, warnings, and deprecated function notices (depending on other settings). Should be enabled in development only.
WP_DEBUG_LOG When true, PHP notices, warnings, and errors are written to wp-content/debug.log. Can also be set to a file path to write to a custom file (use absolute path).
WP_DEBUG_DISPLAY Controls whether debug messages are displayed to the screen. Often set to false in combination with WP_DEBUG_LOG to keep errors off the frontend.
SCRIPT_DEBUG When true, WordPress will load non-minified CSS/JS (useful when debugging scripts).
SAVEQUERIES When true, stores database queries in memory in wpdb->queries for later inspection. Use with caution — memory overhead increases.

Where to set these constants

Always set WP_DEBUG and related constants in wp-config.php, before the line that includes wp-settings.php. That ensures WP reads the values early. Example placement is typically right above the / Thats all, stop editing! Happy blogging. / or right after the database constants.

Basic wp-config.php example

lt?php
// ... database constants above

// Enable debugging for development
define(WP_DEBUG, true)              // Enable debugging mode
define(WP_DEBUG_LOG, true)          // Log to wp-content/debug.log
define(WP_DEBUG_DISPLAY, false)     // Dont show errors on-screen (recommended)
@ini_set(display_errors, 0)

// Optional useful constants
define(SCRIPT_DEBUG, true)          // Load non-minified scripts
define(SAVEQUERIES, true)           // Record database queries (slow)

Safer, environment-aware configuration

Dont leave WP_DEBUG enabled on production. Use environment variables or a WP_ENV constant to toggle debug mode. Common approaches: check an environment variable, check for a local file, or use server environment.

Example: use WP_ENV or getenv()

lt?php
// Determine environment (set WP_ENV via server, .env, or other means)
env = getenv(WP_ENV) ?: production

if (env === development) {
    define(WP_DEBUG, true)
    define(WP_DEBUG_LOG, true)
    define(WP_DEBUG_DISPLAY, true) // allow on local, but false on shared dev
    @ini_set(display_errors, 1)
} else {
    define(WP_DEBUG, false)
    define(WP_DEBUG_LOG, false)
    define(WP_DEBUG_DISPLAY, false)
    @ini_set(display_errors, 0)
}

Default logfile location and custom log files

By default WP_DEBUG_LOG writes to wp-content/debug.log. You can also set WP_DEBUG_LOG to a custom absolute path (string) to write logs elsewhere. Using a custom path can help separate logs or store them outside the webroot.

Default (wp-content/debug.log)

define(WP_DEBUG, true)
define(WP_DEBUG_LOG, true) // writes to WP_CONTENT_DIR . /debug.log
define(WP_DEBUG_DISPLAY, false)

Custom logfile path

define(WP_DEBUG, true)
define(WP_DEBUG_LOG, /var/log/my-site-wordpress-debug.log) // absolute path
define(WP_DEBUG_DISPLAY, false)

If you set a custom path, ensure the web server user has write permissions to that location.

Common ways to log information in PHP/WordPress

  • Use PHP error_log: error_log(message) or error_log(print_r(var, true))
  • Use trigger_error: trigger_error(Something broke, E_USER_NOTICE)
  • Dump variables for log: error_log(var_export(var, true)) or error_log(print_r(var, true))
  • Log SQL queries: define(SAVEQUERIES, true) then inspect wpdb->queries.
  • WP_ functions: _deprecated_function(_old, 1.2, _new) will trigger deprecation warnings when WP_DEBUG is on.

Examples: writing to the debug log

// Log a simple message
error_log(My plugin reached this point.)

// Log a variable or array
my_data = array(a =gt 1, b =gt 2)
error_log(print_r(my_data, true))

// Trigger a PHP user notice (shows in the log)
trigger_error(User-level notice: invalid input, E_USER_NOTICE)

Debugging AJAX, REST API, and CLI requests

WP_DEBUG and WP_DEBUG_LOG apply to front-end, admin, AJAX, REST, and CLI runs, as long as the constants are defined. For AJAX and REST, keep WP_DEBUG_DISPLAY false (or errors may break JSON responses) and rely on logging instead.

AJAX example (admin-ajax.php)

add_action(wp_ajax_my_action, function() {
    data = _POST[data] ?? null
    if (!data) {
        error_log(AJAX my_action received no data:  . print_r(_POST, true))
        wp_send_json_error(Missing data)
    }
    // ... handling ...
    wp_send_json_success([ok =gt true])
})

Inspecting database queries

Enable SAVEQUERIES to capture queries in wpdb->queries (array). This is useful for pinpointing slow queries or debugging excessive queries. Only enable in development because it stores queries in memory.

define(SAVEQUERIES, true)
define(WP_DEBUG, true)
define(WP_DEBUG_LOG, true)
define(WP_DEBUG_DISPLAY, false)

// Later in code (after queries run)
global wpdb
error_log(Queries:  . print_r(wpdb->queries, true))

File permissions and ownership

If debug.log is not created or you get permission errors, confirm the following:

  • The wp-content directory is writable by the web server user (www-data, apache, nginx, etc.).
  • Typical permissions: directories 755, files 644. The owner should be the web server user or a group that includes it.
  • If using a custom log path, adjust ownership/permissions for that path accordingly.

Example permission commands (Linux)

# Set ownership to web server user (example: www-data)
sudo chown -R www-data:www-data /var/www/site

# Ensure directories are 755 and files 644
sudo find /var/www/site -type d -exec chmod 755 {} 
sudo find /var/www/site -type f -exec chmod 644 {} 

Viewing and monitoring logs

  • tail -f on Linux/macOS: tail -f wp-content/debug.log
  • less: less F wp-content/debug.log
  • PowerShell on Windows: Get-Content debug.log -Wait
  • When using a custom file, substitute its path.
# Real-time view on Linux/macOS
tail -f /var/www/site/wp-content/debug.log

Log rotation and size management

Debug logs can grow large. On server environments, use logrotate or other rotation tools. Basic logrotate snippet:

/var/www/site/wp-content/debug.log {
    daily
    rotate 14
    compress
    missingok
    notifempty
    create 644 www-data www-data
}

Adjust ownership and rotation frequency based on your needs.

Advanced: custom logging and third-party libraries

For complex projects, consider using a PSR-3 logger like Monolog and writing logs to syslog, a cloud service, or a location outside the webroot. Example: instantiate Monolog and push messages to a rotating file handler instead of relying solely on WP_DEBUG_LOG.

Basic Monolog usage (concept)

use MonologLogger
use MonologHandlerRotatingFileHandler

log = new Logger(my-site)
handler = new RotatingFileHandler(/var/log/my-site/my-app.log, 7)
log->pushHandler(handler)

log->info(Starting process, [context =gt context])

You can still use WP_DEBUG to surface WP notices while using Monolog for structured application logging.

Interpreting messages in debug.log

  • Notices/Warnigns: Often indicate undefined variables, incorrect arguments, or use of deprecated functions.
  • Deprecated: Signals functions or arguments that will be removed in future WP versions. Update code accordingly.
  • Fatal errors: Stop execution check stack traces and file paths indicated in the log. Fix cause (missing function, fatal call) or disable a plugin/theme until resolved.

Common pitfalls and troubleshooting

  1. WP_DEBUG defined too late: If you define constants after WP has bootstrapped, they may not take effect. Always place them in wp-config.php before require_once ABSPATH . wp-settings.php.
  2. display_errors conflict: PHPs display_errors ini setting may override WP_DEBUG_DISPLAY. Use @ini_set(display_errors, 0) to be explicit when you dont want screen output.
  3. Production enabled by mistake: Leaving WP_DEBUG true on production can leak sensitive paths and data. Verify environment configuration and restrict access to debug logs.
  4. Permissions issues: debug.log not created because the web server user cannot write to wp-content. Fix ownership/permissions.
  5. JSON/API responses broken: Showing PHP notices in API responses can break JSON structure. Use WP_DEBUG_DISPLAY = false and review logs instead.

Debugging with Xdebug and step debugging

The WP_DEBUG constants control PHP/WordPress behavior but do not provide step debugging. For breakpoints, stack inspection, and step-through debugging, install Xdebug and configure your IDE (VS Code, PHPStorm). Use Xdebug for development and disable it in production.

  • Set xdebug.mode=develop,debug in php.ini (Xdebug 3).
  • Use xdebug.start_with_request=yes or trigger cookies to begin a remote session.
  • Combine Xdebug (step debugging) with WP_DEBUG for the best inspection workflow.

Using WP-CLI to change configuration

WP-CLI can modify wp-config.php or set environment-specific settings. Example:

# Set WP_DEBUG in wp-config.php (writes a raw boolean)
wp config set WP_DEBUG true --raw
wp config set WP_DEBUG_LOG true --raw
wp config set WP_DEBUG_DISPLAY false --raw

Examples of real-world debugging patterns

1) Logging during plugin initialization

add_action(plugins_loaded, function() {
    if (defined(WP_DEBUG)  WP_DEBUG) {
        error_log(MyPlugin: plugins_loaded fired)
    }
})

2) Conditional logging only for certain users

add_action(init, function() {
    if (defined(WP_DEBUG)  WP_DEBUG  current_user_can(manage_options)) {
        error_log(Admin accessed init, user ID:  . get_current_user_id())
    }
})

3) Capturing PHP shutdown errors (fatal errors)

register_shutdown_function(function() {
    err = error_get_last()
    if (err !== null) {
        error_log(Shutdown error:  . print_r(err, true))
    }
})

Security and privacy considerations

  • Never expose debug logs publicly. Keep debug.log outside of web-accessible directories or protect via server config.
  • Logs may contain sensitive data (API keys, user data) avoid logging secrets and sanitize before logging.
  • Turn off WP_DEBUG and WP_DEBUG_LOG in production unless you have a controlled, secure logging solution.

Troubleshooting checklist

  1. Confirm WP_DEBUG constants are set in wp-config.php and before wp-settings.php is loaded.
  2. Check WP_DEBUG_LOG file existence and permissions.
  3. Set WP_DEBUG_DISPLAY to false if output breaks pages or JSON.
  4. Use error_log(print_r(…, true)) to log complex data structures.
  5. Use SAVEQUERIES to inspect SQL queries when investigating performance issues.
  6. Use Xdebug for step-by-step diagnostics for complex bugs.

References and further reading

Summary

WP_DEBUG and WP_DEBUG_LOG are powerful tools for finding PHP notices, warnings, deprecations, and runtime errors in WordPress. Use them in development with WP_DEBUG_DISPLAY off on shared environments, log to files, monitor permissions, rotate logs, and never leave verbose debugging enabled on production. Combine WP_DEBUG with targeted error_log statements, SAVEQUERIES, and Xdebug for thorough debugging workflows.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Leave a Reply

Your email address will not be published. Required fields are marked *