TheLib_Debug

The Debug component.

Defined (1)

The class is defined in the following location(s).

/lib/wpmu-lib/inc/class-thelib-debug.php  
  1. class TheLib_Debug extends TheLib { 
  2.  
  3. /** 
  4. * If set to true or false it will override the WP_DEBUG value 
  5. * If set to null the WP_DEBUG and WDEV_DEBUG values are used. 
  6. * @since 1.1.4 
  7. * @internal 
  8. * @var bool 
  9. */ 
  10. protected $enabled = null; 
  11.  
  12. /** 
  13. * If set to true each debug output will contain a stack-trace. 
  14. * Otherwise only the variable will be dumped. 
  15. * @since 1.1.4 
  16. * @internal 
  17. * @var bool 
  18. */ 
  19. protected $stacktrace = true; 
  20.  
  21. /** 
  22. * Toggles the plain-text / HTML output of the debug. 
  23. * All Ajax requests will ignore this flag and use plain-text format. 
  24. * @since 1.1.4 
  25. * @internal 
  26. * @var bool 
  27. */ 
  28. protected $plain_text = false; 
  29.  
  30. /** 
  31. * Constructor. 
  32. * Setup action hooks for debugger. 
  33. * @since 2.0.0 
  34. * @internal 
  35. */ 
  36. public function __construct() { 
  37. remove_all_actions( 'wdev_debug_log' ); 
  38. remove_all_actions( 'wdev_debug_log_trace' ); 
  39. remove_all_actions( 'wdev_debug_dump' ); 
  40. remove_all_actions( 'wdev_debug_trace' ); 
  41.  
  42. add_action( 
  43. 'wdev_debug_log',  
  44. array( $this, 'log' ),  
  45. 10, 99 
  46. ); 
  47.  
  48. add_action( 
  49. 'wdev_debug_log_trace',  
  50. array( $this, 'log_trace' ) 
  51. ); 
  52.  
  53. add_action( 
  54. 'wdev_debug_dump',  
  55. array( $this, 'dump' ),  
  56. 10, 99 
  57. ); 
  58.  
  59. add_action( 
  60. 'wdev_debug_trace',  
  61. array( $this, 'trace' ) 
  62. ); 
  63.  
  64. /** 
  65. * Resets all debug-output flags. 
  66. * @since 1.1.4 
  67. * @api 
  68. */ 
  69. public function reset() { 
  70. $this->enabled = null; 
  71. $this->stacktrace = true; 
  72.  
  73. /** 
  74. * Force-Enable debugging. 
  75. * @since 1.1.4 
  76. * @api 
  77. */ 
  78. public function enable() { 
  79. $this->enabled = true; 
  80.  
  81. /** 
  82. * Force-Disable debugging. 
  83. * @since 1.1.4 
  84. * @api 
  85. */ 
  86. public function disable() { 
  87. $this->enabled = false; 
  88.  
  89. /** 
  90. * Returns the debugging status. False means no debug output is made. 
  91. * @since 2.0.0 
  92. * @api 
  93. * @return bool 
  94. */ 
  95. public function is_enabled() { 
  96. $enabled = $this->enabled; 
  97. $is_ajax = false; 
  98. if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { $is_ajax = true; } 
  99. if ( defined( 'DOING_CRON' ) && DOING_CRON ) { $is_ajax = true; } 
  100.  
  101. if ( null === $enabled ) { 
  102. if ( $is_ajax ) { 
  103. $enabled = WDEV_AJAX_DEBUG; 
  104. } else { 
  105. $enabled = WDEV_DEBUG; 
  106.  
  107. return $enabled; 
  108.  
  109. /** 
  110. * Enable stack-trace. 
  111. * @since 1.1.4 
  112. * @api 
  113. */ 
  114. public function stacktrace_on() { 
  115. $this->stacktrace = true; 
  116.  
  117. /** 
  118. * Disable stack-trace. 
  119. * @since 1.1.4 
  120. * @api 
  121. */ 
  122. public function stacktrace_off() { 
  123. $this->stacktrace = false; 
  124.  
  125. /** 
  126. * Do not format debug output. 
  127. * @since 1.1.4 
  128. * @api 
  129. */ 
  130. public function format_text() { 
  131. $this->plain_text = true; 
  132.  
  133. /** 
  134. * Use HTML to format debug output. 
  135. * @since 1.1.4 
  136. * @api 
  137. */ 
  138. public function format_html() { 
  139. $this->plain_text = false; 
  140.  
  141. /** 
  142. * Determines if the debug output should be made in plain text. 
  143. * @since 2.0.0 
  144. * @api 
  145. * @return bool 
  146. */ 
  147. public function is_plain_text() { 
  148. $plain_text = $this->plain_text; 
  149.  
  150. $is_ajax = false; 
  151. if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) { $is_ajax = true; } 
  152. if ( defined( 'DOING_CRON' ) && DOING_CRON ) { $is_ajax = true; } 
  153. if ( $is_ajax ) { $plain_text = true; } 
  154.  
  155. return $plain_text; 
  156.  
  157. /** 
  158. * Write debug information to error log file. 
  159. * @since 2.0.0 
  160. * @api 
  161. * @param mixed <dynamic> Each param will be dumped 
  162. */ 
  163. public function log( $first_arg ) { 
  164. if ( $this->is_enabled() ) { 
  165. $plain_text = $this->plain_text; 
  166. $this->format_text(); 
  167. $log_file = WP_CONTENT_DIR . '/lib3.log'; 
  168. $time = date( "Y-m-d\tH:i:s\t" ); 
  169.  
  170. foreach ( func_get_args() as $param ) { 
  171. if ( is_scalar( $param ) ) { 
  172. $dump = $param; 
  173. } else { 
  174. $dump = var_export( $param, true ); 
  175. error_log( $time . $dump . "\n", 3, $log_file ); 
  176.  
  177. $this->plain_text = $plain_text; 
  178.  
  179. /** 
  180. * Write stacktrace information to error log file. 
  181. * @since 2.0.0 
  182. * @api 
  183. */ 
  184. public function log_trace() { 
  185. if ( $this->is_enabled() ) { 
  186. $plain_text = $this->plain_text; 
  187. $this->format_text(); 
  188. $log_file = WP_CONTENT_DIR . '/lib3.log'; 
  189.  
  190. // Display the backtrace. 
  191. $trace = $this->trace( false ); 
  192. error_log( $trace, 3, $log_file ); 
  193.  
  194. $this->plain_text = $plain_text; 
  195.  
  196. /** 
  197. * Adds a log-message to the HTTP response header. 
  198. * This is very useful to debug Ajax requests or redirects. 
  199. * @since 2.0.3 
  200. * @param string $message The debug message 
  201. */ 
  202. public function header( $message ) { 
  203. static $Number = 0; 
  204. if ( ! $this->is_enabled() ) { return; } 
  205.  
  206. $Number += 1; 
  207. if ( headers_sent() ) { 
  208. // HTTP Headers already sent, so add the response as HTML comment. 
  209. $message = str_replace( '-->', '--/>', $message ); 
  210. printf( "<!-- Debug-Note[%s]: %s -->\n", $Number, $message ); 
  211. } else { 
  212. // No output was sent yet so add the message to the HTTP headers. 
  213. $message = str_replace( array( "\n", "\r" ), ' ', $message ); 
  214. header( "X-Debug-Note[$Number]: $message", false ); 
  215.  
  216. /** 
  217. * Displays a debug message at the current position on the page. 
  218. * @since 1.0.14 
  219. * @api 
  220. * @param mixed <dynamic> Each param will be dumped. 
  221. */ 
  222. public function dump( $first_arg ) { 
  223. if ( ! $this->is_enabled() ) { return; } 
  224. $plain_text = $this->is_plain_text(); 
  225.  
  226. $this->add_scripts(); 
  227.  
  228. if ( ! $plain_text ) { 
  229. $block_id = 'wdev-debug-' . md5( rand() ); 
  230. $block_label = ''; 
  231. if ( is_scalar( $first_arg ) && ! empty( $first_arg ) ) { 
  232. $block_label = ': ' . (string) $first_arg; 
  233. ?> 
  234. <div class="wdev-debug"> 
  235. <span class="wdev-debug-label" onclick="toggleBlock('<?php echo esc_attr( $block_id ); ?>')"> 
  236. DEBUG<?php echo esc_html( $block_label ); ?> 
  237. </span> 
  238. <div class="<?php echo esc_attr( $block_id ); ?>"> 
  239. <table cellspacing="0" cellpadding="0" width="100%" border="0" class="wdev-dump"> 
  240. <?php 
  241. foreach ( func_get_args() as $param ) { 
  242. $this->_dump_var( $param ); 
  243. ?> 
  244. </table> 
  245. <?php 
  246. } else { 
  247. foreach ( func_get_args() as $param ) { 
  248. $dump = var_export( $param, true ); 
  249. echo "\r\n" . $dump; 
  250.  
  251. // Display the backtrace. 
  252. if ( $this->stacktrace ) { 
  253. $this->trace(); 
  254.  
  255. if ( ! $plain_text ) { 
  256. echo '</div>'; 
  257. echo '<div class="wdev-debug-clear"></div>'; 
  258. echo '</div>'; 
  259.  
  260. /** 
  261. * Output a stack-trace. 
  262. * @since 2.0.0 
  263. * @api 
  264. * @param bool $output Optional. If false then the trace will be returned 
  265. * instead of echo'ed. Default: true (echo) 
  266. * @return string Returns the stack-trace contents. 
  267. */ 
  268. public function trace( $output = true ) { 
  269. if ( ! $this->is_enabled() ) { return; } 
  270. $plain_text = $this->is_plain_text(); 
  271.  
  272. $this->add_scripts(); 
  273. $trace_str = ''; 
  274.  
  275. if ( ! $plain_text ) { 
  276. $block_id = 'wdev-debug-' . md5( rand() ); 
  277. $trace_str .= sprintf( 
  278. '<span class="wdev-trace-toggle" onclick="toggleBlock(\'%1$s-trace\')"> 
  279. <b>Back-Trace</b> 
  280. </span> 
  281. <div class="%1$s-trace" style="display:none"> 
  282. <table class="wdev-trace" width="100%%" cellspacing="0" cellpadding="3" border="1"> 
  283. ',  
  284. esc_attr( $block_id ) 
  285. ); 
  286.  
  287. $trace = debug_backtrace(); 
  288. $trace_num = count( $trace ); 
  289. $line = 0; 
  290.  
  291. for ( $i = 0; $i < $trace_num; $i += 1 ) { 
  292. $item = $trace[$i]; 
  293. $line_item = $item; 
  294. $j = $i; 
  295.  
  296. while ( empty( $line_item['line'] ) && $j < $trace_num ) { 
  297. $line_item = $trace[$j]; 
  298. $j += 1; 
  299.  
  300. self::$core->array->equip( $line_item, 'file', 'line', 'class', 'type', 'function' ); 
  301. self::$core->array->equip( $item, 'args', 'file', 'line', 'class', 'type', 'function' ); 
  302. if ( 0 === strpos( $item['class'], 'TheLib_' ) ) { continue; } 
  303.  
  304. $line += 1; 
  305. $args = ''; 
  306. $arg_num = ''; 
  307. $dummy = array(); 
  308.  
  309. if ( $i > 0 && is_array( $item['args'] ) && count( $item['args'] ) ) { 
  310. foreach ( $item['args'] as $arg ) { 
  311. if ( is_scalar( $arg ) ) { 
  312. if ( is_bool( $arg ) ) { 
  313. $dummy[] = ( $arg ? 'true' : 'false' ); 
  314. } elseif ( is_string( $arg ) ) { 
  315. $dummy[] = '"' . $arg . '"'; 
  316. } else { 
  317. $dummy[] = $arg; 
  318. } elseif ( is_array( $arg ) ) { 
  319. $dummy[] = '<i>[Array]</i>'; 
  320. } elseif ( is_object( $arg ) ) { 
  321. $dummy[] = '<i>[' . get_class( $arg ) . ']</i>'; 
  322. } elseif ( is_null( $arg ) ) { 
  323. $dummy[] = '<i>NULL</i>'; 
  324. } else { 
  325. $dummy[] = '<i>[???]</i>'; 
  326.  
  327. $args = implode( '</font></span><span class="trc-param"><font>', $dummy ); 
  328. $args = '<span class="trc-param"><font>' . $args . '</font></span>'; 
  329.  
  330. if ( $plain_text ) { 
  331. $file = $line_item['file']; 
  332. if ( strlen( $file ) > 80 ) { 
  333. $file = '...' . substr( $line_item['file'], -77 ); 
  334. } else { 
  335. $file = str_pad( $file, 80, ' ', STR_PAD_RIGHT ); 
  336.  
  337. $trace_str .= sprintf( 
  338. "\r\n %s. \t %s \t by %s",  
  339. str_pad( $line, 2, ' ', STR_PAD_LEFT ),  
  340. $file . ': ' . str_pad( $line_item['line'], 5, ' ', STR_PAD_LEFT ),  
  341. $item['class'] . $item['type'] . $item['function'] . '(' . strip_tags( $args ) . ')' 
  342. ); 
  343. } else { 
  344. $trace_str .= sprintf( 
  345. "<tr onclick='_m(this)'><td class='trc-num'>%s</td><td class='trc-loc'>%s</td><td class='trc-arg'>%s</td></tr>\r\n",  
  346. $line,  
  347. $line_item['file'] . ': ' . $line_item['line'],  
  348. $item['class'] . $item['type'] . $item['function'] . '(' . $args . ')' 
  349. ); 
  350.  
  351. if ( $plain_text ) { 
  352. $trace_str .= "\r\n-----\r\n"; 
  353. } else { 
  354. $trace_str .= '</table>'; 
  355. $trace_str .= '</div>'; 
  356.  
  357. if ( $output ) { 
  358. echo '' . $trace_str; 
  359.  
  360. return $trace_str; 
  361.  
  362. /** 
  363. * Outputs an advanced var dump. 
  364. * @since 1.1.0 
  365. * @internal 
  366. * @param any $input The variable/object/value to dump. 
  367. * @param int $default_depth Deeper items will be collapsed 
  368. * @param int $level Do not change this value! 
  369. */ 
  370. protected function _dump_var( $data, $item_key = null, $default_depth = 3, $level = array( null ), $args = array() ) { 
  371. if ( ! is_string( $data ) && is_callable( $data ) ) { 
  372. $type = 'Callable'; 
  373. } else { 
  374. $type = ucfirst( gettype( $data ) ); 
  375.  
  376. if ( empty( $level ) ) { $level = array( null ); } 
  377. $args['containers'] = self::$core->array->get( $args['containers'] ); 
  378. $args['collapsed'] = self::$core->array->get( $args['collapsed'] ); 
  379.  
  380. $type_data = null; 
  381. $type_length = null; 
  382. $full_dump = false; 
  383.  
  384. switch ( $type ) { 
  385. case 'String': 
  386. $type_length = strlen( $data ); 
  387. $type_data = '"' . htmlentities( $data ) . '"'; 
  388. break; 
  389.  
  390. case 'Double': 
  391. case 'Float': 
  392. $type = 'Float'; 
  393. $type_length = strlen( $data ); 
  394. $type_data = htmlentities( $data ); 
  395. break; 
  396.  
  397. case 'Integer': 
  398. $type_length = strlen( $data ); 
  399. $type_data = htmlentities( $data ); 
  400. break; 
  401.  
  402. case 'Boolean': 
  403. $type_length = strlen( $data ); 
  404. $type_data = $data ? 'TRUE' : 'FALSE'; 
  405. break; 
  406.  
  407. case 'NULL': 
  408. $type_length = 0; 
  409. $type_data = 'NULL'; 
  410. break; 
  411.  
  412. case 'Array': 
  413. $type_length = count( $data ); 
  414. break; 
  415.  
  416. case 'Object': 
  417. $full_dump = true; 
  418. break; 
  419.  
  420. $type_label = $type . ( $type_length !== null ? '(' . $type_length . ')' : '' ); 
  421.  
  422. if ( in_array( $type, array( 'Object', 'Array' ) ) ) { 
  423. $populated = false; 
  424.  
  425. $dump_data = (array) $data; 
  426. ksort( $dump_data ); 
  427.  
  428. if ( 'Object' == $type ) { 
  429. $type_label .= ' [' . get_class( $data ) . ']'; 
  430.  
  431. $last_key = end( (array_keys( $dump_data )) ); 
  432. reset( $dump_data ); 
  433.  
  434. foreach ( $dump_data as $key => $value ) { 
  435. if ( ! $populated ) { 
  436. $populated = true; 
  437.  
  438. $id = substr( md5( rand() . ':' . $key . ':' . count( $level ) ), 0, 8 ); 
  439. $args['containers'][] = $id; 
  440. $collapse = count( $args['containers'] ) >= $default_depth; 
  441. if ( $collapse ) { 
  442. $args['collapsed'][] = $id; 
  443.  
  444. $title_args = $args; 
  445. $title_args['toggle'] = $id; 
  446.  
  447. $this->_dump_line( 
  448. $item_key,  
  449. $type_label,  
  450. '',  
  451. $level,  
  452. $title_args 
  453. ); 
  454. unset( $args['protected'] ); 
  455. unset( $args['private'] ); 
  456.  
  457. // Tree right before the item-name 
  458. $new_level = $level; 
  459.  
  460. if ( $last_key == $key ) { 
  461. $new_level[] = false; 
  462. $args['lastkey'] = true; 
  463. } else { 
  464. $new_level[] = true; 
  465. $args['lastkey'] = false; 
  466.  
  467. $encode_key = json_encode( $key ); 
  468. $matches = null; 
  469. if ( 1 === strpos( $encode_key, '\\u0000*\\u0000' ) ) { 
  470. $args['protected'] = true; 
  471. $key = substr( $key, 3 ); 
  472. } elseif ( 1 === preg_match( '/\\\\u0000(\w+)\\\\u0000/i', $encode_key, $matches ) ) { 
  473. $args['private'] = true; 
  474. $key = substr( $key, 2 + strlen( $matches[1] ) ); 
  475.  
  476. $this->_dump_var( 
  477. $value,  
  478. $key,  
  479. $default_depth,  
  480. $new_level,  
  481. $args 
  482. ); 
  483.  
  484. unset( $args['protected'] ); 
  485. unset( $args['private'] ); 
  486. } // end of array/object loop. 
  487.  
  488. if ( ! $populated ) { 
  489. $this->_dump_line( 
  490. $item_key,  
  491. $type_label,  
  492. '',  
  493. $level,  
  494. $args 
  495. ); 
  496. } else { 
  497. $this->_dump_line( 
  498. $item_key,  
  499. $type_label,  
  500. $type_data,  
  501. $level,  
  502. $args 
  503. ); 
  504.  
  505. /** 
  506. * Outputs a single line of the dump_var output. 
  507. * @since 1.1.4 
  508. * @internal 
  509. */ 
  510. protected function _dump_line( $key, $type, $value, $level, $args = array() ) { 
  511. $type_color = '#999'; 
  512. $type_key = strtolower( $type ); 
  513. if ( strlen( $type_key ) > 4 ) { $type_key = substr( $type_key, 0, 4 ); } 
  514.  
  515. $custom_type_colors = array( 
  516. 'stri' => 'green',  
  517. 'doub' => '#0099c5',  
  518. 'floa' => '#0099c5',  
  519. 'inte' => 'red',  
  520. 'bool' => '#92008d',  
  521. 'null' => '#AAA',  
  522. ); 
  523.  
  524. if ( isset( $custom_type_colors[ $type_key ] ) ) { 
  525. $type_color = $custom_type_colors[ $type_key ]; 
  526.  
  527. $collapse = array_intersect( $args['containers'], $args['collapsed'] ); 
  528. $args['do_collapse'] = is_array( $collapse ) && count( $collapse ) > 0; 
  529. if ( ! empty( $args['toggle'] ) ) { 
  530. $args['containers'] = array_diff( $args['containers'], array( $args['toggle'] ) ); 
  531. $args['collapsed'] = array_diff( $args['collapsed'], array( $args['toggle'] ) ); 
  532.  
  533. $collapse_this = array_intersect( $args['containers'], $args['collapsed'] ); 
  534. $args['do_collapse_next'] = $args['do_collapse']; 
  535. $args['do_collapse'] = is_array( $collapse_this ) && count( $collapse_this ) > 0; 
  536.  
  537. $row_class = ''; 
  538. $row_attr = ''; 
  539. if ( ! empty( $args['containers'] ) ) { 
  540. $row_class = implode( ' ', $args['containers'] ); 
  541. if ( ! empty( $args['do_collapse'] ) ) { 
  542. $row_attr = 'style="display:none;"'; 
  543. echo '<tr class="' . $row_class . '"' . $row_attr . '><td>'; 
  544.  
  545. // Property-key, if set. 
  546. if ( $key === null ) { 
  547. // Full Tree-level. 
  548. echo '<span class="dev-tree">'; 
  549. for ( $i = 0; $i < count( $level ); $i += 1 ) { 
  550. if ( null === $level[$i] ) { continue; } 
  551. if ( $level[$i] ) { echo ' * '; } 
  552. else { echo '   '; } 
  553. echo '</span>'; 
  554. } else { 
  555. echo '<span class="dev-tree">'; 
  556. // Tree-level without last level. 
  557. for ( $i = 0; $i < count( $level ) - 1; $i += 1 ) { 
  558. if ( null === $level[$i] ) { continue; } 
  559. if ( $level[$i] ) { echo ' * '; } 
  560. else { echo '   '; } 
  561.  
  562. if ( empty( $args['lastkey'] ) ) { 
  563. echo ' **'; 
  564. } else { 
  565. echo ' **'; 
  566. echo '</span>'; 
  567.  
  568. $key_style = ''; 
  569. if ( ! empty( $args['protected'] ) ) { 
  570. $key_style .= 'color:#900;'; 
  571. $prefix = ''; 
  572. } elseif ( ! empty( $args['private'] ) ) { 
  573. $key_style .= 'color:#C00;font-style:italic;'; 
  574. $prefix = 'PRIVATE '; 
  575. } else { 
  576. $key_style .= 'color:#000;'; 
  577. $prefix = ''; 
  578.  
  579. $valid_ids = array( 'ID', 'id' ); 
  580. $is_id = in_array( (string) $key, $valid_ids ); 
  581. if ( $is_id ) { 
  582. $key_style .= 'background:#FDA;'; 
  583.  
  584. echo '<span class="dev-item dev-item-key" style="' . $key_style . '">[ ' . $prefix . $key . ' ]</span>'; 
  585. echo '<span class="dev-item"> => </span>'; 
  586.  
  587. // Data-Type. 
  588. if ( ! empty( $args['toggle'] ) ) { 
  589. echo '<a href="javascript:toggleDisplay(\''. $args['toggle'] . '\', \'' . trim( $row_class . ' ' . $args['toggle'] ) . '\');" class="dev-item dev-toggle-item">'; 
  590. echo '<span style="color:#666666">' . $type . '</span>  '; 
  591. echo '</a>'; 
  592. } else { 
  593. echo '<span class="dev-item" style="color:#666666">' . $type . '  </span>'; 
  594.  
  595. if ( ! empty( $args['toggle'] ) ) { 
  596. $collapsed = ! empty( $args['do_collapse_next'] ); 
  597. $toggle_style = 'display: ' . ( $collapsed ? 'inline' : 'none' ); 
  598. echo '<span id="plus' . $args['toggle'] . '" class="plus dev-item" style="' . $toggle_style . '"> ⤵</span>'; 
  599.  
  600. // Value. 
  601. if ( $value !== null ) { 
  602. $value_style = ''; 
  603. if ( isset( $args['highlight'] ) ) { 
  604. $value_style = $args['highlight']; 
  605. echo '<span class="dev-item" style="color:' . $type_color . ';' . $value_style . '">' . $value . '</span>'; 
  606.  
  607. echo '</td></tr>'; 
  608. echo "\r\n"; 
  609.  
  610. /** 
  611. * Outputs the CSS and JS scripts required to display the debug dump/trace. 
  612. * @since 2.0.0 
  613. * @internal 
  614. */ 
  615. protected function add_scripts() { 
  616. if ( $this->is_plain_text() ) { return; } 
  617. if ( defined( '__DEBUG_SCRIPT' ) ) { return; } 
  618. define( '__DEBUG_SCRIPT', true ); 
  619.  
  620. if ( ! headers_sent() ) { 
  621. header( 'Content-type: text/html; charset=utf-8' ); 
  622.  
  623. ?> 
  624. <style> 
  625. .wdev-debug { 
  626. clear: both; 
  627. border: 1px solid #C00; 
  628. background: rgba(255, 200, 200, 1); 
  629. padding: 10px; 
  630. margin: 10px; 
  631. position: relative; 
  632. z-index: 99999; 
  633. box-shadow: 0 1px 5px rgba(0, 0, 0, 0.3); 
  634. font-size: 12px; 
  635. font-family: sans-serif; 
  636. font-weight: 200; 
  637. line-height: 1; 
  638. .wdev-debug .dev-tree { 
  639. color: #000; 
  640. opacity: .2; 
  641. font-family: monospace; 
  642. font-size: 19px; 
  643. line-height: 16px; 
  644. float: left; 
  645. .wdev-debug .dev-item { 
  646. float: left; 
  647. line-height: 16px; 
  648. white-space: pre; 
  649. .wdev-debug .dev-toggle-item { 
  650. text-decoration: none; 
  651. background: rgba(255, 255, 255, 0.2); 
  652. display: inline-block; 
  653. .wdev-debug .wdev-dump { 
  654. margin: 0; 
  655. border-collapse: collapse; 
  656. padding: 0; 
  657. border: 0; 
  658. .wdev-debug .wdev-trace-toggle { 
  659. display: block; 
  660. margin: 10px 0 0 0; 
  661. .wdev-debug .wdev-dump td { 
  662. font-size: 12px; 
  663. line-height: 1; 
  664. font-family: sans-serif; 
  665. font-weight: 200; 
  666. background: transparent; 
  667. cursor: default; 
  668. padding: 0; 
  669. border: 0; 
  670. .wdev-debug .wdev-dump tr:hover td { 
  671. background-color: #FFF; 
  672. background-color: rgba(255, 255, 255, 0.3); 
  673. .wdev-debug-clear { 
  674. clear: both; 
  675. display: table; 
  676. padding: 0; 
  677. margin: 0; 
  678. .wdev-debug-label { 
  679. font-size: 11px; 
  680. float: right; 
  681. margin: -10px; 
  682. color: #FFF; 
  683. background-color: #D88; 
  684. padding: 2px 8px; 
  685. cursor: pointer; 
  686. max-width: 50%; 
  687. white-space: nowrap; 
  688. overflow: hidden; 
  689. text-overflow: ellipsis; 
  690. .wdev-debug-label:hover { 
  691. background-color: #E66; 
  692. .wdev-debug pre { 
  693. font-size: 12px !important; 
  694. margin: 1px 0 !important; 
  695. background: rgba(255, 200, 200, 0.8); 
  696. .wdev-trace td { 
  697. padding: 1px 2px !important; 
  698. font-size: 12px; 
  699. vertical-align: top; 
  700. .wdev-trace { 
  701. margin: 4px 0 0 0; 
  702. background: #EBB; 
  703. border-collapse: collapse; 
  704. .wdev-trace tr.mark td { 
  705. background: #EC9; 
  706. .wdev-trace tr td { 
  707. cursor: default; 
  708. .wdev-trace-toggle { 
  709. cursor: pointer; 
  710. .wdev-debug .trc-num { 
  711. width: 40px; 
  712. .wdev-debug .trc-loc { 
  713. width: 60%; 
  714. .wdev-debug .trc-arg { 
  715. width: 40%; 
  716. font-size: 11px; 
  717. white-space: nowrap; 
  718. .wdev-debug .trc-param { 
  719. padding: 0 3px; 
  720. display: block; 
  721. margin: 1px 0 1px 8px; 
  722. .wdev-debug .trc-param font { 
  723. background: rgba( 0, 0, 0, 0.05 ); 
  724. .wdev-debug .trc-param:after { 
  725. content: ', '; 
  726. .wdev-debug .trc-param:last-child:after { 
  727. content: ''; 
  728. </style> 
  729. <script> 
  730. // Toggle whole block (debug/trace) 
  731. function toggleBlock( clsname ) { 
  732. var wrap = document.getElementsByClassName( clsname ); 
  733.  
  734. for ( var i = 0; i < wrap.length; i += 1 ) { 
  735. var state = (wrap[i].style.display == 'none' ? 'block' : 'none'); 
  736. wrap[i].style.display = state; 
  737. // Mark a table row 
  738. function _m( row ) { 
  739. row.classList.toggle( 'mark' ); 
  740. // Toggle a single debug-output-level 
  741. function toggleDisplay( clsname, full_class ) { 
  742. var elements = document.getElementsByClassName( clsname ),  
  743. plus = document.getElementById( "plus" + clsname ),  
  744. plus_state = (plus.style.display == 'none' ? 'inline' : 'none'),  
  745. el_state = (plus_state == 'none' ? 'table-row' : 'none' ),  
  746. sub_id = '',  
  747. sub_state = el_state; 
  748.  
  749. plus.style.display = plus_state; 
  750.  
  751. for ( var i = 0; i < elements.length; i += 1 ) { 
  752. var sub_plus = elements[i].getElementsByClassName( 'plus' ); 
  753.  
  754. if ( elements[i].className == full_class ) { 
  755. if ( sub_plus.length ) { sub_plus[0].style.display = 'inline'; } 
  756. elements[i].style.display = el_state; 
  757. } else { 
  758. if ( sub_plus.length ) { sub_plus[0].style.display = 'inline'; } 
  759. elements[i].style.display = 'none'; 
  760. </script> 
  761. <?php 
  762.  
  763. /** 
  764. * Returns an HTML element that displays a colored label. By default the 
  765. * label is a random/unique MD5 hash. 
  766. * This marker is intended for debugging to identify changes in objects 
  767. * that are loaded via ajax. 
  768. * @since 2.0.1 
  769. * @api 
  770. * @param string $label Optional. The label to display. Default is a 
  771. * random MD5 string. 
  772. * @param array $styles Optional. Array of CSS styles to apply. 
  773. * @return object { 
  774. * Marker details 
  775. * $html 
  776. * $hash 
  777. * $text 
  778. * $color 
  779. * } 
  780. */ 
  781. public function marker_html( $label = null, $styles = array() ) { 
  782. $hash = md5( rand( 1000, 9999 ) . time() ); 
  783.  
  784. if ( null === $label ) { 
  785. $label = $hash; 
  786. } else { 
  787. $hash = md5( $label ); 
  788.  
  789. $color = substr( $hash, 0, 3 ); 
  790. $def_styles = array( 
  791. 'background' => '#' . $color,  
  792. 'color' => '#fff',  
  793. 'width' => '280px',  
  794. 'font-size' => '12px',  
  795. 'text-transform' => 'uppercase',  
  796. 'font-family' => 'monospace',  
  797. 'text-align' => 'center',  
  798. 'margin' => '0 auto 5px',  
  799. 'border-radius' => '3px',  
  800. 'padding' => '4px',  
  801. 'text-shadow' => '0 0 1px #666',  
  802. 'box-shadow' => '0 0 1px #000 inset',  
  803. ); 
  804. $styles = wp_parse_args( 
  805. $styles,  
  806. $def_styles 
  807. ); 
  808.  
  809. $style = ''; 
  810. foreach ( $styles as $key => $val ) { 
  811. $style .= $key . ':' . $val . ';'; 
  812.  
  813. $marker = sprintf( 
  814. '<div style="%1$s">%2$s</div>',  
  815. esc_attr( $style ),  
  816. $label 
  817. ); 
  818.  
  819. return (object) array( 
  820. 'html' => $marker,  
  821. 'hash' => $hash,  
  822. 'text' => $label,  
  823. 'color' => '#' . $color,  
  824. );