PluginProbe
Plugin Memory Usage / 1.2.6
Plugin Memory Usage v1.2.6
trunk 1.0 1.0.2 1.1.0 1.1.2 1.1.3 1.2.0 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0
plugin-memory-usage / plugin-memory-usage.php

plugin-memory-usage.php in Plugin Memory Usage 1.2.6, at plugin-memory-usage.php

1,105 lines 35.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Plugin Memory Usage
4 Plugin URI: https://nett.pro/en/plugins/
5 Description: Display different plugins memory usage and impact on Wordpress.
6 Version: 1.2.6
7 Author: NETT.PRO
8 Author URI: https://nett.pro/en/
9 License: GPLv3
10 */
11
12 // Prevent direct access to this file
13 if (!defined('ABSPATH')) {
14 exit;
15 }
16
17 define('PLUGINMEMORYUSAGE_VERSION', '1.2.6');
18
19
20 function wpmem_memory_usage_admin_menu() {
21 add_menu_page(
22 'Plugin Memory Usage',
23 'Memory Usage',
24 'manage_options',
25 'wp_plugin_memory_usage',
26 'wpmem_memory_usage_admin_page',
27 'dashicons-performance',
28 100
29 );
30 }
31 add_action('admin_menu', 'wpmem_memory_usage_admin_menu');
32
33
34
35
36 // Function to register the dashboard widget
37 function pluginmemoryusage_memory_usage_widget() {
38
39 wp_add_dashboard_widget(
40 'wp_memory_usage',
41 'Plugin Memory Usage <span class="wpmem-version">'.PLUGINMEMORYUSAGE_VERSION.'</span>',
42 'pluginmemoryusage_display_memory_usage_dashboard'
43 );
44 }
45
46 // Hook to add the widget to the dashboard
47 add_action('wp_dashboard_setup', 'pluginmemoryusage_memory_usage_widget', 1);
48
49
50
51
52
53
54
55 // Get supported PHP versions with caching
56 function wpmem_get_supported_php_versions() {
57 $supported_versions = get_transient('wpmem_supported_php_versions');
58
59 if (false === $supported_versions) {
60 $response = wp_remote_get('https://www.php.net/supported-versions.php', array(
61 'sslverify' => false,
62 'timeout' => 5
63 ));
64
65 if (!is_wp_error($response) && 200 === wp_remote_retrieve_response_code($response)) {
66 $html = wp_remote_retrieve_body($response);
67 $supported_versions = wpmem_parse_supported_versions($html);
68 set_transient('wpmem_supported_php_versions', $supported_versions, WEEK_IN_SECONDS);
69 }
70 }
71
72 return is_array($supported_versions) ? $supported_versions : [];
73 }
74
75 // Parse HTML response from PHP.net
76 function wpmem_parse_supported_versions($html) {
77 $versions = [];
78 $dom = new DOMDocument();
79 @$dom->loadHTML($html);
80 $tables = $dom->getElementsByTagName('table');
81
82 foreach ($tables as $table) {
83 $rows = $table->getElementsByTagName('tr');
84 foreach ($rows as $row) {
85 $cells = $row->getElementsByTagName('td');
86 if ($cells->length >= 5) {
87 $version = trim($cells->item(0)->textContent);
88 $eol_date = DateTime::createFromFormat('d M Y', trim($cells->item(3)->textContent));
89
90 if ($eol_date) {
91 $versions[$version] = [
92 'eol' => $eol_date->format('Y-m-d'),
93 'status' => (new DateTime() < $eol_date) ? 'supported' : 'eol'
94 ];
95 }
96 }
97 }
98 }
99
100 return $versions;
101 }
102
103
104
105
106
107
108 function wpmem_get_php_status($current_version) {
109 $supported_versions = wpmem_get_supported_php_versions();
110 $current_branch = preg_replace('/^(\d+\.\d+).*$/', '$1', $current_version);
111
112 // Check if current branch is supported
113 foreach ($supported_versions as $version => $data) {
114 if (version_compare($current_branch, $version, '>=') && $data['status'] === 'supported') {
115 return 'supported';
116 }
117 }
118
119 return 'eol';
120 }
121
122
123
124
125
126
127 // to be shown in several places
128 function pluginmemoryusage_render_system_info() {
129 global $wpdb;
130
131 // Get PHP version and status
132 $php_version = phpversion();
133 $php_status = wpmem_get_php_status($php_version);
134
135 // Dashicons for PHP version status
136 $icons = [
137 'supported' => '<span class="dashicons dashicons-yes-alt" style="color:#46b450; margin-left:5px;" title="PHP version is supported"></span>',
138 'eol' => '<span class="dashicons dashicons-warning" style="color:#dc3232; margin-left:5px;" title="PHP version is end-of-life"></span>'
139 ];
140
141
142
143 // Fetch latest PHP version with error handling
144 $latest_php_version = get_transient('wpmem_latest_php_version');
145 if (false === $latest_php_version) {
146 $response = wp_remote_get('https://www.php.net/releases/?json', array(
147 'sslverify' => false,
148 'timeout' => 5
149 ));
150
151 if (!is_wp_error($response) && 200 === wp_remote_retrieve_response_code($response)) {
152 $data = json_decode(wp_remote_retrieve_body($response), true);
153 if (is_array($data) && !empty($data)) {
154 // Extract versions
155 $versions = array();
156 foreach ($data as $major_version => $release_info) {
157 if (isset($release_info['version'])) {
158 $versions[] = $release_info['version'];
159 }
160 }
161
162 usort($versions, 'version_compare');
163 $latest_php_version = end($versions);
164 set_transient('wpmem_latest_php_version', $latest_php_version, 12 * HOUR_IN_SECONDS);
165 }
166 }
167 }
168
169 // Validation
170 if (empty($latest_php_version) || !preg_match('/^\d+\.\d+(\.\d+)?$/', $latest_php_version)) {
171 $latest_php_version = 'Unknown';
172 }
173
174
175 $is_latest = ($latest_php_version !== 'Unknown') ? version_compare($php_version, $latest_php_version, '>=') : false;
176
177
178
179 // Get MySQL version and status
180 $mysql_version = wp_cache_get('wpmem_mysql_version');
181 if (false === $mysql_version) {
182 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Getting MySQL version requires direct query, no WordPress alternative available
183 $mysql_version = $wpdb->get_var("SELECT VERSION()");
184 wp_cache_set('wpmem_mysql_version', $mysql_version, '', 12 * HOUR_IN_SECONDS);
185 }
186
187 $mysql_status = wpmem_get_mysql_status($mysql_version);
188 $latest_mysql_version = wpmem_get_mysql_latest_version($mysql_version);
189
190 // Enhanced icons for MySQL status with tooltips
191 $mysql_icons = [
192 'supported' => '<span class="dashicons dashicons-yes-alt" style="color: #46b450;" title="MySQL/MariaDB version is currently supported"></span>',
193 'eol' => '<span class="dashicons dashicons-warning" style="color: #dc3232;" title="MySQL/MariaDB version has reached end-of-life - upgrade recommended"></span>',
194 'innovation' => '<span class="dashicons dashicons-lightbulb" style="color: #ffb900;" title="MySQL Innovation Release - shorter support cycle"></span>',
195 ' unknown' => '<span class="dashicons dashicons-editor-help" style="color: #666;" title="Unable to determine MySQL/MariaDB version support status"></span>'
196 ];
197
198 // Check if current version is latest
199 $current_version_number = '';
200 preg_match('/(\d+\.\d+\.\d+)/', $mysql_version, $matches);
201 if (!empty($matches[1])) {
202 $current_version_number = $matches[1];
203 }
204 $is_latest_mysql = ($latest_mysql_version !== 'Unknown' && !empty($current_version_number)) ?
205 version_compare($current_version_number, $latest_mysql_version, '>=') : false;
206
207
208
209
210 // Get max upload size
211 $max_upload = ini_get('upload_max_filesize');
212 $max_post = ini_get('post_max_size');
213 $memory_limit = ini_get('memory_limit');
214 $upload_mb = min(
215 wp_convert_hr_to_bytes($max_upload),
216 wp_convert_hr_to_bytes($max_post),
217 wp_convert_hr_to_bytes($memory_limit)
218 );
219
220 // Get WP and PHP memory limits
221 $wp_memory_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
222 $php_memory_limit = ini_get('memory_limit');
223
224
225 echo '<p class="pluginmemoryusage-system-info-line"><strong>WordPress Version:</strong> ' . esc_html(get_bloginfo('version')) . '</p>';
226 echo '<p class="pluginmemoryusage-system-info-line"><strong>PHP Version:</strong> ' . esc_html($php_version);
227 echo wp_kses_post($icons[$php_status]);
228 if ('Unknown' !== $latest_php_version) {
229 $label = $is_latest ? 'Latest' : 'Latest: ' . esc_html($latest_php_version);
230 $class = $is_latest ? 'pluginmemoryusage_version-latest' : 'pluginmemoryusage_version-outdated';
231 echo ' <span class="' . esc_attr($class) . '">' . esc_html($label) . '</span>';
232 } else {
233 echo ' <span class="php-version-outdated">(Version check failed)</span>';
234 }
235 echo '</p>';
236
237 // Display MySQL version with status
238 echo '<strong>MySQL Version:</strong> ' . esc_html($mysql_version) . ' ';
239 echo wp_kses_post($mysql_icons[$mysql_status]);
240
241 // Show latest version info (similar to PHP version display)
242 if ('Unknown' !== $latest_mysql_version) {
243 $label = $is_latest_mysql ? 'Latest' : 'Latest: ' . esc_html($latest_mysql_version);
244 $class = $is_latest_mysql ? 'pluginmemoryusage_version-latest' : 'pluginmemoryusage_version-outdated';
245 echo ' <span class="' . esc_attr($class) . '">' . esc_html($label) . '</span>';
246
247 } else {
248 echo ' <span class="pluginmemoryusage_version-unknown">(Version check failed)</span>';
249 }
250
251 echo '</p>';
252
253
254 echo '<p class="pluginmemoryusage-system-info-line"><strong>Max Upload Size:</strong> ' . esc_html(size_format($upload_mb)) . '</p>';
255 echo '<p class="pluginmemoryusage-system-info-line"><strong>WordPress Memory Limit:</strong> ' . esc_html(size_format($wp_memory_limit)) . '</p>';
256 echo '<p class="pluginmemoryusage-system-info-line"><strong>PHP Memory Limit:</strong> ' . esc_html($php_memory_limit) . '</p>';
257
258 }
259
260
261
262
263
264
265
266
267
268 // Function to display content in the dashboard widget
269 function pluginmemoryusage_display_memory_usage_dashboard() {
270 global $wpdb;
271
272
273 // Get WordPress memory limit
274 $wp_memory_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
275
276 // Get current memory usage
277 $current_memory_usage = memory_get_usage(true);
278
279 // Calculate percentage used
280 $percentage_used = ($current_memory_usage / $wp_memory_limit) * 100;
281
282
283
284 // Display the data - In seperate function for reusability
285 pluginmemoryusage_render_system_info();
286
287 // Display memory usage
288 echo '<p>Current Memory Usage: ';
289 echo esc_html(size_format($current_memory_usage)) . ' of ' . esc_html(size_format($wp_memory_limit)) . '</p>';
290 echo '<div style="width: 100%; background: #e0e0e0; height: 24px; border-radius: 10px; overflow: hidden;">
291 <div style="width: ' . esc_html(round($percentage_used, 1)) . '%; background: #76c7c0; height: 100%; text-align: center; line-height: 24px;" class="memory-bar-fill">' . esc_html(round($percentage_used, 1)) . '%</div>
292 </div>';
293
294 // Message to increase memory limit if usage is high
295 if ($current_memory_usage > $wp_memory_limit * 0.8) {
296 echo 'You are using more than 80% of allocated memory. Please go to Memory Control Panel to try to increase memory limit ';
297 echo '<p id="memory-increase-result"></p>';
298 }
299
300
301 // Add button to Plugin Memory Control Panel
302 echo '<p><a href="' . esc_html(admin_url('admin.php?page=wp_plugin_memory_usage')) . '" class="button">Plugin Memory Control Panel</a></p>';
303 }
304
305
306
307
308
309
310
311
312
313
314 function wpmem_memory_usage_admin_page() {
315 ?>
316 <div class="wrap">
317 <h1>Plugin Memory Usage - Control Panel</h1>
318
319 <div class="card-container">
320 <div class="card-row">
321 <div class="card card-system-info">
322 <h2>System Information</h2>
323 <?php pluginmemoryusage_render_system_info(); ?>
324 </div>
325
326 <div class="card card-memory-usage">
327 <h2>Current Memory Usage</h2>
328 <?php
329 $wp_memory_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
330 $current_memory_usage = memory_get_usage(true);
331 $percentage_used = ($current_memory_usage / $wp_memory_limit) * 100;
332 ?>
333 <p>Using <span id="current-memory"><?php echo esc_html(size_format($current_memory_usage)); ?></span> of <?php echo esc_html(size_format($wp_memory_limit)); ?></p>
334 <div class="memory-bar">
335 <div id="memory-bar-fill" class="memory-bar-fill" style="width: <?php echo esc_html(round($percentage_used, 1)); ?>%;">
336 <span id="memory-percentage"><?php echo esc_html(round($percentage_used, 1)); ?>%</span>
337 </div>
338 </div>
339
340 <br><button id="refresh-memory" class="button">Refresh Memory Usage</button>
341 <br><br>Memory fluctuate. Please press button once after entering panel.
342
343 <?php
344 if ($current_memory_usage > $wp_memory_limit * 0.8) {
345 echo '<p style="color:red;">You are using more than 80% of allocated memory. Please click button below to try to increase memory limit.</p> ';
346 echo '<p><button id="increase-memory-limit" class="button">Increase Memory Limit</button></p>';
347 echo '<p id="memory-increase-result"></p>';
348 } ?>
349 </div>
350
351 <div class="card card-memory-history">
352 <h2>Memory Usage History</h2>
353
354 <ul id="memory-history-list">
355
356
357 <hr>
358 <p>This plugin measures changes in WordPress memory usage as you activate and deactivate plugins. Here's how it works:</p>
359 <ol>
360 <li>It records the current memory usage of WordPress.</li>
361 <li>When you activate or deactivate a plugin, it measures the memory usage again.</li>
362 <li>The difference between these measurements gives an estimate of the plugin's memory impact.</li>
363 <li>This process is repeated each time you toggle a plugin.</li>
364 </ol>
365 <p>Note: These measurements are estimates and may vary. Factors like caching, other active plugins, and WordPress itself can influence memory usage. For the most accurate results, consider testing in a controlled environment.</p>
366 <p>To begin, try activating or deactivating plugins using the buttons provided. The memory usage history will appear here.</p>|
367
368
369
370 </ul>
371 </div>
372 </div>
373
374 <div class="card card-plugins">
375 <h2>Plugins</h2>
376 <?php
377 $all_plugins = get_plugins();
378 $active_plugins = get_option('active_plugins');
379
380
381
382
383
384 echo '<ul class="plugin-list">';
385 foreach ($all_plugins as $plugin_path => $plugin_data) {
386 $is_active = in_array($plugin_path, $active_plugins);
387 $plugin_id = sanitize_title($plugin_data['Name']);
388 $is_memory_usage_plugin = (strpos($plugin_path, 'plugin-memory-usage') !== false);
389 $li_class = $is_active ? 'plugin-active' : 'plugin-inactive';
390 if ($is_memory_usage_plugin) {
391 $li_class .= ' memory-usage-plugin';
392 }
393 $avg_memory = wpmem_get_average_memory_usage($plugin_path);
394
395 echo '<li class="' . esc_attr($li_class) . '">';
396 echo '<div class="plugin-info">';
397 echo '<span class="plugin-name">' . esc_html($plugin_data['Name']) . ' <span class="avg-memory" title="The average memory usage represents the typical amount of memory consumed by this plugin over time.">(' . esc_html($avg_memory) . ' MB)</span></span>';
398 echo '<div class="plugin-memory-bar" title="Absolute value of last memory change"><div class="plugin-memory-fill"><span class="plugin-memory-text"></span></div></div>';
399 echo '</div>';
400 echo '<div class="plugin-actions">';
401 if ($is_memory_usage_plugin) {
402 echo '<button class="button" disabled>Active</button>';
403 } else {
404 echo '<button class="button toggle-plugin" data-plugin="' . esc_attr($plugin_path) . '" data-action="' . ($is_active ? 'deactivate' : 'activate') . '">';
405 echo $is_active ? 'Deactivate' : 'Activate';
406 echo '</button>';
407 }
408 echo '</div>';
409 echo '</li>';
410 }
411
412 echo '</ul>';
413
414
415
416
417
418 ?>
419 </div>
420 </div>
421 </div>
422
423
424 <?php
425 }
426
427
428
429
430
431 function wpmem_toggle_plugin() {
432 check_ajax_referer('wp_memory_usage_nonce', 'nonce');
433 if (!current_user_can('activate_plugins')) {
434 wp_send_json_error('Insufficient permissions');
435 }
436
437
438 $plugin = isset($_POST['plugin']) ? sanitize_text_field(wp_unslash($_POST['plugin'])) : '';
439 $action = isset($_POST['toggle_action']) ? sanitize_text_field(wp_unslash($_POST['toggle_action'])) : '';
440
441 if (empty($plugin) || empty($action)) {
442 wp_send_json_error('Invalid plugin or action');
443 return;
444 }
445
446
447
448 if ($action === 'activate') {
449 $result = activate_plugin($plugin);
450 } else {
451 $result = deactivate_plugins($plugin);
452 }
453
454 if (is_wp_error($result)) {
455 wp_send_json_error($result->get_error_message());
456 } else {
457 wp_send_json_success();
458 }
459 }
460 add_action('wp_ajax_toggle_plugin', 'wpmem_toggle_plugin');
461
462
463
464
465
466
467 function wpmem_table_exists($table_name) {
468 global $wpdb;
469 $full_table_name = $wpdb->prefix . $table_name;
470
471 // Create a unique cache key
472 $cache_key = 'wpmem_table_exists_' . md5($full_table_name);
473
474 // Try to get the result from cache
475 $table_exists = wp_cache_get($cache_key);
476
477 if (false === $table_exists) {
478 // Cache miss, perform the database query
479 // There isn't a reliable way to check if a table exists in WordPress without making a direct database call
480 $result = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
481 $wpdb->prepare(
482 "SHOW TABLES LIKE %s",
483 $full_table_name
484 )
485 );
486
487 $table_exists = ($result === $full_table_name);
488
489 // Cache the result for future use (cache for 1 hour)
490 wp_cache_set($cache_key, $table_exists, '', 3600);
491 }
492
493 return $table_exists;
494 }
495
496
497
498
499
500 function wpmem_refresh_memory_usage() {
501 check_ajax_referer('wp_memory_usage_nonce', 'nonce');
502
503 global $wpdb;
504 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
505
506 // Check if the table exists
507 if (!wpmem_table_exists('wpmem_plugin_history')) {
508 wpmem_create_history_table();
509 }
510
511
512 $current_memory = memory_get_usage(true);
513 $formatted_memory = size_format($current_memory, 2);
514 $percentage = round(($current_memory / wp_convert_hr_to_bytes(WP_MEMORY_LIMIT)) * 100, 2);
515
516 // Save the measurement if a plugin was toggled
517 if (isset($_POST['plugin']) && isset($_POST['toggle_action'])) {
518 $plugin = sanitize_text_field(wp_unslash($_POST['plugin']));
519 $previous_memory = isset($_POST['previous_memory']) ? intval($_POST['previous_memory']) : 0;
520 $memory_change = $current_memory - $previous_memory;
521 wpmem_save_plugin_measurement($plugin, $memory_change);
522 }
523
524 wp_send_json_success(array(
525 'current_memory' => $formatted_memory,
526 'current_memory_bytes' => $current_memory,
527 'percentage' => $percentage,
528 ));
529 }
530 add_action('wp_ajax_refresh_memory_usage', 'wpmem_refresh_memory_usage');
531
532
533
534
535 add_action('admin_enqueue_scripts', 'wp_memory_usage_enqueue_styles');
536
537 function wp_memory_usage_enqueue_styles($hook) {
538 // Load on all admin pages where the dashboard widget appears
539 wp_enqueue_style('wp-memory-usage-styles',
540 plugins_url('plugin-memory-usage.css', __FILE__),
541 array(),
542 filemtime(plugin_dir_path(__FILE__) . 'plugin-memory-usage.css')
543 );
544 }
545
546
547
548
549 function wpmem_enqueue_scripts($hook) {
550 if ($hook != 'toplevel_page_wp_plugin_memory_usage') {
551 return;
552 }
553 wp_enqueue_script('wpmem-script', plugins_url('plugin-memory-usage.js', __FILE__), array(), '1.0', true);
554 $nonce = wp_create_nonce('wp_memory_usage_nonce');
555 wp_localize_script('wpmem-script', 'wpmemData', array(
556 'wpmem_ajaxurl' => admin_url('admin-ajax.php'),
557 'nonce' => $nonce,
558 'initialMemoryUsage' => memory_get_usage(true),
559 'pluginHistory' => wpmem_get_all_plugin_history()
560 ));
561 }
562 add_action('admin_enqueue_scripts', 'wpmem_enqueue_scripts');
563
564
565
566
567
568 function wpmem_create_history_table() {
569 global $wpdb;
570 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
571 $charset_collate = $wpdb->get_charset_collate();
572
573 $sql = "CREATE TABLE $table_name (
574 id mediumint(9) NOT NULL AUTO_INCREMENT,
575 plugin_path varchar(255) NOT NULL,
576 memory_change bigint(20) NOT NULL,
577 zero_count int(11) NOT NULL DEFAULT 0,
578 timestamp datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
579 PRIMARY KEY (id)
580 ) $charset_collate;";
581
582 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
583 $result = dbDelta($sql);
584
585 if (!empty($wpdb->last_error)) {
586 return false;
587 }
588 return true;
589 }
590
591
592 register_activation_hook(__FILE__, 'wpmem_create_history_table');
593
594
595
596 function wpmem_save_plugin_measurement($plugin_path, $memory_change) {
597 global $wpdb;
598 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
599
600 // Convert memory_change to its absolute value
601 $memory_change = abs($memory_change);
602
603 if ($memory_change == 0) {
604 // Increment zero count for the most recent entry
605 $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
606 $wpdb->prepare(
607 "UPDATE `" . esc_sql($table_name) . "` SET zero_count = zero_count + 1
608 WHERE plugin_path = %s
609 ORDER BY timestamp DESC
610 LIMIT 1",
611 $plugin_path
612 )
613 );
614 } else {
615 // Insert new non-zero measurement
616 $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
617 $table_name,
618 array(
619 'plugin_path' => $plugin_path,
620 'memory_change' => $memory_change,
621 'zero_count' => 0,
622 )
623 );
624 }
625
626 // Clear caches
627 wpmem_clear_plugin_history_cache($plugin_path);
628 wpmem_clear_all_plugin_history_cache();
629 wpmem_clear_average_memory_cache($plugin_path);
630 }
631
632
633
634 function wpmem_get_plugin_history($plugin_path) {
635 global $wpdb;
636 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
637
638 // Create a unique cache key for this query
639 $cache_key = 'wpmem_plugin_history_' . md5($plugin_path);
640
641 // Try to get the results from cache
642 $results = wp_cache_get($cache_key);
643
644 // If the results are not in cache, query the database
645 if (false === $results) {
646 $results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
647 $wpdb->prepare(
648 "SELECT memory_change, timestamp FROM `" . esc_sql($table_name) . "` WHERE plugin_path = %s ORDER BY timestamp DESC LIMIT 5",
649 $plugin_path
650 )
651 );
652
653 // Cache the results for future use
654 wp_cache_set($cache_key, $results, '', 3600); // Cache for 1 hour
655 }
656
657 return $results;
658 }
659
660
661
662 function wpmem_clear_plugin_history_cache($plugin_path) {
663 $cache_key = 'wpmem_plugin_history_' . md5($plugin_path);
664 wp_cache_delete($cache_key);
665 }
666
667
668
669 add_action('wp_ajax_get_plugin_history', 'wpmem_get_plugin_history_ajax');
670 function wpmem_get_plugin_history_ajax() {
671 check_ajax_referer('wp_memory_usage_nonce', 'nonce');
672 if (!isset($_POST['plugin'])) {
673 wp_send_json_error('Plugin not specified');
674 }
675
676 $plugin = sanitize_text_field(wp_unslash($_POST['plugin']));
677 $history = wpmem_get_plugin_history($plugin);
678
679 wp_send_json_success($history);
680 }
681
682
683
684
685
686
687
688
689 function wpmem_get_all_plugin_history() {
690 global $wpdb;
691 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
692
693 // Create a unique cache key for this query
694 $cache_key = 'wpmem_all_plugin_history';
695
696 // Try to get the results from cache
697 $results = wp_cache_get($cache_key);
698
699 // If the results are not in cache, query the database
700 if (false === $results) {
701 $results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
702 $wpdb->prepare(
703 "SELECT plugin_path, memory_change, timestamp
704 FROM `" . esc_sql($table_name) . "`
705 WHERE plugin_path IN (SELECT DISTINCT plugin_path FROM `" . esc_sql($table_name) . "`)
706 ORDER BY timestamp DESC
707 -- %d",
708 1
709 )
710 );
711
712 // Cache the results for future use
713 wp_cache_set($cache_key, $results, '', 3600); // Cache for 1 hour
714 }
715
716 // Process results...
717 $history = array();
718 foreach ($results as $row) {
719 if (!isset($history[$row->plugin_path])) {
720 $history[$row->plugin_path] = array();
721 }
722 if (count($history[$row->plugin_path]) < 5) {
723 $history[$row->plugin_path][] = array(
724 'memory_change' => $row->memory_change,
725 'timestamp' => $row->timestamp
726 );
727 }
728 }
729
730 return $history;
731 }
732
733
734
735
736 function wpmem_clear_all_plugin_history_cache() {
737 wp_cache_delete('wpmem_all_plugin_history');
738 }
739
740
741
742 function wpmem_clear_table_exists_cache() {
743 global $wpdb;
744 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
745 $cache_key = 'wpmem_table_exists_' . $table_name;
746 wp_cache_delete($cache_key);
747 }
748
749
750 // Reset table verification cache when changing plugin state
751 register_activation_hook(__FILE__, 'wpmem_clear_table_exists_cache'); // Pre-activation check
752 register_deactivation_hook(__FILE__, 'wpmem_clear_table_exists_cache'); // Post-deactivation cleanup
753
754
755
756
757
758 function wpmem_get_average_memory_usage($plugin_path) {
759 global $wpdb;
760 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
761
762 // Create a unique cache key
763 $cache_key = 'wpmem_avg_memory_' . md5($plugin_path);
764
765 // Try to get the result from cache
766 $avg_memory = wp_cache_get($cache_key);
767
768 if (false === $avg_memory) {
769 // Cache miss, perform the database query
770 $result = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
771 $wpdb->prepare(
772 "SELECT SUM(memory_change) as total_change,
773 COUNT(*) as non_zero_count,
774 SUM(zero_count) as zero_count
775 FROM `" . esc_sql($table_name) . "`
776 WHERE plugin_path = %s",
777 $plugin_path
778 )
779 );
780
781 if ($result) {
782 $total_count = $result->non_zero_count + $result->zero_count;
783 $avg_memory = $total_count > 0 ? ($result->total_change / $total_count) / (1024 * 1024) : 0;
784 $avg_memory = round($avg_memory, 2); // Round to 2 decimal places
785 } else {
786 $avg_memory = 0;
787 }
788
789 // Cache the result for future use (cache for 5 minutes)
790 wp_cache_set($cache_key, $avg_memory, '', 300);
791 }
792
793 return $avg_memory;
794 }
795
796
797
798 function wpmem_clear_average_memory_cache($plugin_path) {
799 $cache_key = 'wpmem_avg_memory_' . md5($plugin_path);
800 wp_cache_delete($cache_key);
801 }
802
803
804
805 add_action('wp_ajax_update_average_memory', 'wpmem_update_average_memory');
806 add_action('wp_ajax_nopriv_update_average_memory', 'wpmem_update_average_memory');
807
808 function wpmem_update_average_memory() {
809 // Check nonce for security
810 if (!isset($_POST['nonce'])) {
811 wp_send_json_error('Security token not provided');
812 }
813
814 $nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
815 if (!wp_verify_nonce($nonce, 'wp_memory_usage_nonce')) {
816 wp_send_json_error('Invalid security token');
817 }
818
819 if (!isset($_POST['plugin_path'])) {
820 wp_send_json_error('Plugin path not provided');
821 }
822
823 $plugin_path = sanitize_text_field(wp_unslash($_POST['plugin_path']));
824 $avg_memory = wpmem_get_average_memory_usage($plugin_path);
825
826 wp_send_json_success(array('avg_memory' => $avg_memory));
827 }
828
829
830
831
832
833
834 function wpmem_add_increase_memory_button($content) {
835 $wp_memory_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
836 $current_memory_usage = memory_get_usage(true);
837
838 if ($current_memory_usage > $wp_memory_limit) {
839 $content .= '<button id="increase-memory-limit" class="button">Increase Memory Limit</button>';
840 $content .= '<span id="memory-increase-result"></span>';
841 }
842
843 return $content;
844 }
845 add_filter('wpmem_memory_usage_content', 'wpmem_add_increase_memory_button');
846
847
848
849
850 function wpmem_increase_memory_limit() {
851 check_ajax_referer('wp_memory_usage_nonce', 'nonce');
852
853 if (!current_user_can('manage_options')) {
854 wp_send_json_error(array('message' => 'Insufficient permissions'));
855 }
856
857 $current_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
858
859 // If current limit is 160MB or less, double it. Otherwise, increase by 25%.
860 if ($current_limit < 160 * 1024 * 1024) { // 160 MB in bytes
861 $new_limit = $current_limit * 2;
862 } else {
863 $new_limit = (int)($current_limit * 1.25); // Increase by 25%
864 }
865
866 // Optional: Cap the maximum limit to avoid runaway values (e.g., 512MB)
867 $max_limit = 512 * 1024 * 1024; // 512 MB in bytes
868 if ($new_limit > $max_limit) {
869 $new_limit = $max_limit;
870 }
871
872 // Attempt to increase the limit
873 if (wpmem_set_memory_limit($new_limit)) {
874 wp_send_json_success(array('new_limit' => size_format($new_limit)));
875 } else {
876 wp_send_json_error(array('message' => 'Unable to increase memory limit. You may need to contact your hosting provider.'));
877 }
878 }
879 add_action('wp_ajax_increase_memory_limit', 'wpmem_increase_memory_limit');
880
881
882
883 function wpmem_set_memory_limit($new_limit) {
884 global $wp_filesystem;
885
886 // Initialize the WP filesystem
887 if (empty($wp_filesystem)) {
888 require_once (ABSPATH . '/wp-admin/includes/file.php');
889 WP_Filesystem();
890 }
891
892 $wp_config_file = ABSPATH . 'wp-config.php';
893 $config_content = $wp_filesystem->get_contents($wp_config_file);
894
895 if ($config_content === false) {
896 return false;
897 }
898
899 $new_limit_formatted = size_format($new_limit);
900
901 if (preg_match("/define\(\s*'WP_MEMORY_LIMIT',\s*'.*?'\s*\);/", $config_content)) {
902 // WP_MEMORY_LIMIT is already defined, so update it
903 $new_content = preg_replace(
904 "/define\(\s*'WP_MEMORY_LIMIT',\s*'.*?'\s*\);/",
905 "define('WP_MEMORY_LIMIT', '$new_limit_formatted');",
906 $config_content
907 );
908 } else {
909 // WP_MEMORY_LIMIT is not defined, so add it
910 $new_content = preg_replace(
911 "/<\?php/",
912 "<?php\ndefine('WP_MEMORY_LIMIT', '$new_limit_formatted');",
913 $config_content,
914 1
915 );
916 }
917
918 if ($wp_filesystem->put_contents($wp_config_file, $new_content) === false) {
919 return false;
920 }
921
922 return true;
923 }
924
925
926
927
928
929
930 function wpmem_add_settings_link($links) {
931 $settings_link = '<a href="' . admin_url('admin.php?page=wp_plugin_memory_usage') . '">Settings</a>';
932 array_unshift($links, $settings_link);
933 return $links;
934 }
935
936 $plugin = plugin_basename(__FILE__);
937 add_filter("plugin_action_links_$plugin", 'wpmem_add_settings_link');
938
939
940
941
942
943 function wpmem_add_memory_to_admin_bar($wp_admin_bar) {
944 $wp_memory_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
945 $current_memory_usage = memory_get_usage(true);
946 $percentage_used = round(($current_memory_usage / $wp_memory_limit) * 100, 1);
947
948
949 // Determine color class based on memory usage
950 if ($percentage_used >= 90) {
951 $color_class = 'wpmem-critical'; // Red
952 } elseif ($percentage_used >= 75) {
953 $color_class = 'wpmem-warning'; // Orange
954 } elseif ($percentage_used >= 50) {
955 $color_class = 'wpmem-moderate'; // Yellow
956 } else {
957 $color_class = 'wpmem-good'; // Green
958 }
959
960 $wp_admin_bar->add_node(array(
961 'id' => 'wpmem_memory_usage',
962 'title' => '<span class="' . esc_attr($color_class) . '">MEM: ' . $percentage_used . '%</span>',
963 'href' => admin_url('admin.php?page=wp_plugin_memory_usage'),
964 'meta' => array(
965 'title' => 'Current memory usage: ' . size_format($current_memory_usage) . ' of ' . size_format($wp_memory_limit),
966 ),
967 ));
968 }
969 add_action('admin_bar_menu', 'wpmem_add_memory_to_admin_bar', 100);
970
971
972
973
974
975 function wpmem_get_mysql_versions_from_api() {
976 $mysql_versions = get_transient('wpmem_mysql_eol_data');
977 if (false === $mysql_versions) {
978 // Get MySQL data
979 $mysql_response = wp_remote_get('https://endoflife.date/api/mysql.json', array(
980 'sslverify' => false,
981 'timeout' => 5
982 ));
983
984 // Get MariaDB data
985 $mariadb_response = wp_remote_get('https://endoflife.date/api/mariadb.json', array(
986 'sslverify' => false,
987 'timeout' => 5
988 ));
989
990 $versions_data = ['mysql' => [], 'mariadb' => []];
991
992 if (!is_wp_error($mysql_response) && 200 === wp_remote_retrieve_response_code($mysql_response)) {
993 $mysql_data = json_decode(wp_remote_retrieve_body($mysql_response), true);
994 if (is_array($mysql_data)) {
995 foreach ($mysql_data as $version_info) {
996 $cycle = $version_info['cycle'];
997 $eol_date = $version_info['eol'] ?? null;
998
999 if ($eol_date && $eol_date !== false) {
1000 $versions_data['mysql'][$cycle] = [
1001 'eol_date' => $eol_date,
1002 'latest' => $version_info['latest'] ?? '',
1003 'support_end' => $version_info['support'] ?? $eol_date
1004 ];
1005 }
1006 }
1007 }
1008 }
1009
1010 if (!is_wp_error($mariadb_response) && 200 === wp_remote_retrieve_response_code($mariadb_response)) {
1011 $mariadb_data = json_decode(wp_remote_retrieve_body($mariadb_response), true);
1012 if (is_array($mariadb_data)) {
1013 foreach ($mariadb_data as $version_info) {
1014 $cycle = $version_info['cycle'];
1015 $eol_date = $version_info['eol'] ?? null;
1016
1017 if ($eol_date && $eol_date !== false) {
1018 $versions_data['mariadb'][$cycle] = [
1019 'eol_date' => $eol_date,
1020 'latest' => $version_info['latest'] ?? '', // This is the key addition
1021 'lts' => $version_info['lts'] ?? false
1022 ];
1023 }
1024 }
1025 }
1026 }
1027
1028 // Cache for one week
1029 set_transient('wpmem_mysql_eol_data', $versions_data, WEEK_IN_SECONDS);
1030 $mysql_versions = $versions_data;
1031 }
1032
1033 return $mysql_versions;
1034 }
1035
1036
1037 function wpmem_get_mysql_latest_version($current_version) {
1038 $version_data = wpmem_get_mysql_versions_from_api();
1039 $is_mariadb = stripos($current_version, 'mariadb') !== false;
1040
1041 // Extract version number
1042 preg_match('/(\d+\.\d+)/', $current_version, $matches);
1043 $version_number = $matches[1] ?? '';
1044
1045 if (empty($version_number)) {
1046 return 'Unknown';
1047 }
1048
1049 $database_type = $is_mariadb ? 'mariadb' : 'mysql';
1050 $versions = $version_data[$database_type] ?? [];
1051
1052 if (isset($versions[$version_number]) && !empty($versions[$version_number]['latest'])) {
1053 return $versions[$version_number]['latest'];
1054 }
1055
1056 return 'Unknown';
1057 }
1058
1059
1060
1061
1062
1063 function wpmem_get_mysql_status($current_version) {
1064 $version_data = wpmem_get_mysql_versions_from_api();
1065 $is_mariadb = stripos($current_version, 'mariadb') !== false;
1066
1067 // Extract version number
1068 preg_match('/(\d+\.\d+)/', $current_version, $matches);
1069 $version_number = $matches[1] ?? '';
1070
1071 if (empty($version_number)) {
1072 return 'unknown';
1073 }
1074
1075 $database_type = $is_mariadb ? 'mariadb' : 'mysql';
1076 $versions = $version_data[$database_type] ?? [];
1077
1078 if (isset($versions[$version_number])) {
1079 $version_info = $versions[$version_number];
1080 $eol_date_str = $version_info['eol_date'];
1081
1082 // Handle different date formats from API
1083 if ($eol_date_str === true || $eol_date_str === false) {
1084 return $eol_date_str === false ? 'supported' : 'eol';
1085 }
1086
1087 try {
1088 $eol_date = new DateTime($eol_date_str);
1089 $now = new DateTime();
1090
1091 return ($now < $eol_date) ? 'supported' : 'eol';
1092 } catch (Exception $e) {
1093 return 'unknown';
1094 }
1095 }
1096
1097 return 'unknown';
1098 }
1099
1100
1101
1102
1103
1104
1105 ?>