Changeset 3495003
- Timestamp:
- 03/30/2026 11:03:37 PM (2 days ago)
- Location:
- patchwing/trunk
- Files:
-
- 5 edited
-
includes/class-core.php (modified) (1 diff)
-
includes/class-dashboard.php (modified) (9 diffs)
-
includes/class-debug-log.php (modified) (1 diff)
-
patchwing.php (modified) (2 diffs)
-
readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
patchwing/trunk/includes/class-core.php
r3493544 r3495003 270 270 <h1><?php esc_html_e( 'Settings', 'patchwing' ); ?></h1> 271 271 </div> 272 <?php 273 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce is verified by WordPress core via options.php for settings forms; this is a read-only redirect flag set by WP itself. 274 $settings_updated = isset( $_GET['settings-updated'] ) ? sanitize_text_field( wp_unslash( $_GET['settings-updated'] ) ) : ''; 275 if ( $settings_updated ) : ?> 276 <div class="notice notice-success is-dismissible"> 277 <p><?php esc_html_e( 'Settings saved successfully.', 'patchwing' ); ?></p> 278 </div> 279 <?php endif; ?> 272 280 <form method="post" action="options.php"> 273 281 <?php -
patchwing/trunk/includes/class-dashboard.php
r3493544 r3495003 123 123 124 124 // CPU Metrics 125 $cpu_cores = self::patchwing_getRealCores(); 126 if ($cpu_cores > 0) { 127 $cpu_load = function_exists('sys_getloadavg') ? sys_getloadavg()[0] : 0; 128 $cpu_pct = round(($cpu_load / $cpu_cores) * 100, 2); 129 // echo "Cores Detected: $cores\n"; 125 // $cpu_cores = self::patchwing_getRealCores(); 126 // if ($cpu_cores > 0) { 127 // $cpu_load = function_exists('sys_getloadavg') ? sys_getloadavg()[0] : 0; 128 // $cpu_pct = round(($cpu_load / $cpu_cores) * 100, 2); 129 // // echo "Cores Detected: $cores\n"; 130 // } else { 131 // $cpu_cores = 2; // fallback assumption 132 // $cpu_load = function_exists('sys_getloadavg') ? sys_getloadavg()[0] : 0; 133 // $cpu_pct = round(($cpu_load / $cpu_cores) * 100, 2); 134 // // echo "Cores could not be detected. Assuming 2 core.\n"; 135 // } 136 // $cpu_status = $cpu_pct === null ? 'moderate' : ( $cpu_pct < 50 ? 'excellent' : ( $cpu_pct < 80 ? 'moderate' : 'high' ) ); 137 $cpu_cores = self::patchwing_getRealCores(); 138 $load_averages = function_exists('sys_getloadavg') ? sys_getloadavg() : [0, 0, 0]; 139 $cpu_load = $load_averages[0]; 140 if ( $cpu_cores && $cpu_cores > 0 ) { 141 $cpu_pct = round( ( $cpu_load / $cpu_cores ) * 100, 2 ); 130 142 } else { 131 $cpu_cores = 2; // fallback assumption 132 $cpu_load = function_exists('sys_getloadavg') ? sys_getloadavg()[0] : 0; 133 $cpu_pct = round(($cpu_load / $cpu_cores) * 100, 2); 134 // echo "Cores could not be detected. Assuming 2 core.\n"; 135 } 136 $cpu_status = $cpu_pct === null ? 'moderate' : ( $cpu_pct < 50 ? 'excellent' : ( $cpu_pct < 80 ? 'moderate' : 'high' ) ); 143 $cpu_cores = null; 144 $cpu_pct = null; 145 } 146 $cpu_status = ( null === $cpu_cores ) ? 'Not Available' : ( $cpu_pct < 50 ? 'excellent' : ( $cpu_pct < 85 ? 'moderate' : 'high' ) ); 137 147 138 148 // Memory Metrics 139 $memory_usage = memory_get_usage( true ); 140 $memory_limit = ini_get( 'memory_limit' ); 141 $memory_limit_bytes = wp_convert_hr_to_bytes( $memory_limit ); 142 $memory_pct = $memory_limit_bytes > 0 ? round( ( $memory_usage / $memory_limit_bytes ) * 100, 2 ) : null; 143 $mem_status = $memory_pct === null ? 'moderate' : ( $memory_pct < 60 ? 'excellent' : ( $memory_pct < 80 ? 'moderate' : 'high' ) ); 149 // $memory_usage = memory_get_usage( true ); 150 // $memory_limit = ini_get( 'memory_limit' ); 151 // $memory_limit_bytes = wp_convert_hr_to_bytes( $memory_limit ); 152 // $memory_pct = $memory_limit_bytes > 0 ? round( ( $memory_usage / $memory_limit_bytes ) * 100, 2 ) : null; 153 // $mem_status = $memory_pct === null ? 'moderate' : ( $memory_pct < 60 ? 'excellent' : ( $memory_pct < 80 ? 'moderate' : 'high' ) ); 154 $mem = self::getUsage(); 155 $memory_usage = $mem['used']; 156 $memory_limit = $mem['total']; 157 $memory_pct = $mem['pct']; 158 $mem_status = ( $memory_pct === null || $memory_pct == 0 ) ? 'Not Available' : ( $memory_pct < 60 ? 'excellent' : ( $memory_pct < 80 ? 'moderate' : 'high' ) ); 144 159 145 160 // Plugin & Theme Data … … 172 187 <p><strong><?php esc_html_e( 'CPU Load:', 'patchwing' ); ?></strong> 173 188 <?php 174 if ( $cpu_ load !== null ) {189 if ( $cpu_cores != null ) { 175 190 /* translators: 1: load average, 2: number of cores, 3: percentage */ 176 191 echo esc_html( sprintf( __( '%1$s (%2$d cores, %3$s%%)', 'patchwing' ), round($cpu_load,2), $cpu_cores, $cpu_pct ) ); … … 189 204 <strong><?php esc_html_e( 'Memory Usage:', 'patchwing' ); ?></strong> 190 205 <?php 191 // translators: %s is the percentage of the PHP memory limit used. 192 echo $memory_pct !== null ? esc_html( sprintf( __( '%s%% of PHP limit', 'patchwing' ), $memory_pct ) ) : esc_html__( 'Not Available', 'patchwing' ); 206 //$memory_limit = 0.12; 207 if ( $memory_limit > 0 ) { 208 /* translators: 1: Memory usage (e.g. 0.5), 2: Total memory limit (e.g. 2), 3: Percentage used (e.g. 25). */ 209 echo esc_html( sprintf( __( '%1$s of %2$s GB (%3$s%%)', 'patchwing' ), $memory_usage, $memory_limit, $memory_pct ) ); 210 } else { 211 echo esc_html__( 'Not Available', 'patchwing' ); 212 } 193 213 ?> 194 214 </p> … … 277 297 278 298 // CPU Metrics 279 $cpu_cores = self::patchwing_getRealCores();280 if ($cpu_cores > 0) {281 $cpu_load = function_exists('sys_getloadavg') ? sys_getloadavg()[0] : 0;282 $cpu_pct = round(($cpu_load / $cpu_cores) * 100, 2);283 // echo "Cores Detected: $cores\n";299 $cpu_cores = self::patchwing_getRealCores(); 300 $load_averages = function_exists('sys_getloadavg') ? sys_getloadavg() : [0, 0, 0]; 301 $cpu_load = $load_averages[0]; 302 if ( $cpu_cores && $cpu_cores > 0 ) { 303 $cpu_pct = round( ( $cpu_load / $cpu_cores ) * 100, 2 ); 284 304 } else { 285 $cpu_cores = 2; // fallback assumption 286 $cpu_load = function_exists('sys_getloadavg') ? sys_getloadavg()[0] : 0; 287 $cpu_pct = round(($cpu_load / $cpu_cores) * 100, 2); 288 // echo "Cores could not be detected. Assuming 2 core.\n"; 289 } 290 $cpu_status = $cpu_pct === null ? 'moderate' : ( $cpu_pct < 50 ? 'excellent' : ( $cpu_pct < 80 ? 'moderate' : 'high' ) ); 291 292 $memory_usage = memory_get_usage( true ); 293 $php_mem_limit = ini_get( 'memory_limit' ); 294 $php_mem_bytes = wp_convert_hr_to_bytes( $php_mem_limit ); 295 296 $memory_pct = $php_mem_bytes > 0 ? round( ( $memory_usage / $php_mem_bytes ) * 100, 2 ) : 'N/A'; 297 298 $mem_status = is_numeric( $memory_pct ) ? ( $memory_pct < 60 ? 'Excellent' : ( $memory_pct < 80 ? 'Moderate' : 'High' ) ) : 'Unknown'; 305 $cpu_cores = null; 306 $cpu_pct = null; 307 } 308 $cpu_status = ( null === $cpu_cores ) ? 'Not Available' : ( $cpu_pct < 50 ? 'excellent' : ( $cpu_pct < 85 ? 'moderate' : 'high' ) ); 309 310 // Memory Metrics 311 $mem = self::getUsage(); 312 $memory_usage = $mem['used']; 313 $memory_limit = $mem['total']; 314 $memory_pct = $mem['pct']; 315 $mem_status = ( $memory_pct === null || $memory_pct == 0 ) ? 'Not Available' : ( $memory_pct < 60 ? 'excellent' : ( $memory_pct < 80 ? 'moderate' : 'high' ) ); 299 316 300 317 $server_ip = isset($_SERVER['SERVER_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_ADDR'])) : (isset($_SERVER['LOCAL_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['LOCAL_ADDR'])) : 'N/A'); … … 304 321 __( 'IP Address', 'patchwing' ) => $server_ip, 305 322 __( 'Web Server', 'patchwing' ) => $server_sw, 306 __( 'CPU Load', 'patchwing' ) => $cpu_ load !== null ? sprintf( '%s (%d cores, %s%%)', round($cpu_load,2), $cpu_cores, $cpu_pct ) : 'N/A',323 __( 'CPU Load', 'patchwing' ) => $cpu_cores !== null ? sprintf( '%s (%d cores, %s%%)', round($cpu_load,2), $cpu_cores, $cpu_pct ) : 'Not Available', 307 324 __( 'CPU Load Status', 'patchwing' ) => ucfirst( $cpu_status ), 308 __( 'Memory Usage', 'patchwing' ) => $memory_pct !== null ? $memory_pct . '%' : 'Not Available', 325 __( 'Memory Usage', 'patchwing' ) => ( $memory_limit > 0 && null !== $memory_pct ) ? sprintf( 326 /* translators: 1: Memory usage, 2: Memory limit, 3: Percentage used. */ 327 __( '%1$s of %2$s GB (%3$s%%)', 'patchwing' ), $memory_usage, $memory_limit, $memory_pct ) : __( 'Not Available', 'patchwing' ), 309 328 __( 'Memory Usage Status', 'patchwing' ) => ucfirst( $mem_status ), 310 329 ]; … … 387 406 388 407 // CPU Metrics 389 $cpu_cores = self::patchwing_getRealCores();390 if ($cpu_cores > 0) {391 $cpu_load = function_exists('sys_getloadavg') ? sys_getloadavg()[0] : 0;392 $cpu_pct = round(($cpu_load / $cpu_cores) * 100, 2);393 // echo "Cores Detected: $cores\n";408 $cpu_cores = self::patchwing_getRealCores(); 409 $load_averages = function_exists('sys_getloadavg') ? sys_getloadavg() : [0, 0, 0]; 410 $cpu_load = $load_averages[0]; 411 if ( $cpu_cores && $cpu_cores > 0 ) { 412 $cpu_pct = round( ( $cpu_load / $cpu_cores ) * 100, 2 ); 394 413 } else { 395 $cpu_cores = 2; // fallback assumption 396 $cpu_load = function_exists('sys_getloadavg') ? sys_getloadavg()[0] : 0; 397 $cpu_pct = round(($cpu_load / $cpu_cores) * 100, 2); 398 // echo "Cores could not be detected. Assuming 2 core.\n"; 399 } 400 $cpu_status = $cpu_pct === null ? 'moderate' : ( $cpu_pct < 50 ? 'excellent' : ( $cpu_pct < 80 ? 'moderate' : 'high' ) ); 401 402 $memory_usage = memory_get_usage( true ); 403 $php_mem_limit = ini_get( 'memory_limit' ); 404 $php_mem_bytes = wp_convert_hr_to_bytes( $php_mem_limit ); 405 $memory_pct = $php_mem_bytes > 0 ? round( ( $memory_usage / $php_mem_bytes ) * 100, 2 ) : 'N/A'; 406 $mem_status = is_numeric( $memory_pct ) ? ( $memory_pct < 60 ? 'Excellent' : ( $memory_pct < 80 ? 'Moderate' : 'High' ) ) : 'Unknown'; 414 $cpu_cores = null; 415 $cpu_pct = null; 416 } 417 $cpu_status = ( null === $cpu_cores ) ? 'Not Available' : ( $cpu_pct < 50 ? 'excellent' : ( $cpu_pct < 85 ? 'moderate' : 'high' ) ); 418 419 // Memory Metrics 420 $mem = self::getUsage(); 421 $memory_usage = $mem['used']; 422 $memory_limit = $mem['total']; 423 $memory_pct = $mem['pct']; 424 $mem_status = ( $memory_pct === null || $memory_pct == 0 ) ? 'Not Available' : ( $memory_pct < 60 ? 'excellent' : ( $memory_pct < 80 ? 'moderate' : 'high' ) ); 407 425 408 426 $server_ip = isset($_SERVER['SERVER_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_ADDR'])) : (isset($_SERVER['LOCAL_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['LOCAL_ADDR'])) : 'N/A'); … … 412 430 __( 'IP Address', 'patchwing' ) => $server_ip, 413 431 __( 'Web Server', 'patchwing' ) => $server_sw, 414 __( 'CPU Load', 'patchwing' ) => $cpu_ load !== null ? sprintf( '%s (%d cores, %s%%)', round($cpu_load,2), $cpu_cores, $cpu_pct ) : 'N/A',432 __( 'CPU Load', 'patchwing' ) => $cpu_cores !== null ? sprintf( '%s (%d cores, %s%%)', round($cpu_load,2), $cpu_cores, $cpu_pct ) : 'Not Available', 415 433 __( 'CPU Load Status', 'patchwing' ) => ucfirst( $cpu_status ), 416 __( 'Memory Usage', 'patchwing' ) => $memory_pct !== null ? $memory_pct . '%' : 'Not Available', 434 __( 'Memory Usage', 'patchwing' ) => ( $memory_limit > 0 && null !== $memory_pct ) ? sprintf( 435 /* translators: 1: Memory usage, 2: Memory limit, 3: Percentage used. */ 436 __( '%1$s of %2$s GB (%3$s%%)', 'patchwing' ), $memory_usage, $memory_limit, $memory_pct ) : __( 'Not Available', 'patchwing' ), 417 437 __( 'Memory Usage Status', 'patchwing' ) => ucfirst( $mem_status ), 418 438 ]; … … 454 474 } 455 475 456 public static function patchwing_getRealCores() { 476 /** 477 * Returns the number of logical CPU cores. 478 * Uses a Singleton pattern to cache the result for the current request. 479 */ 480 public static function patchwing_getRealCores() 481 { 457 482 // Try to get cached value first 458 483 $cached = get_transient( 'patchwing_real_cores' ); … … 461 486 } 462 487 463 $cores = 1; // Default fallback 464 465 // Strategy 1: Environment variables 466 $vars = [ 'NUMBER_OF_PROCESSORS', '_NPROCESSORS_ONLN', 'OMP_NUM_THREADS' ]; 467 foreach ( $vars as $var ) { 468 $val = getenv( $var ); 469 if ( $val && (int) $val > 0 ) { 470 $cores = (int) $val; 488 $coreCount = null; 489 490 switch (PHP_OS_FAMILY) { 491 case 'Darwin': // macOS 492 $coreCount = self::execute('/usr/sbin/sysctl -n hw.ncpu') ? : self::execute('/usr/bin/getconf _NPROCESSORS_ONLN'); 471 493 break; 472 } 473 } 474 475 // Strategy 2: sys_getloadavg() approximation 476 if ( $cores === 1 && function_exists( 'sys_getloadavg' ) ) { 477 $load = sys_getloadavg(); 478 if ( is_array( $load ) && ! empty( $load ) ) { 479 $cores = max( 1, (int) round( $load[0] ) ); 480 } 494 495 case 'Linux': 496 // Attempt to read the file directly (fastest, no shell required) 497 if (is_readable('/proc/cpuinfo')) { 498 $cpuinfo = file_get_contents('/proc/cpuinfo'); 499 $coreCount = substr_count($cpuinfo, 'processor'); 500 } 501 502 // Fallback to nproc if file read failed 503 if (!$coreCount) { 504 $coreCount = self::execute('nproc'); 505 } 506 break; 507 508 case 'Windows': 509 // Use environment variable first 510 $envCores = getenv('NUMBER_OF_PROCESSORS'); 511 if ($envCores !== false) { 512 $coreCount = (int)$envCores; 513 } else { 514 // Fallback to WMIC 515 $wmic = self::execute('wmic cpu get NumberOfLogicalProcessors /value'); 516 if (preg_match('/(\d+)/', (string)$wmic, $matches)) { 517 $coreCount = (int)$matches[1]; 518 } 519 } 520 break; 521 522 case 'BSD': 523 $coreCount = self::execute('/sbin/sysctl -n hw.ncpu'); 524 break; 525 } 526 527 // Final fallback to 1 if all detection methods failed 528 if (!$coreCount || $coreCount <= 0) { 529 $coreCount = 0; 481 530 } 482 531 483 532 // Cache result for 24 hours 484 set_transient( 'patchwing_real_cores', $cores, DAY_IN_SECONDS ); 485 486 return $cores; 533 set_transient( 'patchwing_real_cores', $coreCount, DAY_IN_SECONDS ); 534 535 return $coreCount; 536 } 537 538 /** 539 * Internal helper to execute shell commands safely. 540 */ 541 private static function execute(string $command): ?int 542 { 543 if (!function_exists('shell_exec')) { 544 return null; 545 } 546 547 $result = shell_exec($command . ' 2>/dev/null'); 548 return $result !== null ? (int)trim($result) : null; 549 } 550 551 552 public static function getUsage(): array 553 { 554 $total = 0; 555 $free = 0; 556 557 // Check if shell_exec is even allowed on this server 558 $can_exec = function_exists('shell_exec') && !in_array('shell_exec', array_map('trim', explode(',', ini_get('disable_functions')))); 559 560 switch (PHP_OS_FAMILY) { 561 case 'Windows': 562 if ($can_exec) { 563 // Try PowerShell first (Modern Windows 10/11) 564 $psRes = shell_exec('powershell -Command "Get-CimInstance Win32_OperatingSystem | Select-Object TotalVisibleMemorySize, FreePhysicalMemory"'); 565 if ($psRes && preg_match('/(\d+)\s+(\d+)/', $psRes, $matches)) { 566 $total = $matches[1] * 1024; 567 $free = $matches[2] * 1024; 568 } else { 569 // Fallback to WMIC (Legacy Windows) 570 $totalStr = shell_exec('wmic OS get TotalVisibleMemorySize /Value'); 571 $freeStr = shell_exec('wmic OS get FreePhysicalMemory /Value'); 572 preg_match('/(\d+)/', (string)$totalStr, $tMatches); 573 preg_match('/(\d+)/', (string)$freeStr, $fMatches); 574 $total = ($tMatches[1] ?? 0) * 1024; 575 $free = ($fMatches[1] ?? 0) * 1024; 576 } 577 } 578 break; 579 580 case 'Linux': 581 // Try /proc/meminfo first (most efficient) 582 if (is_readable('/proc/meminfo')) { 583 $meminfo = file_get_contents('/proc/meminfo'); 584 preg_match('/MemTotal:\s+(\d+)/', $meminfo, $tMatches); 585 preg_match('/MemAvailable:\s+(\d+)/', $meminfo, $fMatches); 586 // If MemAvailable isn't there (older kernels), use MemFree + Buffers + Cached 587 if (empty($fMatches)) { 588 preg_match('/MemFree:\s+(\d+)/', $meminfo, $freeM); 589 preg_match('/Buffers:\s+(\d+)/', $meminfo, $bufM); 590 preg_match('/^Cached:\s+(\d+)/m', $meminfo, $cacheM); 591 $total = ($tMatches[1] ?? 0) * 1024; 592 $free = (($freeM[1] ?? 0) + ($bufM[1] ?? 0) + ($cacheM[1] ?? 0)) * 1024; 593 } else { 594 $total = ($tMatches[1] ?? 0) * 1024; 595 $free = ($fMatches[1] ?? 0) * 1024; 596 } 597 } 598 599 // Fallback: If proc failed or returned 0, try the 'free' command 600 if ($total === 0 && $can_exec) { 601 $freeOut = shell_exec('free -b'); // -b for bytes 602 if ($freeOut) { 603 $lines = explode("\n", trim($freeOut)); 604 if (isset($lines[1])) { 605 // Standard 'free' output: Mem: total used free shared buff/cache available 606 $stats = preg_split('/\s+/', $lines[1]); 607 $total = (int)($stats[1] ?? 0); 608 // Use 'available' (last column) if it exists, otherwise use 'free' 609 $free = (int)($stats[6] ?? $stats[3]); 610 } 611 } 612 } 613 break; 614 615 case 'Darwin': 616 // macOS 617 if ($can_exec) { 618 $total = (int)shell_exec('/usr/sbin/sysctl -n hw.memsize'); 619 $vmStat = shell_exec('/usr/bin/vm_stat'); 620 if (preg_match('/page size of (\d+) bytes/', (string)$vmStat, $pMatch)) { 621 $pageSize = $pMatch[1]; 622 preg_match('/Pages free:\s+(\d+)/', $vmStat, $fMatch); 623 preg_match('/Pages purgeable:\s+(\d+)/', $vmStat, $purMatch); 624 $free = (($fMatch[1] ?? 0) + ($purMatch[1] ?? 0)) * $pageSize; 625 } 626 } 627 break; 628 } 629 630 if ($total <= 0) { 631 return ['total' => 0, 'used' => 0, 'free' => 0, 'pct' => 0]; 632 } 633 634 $used = $total - $free; 635 return [ 636 'total' => round($total / 1024 / 1024 / 1024, 2), 637 'used' => round($used / 1024 / 1024 / 1024, 2), 638 'free' => $free, 639 'pct' => round(($used / $total) * 100, 2) 640 ]; 487 641 } 488 642 -
patchwing/trunk/includes/class-debug-log.php
r3493544 r3495003 33 33 } 34 34 35 $wp_config = ABSPATH . 'wp-config.php'; 35 // $wp_config = ABSPATH . 'wp-config.php'; 36 // Auto-detect wp-config.php (Cross-Platform & Secure) 37 $wp_config = ''; 38 $current_path = ABSPATH . 'wp-config.php'; 39 40 // Use untrailingslashit to ensure dirname() works consistently on all OS 41 $parent_dir = dirname(untrailingslashit(ABSPATH)); 42 $parent_path = $parent_dir . DIRECTORY_SEPARATOR . 'wp-config.php'; 43 $parent_settings = $parent_dir . DIRECTORY_SEPARATOR . 'wp-settings.php'; 44 45 if (file_exists($current_path)) { 46 $wp_config = $current_path; 47 } 48 elseif (@file_exists($parent_path) && !file_exists($parent_settings)) { 49 // Only move up if wp-settings.php is NOT there (standard WP security practice) 50 $wp_config = $parent_path; 51 } 52 53 // Normalize path for consistent internal WP handling 54 if ($wp_config) { 55 $wp_config = wp_normalize_path($wp_config); 56 } 57 36 58 $action_performed = false; 37 59 -
patchwing/trunk/patchwing.php
r3493544 r3495003 6 6 * Author: Nafiz 7 7 * Author URI: https://profiles.wordpress.org/urnafiz/ 8 * Version: 1.0. 08 * Version: 1.0.1 9 9 * Requires PHP: 7.4 10 10 * Requires at least: 5.9 … … 20 20 21 21 // Set plugin version. 22 define( 'PATCHWING_PLUGIN_VERSION', '1.0. 0' );22 define( 'PATCHWING_PLUGIN_VERSION', '1.0.1' ); 23 23 24 24 // Set plugin file. -
patchwing/trunk/readme.txt
r3493544 r3495003 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 1.0. 07 Stable tag: 1.0.1 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 42 42 == Changelog == 43 43 44 = 1.0.1 = 45 * Enhanced plugin settings page. 46 * Enhanced wp-config.php detection logic. 47 * Improved accuracy for real time CPU and Memory usage reporting. 48 44 49 = 1.0.0 = 45 50 * Initial release.
Note: See TracChangeset
for help on using the changeset viewer.