Skip to content

Instantly share code, notes, and snippets.

@petertwise
Last active June 27, 2025 21:01
Show Gist options
  • Save petertwise/1a1ee1ae847ae5a60c54d3ba158b6d7c to your computer and use it in GitHub Desktop.
Save petertwise/1a1ee1ae847ae5a60c54d3ba158b6d7c to your computer and use it in GitHub Desktop.
Square Candy Error Logging Overrides for WordPress
<?php
/**
* Square Candy Error Logging
* Plugin Name: Square Candy Error Logging
* Plugin URI: https://gist.github.com/petertwise/1a1ee1ae847ae5a60c54d3ba158b6d7c
* Description: Overrides the default WordPress error logging to use our own settings.
* Version: 1.0.0
* Author: Square Candy
* Author URI: https://squarecandy.com
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
*/
// if this file is accessed directly, exit
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// gives us a chance to set the error log path explicitly
// this triggers the more helpful separate php error log instead of the smooshed/truncated nginx/apache log
if ( defined( 'SQCDY_ERROR_LOG_PATH' ) && ! empty( SQCDY_ERROR_LOG_PATH ) ) {
if ( 1 === SQCDY_ERROR_LOG_PATH || true === SQCDY_ERROR_LOG_PATH ) {
// if the constant is set to true or 1, use our new custom default error log path
// get the curent site domain
$site_domain = wp_parse_url( get_site_url(), PHP_URL_HOST );
// get the current site path, one directory up from the root
$log_path = dirname( ABSPATH ) . '/logs';
// check if log path exists as a directory, if not create it
if ( ! is_dir( $log_path ) ) {
wp_mkdir_p( $log_path );
}
// set the error log path to the logs directory with the site domain in the filename
$log_file = $log_path . '/' . $site_domain . '-sqcdy-php.log';
ini_set( 'error_log', $log_file );
} elseif ( is_string( SQCDY_ERROR_LOG_PATH ) ) {
// if the constant is a string use it for the error log path
ini_set( 'error_log', SQCDY_ERROR_LOG_PATH );
}
}
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) :
// change the default WP_DEBUG reporting level to ignore notices and deprecated errors;
$error_level = (int) E_ALL ^ ( E_NOTICE | E_USER_NOTICE | E_DEPRECATED );
// but allow us to override this via config to show all errors
if ( defined( 'SQCDY_DEBUG_ALL' ) && SQCDY_DEBUG_ALL ) {
$error_level = (int) E_ALL;
}
// and allow us to override the error level to anything specified via config
if ( defined( 'SQCDY_DEBUG_ERROR_LEVEL' ) && SQCDY_DEBUG_ERROR_LEVEL ) {
$error_level = SQCDY_DEBUG_ERROR_LEVEL;
}
error_reporting( $error_level ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions, WordPress.PHP.DiscouragedPHPFunctions
endif;

Square Candy Error Logging

FAQ

Why can't this be a regular plugin? Or why can't I just override these settings in php.ini instead?

This code needs to go in mu-plugins because of some quirks of how WP Core itself overrides the error logging settings.

  • If you make changes in php.ini or other server level settings, they will get overridden by WP Core
  • If you put ini_set and error_reporting changes in wp-config.php - same thing - they will load before the core files that modify error logging and get overridden.
  • If you use a regular plugin, then all of the errors in plugins that come before this one alphabetically will fire before these settings do.
  • So mu-plugins in the only dependable place to run this code.

1. Install MU Plugin

Place the my-squarecandy-error-logging.php file in wp-content/mu-plugins/

2. Configure error logging

Define the SQCDY_ERROR_LOG_PATH constant in your wp-config.php

  • Set to false or just don't define it to use the server and WP default error log paths.
  • Set to true to use our new custom default path of ../logs/{site-domain}-sqcdy-php.log. The plugin will automatically create the logs directory one level up from the WordPress root if it does not exist.
  • Set to any custom absolute error log path if you need something other than the default.

If this option is used, it will be used instead of /wp-content/debug.log if WP_DEBUG is true, and will separate out the PHP errors from the web server error log even with WP_DEBUG off.

Nginx logs rendering of PHP errors in partciular can be quite problematic. They are often truncated, grouped together or contain misleading layers of error levels.

Example nginx log entry: (note that it includes all the keywords "error", "message" and "Warning" for a warning level error)

2025/06/26 12:12:07 [error] 997946#997946: *176601 FastCGI sent in stderr: "PHP message: PHP Warning:  Undefined variable $does_not_exist in ...

Example PHP error log entry:

2025/06/26 12:12:07 PHP Warning:  Undefined variable $does_not_exist in ...

3. Configure error level

With this plugin installed and no additional configuration, the default WordPress error level is set to ignore notices and deprecated errors. This will stop the logs from being filled with "doing it wrong" notices and deprecated errors that are not actually errors yet. ( _load_textdomain_just_in_time errors will be skipped )

You can override this default error level by defining the following constants in your wp-config.php:

  • SQCDY_DEBUG_ALL - set to true to show all errors, including notices and deprecated errors.
  • SQCDY_DEBUG_ERROR_LEVEL - set to an integer value to override the error level, e.g. E_ALL, E_ERROR, etc.

Typical Example wp-config.php configuration:

define( 'WP_DEBUG', true ); // enable debugging
define( 'WP_DEBUG_LOG', true ); // enable debug log
define( 'WP_DEBUG_DISPLAY', false ); // disable debug display on the front-end

define( 'SQCDY_ERROR_LOG_PATH', true ); // use the default error log path

// uncomment to show all errors
// define( 'SQCDY_DEBUG_ALL', true );

// uncomment to override the error level to something custom
// define( 'SQCDY_DEBUG_ERROR_LEVEL', E_ALL ^ E_USER_NOTICE );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment