Created
November 26, 2022 09:16
-
-
Save sumitpore/f65f4a8ff40df963934286fbeacb9061 to your computer and use it in GitHub Desktop.
R Debug Plugin Created by Andrey "Rarst" Savchenko
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
Plugin Name: R Debug | |
Description: Set of dump helpers for debug. | |
Author: Andrey "Rarst" Savchenko | |
Author URI: https://www.rarst.net/ | |
License: MIT | |
*/ | |
/** | |
* Class with static dump methods | |
*/ | |
class R_Debug | |
{ | |
/** | |
* List basic performance stats | |
* | |
* @param bool $visible display or only include in source | |
*/ | |
static function list_performance($visible = false) | |
{ | |
if (defined('DOING_AJAX')) { | |
return; | |
} | |
$stat = sprintf( | |
'%d queries in %s seconds, using %.2fMB memory', | |
get_num_queries(), | |
timer_stop(0, 3), | |
memory_get_peak_usage() / 1024 / 1024 | |
); | |
echo $visible ? $stat : "<!-- {$stat} -->"; | |
} | |
/** | |
* List defined constants | |
* | |
* @param bool|string $filter limit to matching names or values | |
*/ | |
static function list_constants($filter = false) | |
{ | |
$constants = get_defined_constants(); | |
if (false !== $filter) { | |
$temp = array(); | |
foreach ($constants as $key => $constant) { | |
if (false !== stripos($key, $filter) || false !== stripos($constant, $filter)) { | |
$temp[$key] = $constant; | |
} | |
} | |
$constants = $temp; | |
} | |
ksort($constants); | |
self::dump($constants); | |
} | |
/** | |
* Concatenate print_r of all input and echo in pre tags. | |
*/ | |
static function dump() | |
{ | |
ob_start(); | |
$output = ''; | |
foreach (func_get_args() as $arg) { | |
$output .= print_r($arg, true); | |
} | |
echo '<pre>' . $output . '</pre>'; | |
$buffer = ob_get_clean(); | |
if (isset($_GET['save_debug_to_file']) && filter_var($_GET['save_debug_to_file'])) { | |
error_log($buffer, 3, WP_CONTENT_DIR . '/r-debug.html'); | |
} else { | |
echo $buffer; | |
} | |
} | |
/** | |
* List cron entries with time remaining till next run | |
*/ | |
static function list_cron() | |
{ | |
ob_start(); | |
$cron = _get_cron_array(); | |
echo '<pre>'; | |
$offset = get_option('gmt_offset') * 3600; | |
foreach ($cron as $time => $entry) { | |
$when = '<strong>In ' . human_time_diff($time) . '</strong> (' . $time . ' ' . date_i18n(DATE_RSS, $time + $offset) . ')'; | |
echo "<br />>>>>>\t{$when}<br />"; | |
foreach (array_keys($entry) as $function) { | |
echo "\t{$function}<br />"; | |
self::list_hooks($function); | |
} | |
} | |
echo '</pre>'; | |
$buffer = ob_get_clean(); | |
if (isset($_GET['save_debug_to_file']) && filter_var($_GET['save_debug_to_file'])) { | |
error_log($buffer, 3, WP_CONTENT_DIR . '/r-debug.html'); | |
} else { | |
echo $buffer; | |
} | |
} | |
/** | |
* List hooks as currently defined | |
* | |
* @param bool|string $filter limit to matching names | |
*/ | |
static function list_hooks($filter = false) | |
{ | |
global $wp_filter; | |
$skip_filter = empty($filter); | |
$hooks = $wp_filter; | |
ksort($hooks); | |
foreach ($hooks as $tag => $hook) { | |
if ($skip_filter || false !== strpos($tag, $filter)) { | |
self::dump_hook($tag, $hook); | |
} | |
} | |
} | |
/** | |
* Output hook info | |
* | |
* @param string $tag hook name | |
* @param WP_Hook|array $hook hook data | |
*/ | |
static function dump_hook($tag, $hook) | |
{ | |
static $counter = 0; | |
if ($hook instanceof WP_Hook) { | |
$hook = $hook->callbacks; | |
} | |
ksort($hook); | |
ob_start(); | |
$counter = $counter + 1; | |
echo "<pre>>>>>>\t<strong>{$counter} - {$tag}</strong><br />"; | |
foreach ($hook as $priority => $functions) { | |
echo $priority; | |
foreach ($functions as $function) { | |
echo "\t"; | |
$callback = $function['function']; | |
if (is_string($callback)) { | |
echo $callback; | |
} elseif (is_a($callback, 'Closure')) { | |
$closure = new ReflectionFunction($callback); | |
echo 'closure from ' . $closure->getFileName() . '::' . $closure->getStartLine(); | |
} elseif (is_object($callback)) { | |
$class = new ReflectionClass($callback); | |
$name = $class->getName(); | |
if (0 === strpos($name, 'class@anonymous')) { | |
echo 'anonymous class from ' . $class->getFileName() . '::' . $class->getStartLine(); | |
} else { | |
echo $name; | |
} | |
} elseif (is_string($callback[0])) { // static method call | |
echo $callback[0] . '::' . $callback[1]; | |
} elseif (is_object($callback[0])) { | |
echo get_class($callback[0]) . '->' . $callback[1]; | |
} | |
echo (1 == $function['accepted_args']) ? '<br />' : " ({$function['accepted_args']}) <br />"; | |
} | |
} | |
echo '</pre>'; | |
$buffer = ob_get_clean(); | |
if (isset($_GET['save_debug_to_file']) && filter_var($_GET['save_debug_to_file'])) { | |
error_log($buffer, 3, WP_CONTENT_DIR . '/r-debug.html'); | |
} else { | |
echo $buffer; | |
} | |
} | |
/** | |
* Enable live listing of hooks as they run | |
* | |
* @param bool|string $hook limit to matching names | |
*/ | |
static function list_live_hooks($hook = false) | |
{ | |
if (false === $hook) { | |
$hook = 'all'; | |
} | |
add_action($hook, array(__CLASS__, 'list_hook_details'), -1); | |
} | |
/** | |
* Handler for live hooks output | |
* | |
* @param mixed $input | |
* | |
* @return mixed | |
*/ | |
static function list_hook_details($input = null) | |
{ | |
global $wp_filter; | |
$tag = current_filter(); | |
if (isset($wp_filter[$tag])) { | |
self::dump_hook($tag, $wp_filter[$tag]); | |
} | |
return $input; | |
} | |
/** | |
* List active plugins | |
*/ | |
static function list_plugins() | |
{ | |
self::dump(get_option('active_plugins')); | |
} | |
/** | |
* List post's fields, custom fields, and terms | |
* | |
* @param int $post_id | |
*/ | |
static function list_post($post_id = null) | |
{ | |
if (empty($post_id)) { | |
$post_id = get_the_ID(); | |
} | |
self::dump( | |
get_post($post_id), | |
get_post_custom($post_id), | |
wp_get_post_terms($post_id, get_post_taxonomies($post_id)) | |
); | |
} | |
/** | |
* List performed MySQL queries | |
*/ | |
static function list_queries() | |
{ | |
global $wpdb; | |
if (!defined('SAVEQUERIES') || !SAVEQUERIES) { | |
trigger_error('SAVEQUERIES needs to be defined', E_USER_NOTICE); | |
return; | |
} | |
ob_start(); | |
echo '<pre>'; | |
foreach ($wpdb->queries as $query) { | |
list($request, $duration, $backtrace) = $query; | |
$duration = sprintf('%f', $duration); | |
$backtrace = explode(',', $backtrace); | |
$backtrace = trim(array_pop($backtrace)); | |
if ('get_option' == $backtrace) { | |
preg_match_all('/\option_name.*?=.*?\'(.+?)\'/', $request, $matches); | |
$backtrace .= "({$matches[1][0]})"; | |
} | |
echo "<br /><code>{$request}</code><br />{$backtrace} in {$duration}s<br />"; | |
} | |
echo '<br /></pre>'; | |
$buffer = ob_get_clean(); | |
if (isset($_GET['save_debug_to_file']) && filter_var($_GET['save_debug_to_file'])) { | |
error_log($buffer, 3, WP_CONTENT_DIR . '/r-debug.html'); | |
} else { | |
echo $buffer; | |
} | |
} | |
/** | |
* Run EXPLAIN on provided MySQL query or last query performed. | |
* | |
* @param string $query | |
*/ | |
static function explain_query($query = '') | |
{ | |
/** @var wpdb $wpdb */ | |
global $wpdb; | |
if (empty($query)) { | |
$query = $wpdb->last_query; | |
} | |
self::dump( | |
$query, | |
$wpdb->get_results('EXPLAIN EXTENDED ' . $query), | |
$wpdb->get_results('SHOW WARNINGS') | |
); | |
} | |
} | |
// In Debug Mode, save list of hooks being executed on current page in wp-content/r-debug.log | |
// Enable below block, only during debugging. | |
// if (isset($_GET['debugging']) && filter_var($_GET['debugging'], FILTER_VALIDATE_BOOLEAN)) { | |
$_GET['save_debug_to_file'] = true; | |
$_GET['empty_old_log_in_debug_file'] = true; | |
R_Debug::list_live_hooks(); | |
// } | |
if (isset($_GET['empty_old_log_in_debug_file']) && filter_var($_GET['empty_old_log_in_debug_file'])) { | |
$fp = fopen(WP_CONTENT_DIR . '/r-debug.html', "w"); | |
if ($fp !== false) { | |
ftruncate($fp, 0); | |
fclose($fp); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment