PluginProbe
Plugin Memory Usage / 1.2.4
Plugin Memory Usage v1.2.4
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.4, at plugin-memory-usage.php

923 lines 29.1 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.4
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.4');
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 // Get MySQL version (with caching)
178 $mysql_version = wp_cache_get('wpmem_mysql_version');
179 if (false === $mysql_version) {
180 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- No WP API for MySQL version; safe, read-only query and result is cached.
181 $mysql_version = $wpdb->get_var("SELECT VERSION()");
182 wp_cache_set('wpmem_mysql_version', $mysql_version, '', 12 * HOUR_IN_SECONDS);
183 }
184
185 // Get max upload size
186 $max_upload = ini_get('upload_max_filesize');
187 $max_post = ini_get('post_max_size');
188 $memory_limit = ini_get('memory_limit');
189 $upload_mb = min(
190 wp_convert_hr_to_bytes($max_upload),
191 wp_convert_hr_to_bytes($max_post),
192 wp_convert_hr_to_bytes($memory_limit)
193 );
194
195 // Get WP and PHP memory limits
196 $wp_memory_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
197 $php_memory_limit = ini_get('memory_limit');
198
199
200 echo '<p class="pluginmemoryusage-system-info-line"><strong>WordPress Version:</strong> ' . esc_html(get_bloginfo('version')) . '</p>';
201 echo '<p class="pluginmemoryusage-system-info-line"><strong>PHP Version:</strong> ' . esc_html($php_version);
202 echo wp_kses_post($icons[$php_status]);
203 if ('Unknown' !== $latest_php_version) {
204 $label = $is_latest ? 'Latest' : 'Latest: ' . esc_html($latest_php_version);
205 $class = $is_latest ? 'php-version-latest' : 'php-version-outdated';
206 echo ' <span class="' . esc_attr($class) . '">' . esc_html($label) . '</span>';
207 } else {
208 echo ' <span class="php-version-outdated">(Version check failed)</span>';
209 }
210 echo '</p>';
211
212 echo '<p class="pluginmemoryusage-system-info-line"><strong>MySQL Version:</strong> ' . esc_html($mysql_version) . '</p>';
213 echo '<p class="pluginmemoryusage-system-info-line"><strong>Max Upload Size:</strong> ' . esc_html(size_format($upload_mb)) . '</p>';
214 echo '<p class="pluginmemoryusage-system-info-line"><strong>WordPress Memory Limit:</strong> ' . esc_html(size_format($wp_memory_limit)) . '</p>';
215 echo '<p class="pluginmemoryusage-system-info-line"><strong>PHP Memory Limit:</strong> ' . esc_html($php_memory_limit) . '</p>';
216
217 }
218
219
220
221
222
223
224
225
226
227 // Function to display content in the dashboard widget
228 function pluginmemoryusage_display_memory_usage_dashboard() {
229 global $wpdb;
230
231
232 // Get WordPress memory limit
233 $wp_memory_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
234
235 // Get current memory usage
236 $current_memory_usage = memory_get_usage(true);
237
238 // Calculate percentage used
239 $percentage_used = ($current_memory_usage / $wp_memory_limit) * 100;
240
241
242
243 // Display the data - In seperate function for reusability
244 pluginmemoryusage_render_system_info();
245
246 // Display memory usage
247 echo '<p>Current Memory Usage: ';
248 echo esc_html(size_format($current_memory_usage)) . ' of ' . esc_html(size_format($wp_memory_limit)) . '</p>';
249 echo '<div style="width: 100%; background: #e0e0e0; height: 24px; border-radius: 10px; overflow: hidden;">
250 <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>
251 </div>';
252
253 // Message to increase memory limit if usage is high
254 if ($current_memory_usage > $wp_memory_limit * 0.8) {
255 echo 'You are using more than 80% of allocated memory. Please go to Memory Control Panel to try to increase memory limit ';
256 echo '<p id="memory-increase-result"></p>';
257 }
258
259
260 // Add button to Plugin Memory Control Panel
261 echo '<p><a href="' . esc_html(admin_url('admin.php?page=wp_plugin_memory_usage')) . '" class="button">Plugin Memory Control Panel</a></p>';
262 }
263
264
265
266
267
268
269
270
271
272
273 function wpmem_memory_usage_admin_page() {
274 ?>
275 <div class="wrap">
276 <h1>Plugin Memory Usage - Control Panel</h1>
277
278 <div class="card-container">
279 <div class="card-row">
280 <div class="card card-system-info">
281 <h2>System Information</h2>
282 <?php pluginmemoryusage_render_system_info(); ?>
283 </div>
284
285 <div class="card card-memory-usage">
286 <h2>Current Memory Usage</h2>
287 <?php
288 $wp_memory_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
289 $current_memory_usage = memory_get_usage(true);
290 $percentage_used = ($current_memory_usage / $wp_memory_limit) * 100;
291 ?>
292 <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>
293 <div class="memory-bar">
294 <div id="memory-bar-fill" class="memory-bar-fill" style="width: <?php echo esc_html(round($percentage_used, 1)); ?>%;">
295 <span id="memory-percentage"><?php echo esc_html(round($percentage_used, 1)); ?>%</span>
296 </div>
297 </div>
298
299 <br><button id="refresh-memory" class="button">Refresh Memory Usage</button>
300 <br><br>Memory fluctuate. Please press button once after entering panel.
301
302 <?php
303 if ($current_memory_usage > $wp_memory_limit * 0.8) {
304 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> ';
305 echo '<p><button id="increase-memory-limit" class="button">Increase Memory Limit</button></p>';
306 echo '<p id="memory-increase-result"></p>';
307 } ?>
308 </div>
309
310 <div class="card card-memory-history">
311 <h2>Memory Usage History</h2>
312
313 <ul id="memory-history-list">
314
315
316 <hr>
317 <p>This plugin measures changes in WordPress memory usage as you activate and deactivate plugins. Here's how it works:</p>
318 <ol>
319 <li>It records the current memory usage of WordPress.</li>
320 <li>When you activate or deactivate a plugin, it measures the memory usage again.</li>
321 <li>The difference between these measurements gives an estimate of the plugin's memory impact.</li>
322 <li>This process is repeated each time you toggle a plugin.</li>
323 </ol>
324 <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>
325 <p>To begin, try activating or deactivating plugins using the buttons provided. The memory usage history will appear here.</p>|
326
327
328
329 </ul>
330 </div>
331 </div>
332
333 <div class="card card-plugins">
334 <h2>Plugins</h2>
335 <?php
336 $all_plugins = get_plugins();
337 $active_plugins = get_option('active_plugins');
338
339
340
341
342
343 echo '<ul class="plugin-list">';
344 foreach ($all_plugins as $plugin_path => $plugin_data) {
345 $is_active = in_array($plugin_path, $active_plugins);
346 $plugin_id = sanitize_title($plugin_data['Name']);
347 $is_memory_usage_plugin = (strpos($plugin_path, 'plugin-memory-usage') !== false);
348 $li_class = $is_active ? 'plugin-active' : 'plugin-inactive';
349 if ($is_memory_usage_plugin) {
350 $li_class .= ' memory-usage-plugin';
351 }
352 $avg_memory = wpmem_get_average_memory_usage($plugin_path);
353
354 echo '<li class="' . esc_attr($li_class) . '">';
355 echo '<div class="plugin-info">';
356 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>';
357 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>';
358 echo '</div>';
359 echo '<div class="plugin-actions">';
360 if ($is_memory_usage_plugin) {
361 echo '<button class="button" disabled>Active</button>';
362 } else {
363 echo '<button class="button toggle-plugin" data-plugin="' . esc_attr($plugin_path) . '" data-action="' . ($is_active ? 'deactivate' : 'activate') . '">';
364 echo $is_active ? 'Deactivate' : 'Activate';
365 echo '</button>';
366 }
367 echo '</div>';
368 echo '</li>';
369 }
370
371 echo '</ul>';
372
373
374
375
376
377 ?>
378 </div>
379 </div>
380 </div>
381
382
383 <?php
384 }
385
386
387
388
389
390 function wpmem_toggle_plugin() {
391 check_ajax_referer('wp_memory_usage_nonce', 'nonce');
392 if (!current_user_can('activate_plugins')) {
393 wp_send_json_error('Insufficient permissions');
394 }
395
396
397 $plugin = isset($_POST['plugin']) ? sanitize_text_field(wp_unslash($_POST['plugin'])) : '';
398 $action = isset($_POST['toggle_action']) ? sanitize_text_field(wp_unslash($_POST['toggle_action'])) : '';
399
400 if (empty($plugin) || empty($action)) {
401 wp_send_json_error('Invalid plugin or action');
402 return;
403 }
404
405
406
407 if ($action === 'activate') {
408 $result = activate_plugin($plugin);
409 } else {
410 $result = deactivate_plugins($plugin);
411 }
412
413 if (is_wp_error($result)) {
414 wp_send_json_error($result->get_error_message());
415 } else {
416 wp_send_json_success();
417 }
418 }
419 add_action('wp_ajax_toggle_plugin', 'wpmem_toggle_plugin');
420
421
422
423
424
425
426 function wpmem_table_exists($table_name) {
427 global $wpdb;
428 $full_table_name = $wpdb->prefix . $table_name;
429
430 // Create a unique cache key
431 $cache_key = 'wpmem_table_exists_' . md5($full_table_name);
432
433 // Try to get the result from cache
434 $table_exists = wp_cache_get($cache_key);
435
436 if (false === $table_exists) {
437 // Cache miss, perform the database query
438 // There isn't a reliable way to check if a table exists in WordPress without making a direct database call
439 $result = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
440 $wpdb->prepare(
441 "SHOW TABLES LIKE %s",
442 $full_table_name
443 )
444 );
445
446 $table_exists = ($result === $full_table_name);
447
448 // Cache the result for future use (cache for 1 hour)
449 wp_cache_set($cache_key, $table_exists, '', 3600);
450 }
451
452 return $table_exists;
453 }
454
455
456
457
458
459 function wpmem_refresh_memory_usage() {
460 check_ajax_referer('wp_memory_usage_nonce', 'nonce');
461
462 global $wpdb;
463 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
464
465 // Check if the table exists
466 if (!wpmem_table_exists('wpmem_plugin_history')) {
467 wpmem_create_history_table();
468 }
469
470
471 $current_memory = memory_get_usage(true);
472 $formatted_memory = size_format($current_memory, 2);
473 $percentage = round(($current_memory / wp_convert_hr_to_bytes(WP_MEMORY_LIMIT)) * 100, 2);
474
475 // Save the measurement if a plugin was toggled
476 if (isset($_POST['plugin']) && isset($_POST['toggle_action'])) {
477 $plugin = sanitize_text_field(wp_unslash($_POST['plugin']));
478 $previous_memory = isset($_POST['previous_memory']) ? intval($_POST['previous_memory']) : 0;
479 $memory_change = $current_memory - $previous_memory;
480 wpmem_save_plugin_measurement($plugin, $memory_change);
481 }
482
483 wp_send_json_success(array(
484 'current_memory' => $formatted_memory,
485 'current_memory_bytes' => $current_memory,
486 'percentage' => $percentage,
487 ));
488 }
489 add_action('wp_ajax_refresh_memory_usage', 'wpmem_refresh_memory_usage');
490
491
492
493
494 add_action('admin_enqueue_scripts', 'wp_memory_usage_enqueue_styles');
495
496 function wp_memory_usage_enqueue_styles($hook) {
497 // Load on all admin pages where the dashboard widget appears
498 wp_enqueue_style('wp-memory-usage-styles',
499 plugins_url('plugin-memory-usage.css', __FILE__),
500 array(),
501 filemtime(plugin_dir_path(__FILE__) . 'plugin-memory-usage.css')
502 );
503 }
504
505
506
507
508 function wpmem_enqueue_scripts($hook) {
509 if ($hook != 'toplevel_page_wp_plugin_memory_usage') {
510 return;
511 }
512 wp_enqueue_script('wpmem-script', plugins_url('plugin-memory-usage.js', __FILE__), array(), '1.0', true);
513 $nonce = wp_create_nonce('wp_memory_usage_nonce');
514 wp_localize_script('wpmem-script', 'wpmemData', array(
515 'wpmem_ajaxurl' => admin_url('admin-ajax.php'),
516 'nonce' => $nonce,
517 'initialMemoryUsage' => memory_get_usage(true),
518 'pluginHistory' => wpmem_get_all_plugin_history()
519 ));
520 }
521 add_action('admin_enqueue_scripts', 'wpmem_enqueue_scripts');
522
523
524
525
526
527 function wpmem_create_history_table() {
528 global $wpdb;
529 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
530 $charset_collate = $wpdb->get_charset_collate();
531
532 $sql = "CREATE TABLE $table_name (
533 id mediumint(9) NOT NULL AUTO_INCREMENT,
534 plugin_path varchar(255) NOT NULL,
535 memory_change bigint(20) NOT NULL,
536 zero_count int(11) NOT NULL DEFAULT 0,
537 timestamp datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
538 PRIMARY KEY (id)
539 ) $charset_collate;";
540
541 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
542 $result = dbDelta($sql);
543
544 if (!empty($wpdb->last_error)) {
545 return false;
546 }
547 return true;
548 }
549
550
551 register_activation_hook(__FILE__, 'wpmem_create_history_table');
552
553
554
555 function wpmem_save_plugin_measurement($plugin_path, $memory_change) {
556 global $wpdb;
557 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
558
559 // Convert memory_change to its absolute value
560 $memory_change = abs($memory_change);
561
562 if ($memory_change == 0) {
563 // Increment zero count for the most recent entry
564 $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
565 $wpdb->prepare(
566 "UPDATE `" . esc_sql($table_name) . "` SET zero_count = zero_count + 1
567 WHERE plugin_path = %s
568 ORDER BY timestamp DESC
569 LIMIT 1",
570 $plugin_path
571 )
572 );
573 } else {
574 // Insert new non-zero measurement
575 $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
576 $table_name,
577 array(
578 'plugin_path' => $plugin_path,
579 'memory_change' => $memory_change,
580 'zero_count' => 0,
581 )
582 );
583 }
584
585 // Clear caches
586 wpmem_clear_plugin_history_cache($plugin_path);
587 wpmem_clear_all_plugin_history_cache();
588 wpmem_clear_average_memory_cache($plugin_path);
589 }
590
591
592
593 function wpmem_get_plugin_history($plugin_path) {
594 global $wpdb;
595 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
596
597 // Create a unique cache key for this query
598 $cache_key = 'wpmem_plugin_history_' . md5($plugin_path);
599
600 // Try to get the results from cache
601 $results = wp_cache_get($cache_key);
602
603 // If the results are not in cache, query the database
604 if (false === $results) {
605 $results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
606 $wpdb->prepare(
607 "SELECT memory_change, timestamp FROM `" . esc_sql($table_name) . "` WHERE plugin_path = %s ORDER BY timestamp DESC LIMIT 5",
608 $plugin_path
609 )
610 );
611
612 // Cache the results for future use
613 wp_cache_set($cache_key, $results, '', 3600); // Cache for 1 hour
614 }
615
616 return $results;
617 }
618
619
620
621 function wpmem_clear_plugin_history_cache($plugin_path) {
622 $cache_key = 'wpmem_plugin_history_' . md5($plugin_path);
623 wp_cache_delete($cache_key);
624 }
625
626
627
628 add_action('wp_ajax_get_plugin_history', 'wpmem_get_plugin_history_ajax');
629 function wpmem_get_plugin_history_ajax() {
630 check_ajax_referer('wp_memory_usage_nonce', 'nonce');
631 if (!isset($_POST['plugin'])) {
632 wp_send_json_error('Plugin not specified');
633 }
634
635 $plugin = sanitize_text_field(wp_unslash($_POST['plugin']));
636 $history = wpmem_get_plugin_history($plugin);
637
638 wp_send_json_success($history);
639 }
640
641
642
643
644
645
646
647
648 function wpmem_get_all_plugin_history() {
649 global $wpdb;
650 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
651
652 // Create a unique cache key for this query
653 $cache_key = 'wpmem_all_plugin_history';
654
655 // Try to get the results from cache
656 $results = wp_cache_get($cache_key);
657
658 // If the results are not in cache, query the database
659 if (false === $results) {
660 $results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
661 $wpdb->prepare(
662 "SELECT plugin_path, memory_change, timestamp
663 FROM `" . esc_sql($table_name) . "`
664 WHERE plugin_path IN (SELECT DISTINCT plugin_path FROM `" . esc_sql($table_name) . "`)
665 ORDER BY timestamp DESC
666 -- %d",
667 1
668 )
669 );
670
671 // Cache the results for future use
672 wp_cache_set($cache_key, $results, '', 3600); // Cache for 1 hour
673 }
674
675 // Process results...
676 $history = array();
677 foreach ($results as $row) {
678 if (!isset($history[$row->plugin_path])) {
679 $history[$row->plugin_path] = array();
680 }
681 if (count($history[$row->plugin_path]) < 5) {
682 $history[$row->plugin_path][] = array(
683 'memory_change' => $row->memory_change,
684 'timestamp' => $row->timestamp
685 );
686 }
687 }
688
689 return $history;
690 }
691
692
693
694
695 function wpmem_clear_all_plugin_history_cache() {
696 wp_cache_delete('wpmem_all_plugin_history');
697 }
698
699
700
701 function wpmem_clear_table_exists_cache() {
702 global $wpdb;
703 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
704 $cache_key = 'wpmem_table_exists_' . $table_name;
705 wp_cache_delete($cache_key);
706 }
707
708
709 // Reset table verification cache when changing plugin state
710 register_activation_hook(__FILE__, 'wpmem_clear_table_exists_cache'); // Pre-activation check
711 register_deactivation_hook(__FILE__, 'wpmem_clear_table_exists_cache'); // Post-deactivation cleanup
712
713
714
715
716
717 function wpmem_get_average_memory_usage($plugin_path) {
718 global $wpdb;
719 $table_name = $wpdb->prefix . 'wpmem_plugin_history';
720
721 // Create a unique cache key
722 $cache_key = 'wpmem_avg_memory_' . md5($plugin_path);
723
724 // Try to get the result from cache
725 $avg_memory = wp_cache_get($cache_key);
726
727 if (false === $avg_memory) {
728 // Cache miss, perform the database query
729 $result = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
730 $wpdb->prepare(
731 "SELECT SUM(memory_change) as total_change,
732 COUNT(*) as non_zero_count,
733 SUM(zero_count) as zero_count
734 FROM `" . esc_sql($table_name) . "`
735 WHERE plugin_path = %s",
736 $plugin_path
737 )
738 );
739
740 if ($result) {
741 $total_count = $result->non_zero_count + $result->zero_count;
742 $avg_memory = $total_count > 0 ? ($result->total_change / $total_count) / (1024 * 1024) : 0;
743 $avg_memory = round($avg_memory, 2); // Round to 2 decimal places
744 } else {
745 $avg_memory = 0;
746 }
747
748 // Cache the result for future use (cache for 5 minutes)
749 wp_cache_set($cache_key, $avg_memory, '', 300);
750 }
751
752 return $avg_memory;
753 }
754
755
756
757 function wpmem_clear_average_memory_cache($plugin_path) {
758 $cache_key = 'wpmem_avg_memory_' . md5($plugin_path);
759 wp_cache_delete($cache_key);
760 }
761
762
763
764 add_action('wp_ajax_update_average_memory', 'wpmem_update_average_memory');
765 add_action('wp_ajax_nopriv_update_average_memory', 'wpmem_update_average_memory');
766
767 function wpmem_update_average_memory() {
768 // Check nonce for security
769 if (!isset($_POST['nonce'])) {
770 wp_send_json_error('Security token not provided');
771 }
772
773 $nonce = sanitize_text_field(wp_unslash($_POST['nonce']));
774 if (!wp_verify_nonce($nonce, 'wp_memory_usage_nonce')) {
775 wp_send_json_error('Invalid security token');
776 }
777
778 if (!isset($_POST['plugin_path'])) {
779 wp_send_json_error('Plugin path not provided');
780 }
781
782 $plugin_path = sanitize_text_field(wp_unslash($_POST['plugin_path']));
783 $avg_memory = wpmem_get_average_memory_usage($plugin_path);
784
785 wp_send_json_success(array('avg_memory' => $avg_memory));
786 }
787
788
789
790
791
792
793 function wpmem_add_increase_memory_button($content) {
794 $wp_memory_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
795 $current_memory_usage = memory_get_usage(true);
796
797 if ($current_memory_usage > $wp_memory_limit) {
798 $content .= '<button id="increase-memory-limit" class="button">Increase Memory Limit</button>';
799 $content .= '<span id="memory-increase-result"></span>';
800 }
801
802 return $content;
803 }
804 add_filter('wpmem_memory_usage_content', 'wpmem_add_increase_memory_button');
805
806
807
808
809 function wpmem_increase_memory_limit() {
810 check_ajax_referer('wp_memory_usage_nonce', 'nonce');
811
812 if (!current_user_can('manage_options')) {
813 wp_send_json_error(array('message' => 'Insufficient permissions'));
814 }
815
816 $current_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
817
818 // If current limit is 160MB or less, double it. Otherwise, increase by 25%.
819 if ($current_limit < 160 * 1024 * 1024) { // 160 MB in bytes
820 $new_limit = $current_limit * 2;
821 } else {
822 $new_limit = (int)($current_limit * 1.25); // Increase by 25%
823 }
824
825 // Optional: Cap the maximum limit to avoid runaway values (e.g., 512MB)
826 $max_limit = 512 * 1024 * 1024; // 512 MB in bytes
827 if ($new_limit > $max_limit) {
828 $new_limit = $max_limit;
829 }
830
831 // Attempt to increase the limit
832 if (wpmem_set_memory_limit($new_limit)) {
833 wp_send_json_success(array('new_limit' => size_format($new_limit)));
834 } else {
835 wp_send_json_error(array('message' => 'Unable to increase memory limit. You may need to contact your hosting provider.'));
836 }
837 }
838 add_action('wp_ajax_increase_memory_limit', 'wpmem_increase_memory_limit');
839
840
841
842 function wpmem_set_memory_limit($new_limit) {
843 global $wp_filesystem;
844
845 // Initialize the WP filesystem
846 if (empty($wp_filesystem)) {
847 require_once (ABSPATH . '/wp-admin/includes/file.php');
848 WP_Filesystem();
849 }
850
851 $wp_config_file = ABSPATH . 'wp-config.php';
852 $config_content = $wp_filesystem->get_contents($wp_config_file);
853
854 if ($config_content === false) {
855 return false;
856 }
857
858 $new_limit_formatted = size_format($new_limit);
859
860 if (preg_match("/define\(\s*'WP_MEMORY_LIMIT',\s*'.*?'\s*\);/", $config_content)) {
861 // WP_MEMORY_LIMIT is already defined, so update it
862 $new_content = preg_replace(
863 "/define\(\s*'WP_MEMORY_LIMIT',\s*'.*?'\s*\);/",
864 "define('WP_MEMORY_LIMIT', '$new_limit_formatted');",
865 $config_content
866 );
867 } else {
868 // WP_MEMORY_LIMIT is not defined, so add it
869 $new_content = preg_replace(
870 "/<\?php/",
871 "<?php\ndefine('WP_MEMORY_LIMIT', '$new_limit_formatted');",
872 $config_content,
873 1
874 );
875 }
876
877 if ($wp_filesystem->put_contents($wp_config_file, $new_content) === false) {
878 return false;
879 }
880
881 return true;
882 }
883
884
885
886
887
888
889 function wpmem_add_settings_link($links) {
890 $settings_link = '<a href="' . admin_url('admin.php?page=wp_plugin_memory_usage') . '">Settings</a>';
891 array_unshift($links, $settings_link);
892 return $links;
893 }
894
895 $plugin = plugin_basename(__FILE__);
896 add_filter("plugin_action_links_$plugin", 'wpmem_add_settings_link');
897
898
899
900
901
902 function wpmem_add_memory_to_admin_bar($wp_admin_bar) {
903 $wp_memory_limit = wp_convert_hr_to_bytes(WP_MEMORY_LIMIT);
904 $current_memory_usage = memory_get_usage(true);
905 $percentage_used = round(($current_memory_usage / $wp_memory_limit) * 100, 1);
906
907 $wp_admin_bar->add_node(array(
908 'id' => 'wpmem_memory_usage',
909 'title' => 'MEM: ' . $percentage_used . '%',
910 'href' => admin_url('admin.php?page=wp_plugin_memory_usage'),
911 'meta' => array(
912 'title' => 'Current memory usage',
913 ),
914 ));
915 }
916 add_action('admin_bar_menu', 'wpmem_add_memory_to_admin_bar', 100);
917
918
919
920
921
922
923 ?>