Skip to content

Instantly share code, notes, and snippets.

@warwickandersonza
Last active April 22, 2024 18:18
Show Gist options
  • Save warwickandersonza/d78e4c660b2c20ac37da5bb48ee6b6a8 to your computer and use it in GitHub Desktop.
Save warwickandersonza/d78e4c660b2c20ac37da5bb48ee6b6a8 to your computer and use it in GitHub Desktop.
Asynchronous WordPress debugging functions
<?php
define( 'WAR_LOG_FILE', sprintf( '%s%sdebug.html', __DIR__, DIRECTORY_SEPARATOR ) );
define( 'WAR_LOG_URL', sprintf( 'https://%s/debug.php', $_SERVER['HTTP_HOST'] ?? '' ) );
/**
* @param mixed $arg
*
* @return mixed
*/
function _debug_arg( mixed $arg ): mixed {
if ( is_object( $arg ) ) {
return get_class( $arg );
}
if ( is_array( $arg ) ) {
return array_map( function ( $item ) {
return _debug_arg( $item );
}, $arg );
}
return $arg;
}
/**
* @param string $content
* @param string $name
*
* @return void
*/
function _debug_put( string $content, string $name = '' ): void {
if ( is_array( $name ) ) {
$name = implode( ', ', $name );
}
if ( is_object( $name ) ) {
$name = get_class( $name );
}
if ( ! is_string( $name ) ) {
$name = (string) $name;
}
$log = sprintf( '<pre class="header"><small><b>%s / <span class="name">%s</span></b></small></pre><pre>%s</pre>', date( 'Y-m-d H:i:s' ), $name, $content );
$log = mb_convert_encoding( $log, 'UTF-8' );
file_put_contents( WAR_LOG_FILE, $log, FILE_APPEND );
}
/**
* @param mixed $variable
* @param string $name
* @param int $i
* @param array|null $trace
*
* @return void
*/
function _debug_dump( mixed $variable, string $name = '', int $i = 1, array $trace = null ): void {
ob_start();
var_dump( $variable ); $line = __LINE__;
$dump = ob_get_clean();
$trace = $trace ?? debug_backtrace();
$callerFile = $trace[ $i ]['file'];
$callerLine = $trace[ $i ]['line'];
$dump = str_replace( sprintf( '%s:%s:', __FILE__, $line ), sprintf( '%s:%s:', $callerFile, $callerLine ), $dump );
_debug_put( $dump, $name );
}
/**
* @param bool $reverse
* @param string $name
* @param bool $skip_args
*
* @return void
*/
function _debug_trace( bool $reverse = false, string $name = '', bool $skip_args = false ): void {
$trace = array();
foreach ( debug_backtrace() as $step ) {
$details = array(
'file' => $step['file'] ?? null,
'line' => $step['line'] ?? null,
'class' => $step['class'] ?? null,
'function' => $step['function'] ?? null,
);
if ( ! $skip_args ) {
$args = array();
foreach ( $step['args'] as $arg ) {
$args[] = _debug_arg( $arg );
}
if ( count( $args ) ) {
$details['args'] = $args;
}
}
$trace[] = $details;
}
if ( $reverse ) {
$trace = array_reverse( $trace );
}
_debug_dump( $trace, $name );
}
/**
* @param mixed $variable
*
* @return string
*/
function _debug_type( mixed $variable ): string {
return is_object( $variable ) ? get_class( $variable ) : gettype( $variable );
}
/**
* @return void
*/
function war_clear(): void {
unlink( WAR_LOG_FILE );
}
/**
* @param mixed $variable
* @param string $name
*
* @return void
*/
function war_log( mixed $variable, string $name = '' ): void {
_debug_dump( $variable, $name );
}
/**
* @param bool $condition
* @param mixed $variable
* @param string $name
*
* @return void
*/
function war_logif( bool $condition, mixed $variable, string $name = '' ): void {
if ( $condition ) {
_debug_dump( $variable, $name );
}
}
/**
* @param bool $reverse
* @param string $name
* @param bool $skip_args
*
* @return void
*/
function war_trace( bool $reverse = false, string $name = '', bool $skip_args = false ): void {
_debug_trace( $reverse, $name, $skip_args );
}
/**
* @param bool $condition
* @param bool $reverse
* @param string $name
* @param bool $skip_args
*
* @return void
*/
function war_traceif( bool $condition, bool $reverse = false, string $name = '', bool $skip_args = false ): void {
if ( $condition ) {
_debug_trace( $reverse, $name, $skip_args);
}
}
/**
* @param string $variable
* @param string $name
*
* @return void
*/
function war_put( mixed $variable, string $name = '' ): void {
_debug_put( $variable, $name );
}
/**
* @param mixed $variable
* @param string $name
*
* @return void
*/
function war_type( mixed $variable, string $name = '' ): void {
_debug_dump( _debug_type( $variable ), $name );
}
/**
* @param string $hook_name
* @param int $priority
* @param int $accepted_args
*
* @return void
*/
function war_filter( string $hook_name, int $priority = 10, int $accepted_args = 1 ): void {
$trace = debug_backtrace();
add_filter( $hook_name, function () use ( $hook_name, $trace ) {
$variable = array();
foreach ( func_get_args() as $i => $value ) {
if ( 0 === $i ) {
$variable['value'] = $value;
} else {
$n = $i - 1;
$key = 'arg' . $n;
$variable[ $key ] = $value;
}
}
_debug_dump( $variable, $hook_name, 0, $trace );
return func_get_arg( 0 );
}, $priority, $accepted_args );
}
/**
* @param string $hook_name
* @param int $priority
* @param int $accepted_args
*
* @return void
*/
function war_action( string $hook_name, int $priority = 10, int $accepted_args = 1 ): void {
$trace = debug_backtrace();
add_action( $hook_name, function () use ( $hook_name, $trace ) {
$variable = array();
foreach ( func_get_args() as $i => $value ) {
$n = $i - 1;
$key = 'arg' . $n;
$variable[ $key ] = $value;
}
_debug_dump( $variable, $hook_name, 0, $trace );
}, $priority, $accepted_args );
}
if ( ! defined('ABSPATH' ) ):
if ( ! empty( $_GET['clear'] ) && 'clear' === $_GET['clear'] ) {
unlink( WAR_LOG_FILE );
header( 'Location:' . WAR_LOG_URL );
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Debug Log</title>
<style>
:root {
--solarized-base03: #002b36;
--solarized-base02: #073642;
--solarized-base01: #586e75;
--solarized-base00: #657b83;
--solarized-base0: #839496;
--solarized-base1: #93a1a1;
--solarized-base2: #eee8d5;
--solarized-base3: #fdf6e3;
--solarized-yellow: #b58900;
--solarized-orange: #cb4b16;
--solarized-red: #dc322f;
--solarized-magenta: #d33682;
--solarized-violet: #6c71c4;
--solarized-blue: #268bd2;
--solarized-cyan: #2aa198;
--solarized-green: #859900;
}
body {
margin-top: 58px;
color: var(--solarized-base01);
background-color: var(--solarized-base3);
}
#controls {
margin: 0;
padding: 6px;
position: fixed;
top: 8px;
left: 8px;
background-color: var(--solarized-base3);
}
#controls a {
color: var(--solarized-red);
}
.header {
margin-top: 30px;
border-top: solid 1px var(--solarized-base01);
padding-top: 30px;
}
.name {
color: var(--solarized-red);
}
font[color="#888a85"] {
color: var(--solarized-base01);
}
font[color="#75507b"] {
color: var(--solarized-violet) !important;
}
font[color="#3465a4"] {
color: var(--solarized-blue) !important;
}
font[color="#4e9a06"] {
color: var(--solarized-green) !important;
}
font[color="#cc0000"] {
color: var(--solarized-red) !important;
}
@media screen and (prefers-color-scheme: dark) {
body {
color: var(--solarized-base1);
background-color: var(--solarized-base03);
}
#controls {
background-color: var(--solarized-base03);
}
.header {
border-top: solid 1px var(--solarized-base1);
}
font[color="#888a85"] {
color: var(--solarized-base1);
}
}
</style>
</head>
<body>
<pre id="controls"><a href="<?php echo WAR_LOG_URL; ?>?clear=clear">Clear</a> | <a href="<?php echo WAR_LOG_URL; ?>">Refresh</a></pre>
<?php if ( file_exists( WAR_LOG_FILE ) ) include WAR_LOG_FILE; ?>
</body>
</html>
<?php endif;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment