PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.7.4
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.7.4
1.9.5 1.9.4 1.9.3 trunk 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.6 1.6.1 1.6.10 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 All 40 releases
← All changes | lib/helper.php +292 -83 1.61.7.4 View file →
@@ -1,6 +1,6 @@
1 1 <?php
2 -/*
2 +/**
3 3 +=====================================================================+
4 4 | ____ _ ____ __ _ _ |
5 5 | / ___|___ __| | ___ | _ \ _ __ ___ / _(_) | ___ _ __ |
6 6 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
@@ -6,66 +6,125 @@
6 6 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
7 7 | | |__| (_) | (_| | __/ | __/| | | (_) | _| | | __/ | |
8 8 | \____\___/ \__,_|\___| |_| |_| \___/|_| |_|_|\___|_| |
9 9 | |
10 - | (c) Jerome Bruandet ~ https://code-profiler.com/ |
10 + | (c) Jerome Bruandet ~ https://nintechnet.com/codeprofiler/ |
11 11 +=====================================================================+
12 12 */
13 13
14 -if (! defined('ABSPATH') ) { die('Forbidden'); }
14 +if (! defined('ABSPATH') ) {
15 + die('Forbidden');
16 +}
15 17
16 18 // =====================================================================
17 19 // Various constants
18 20
19 -$upload_dir = wp_upload_dir();
20 -define('CODE_PROFILER_UPLOAD_DIR', $upload_dir['basedir'] .'/code-profiler');
21 +// The profiles directory can be defined in the wp-config.php script
22 +if (! defined('CODE_PROFILER_UPLOAD_DIR') ) {
23 + // When running Code Profiler via WP CLI on a child site of a multisite installation,
24 + // we need to get the main site upload folder otherwise wp_upload_dir will return
25 + // the child site's
26 + if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined('MULTISITE') ) ) {
27 + $upload_dir = code_profiler_upload_dir();
28 + } else {
29 + $upload_dir = wp_upload_dir();
30 + }
31 + define('CODE_PROFILER_UPLOAD_DIR', $upload_dir['basedir'] .'/code-profiler');
32 +}
21 33 define('CODE_PROFILER_LOG', CODE_PROFILER_UPLOAD_DIR .'/log.php');
22 34 define('CODE_PROFILER_TMP_IOSTATS_LOG', 'iostats.tmp');
23 35 define('CODE_PROFILER_TMP_SUMMARY_LOG', 'summary.tmp');
24 -define('CODE_PROFILER_TMP_TICKS_LOG', 'ticks.tmp');
36 +define('CODE_PROFILER_TMP_CALLS_LOG', 'calls.tmp');
25 37 define('CODE_PROFILER_TMP_DISKIO_LOG', 'diskio.tmp');
38 +define('CODE_PROFILER_TMP_CONNECTIONS_LOG', 'connections.tmp');
26 39 define('CODE_PROFILER_UPDATE_NOTICE', '<div class="updated notice is-dismissible"><p>%s</p></div>');
27 40 define('CODE_PROFILER_ERROR_NOTICE', '<div class="error notice is-dismissible"><p>%s</p></div>');
28 -global $wp_version;
29 -if (! defined('CODE_PROFILER_UA') ) { // UA signatures can be user-defined in the wp-config.php
30 - define ('CODE_PROFILER_UA', [
31 - esc_html__('Desktop', 'code-profiler') => [
32 - 'Firefox' => 'Mozilla/5.0 (Linux x86_64; rv:110.0) Gecko/20100101 Firefox/110.0',
33 - 'Chrome' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko)'.
34 - ' Chrome/111.0.0.0 Safari/537.36',
35 - 'Edge' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,'.
36 - ' like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/110.0.1587.63'
37 - ],
38 - esc_html__('Mobile', 'code-profiler') => [
39 - 'Android Phone' => 'Mozilla/5.0 (Android 13; Mobile; rv:68.0) Gecko/68.0 Firefox/110.0',
40 - 'Android Tablet' => 'Mozilla/5.0 (Linux; Android 13.0; SAMSUNG-SM-T377A Build/NMF26X)'.
41 - ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Mobile Safari/537.36',
42 - 'iPhone' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_3_1 like Mac OS X) AppleWebKit/605.1.15'.
43 - ' (KHTML, like Gecko) Version/16.3 Mobile/15E148 Safari/604.1',
44 - 'iPad' => 'Mozilla/5.0 (iPad; CPU OS 16_3_1 like Mac OS X) AppleWebKit/605.1.15'.
45 - ' (KHTML, like Gecko) GSA/213.0.449417121 Mobile/15E148 Safari/605.1.15'
46 - ],
47 - esc_html__('Bot', 'code-profiler') => [
48 - 'Google Bot' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
49 - 'WordPress' => 'Mozilla/5.0 (compatible; CodeProfiler for WordPress/'. $wp_version .
50 - '; https://code-profiler.com/)'
51 - ]
41 +if (! defined('CODE_PROFILER_MUPLUGIN') ) {
42 + // MU plugin's name can be defined in the wp-config.php
43 + define('CODE_PROFILER_MUPLUGIN', '0----code-profiler.php');
44 +}
52 45
53 - ] );
46 +/**
47 + * Since WP 6.7, translation loading must not be triggered too early.
48 + */
49 +add_action('init', 'code_profiler_i18n_constants');
50 +function code_profiler_i18n_constants() {
51 +
52 + global $wp_version;
53 + if (! defined('CODE_PROFILER_UA') ) { // UA signatures can be user-defined in the wp-config.php
54 + define ('CODE_PROFILER_UA', [
55 + esc_html__('Desktop', 'code-profiler') => [
56 + 'Firefox' => 'Mozilla/5.0 (Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0',
57 + 'Chrome' => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML,'.
58 + ' like Gecko) Chrome/133.0.0.0 Safari/537.36',
59 + 'Edge' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,'.
60 + ' like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/131.0.2903.86'
61 + ],
62 + esc_html__('Mobile', 'code-profiler') => [
63 + 'Android Phone' => 'Mozilla/5.0 (Android 15; Mobile; rv:68.0) Gecko/68.0 Firefox/135.0',
64 + 'Android Tablet' => 'Mozilla/5.0 (Linux; Android 15.0; SAMSUNG-SM-T377A Build/NMF26X)'.
65 + ' AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Mobile Safari/537.36',
66 + 'iPhone' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_7_2 like Mac OS X) AppleWebKit/605.1.15'.
67 + ' (KHTML, like Gecko) Version/17_7_2 Mobile/15E148 Safari/604.1',
68 + 'iPad' => 'Mozilla/5.0 (iPad; CPU OS 17_7_2 like Mac OS X) AppleWebKit/605.1.15'.
69 + ' (KHTML, like Gecko) GSA/213.0.449417121 Mobile/15E148 Safari/605.1.15'
70 + ],
71 + esc_html__('Bot', 'code-profiler') => [
72 + 'Google Bot' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',
73 + 'WordPress' => 'Mozilla/5.0 (compatible; CodeProfiler for WordPress/'. $wp_version .
74 + '; https://nintechnet.com/codeprofiler/)'
75 + ]
76 +
77 + ] );
78 + }
79 + define('CODE_PROFILER_ACCURACY', [
80 + 1 => __('Highest', 'code-profiler'),
81 + 5 => __('High', 'code-profiler'),
82 + 10 => __('Moderate', 'code-profiler'),
83 + 15 => __('Low', 'code-profiler'),
84 + 20 => __('Lowest', 'code-profiler')
85 + ]);
54 86 }
55 87
56 -if (! defined('CODE_PROFILER_MUPLUGIN') ) {
57 - // MU plugin's name can be defined in the wp-config.php
58 - define('CODE_PROFILER_MUPLUGIN', '0----code-profiler.php');
88 +// =====================================================================
89 +// Find the main site upload dir on a multisite installation.
90 +// Used when running the profiler via WP CLI.
91 +// This code is based on the WP private _wp_upload_dir function.
92 +
93 +function code_profiler_upload_dir() {
94 +
95 + $upload_path = trim( get_option('upload_path') );
96 + if ( empty( $upload_path ) || 'wp-content/uploads' === $upload_path ) {
97 + $basedir = WP_CONTENT_DIR . '/uploads';
98 + } elseif ( strpos( $upload_path, ABSPATH ) !== 0 ) {
99 + // $basedir is absolute, $upload_path is (maybe) relative to ABSPATH.
100 + $basedir = path_join( ABSPATH, $upload_path );
101 + } else {
102 + $basedir = $upload_path;
103 + }
104 +
105 + if ( defined('UPLOADS') && ! ( is_multisite() && get_site_option('ms_files_rewriting') ) ) {
106 + $basedir = ABSPATH . UPLOADS;
107 + }
108 +
109 + return ['basedir' => $basedir];
59 110 }
60 -define('CODE_PROFILER_ACCURACY', [
61 - 1 => __('Highest (default)', 'code-profiler'),
62 - 5 => __('High', 'code-profiler'),
63 - 10 => __('Moderate', 'code-profiler'),
64 - 15 => __('Low', 'code-profiler'),
65 - 20 => __('Lowest', 'code-profiler')
66 -]);
111 +
67 112 // =====================================================================
113 +// Prevent cURL timeout if a plugin changes its timeout options.
114 +
115 +function code_profiler_curl_timeout( $handle, $parsed_args, $url ) {
116 +
117 + if ( isset( $_REQUEST['action'] ) &&
118 + $_REQUEST['action'] == 'codeprofiler_start_profiler') {
119 +
120 + curl_setopt( $handle, CURLOPT_CONNECTTIMEOUT, 300 );
121 + curl_setopt( $handle, CURLOPT_TIMEOUT, 300 );
122 + }
123 +}
124 +add_action('http_api_curl', 'code_profiler_curl_timeout', 1000, 3 );
125 +
126 +// =====================================================================
68 127 // Update version in the DB and check if options must be updated.
69 128
70 129 function code_profiler_init_update() {
71 130
@@ -110,8 +169,12 @@
110 169
111 170 if (! file_exists( CODE_PROFILER_UPLOAD_DIR ) ) {
112 171 mkdir( CODE_PROFILER_UPLOAD_DIR, 0755 );
113 172 }
173 + if (! is_writable( CODE_PROFILER_UPLOAD_DIR ) ) {
174 + // PHP running as an Apache module?
175 + chmod( CODE_PROFILER_UPLOAD_DIR, 0777 );
176 + }
114 177 if (! file_exists( CODE_PROFILER_UPLOAD_DIR .'/index.html') ) {
115 178 touch( CODE_PROFILER_UPLOAD_DIR .'/index.html');
116 179 }
117 180 // For Apache & Litespeed
@@ -166,12 +229,59 @@
166 229
167 230 }
168 231
169 232 // =====================================================================
233 +// Check the PHP memory limit and return a suggested size
234 +// for the profiler's buffer.
235 +
236 +function code_profiler_suggested_memory() {
237 +
238 + $memory_limit = ini_get('memory_limit');
239 +
240 + if ('-1' == $memory_limit ) {
241 + // Return max size
242 + return 10;
243 + }
244 +
245 + if ( preg_match('/^(\d+)([PTGMK])$/i', $memory_limit, $match ) ) {
246 + $bytes = (int) $match[1];
247 + switch ( strtoupper( $match[2] ) ) {
248 + case 'P':
249 + $bytes *= 1024;
250 + case 'T':
251 + $bytes *= 1024;
252 + case 'G':
253 + $bytes *= 1024;
254 + case 'M':
255 + $bytes *= 1024;
256 + case 'K':
257 + $bytes *= 1024;
258 + }
259 + // 256 MB
260 + if ( $bytes >= 268435456 ) {
261 + return 10;
262 + // 128 MB
263 + } elseif ( $bytes >= 134217728 ) {
264 + return 7;
265 + // 64 MB
266 + } elseif ( $bytes >= 67108864 ) {
267 + return 4;
268 + // <64 MB
269 + } else {
270 + return 1;
271 + }
272 + }
273 + // Don't know :/
274 + return 5;
275 +}
276 +
277 +// =====================================================================
170 278 // Create the default options.
171 279
172 280 function code_profiler_default_options() {
173 281
282 + $buffer = code_profiler_suggested_memory();
283 +
174 284 $cp_options = [
175 285 'show_paths' => 'relative',
176 286 'display_name' => 'full',
177 287 'truncate_name' => 30,
@@ -182,9 +292,10 @@
182 292 'warn_composer' => 1,
183 293 'enable_wpcli' => 1,
184 294 'disable_wpcron' => 1,
185 295 'http_response' => '^(?:3|4|5)\d{2}$',
186 - 'accuracy' => 1
296 + 'accuracy' => 1,
297 + 'buffer' => (int) $buffer
187 298 ];
188 299
189 300 update_option('code-profiler', $cp_options );
190 301
@@ -189,15 +300,23 @@
189 300 update_option('code-profiler', $cp_options );
190 301
191 302 }
192 303
193 -// =====================================================================
304 +// ===================================================================== 2023-06-14
194 305 // Create a profile name.
195 306
196 307 function code_profiler_profile_name() {
197 308
198 309 return date('Y-m-d_') . substr( time(), 4 );
310 +}
199 311
312 +// ===================================================================== 2023-06-14
313 +// Disable PHP display_errors so that notice, warning and error messages
314 +// don't show up in the AJAX response.
315 +
316 +function code_profiler_hide_errors() {
317 +
318 + ini_set('display_errors', 0 );
200 319 }
201 320
202 321 // =====================================================================
203 322 // Disable opcode cache.
@@ -204,14 +323,15 @@
204 323
205 324 function code_profiler_disable_opcode() {
206 325
207 326 try {
208 - if (extension_loaded('Zend OPcache')) {
327 + if ( extension_loaded('Zend OPcache') ) {
209 328 ini_set('opcache.enable', 0);
210 329 } elseif ( extension_loaded('wincache') ) {
211 330 ini_set('wincache.fcenabled', 0);
212 331 }
213 332 set_time_limit(0);
333 + ini_set('memory_limit', -1);
214 334
215 335 } catch ( Exception $e ) { }
216 336
217 337 $cp_options = get_option('code-profiler');
@@ -219,36 +339,32 @@
219 339 if (! defined('DISABLE_WP_CRON') ) {
220 340 define('DISABLE_WP_CRON', true );
221 341 }
222 342 }
343 +}
223 344
224 -}
225 345 // =====================================================================
226 -// Verify the security key when running the profile.
346 +// Verify the security key when running the profiler.
227 347
228 348 function code_profiler_verify_key() {
229 349
230 350 $response = [
231 351 'status' => 'error',
232 - 'message' => __('Security keys do not match. Reload the page and try again (%s)', 'code-profiler')
352 + 'message' => __('Security keys do not match. Reload the page and try again (%s)',
353 + 'code-profiler')
233 354 ];
234 355
235 - $cp_options = get_option('code-profiler');
356 + if ( empty( $_REQUEST['profiler_key'] ) ) {
357 + $response['message'] = sprintf( $response['message'], '001');
236 358
237 - if ( empty( $cp_options['hash'] ) ) {
238 - $response['message'] = sprintf( $response['message'], '#1');
239 -
240 359 } else {
241 - if ( empty( $_REQUEST['profiler_key'] ) ) {
242 - $response['message'] = sprintf( $response['message'], '#2');
243 -
244 - } else {
245 - if ( $cp_options['hash'] == sha1( $_REQUEST['profiler_key'] ) ) {
246 - return;
247 - } else {
248 - $response['message'] = sprintf( $response['message'], '#3');
249 - }
360 + $file = CODE_PROFILER_UPLOAD_DIR .'/key_'. sha1( $_REQUEST['profiler_key'] ) .'.tmp';
361 + if ( file_exists( $file ) ) {
362 + // Delete it and accept the request
363 + unlink( $file );
364 + return;
250 365 }
366 + $response['message'] = sprintf( $response['message'], '002');
251 367 }
252 368 wp_send_json( $response );
253 369
254 370 }
@@ -287,18 +403,37 @@
287 403 code_profiler_write2log( $string, 8, $create );
288 404 }
289 405
290 406 // =====================================================================
407 +// Retrieve and return matching files from a directory.
408 +
409 +function code_profiler_glob( $directory, $regex, $pathname = false ) {
410 +
411 + $list = [];
412 +
413 + foreach ( new DirectoryIterator( $directory ) as $finfo ) {
414 + if (! $finfo->isDot() && preg_match("`$regex`", $finfo->getFilename() ) ) {
415 + if ( $pathname ) {
416 + $list[] = $finfo->getPathname();
417 + } else {
418 + $list[] = $finfo->getFilename();
419 + }
420 + }
421 + }
422 + return $list;
423 +}
424 +
425 +// =====================================================================
291 426 // Verify if a profile exists and return its full path.
292 427
293 428 function code_profiler_get_profile_path( $id, $type = 'slugs') {
294 429
295 - $return = false;
430 + if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) {
296 431
297 - if (! empty( $id ) && preg_match('/^\d{10}\.\d+$/', $id ) ) {
298 - $glob = glob( CODE_PROFILER_UPLOAD_DIR ."/$id.*.$type.profile" );
432 + $glob = code_profiler_glob(CODE_PROFILER_UPLOAD_DIR, "$id\..+\.$type\.profile$", true);
433 +
299 434 if ( is_array( $glob ) && ! empty( $glob[0] ) ) {
300 - if ( preg_match( "`/$id\.(.+?).$type.profile$`", $glob[0], $match ) ) {
435 + if ( preg_match( "`$id\.(.+?).$type.profile$`", $glob[0], $match ) ) {
301 436
302 437 return CODE_PROFILER_UPLOAD_DIR. "/$id.{$match[1]}";
303 438 }
304 439 }
@@ -326,10 +461,17 @@
326 461 $buffer['error'] = $err;
327 462 return $buffer;
328 463 }
329 464
465 + /**
466 + * We don't use fgetcsv() as it requires the $escape parameter since PHP 8.4
467 + */
330 468 while (! feof( $fh ) ) {
331 - $buffer[] = fgetcsv( $fh, 1000, "\t" );
469 + $tmp = trim( fgets( $fh, 1000 ) );
470 + if (! $tmp ) {
471 + continue;
472 + }
473 + $buffer[] = explode( "\t", $tmp );
332 474 }
333 475
334 476 fclose( $fh );
335 477
@@ -384,9 +526,9 @@
384 526
385 527 $string = $open;
386 528
387 529 if ( empty( $decode->items ) ) {
388 - $tmp = 'N/A';
530 + $tmp = __('N/A', 'code-profiler');
389 531 } else {
390 532 $tmp = (int) --$decode->items;
391 533 }
392 534 $string .= sprintf(
@@ -396,9 +538,9 @@
396 538
397 539 $string .= $div;
398 540
399 541 if ( empty( $decode->time ) ) {
400 - $tmp = 'N/A';
542 + $tmp = __('N/A', 'code-profiler');
401 543 } else {
402 544 $tmp = number_format( $decode->time, 4 );
403 545 }
404 546 $string .= sprintf(
@@ -408,9 +550,9 @@
408 550
409 551 $string .= $div;
410 552
411 553 if ( empty( $decode->memory ) ) {
412 - $tmp = 'N/A';
554 + $tmp = __('N/A', 'code-profiler');
413 555 } else {
414 556 $tmp = number_format( $decode->memory, 2);
415 557 }
416 558 $string .= sprintf(
@@ -420,11 +562,11 @@
420 562
421 563 $string .= $div;
422 564
423 565 if ( empty( $decode->io ) ) {
424 - $tmp = 'N/A';
566 + $tmp = __('N/A', 'code-profiler');
425 567 } else {
426 - $tmp = number_format( $decode->io );
568 + $tmp = number_format( (int) $decode->io );
427 569 }
428 570 $string .= sprintf(
429 571 __('File I/O operations: %s', 'code-profiler'),
430 572 $tmp
@@ -432,11 +574,11 @@
432 574
433 575 $string .= $div;
434 576
435 577 if ( empty( $decode->queries ) ) {
436 - $tmp = 'N/A';
578 + $tmp = __('N/A', 'code-profiler');
437 579 } else {
438 - $tmp = number_format( $decode->queries );
580 + $tmp = number_format( (int) $decode->queries );
439 581 }
440 582 $string .= sprintf(
441 583 __('SQL queries: %s', 'code-profiler'),
442 584 $tmp
@@ -441,8 +583,20 @@
441 583 __('SQL queries: %s', 'code-profiler'),
442 584 $tmp
443 585 );
444 586
587 + $string .= $div;
588 +
589 + if ( empty( CODE_PROFILER_ACCURACY[ $decode->precision ] ) ) {
590 + $tmp = __('N/A', 'code-profiler');
591 + } else {
592 + $tmp = CODE_PROFILER_ACCURACY[ $decode->precision ];
593 + }
594 + $string .= sprintf(
595 + __('Accuracy: %s', 'code-profiler'),
596 + $tmp
597 + );
598 +
445 599 $string .= $close;
446 600
447 601 return $string;
448 602 }
@@ -447,29 +601,30 @@
447 601 return $string;
448 602 }
449 603
450 604 // =====================================================================
451 -// Remove *tmp files left after an HTTP error (4xx or 5xx).
605 +// Remove *tmp files left in the profiles folder.
452 606
453 607 function code_profiler_cleantmpfiles() {
454 608
455 - $glob = glob( CODE_PROFILER_UPLOAD_DIR .'/*.tmp');
609 + $glob = code_profiler_glob( CODE_PROFILER_UPLOAD_DIR, '\.tmp$', true );
610 +
456 611 if ( is_array( $glob ) ) {
457 - $count = 0;
458 612 foreach( $glob as $file ) {
459 - $count++;
460 613 unlink( $file );
461 614 }
462 - if ( $count ) {
463 - code_profiler_log_info( sprintf(
464 - __('Deleting %s temporary files found in the profiles folder', 'code-profiler'),
465 - (int) $count
466 - ) );
467 - }
468 615 }
469 616 }
470 617
471 618 // =====================================================================
619 +// Remove non-ASCII characters from a string.
620 +
621 +function code_profiler_ASCII_filter( $string ) {
622 +
623 + return preg_replace('/[\x00-\x1f\x7f-\xff]/', '', $string );
624 +}
625 +
626 +// =====================================================================
472 627 // Clear the log if it's bigger than 100KB.
473 628
474 629 function code_profiler_clearlog() {
475 630
@@ -477,9 +632,9 @@
477 632 file_put_contents( CODE_PROFILER_LOG, "<?php exit; ?>\n" );
478 633 }
479 634 }
480 635
481 -// =====================================================================
636 +// ===================================================================== 2023-06-15
482 637 // We don't want to be bothered by other themes/plugins' admin notices.
483 638
484 639 add_action('admin_head', 'code_profiler_hide_admin_notices');
485 640
@@ -486,9 +641,63 @@
486 641 function code_profiler_hide_admin_notices() {
487 642 if ( isset( $_GET['page'] ) && $_GET['page'] == 'code-profiler') {
488 643 remove_all_actions('admin_notices');
489 644 remove_all_actions('all_admin_notices');
645 + add_filter('admin_footer_text', 'code_profiler_admin_footer');
490 646 }
647 +}
648 +
649 +function code_profiler_admin_footer () {
650 + echo '<span id="footer-thankyou">'.
651 + sprintf(
652 + /* Translators: %s are the '<a href="">' and '</a>' anchors */
653 + esc_html(
654 + 'Thank you for using %sCode Profiler%s.',
655 + 'code-profiler'
656 + ),
657 + '<a href="https://nintechnet.com/codeprofiler/" target="_blank">',
658 + '</a>'
659 + ).
660 + '</span>';
661 +}
662 +
663 +// =====================================================================
664 +// Display/hide an element depending on some value
665 +
666 +function code_profiler_hide( $var, $val ) {
667 +
668 + if ( $var == $val ) {
669 + echo " style='display:none'";
670 + }
671 +}
672 +
673 +// =====================================================================
674 +// Retrieve all themes.
675 +
676 +function code_profiler_get_themes() {
677 +
678 + $list = [];
679 +
680 + // Make sure the function is loaded
681 + if (! function_exists('wp_get_themes') ) {
682 + require_once ABSPATH . 'wp-includes/theme.php';
683 + }
684 + $themes = wp_get_themes();
685 + foreach( $themes as $k => $v ) {
686 + if ( $v->Name ) {
687 + $list[ $k ] = [
688 + 'n' => $v->Name,
689 +
690 + 't' => $v->Template
691 + ];
692 + } else {
693 + $list[ $k ] = [
694 + 'n' => $k,
695 + 't' => $v->Template
696 + ];
697 + }
698 + }
699 + return $list;
491 700 }
492 701
493 702 // =====================================================================
494 703 // EOF