PluginProbe
Plugin Memory Usage / 1.2.3
Plugin Memory Usage v1.2.3
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.3, at plugin-memory-usage.php

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