Skip to content

Instantly share code, notes, and snippets.

@Rayken
Last active December 17, 2015 22:49
Show Gist options
  • Save Rayken/5685176 to your computer and use it in GitHub Desktop.
Save Rayken/5685176 to your computer and use it in GitHub Desktop.
Debugging WordPress with the JavaScript Console
<?php
/**
* WordPress Console Debug
*
* Debug PHP using the JavaScript console.
* Enable this plugin and view your console for more information on how to use it.
*
* @package WP_console_debug
* @author DRSK
* @license WTFPL
*
* @wordpress-plugin
* Plugin Name: WordPress Console Debug
* Description: Debug PHP using the JavaScript console. View your console after activation for more details.
* Version: 1.0
* Author: DRSK
*/
// If this file is called directly
if( !defined( 'WP_PLUGIN_URL' ) || !defined( 'WPINC' ) )
die( 'Restricted access' );
// WP_console_debug
class WP_console_debug {
/**
* Static variables
*/
static $console_debug = null;
/**
* Initialization of the plugin
*/
function __construct() {
// set up constants for debugging types
if( !defined( 'LOG' ) ) define( 'LOG', 1 );
if( !defined( 'INFO' ) ) define( 'INFO', 2 );
if( !defined( 'WARN' ) ) define( 'WARN', 3 );
if( !defined( 'ERROR' ) ) define( 'ERROR', 4 );
// new line
define( 'NL', "\r\n" );
// add debugging to footers
add_action( 'wp_footer', array( $this, 'print_console' ) );
add_action( 'admin_footer', array( $this, 'print_console' ) );
}
/**
* Create debugging output in JavaScript
*/
public function debug( $name = null, $var = null, $type = LOG ) {
global $wpdb, $template;
// debugging template files
if( $name == TEMPLATE )
$name = basename( $template );
// fallback: if an object or array has been called as $name
if( is_object( $name ) || is_array( $name ) ) {
$var = $name;
$name = null;
}
// gather information about the call
$debug_call = $this->track_debug_call();
// start output
if( $debug_call && ( $name || $var ) )
$output = 'console.debug("Debug from '. str_replace( array( "\\" ), "\\\\", $debug_call['file'] ) . ' @ line ' . $debug_call['line']. ':");'.NL;
elseif( $debug_call && ( !$name || !$var ) )
$output = 'console.error("Something went wrong. Please check ' . str_replace( array( "\\" ), "\\\\", $debug_call['file'] ) . ' @ line ' . $debug_call['line']. '.");'.NL;
// standard output
if( $name && ( is_string( $name ) || is_int( $name ) ) ) {
switch( $type ) {
case LOG:
$output .= 'console.log("'.$name.'");'.NL;
break;
case INFO:
$output .= 'console.info("'.$name.'");'.NL;
break;
case WARN:
$output .= 'console.warn("'.$name.'");'.NL;
break;
case ERROR:
$output .= 'console.error("'.$name.'");'.NL;
break;
}
}
// if a variable has been set (or $name is an object or array)
if( !empty( $var ) ) {
if( is_object( $var ) || is_array( $var ) ) {
// JSON encode the $var and let the console do its magic
if( $var )
$object = json_encode( $var );
else
$object = 'No data available';
// uniquify each variable, just in case
if( !$name )
$name = intval( $debug_call['line'] );
// create unique JavaScript variables based on $name
$output .= 'var object'.preg_replace( '~[^A-Z|0-9]~i', "_", $name ).' = \''.str_replace( array( "'", '\"', '\r\n', '\n' ), "\'", $object ).'\';'.NL;
$output .= 'var val'.preg_replace( '~[^A-Z|0-9]~i', "_", $name ).' = eval("(" + object'.preg_replace( '~[^A-Z|0-9]~i', "_", $name ).' + ")" );'.NL;
// output for objects and arrays
switch($type) {
case LOG:
$output .= 'console.debug(val'.preg_replace( '~[^A-Z|0-9]~i', "_", $name ).');'.NL;
break;
case INFO:
$output .= 'console.info(val'.preg_replace( '~[^A-Z|0-9]~i', "_", $name ).');'.NL;
break;
case WARN:
$output .= 'console.warn(val'.preg_replace( '~[^A-Z|0-9]~i', "_", $name ).');'.NL;
break;
case ERROR:
$output .= 'console.error(val'.preg_replace( '~[^A-Z|0-9]~i', "_", $name ).');'.NL;
break;
}
} else {
// output for variables
switch($type) {
case LOG:
$output .= 'console.debug("'.str_replace( '"', '\\"', $var ).'");'.NL;
break;
case INFO:
$output .= 'console.info("'.str_replace( '"', '\\"', $var ).'");'.NL;
break;
case WARN:
$output .= 'console.warn("'.str_replace( '"', '\\"', $var ).'");'.NL;
break;
case ERROR:
$output .= 'console.error("'.str_replace( '"', '\\"', $var ).'");'.NL;
break;
}
}
}
// assign the output to the static variable as an array
self::$console_debug[] = $output;
}
/**
* Trackback call data from function debug
*/
private function track_debug_call() {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// locate the debugging
if( 'console_debug' == $backtrace[2]['function'] )
return $backtrace[2];
else
return false;
}
/**
* Output the debugging and help menu
*/
public function print_console() {
// start WP Console Debug
echo NL.'<!-- WordPress Console Debug -->';
// IE and other browsers without a good console
$ie = NL.'<!-- Internet Explorer -->' . NL .'<script type="text/javascript">'.NL;
$ie .= '(function(f){f||(f=window.console={log:function(a,b,c,d,e){},info:function(a,b,c,d,e){},warn:function(a,b,c,d,e){},error:function(a,b,c,d,e){}});if(!Function.prototype.bind){Function.prototype.bind=function(a){var b=this,args=Array.prototype.slice.call(arguments,1);return function(){return b.apply(a,Array.prototype.concat.apply(args,arguments))}}}if(typeof(f.log)===\'object\'){f.log=Function.prototype.call.bind(f.log,f);f.info=Function.prototype.call.bind(f.info,f);f.warn=Function.prototype.call.bind(f.warn,f);f.error=Function.prototype.call.bind(f.error,f)}(\'group\'in f)||(f.group=function(a){f.info("\n------------\n"+a+"\n------------")});(\'groupEnd\'in f)||(f.groupEnd=function(){});(\'time\'in f)||(function(){var c={};f.time=function(a){c[a]=new Date().getTime()};f.timeEnd=function(a){var b=new Date().getTime(),time=(a in c)?b-c[a]:0;f.info(a+\': \'+time+\'ms\')}}())})(window.console);';
$ie .= 'if (!window.console) console = {};';
$ie .= 'console.log = console.log || function(){};';
$ie .= 'console.warn = console.warn || function(){};';
$ie .= 'console.error = console.error || function(){};';
$ie .= 'console.info = console.info || function(){};';
$ie .= 'console.debug = console.debug || function(){};';
$ie .= 'console.groupCollapsed = console.groupCollapsed || function(){};';
$ie .= 'console.groupEnd = console.groupEnd || function(){};';
$ie .= '</script>';
echo $ie;
// set up help menu
$help = NL.'<!-- Help Menu -->' . NL .'<script type="text/javascript">';
$help .= 'console.groupCollapsed("WordPress Console Debug");'.NL;
$help .= 'console.log("To hide this menu, use: define( \'WPDC_HELP\', false );");'.NL;
$help .= 'console.warn("Note: the console is very limited in IE and does not work as intended.");'.NL;
$help .= 'console.groupCollapsed("Standard debugging");'.NL;
$help .= 'console.debug("Examples for simple debugging");'.NL;
$help .= 'console.log("// Simple message to console \nconsole_debug(\"A very simple message\"); \n \n// Variable to console \n$x = 3; \n$y = 5; \n$z = $x/$y; \nconsole_debug(\"Variable Z: \", $z); \n \n// A warning \nconsole_debug(\"A simple Warning\", null, WARN); \n \n// Info \nconsole_debug(\"A simple Info message\", null, INFO); \n \n// An error \nconsole_debug(\"A simple error messsage\", null, ERROR); \n \n// Array in console \n$fruits = array(\"banana\", \"apple\", \"strawberry\", \"pineaple\"); \n$fruits = array_reverse($fruits); \nconsole_debug(\"Fruits array\", $fruits); \n \n \n// Object to console \n$book = new stdClass; \n$book->title = \"Harry Potter and the Prisoner of Azkaban\"; \n$book->author = \"J. K. Rowling\"; \n$book->publisher = \"Arthur A. Levine Books\"; \n$book->amazon_link = \"http://www.amazon.com/dp/0439136369/\"; \nconsole_debug(\"Object\", $book);");'.NL;
$help .= 'console.groupEnd();'.NL;
$help .= 'console.groupCollapsed("WordPress Debugging");'.NL;
$help .= 'console.debug("Examples for WordPress debugging");'.NL;
$help .= 'console.log("console_debug(get_the_id());\nconsole_debug(\"Post name:\", $post->post_name);\nconsole_debug(\"Post meta:\", get_post_meta( $post->ID ));\n\n//Check template\nWithin a template: console_debug( TEMPLATE );\nCheck all templates: add_action( \'the_content\', function( $content ) { return $content . console_debug( TEMPLATE ); } );\n\n//Check post data\nWithin a teplate: console_debug( $post );\nCheck post data everywhere: add_action( \'the_content\', function( $content ) { global $post; return $content . console_debug( $post ); } );");'.NL;
$help .= 'console.groupEnd();'.NL;
$help .= 'console.groupEnd();'.NL;
$help .= '</script>';
// if help constant is false, don't show the menu
if( ( defined( 'WPDC_HELP' ) && WPDC_HELP !== FALSE ) || !defined( 'WPDC_HELP' ) )
echo $help;
// loop debugs
if( self::$console_debug ) {
$debug_output = NL.'<!-- Debugging -->' . NL .'<script type="text/javascript">'.NL;
foreach( self::$console_debug as $debug )
$debug_output .= $debug;
$debug_output .= '</script>';
echo $debug_output;
}
echo NL.'<!-- end: WordPress console debug -->'.NL;
}
}
// create new instance of the class
$wp_console_debug = new WP_console_debug();
// debug function
function console_debug( $name = null, $var = null, $type = LOG ) {
global $wp_console_debug;
return $wp_console_debug->debug( $name, $var, $type );
}
@redbar0n
Copy link

redbar0n commented Jul 6, 2015

Neat script! Though, just to let you and potential others know: I'm afraid it doesn't work in WordPress hooks where a page redirect is executed immediately after the hook, like publish_to_publish (pressing "update" on a post). http://wordpress.stackexchange.com/questions/193641/how-to-use-output-buffering-in-wordpress-hooked-functions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment