PluginProbe
Plugin Report / 1.7
Plugin Report v1.7
2.2.4 trunk 1.1 1.2 1.3 1.4 1.5 1.6 1.6.1 1.7 1.8 1.8.1 1.8.2 1.8.3 1.9 1.9.1 1.9.2 1.9.3 2.0.0 2.0.1 2.0.2 2.1 2.1.1 2.2.0 2.2.1 All 27 releases
← All changes | rt-plugin-report.php +235 -82 1.21.7 View file →
@@ -1,14 +1,16 @@
1 1 <?php
2 2 /**
3 3 * Plugin Name: Plugin Report
4 - * Plugin URI: https://roytanck.com
4 + * Plugin URI: https://roytanck.com/?p=277
5 5 * Description: Provides detailed information about currently installed plugins
6 - * Version: 1.2
6 + * Version: 1.7
7 7 * Requires at least: 4.6
8 8 * Requires PHP: 5.6
9 9 * Author: Roy Tanck
10 + * Author URI: https://roytanck.com
10 11 * License: GPLv3
12 + * Network: true
11 13 */
12 14
13 15 // If called without WordPress, exit.
14 16 if ( ! defined( 'ABSPATH' ) ) {
@@ -19,12 +21,19 @@
19 21 if ( is_admin() && ! class_exists( 'RT_Plugin_Report' ) ) {
20 22
21 23 class RT_Plugin_Report {
22 24
23 - public $cols_per_row = 6;
24 - public $cache_lifetime = DAY_IN_SECONDS;
25 - public $cache_lifetime_norepo = WEEK_IN_SECONDS;
25 + // CSS class constants.
26 + const CSS_CLASS_LOW = 'pr-risk-low';
27 + const CSS_CLASS_MED = 'pr-risk-medium';
28 + const CSS_CLASS_HIGH = 'pr-risk-high';
26 29
30 + // Other class constants.
31 + const PLUGIN_VERSION = '1.7';
32 + const COLS_PER_ROW = 7;
33 + const CACHE_LIFETIME = DAY_IN_SECONDS;
34 + const CACHE_LIFETIME_NOREPO = WEEK_IN_SECONDS;
35 +
27 36 /**
28 37 * Constructor
29 38 */
30 39 public function __construct() {
@@ -42,11 +51,13 @@
42 51 } else {
43 52 add_action( 'admin_menu', array( $this, 'register_settings_page' ) );
44 53 }
45 54 // Hook for the admin js.
46 - add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_js' ) );
55 + add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
47 56 // Add the AJAX hook.
48 57 add_action( 'wp_ajax_rt_get_plugin_info', array( $this, 'get_plugin_info' ) );
58 + // Hook into the WP Upgrader to selectively delete cache items.
59 + add_action( 'upgrader_process_complete', array( $this, 'upgrade_delete_cache_items' ), 10, 2 );
49 60 }
50 61
51 62
52 63 /**
@@ -53,12 +64,12 @@
53 64 * Add a new options page to the network admin
54 65 */
55 66 public function register_settings_page() {
56 67 add_plugins_page(
57 - esc_html__( 'Plugin Report', 'plugin-report' ),
58 - esc_html__( 'Plugin Report', 'plugin-report' ),
68 + esc_html_x( 'Plugin Report', 'Page and menu title', 'plugin-report' ),
69 + esc_html_x( 'Plugin Report', 'Page and menu title', 'plugin-report' ),
59 70 'manage_options',
60 - 'rt_plugin_report',
71 + 'plugin_report',
61 72 array( $this, 'settings_page' )
62 73 );
63 74 }
64 75
@@ -80,22 +91,22 @@
80 91
81 92 // Refresh the cache, but only if this is a fresh timestamp (not if the page has been refreshed with the timestamp still in the URL).
82 93 if ( isset( $_GET['clear_cache'] ) ) {
83 94 $new_timestamp = intval( $_GET['clear_cache'] );
84 - $last_timestamp = intval( get_site_transient( 'rt_plugin_report_cache_cleared' ) );
95 + $last_timestamp = intval( get_site_transient( 'plugin_report_cache_cleared' ) );
85 96 if ( ! $last_timestamp || $new_timestamp > $last_timestamp ) {
86 97 $this->clear_cache();
87 - set_site_transient( 'rt_plugin_report_cache_cleared', $new_timestamp, $this->cache_lifetime );
98 + set_site_transient( 'plugin_report_cache_cleared', $new_timestamp, self::CACHE_LIFETIME );
88 99 }
89 100 }
90 101
91 102 // Start the page's output.
92 103 echo '<div class="wrap">';
93 - echo '<h1>' . esc_html__( 'Plugin Report', 'plugin-report' ) . '</h1>';
104 + echo '<h1>' . esc_html_x( 'Plugin Report', 'Page and menu title', 'plugin-report' ) . '</h1>';
94 105 echo '<p>';
95 106 $version_temp = '<span class="' . $this->get_version_risk_classname( $wp_version, $wp_latest ) . '">' . $wp_version . '</span>';
96 - /* translators: %s = Current WordPress version number */
97 - echo sprintf( __( 'Currently running WordPress version: %s.', 'plugin-report' ), $version_temp );
107 + /* translators: %1$s: Current WordPress version number, %2$s: Current PHP version number */
108 + echo sprintf( __( 'Currently running WordPress version %1$s and PHP version %2$s.', 'plugin-report' ), $version_temp, phpversion() );
98 109 if ( version_compare( $wp_version, $wp_latest, '<' ) ) {
99 110 /* translators: %s = Available new version number */
100 111 echo sprintf( ' (' . esc_html__( 'An upgrade to %s is available', 'plugin-report' ) . ')', $wp_latest );
101 112 }
@@ -102,28 +113,32 @@
102 113 echo '</p>';
103 114 echo '<p>';
104 115 // Clear cache and reload.
105 116 if ( is_multisite() ) {
106 - $page_url = 'network/plugins.php?page=rt_plugin_report';
117 + $page_url = 'network/plugins.php?page=plugin_report';
107 118 } else {
108 - $page_url = 'plugins.php?page=rt_plugin_report';
119 + $page_url = 'plugins.php?page=plugin_report';
109 120 }
110 121 echo '<a href="' . admin_url( $page_url . '&clear_cache=' . current_time( 'timestamp' ) ) . '">' . esc_html__( 'Clear cached plugin data and reload', 'plugin-report' ) . '</a>';
111 122 echo '</p>';
112 123 echo '<h3>' . esc_html__( 'Currently installed plugins', 'plugin-report' ) . '</h3>';
113 - echo '<p id="rt-plugin-report-progress"></p>';
124 + echo '<p id="plugin-report-progress"></p>';
114 125 echo '<p>';
115 126
116 127 // The report's main table.
117 - echo '<table id="rt-plugin-report-table" class="wp-list-table widefat fixed striped">';
128 + echo '<table id="plugin-report-table" class="wp-list-table widefat fixed striped">';
129 + echo '<thead>';
118 130 echo '<tr>';
119 131 echo '<th>' . esc_html__( 'Name', 'plugin-report' ) . '</th>';
120 132 echo '<th>' . esc_html__( 'Author', 'plugin-report' ) . '</th>';
121 - echo '<th>' . esc_html__( 'Installed version', 'plugin-report' ) . '</th>';
133 + echo '<th>' . esc_html__( 'Activated', 'plugin-report' ) . '</th>';
134 + echo '<th data-sort-method="none" class="no-sort">' . esc_html__( 'Installed version', 'plugin-report' ) . '</th>';
122 135 echo '<th>' . esc_html__( 'Last update', 'plugin-report' ) . '</th>';
123 - echo '<th>' . esc_html__( 'Tested up to WP version', 'plugin-report' ) . '</th>';
124 - echo '<th>' . esc_html__( 'Rating', 'plugin-report' ) . '</th>';
136 + echo '<th data-sort-method="dotsep">' . esc_html__( 'Tested up to WP version', 'plugin-report' ) . '</th>';
137 + echo '<th data-sort-method="number">' . esc_html__( 'Rating', 'plugin-report' ) . '</th>';
125 138 echo '</tr>';
139 + echo '</thead>';
140 + echo '<tbody>';
126 141
127 142 foreach ( $plugins as $key => $plugin ) {
128 143 $slug = $this->get_plugin_slug( $key );
129 144 $cache_key = $this->create_cache_key( $slug );
@@ -132,18 +147,19 @@
132 147 // Use the cached report to create a table row.
133 148 echo $this->render_table_row( $cache );
134 149 } else {
135 150 // Render a special table row that's used as a signal to the front-end js that new data is needed.
136 - echo '<tr class="rt-plugin-report-row-temp-' . $slug . '"><td colspan="' . $this->cols_per_row . '">loading...</td></tr>';
151 + echo '<tr class="plugin-report-row-temp-' . $slug . '"><td colspan="' . self::COLS_PER_ROW . '">' . esc_html__( 'Loading...', 'plugin-report' ) . '</td></tr>';
137 152 }
138 153 }
139 154
155 + echo '</tbody>';
140 156 echo '</table>';
157 + echo '</p>';
141 158
142 - echo '<div id="rt-debug"></div>';
159 + echo '<p id="plugin-report-buttons"></p>';
143 160
144 161 // Wrap up.
145 - echo '</p>';
146 162 echo '</div>';
147 163 }
148 164
149 165
@@ -149,25 +165,31 @@
149 165
150 166 /**
151 167 * Enqueue admin javascript
152 168 */
153 - public function enqueue_js( $hook ) {
169 + public function enqueue_assets( $hook ) {
154 170 // Check if we're on the right screen.
155 - if ( 'plugins_page_rt_plugin_report' != $hook ) {
171 + if ( 'plugins_page_plugin_report' !== $hook ) {
156 172 return;
157 173 }
158 - // register the plugin's admin js, and require jquery
159 - wp_enqueue_script( 'rt-plugin-report-js', plugins_url( '/js/rt-plugin-report.js', __FILE__ ), array( 'jquery' ) );
160 - // add some variables to the page, to be used by the javascript
174 + // Register the plugin's admin js, and require jquery.
175 + wp_enqueue_script( 'plugin-report-js', plugins_url( '/js/plugin-report.js', __FILE__ ), array( 'jquery', 'plugin-report-tablesort-js' ), self::PLUGIN_VERSION );
176 + wp_enqueue_script( 'plugin-report-tablesort-js', plugins_url( '/js/tablesort.min.js', __FILE__ ), array( 'jquery' ), '5.1.0' );
177 + wp_enqueue_script( 'plugin-report-tablesort-number-js', plugins_url( '/js/tablesort.number.min.js', __FILE__ ), array( 'plugin-report-tablesort-js' ), '5.1.0' );
178 + wp_enqueue_script( 'plugin-report-tablesort-dotsep-js', plugins_url( '/js/tablesort.dotsep.min.js', __FILE__ ), array( 'plugin-report-tablesort-js' ), '5.1.0' );
179 + // Add some variables to the page, to be used by the javascript.
161 180 $slugs = $this->get_plugin_slugs();
162 181 $slugs_str = implode( ',', $slugs );
163 182 $vars = array(
164 - 'plugin_slugs' => $slugs_str,
165 - 'ajax_nonce' => wp_create_nonce( 'rt_plugin_report_nonce' ),
183 + 'plugin_slugs' => $slugs_str,
184 + 'ajax_nonce' => wp_create_nonce( 'plugin_report_nonce' ),
185 + 'export_btn' => __( 'Export .csv file', 'plugin-report' ),
186 + 'plugin_url_header' => __( 'Plugin URL', 'plugin-report' ),
187 + 'author_url_header' => __( 'Author URL', 'plugin-report' ),
166 188 );
167 - wp_localize_script( 'rt-plugin-report-js', 'rt_plugin_report_vars', $vars );
189 + wp_localize_script( 'plugin-report-js', 'plugin_report_vars', $vars );
168 190 // Enqueue admin CSS file.
169 - wp_enqueue_style( 'rt-plugin-report-css', plugin_dir_url( __FILE__ ) . 'css/rt-plugin-report.css' );
191 + wp_enqueue_style( 'plugin-report-css', plugin_dir_url( __FILE__ ) . 'css/plugin-report.css', array(), self::PLUGIN_VERSION );
170 192 }
171 193
172 194
173 195 /**
@@ -202,9 +224,9 @@
202 224 */
203 225 public function get_plugin_info() {
204 226
205 227 // Check the ajax nonce, display an error if the check fails.
206 - if ( ! check_ajax_referer( 'rt_plugin_report_nonce', 'nonce', false ) ) {
228 + if ( ! check_ajax_referer( 'plugin_report_nonce', 'nonce', false ) ) {
207 229 wp_die();
208 230 }
209 231
210 232 // Check user capabilites, just to be sure.
@@ -232,9 +254,9 @@
232 254 'html' => $table_row,
233 255 'message' => 'Success!',
234 256 );
235 257 // Return the response.
236 - echo json_encode( $response );
258 + echo wp_json_encode( $response );
237 259
238 260 wp_die();
239 261 }
240 262
@@ -258,14 +280,15 @@
258 280 // Get the locally available info, and add it to the report.
259 281 foreach ( $plugins as $key => $plugin ) {
260 282 if ( $this->get_plugin_slug( $key ) == $slug ) {
261 283 $report['local_info'] = $plugin;
284 + $report['file_path'] = $key;
262 285 break;
263 286 }
264 287 }
265 288
266 289 // Use the wordpress.org repository API to get detailed information.
267 - $args = array(
290 + $args = array(
268 291 'slug' => $slug,
269 292 'fields' => array(
270 293 'description' => false,
271 294 'sections' => false,
@@ -272,8 +295,9 @@
272 295 'tags' => false,
273 296 'version' => true,
274 297 'tested' => true,
275 298 'requires' => true,
299 + 'requires_php' => true,
276 300 'compatibility' => true,
277 301 'author' => true,
278 302 ),
279 303 );
@@ -282,12 +306,15 @@
282 306 // Add the repo info to the report.
283 307 if ( ! is_wp_error( $returned_object ) ) {
284 308 $report['repo_info'] = maybe_unserialize( $returned_object );
285 309 // Cache the report.
286 - set_site_transient( $cache_key, $report, $this->cache_lifetime );
310 + set_site_transient( $cache_key, $report, self::CACHE_LIFETIME );
287 311 } else {
288 - // Cache for an extra long time when the plgin is not in the repo.
289 - set_site_transient( $cache_key, $report, $this->cache_lifetime_norepo );
312 + // Store the error code and message in the report.
313 + $report['repo_error_code'] = $returned_object->get_error_code();
314 + $report['repo_error_message'] = $returned_object->get_error_message();
315 + // Cache for an extra long time when the plugin is not in the repo.
316 + set_site_transient( $cache_key, $report, self::CACHE_LIFETIME_NOREPO );
290 317 }
291 318 } else {
292 319 $report = $cache;
293 320 }
@@ -309,35 +336,97 @@
309 336 $wp_latest = $this->check_core_updates();
310 337 // Check if the report is valid.
311 338 if ( $report == null ) {
312 339 $html = $this->render_error_row( esc_html__( 'No plugin data available.', 'plugin-report' ) );
313 - } elseif ( ! isset( $report['repo_info'] ) ) {
314 - /* translators: %s = Slug of the plugin */
315 - $html = $this->render_error_row( sprintf( esc_html__( 'This plugin "%s" does not appear to be in the wordpress.org repository.', 'plugin-report' ), $report['slug'] ) );
316 340 } else {
317 - $html = '<tr class="rt-plugin-report-row-' . $report['slug'] . '">';
341 + // Start the new table row.
342 + $html = '<tr class="plugin-report-row-' . $report['slug'] . '">';
318 343 // Name.
319 - $html .= '<td><a href="https://wordpress.org/plugins/' . $report['slug'] . '">' . $report['repo_info']->name . '</a></td>';
344 + if ( isset( $report['local_info']['PluginURI'] ) && ! empty( $report['local_info']['PluginURI'] ) ) {
345 + $html .= '<td><a href="' . $report['local_info']['PluginURI'] . '"><strong>' . $report['local_info']['Name'] . '</strong></a></td>';
346 + } else {
347 + $html .= '<td><strong>' . $report['local_info']['Name'] . '</strong></td>';
348 + }
320 349 // Author.
321 - $html .= '<td>' . $report['repo_info']->author . '</td>';
350 + if ( isset( $report['local_info']['AuthorURI'] ) && ! empty( $report['local_info']['AuthorURI'] ) ) {
351 + $html .= '<td><a href="' . $report['local_info']['AuthorURI'] . '">' . $report['local_info']['Author'] . '</a></td>';
352 + } else {
353 + $html .= '<td>' . $report['local_info']['Author'] . '</td>';
354 + }
355 + // Activated.
356 + $active = __( 'Please clear cache to update', 'plugin-report' );
357 + $css_class = self::CSS_CLASS_MED;
358 + if ( is_multisite() ) {
359 + $activation_status = $this->get_multisite_activation( $report['file_path'] );
360 + if ( true === $activation_status['network'] ) {
361 + $css_class = self::CSS_CLASS_LOW;
362 + $html .= '<td class="' . $css_class . '">' . __( 'Network activated', 'plugin-report' ) . '</td>';
363 + } else {
364 + $css_class = ( $activation_status['active'] > 0 ) ? self::CSS_CLASS_LOW : self::CSS_CLASS_HIGH;
365 + $html .= '<td class="' . $css_class . '">' . $activation_status['active'] . '/' . $activation_status['sites'] . '</td>';
366 + }
367 + } else {
368 + if ( isset( $report['file_path'] ) ) {
369 + $active = is_plugin_active( $report['file_path'] ) ? __( 'Yes', 'plugin-report' ) : __( 'No', 'plugin-report' );
370 + $css_class = is_plugin_active( $report['file_path'] ) ? self::CSS_CLASS_LOW : self::CSS_CLASS_HIGH;
371 + }
372 + $html .= '<td class="' . $css_class . '">' . $active . '</td>';
373 + }
322 374 // Installed / available version.
323 - $html .= '<td><span class="' . $this->get_version_risk_classname( $report['local_info']['Version'], $report['repo_info']->version ) . '">';
324 - $html .= $report['local_info']['Version'] . '</span>';
325 - if ( $report['local_info']['Version'] != $report['repo_info']->version ) {
326 - $html .= ' (' . $report['repo_info']->version . ' available)';
375 + if ( isset( $report['repo_info'] ) ) {
376 + $css_class = $this->get_version_risk_classname( $report['local_info']['Version'], $report['repo_info']->version );
377 + $html .= '<td class="' . $css_class . '">';
378 + $html .= $report['local_info']['Version'];
379 + if ( $report['local_info']['Version'] != $report['repo_info']->version ) {
380 + // Any platform upgrades needed?
381 + global $wp_version;
382 + $needs_php_upgrade = isset( $report['repo_info']->requires_php ) ? version_compare( phpversion(), $report['repo_info']->requires_php, '<' ) : false;
383 + $needs_wp_upgrade = isset( $report['repo_info']->requires ) ? version_compare( $wp_version, $report['repo_info']->requires, '<' ) : false;
384 + // Create the additional message.
385 + if ( $needs_wp_upgrade && $needs_php_upgrade ) {
386 + /* translators: %1$s: Plugin version number, %2$s: WP version number, %3$s: PHP version number */
387 + $html .= ' <span class="pr-additional-info">' . sprintf( esc_html__( '(%1$s available, requires WP %2$s and PHP %3$s)', 'plugin-report'), $report['repo_info']->version, $report['repo_info']->requires, $report['repo_info']->requires_php ) . '</span>';
388 + } elseif ( $needs_wp_upgrade ) {
389 + /* translators: %1$s: Plugin version number, %2$s: WP version number. */
390 + $html .= ' <span class="pr-additional-info">' . sprintf( esc_html__( '(%1$s available, requires WP %2$s)', 'plugin-report'), $report['repo_info']->version, $report['repo_info']->requires ) . '</span>';
391 + } elseif ( $needs_php_upgrade ) {
392 + /* translators: %1$s: Plugin version number, %2$s: PHP version number. */
393 + $html .= ' <span class="pr-additional-info">' . sprintf( esc_html__( '(%1$s available, requires PHP %2$s)', 'plugin-report'), $report['repo_info']->version, $report['repo_info']->requires_php ) . '</span>';
394 + } else {
395 + /* translators: %s: Plugin version number. */
396 + $html .= ' <span class="pr-additional-info">' . sprintf( esc_html__( '(%s available)', 'plugin-report'), $report['repo_info']->version ) . '</span>';
397 + }
398 + }
399 + $html .= '</td>';
400 + } else {
401 + $html .= '<td>' . $report['local_info']['Version'] . '</td>';
327 402 }
328 - $html .= '</td>';
329 403 // Last updates.
330 - $time_update = new DateTime( $report['repo_info']->last_updated );
331 - $time_diff = human_time_diff( $time_update->getTimestamp(), current_time( 'timestamp' ) );
332 - $css_class = $this->get_timediff_risk_classname( current_time( 'timestamp' ) - $time_update->getTimestamp() );
333 - $html .= '<td class="' . $css_class . '">' . $time_diff . '</td>';
404 + if ( isset( $report['repo_info'] ) ) {
405 + $time_update = new DateTime( $report['repo_info']->last_updated );
406 + $time_diff = human_time_diff( $time_update->getTimestamp(), current_time( 'timestamp' ) );
407 + $css_class = $this->get_timediff_risk_classname( current_time( 'timestamp' ) - $time_update->getTimestamp() );
408 + $html .= '<td class="' . $css_class . '" data-sort="' . $time_update->getTimestamp() . '">' . $time_diff . '</td>';
409 + } else {
410 + $html .= $this->render_error_cell();
411 + }
334 412 // Tested up to.
335 - $html .= '<td class="' . $this->get_version_risk_classname( $report['repo_info']->tested, $wp_latest ) . '">' . $report['repo_info']->tested . '</td>';
413 + if ( isset( $report['repo_info'] ) ) {
414 + $css_class = $this->get_version_risk_classname( $report['repo_info']->tested, $wp_latest );
415 + $html .= '<td class="' . $css_class . '">' . $report['repo_info']->tested . '</td>';
416 + } else {
417 + $html .= $this->render_error_cell();
418 + }
336 419 // Overall user rating.
337 - $css_class = ( intval( $report['repo_info']->num_ratings ) > 0 ) ? $this->get_percentage_risk_classname( intval( $report['repo_info']->rating ) ) : '';
338 - $html .= '<td class="' . $css_class . '">' . ( ( intval( $report['repo_info']->num_ratings ) > 0 ) ? $report['repo_info']->rating . '%' : esc_html__( 'No data available', 'plugin-report' ) ) . '</td>';
339 - $html .= '</tr>';
420 + if ( isset( $report['repo_info'] ) ) {
421 + $css_class = ( intval( $report['repo_info']->num_ratings ) > 0 ) ? $this->get_percentage_risk_classname( intval( $report['repo_info']->rating ) ) : '';
422 + $value_text = ( ( intval( $report['repo_info']->num_ratings ) > 0 ) ? $report['repo_info']->rating . '%' : esc_html__( 'No data available', 'plugin-report' ) );
423 + $html .= '<td class="' . $css_class . '">' . $value_text . '</td>';
424 + } else {
425 + $html .= $this->render_error_cell();
426 + }
427 + // Close the new table row.
428 + $html .= '</tr>';
340 429 }
341 430 return $html;
342 431 }
343 432
@@ -345,26 +434,33 @@
345 434 /**
346 435 * Format an error message as a table row, so we can return it to javascript
347 436 */
348 437 private function render_error_row( $message ) {
349 - return '<tr class="rt-pluginreport-row-error"><td colspan="' . $this->cols_per_row . '">' . $message . '</td></tr>';
438 + return '<tr class="pluginreport-row-error"><td colspan="' . self::COLS_PER_ROW . '">' . $message . '</td></tr>';
350 439 }
351 440
352 441
353 442 /**
443 + * Format an error message as a table cell, so we can return it to javascript
444 + */
445 + private function render_error_cell( $message = null ) {
446 + if ( ! $message ) {
447 + $message = esc_html__( 'No data available', 'plugin-report' );
448 + }
449 + return '<td class="pluginreport-cell-error">' . $message . '</td>';
450 + }
451 +
452 +
453 + /**
354 454 * Figure out what CSS class to use based on current and optimal version numbers
355 455 */
356 456 private function get_version_risk_classname( $available, $optimal ) {
357 - // If the version match, indicate low risk.
358 - if ( version_compare( $available, $optimal, '==' ) ) {
359 - return 'rt-risk-low';
457 + // If the version is equal or higher, indicate low risk.
458 + if ( version_compare( $available, $optimal, '>=' ) ) {
459 + return self::CSS_CLASS_LOW;
360 460 }
361 - // If major version match, indicate medium risk.
362 - if ( version_compare( $this->major_release_version_nr( $available ), $this->major_release_version_nr( $optimal ), '==' ) ) {
363 - return 'rt-risk-medium';
364 - }
365 461 // Else, indicate high risk.
366 - return 'rt-risk-high';
462 + return self::CSS_CLASS_HIGH;
367 463 }
368 464
369 465
370 466 /**
@@ -371,14 +467,14 @@
371 467 * Assess the risk associated with low ratings or poor compatibility feedback, return corresponding CSS class
372 468 */
373 469 private function get_percentage_risk_classname( $perc ) {
374 470 if ( $perc < 70 ) {
375 - return 'rt-risk-high';
471 + return self::CSS_CLASS_HIGH;
376 472 }
377 473 if ( $perc < 90 ) {
378 - return 'rt-risk-medium';
474 + return self::CSS_CLASS_MED;
379 475 }
380 - return 'rt-risk-low';
476 + return self::CSS_CLASS_LOW;
381 477 }
382 478
383 479
384 480 /**
@@ -386,14 +482,14 @@
386 482 */
387 483 private function get_timediff_risk_classname( $time_diff ) {
388 484 $days = $time_diff / ( DAY_IN_SECONDS );
389 485 if ( $days > 365 ) {
390 - return 'rt-risk-high';
486 + return self::CSS_CLASS_HIGH;
391 487 }
392 488 if ( $days > 90 ) {
393 - return 'rt-risk-medium';
489 + return self::CSS_CLASS_MED;
394 490 }
395 - return 'rt-risk-low';
491 + return self::CSS_CLASS_LOW;
396 492 }
397 493
398 494
399 495 /**
@@ -416,14 +512,44 @@
416 512 }
417 513
418 514
419 515 /**
420 - * Extract the major release number from a WP version nr
516 + * Gather statistics about a plugin's activation on a multisite install
421 517 */
422 - private function major_release_version_nr( $version ) {
423 - $parts = explode( '.', $version );
424 - $parts = array_slice( $parts, 0, 2 );
425 - return implode( '.', $parts );
518 + private function get_multisite_activation( $path ) {
519 + // Create an array to contain the return values.
520 + $activation_status = array(
521 + 'network' => false,
522 + 'active' => 0,
523 + 'sites' => 1,
524 + );
525 + // Check if the plugin is network activated.
526 + $network_plugins = get_site_option( 'active_sitewide_plugins', null );
527 + if ( array_key_exists( $path, $network_plugins ) ) {
528 + $activation_status['network'] = true;
529 + } else {
530 + // Get a list of all sites in the multisite install.
531 + $args = array(
532 + 'number' => 9999,
533 + 'fields' => 'ids',
534 + );
535 + $sites = get_sites( $args );
536 + // Add the total number of sites to the return array.
537 + $activation_status['sites'] = count( $sites );
538 + // Loop through the sites to find where the plugin is active.
539 + foreach ( $sites as $site_id ) {
540 + $plugins = get_blog_option( $site_id, 'active_plugins', null );
541 + if ( $plugins ) {
542 + foreach ( $plugins as $plugin_path ) {
543 + if ( $plugin_path === $path ) {
544 + $activation_status['active']++;
545 + }
546 + }
547 + }
548 + }
549 + }
550 + // Return the data we gathered.
551 + return $activation_status;
426 552 }
427 553
428 554
429 555 /**
@@ -429,9 +555,9 @@
429 555 /**
430 556 * Create a cache key that is unique to the provided plugin slug.
431 557 */
432 558 private function create_cache_key( $slug ) {
433 - // Create a hash for the plugiin slug.
559 + // Create a hash for the plugin slug.
434 560 $slug_hash = hash( 'sha256', $slug );
435 561 // Prefix and limit the string to 40 characters to avoid issues with long keys.
436 562 $cache_key = 'rtpr_' . substr( $slug_hash, 0, 35 );
437 563 // Return the key.
@@ -442,19 +568,46 @@
442 568 /**
443 569 * Clear all cached plugin info
444 570 */
445 571 private function clear_cache() {
572 + // Request a list of all plugins.
446 573 $plugins = get_plugins();
574 + // Loop through the plugins array, and delete cache items.
447 575 foreach ( $plugins as $key => $plugin ) {
448 - $slug = $this->get_plugin_slug( $key );
576 + $slug = $this->get_plugin_slug( $key );
577 + $this->clear_cache_item( $slug );
578 + }
579 + }
580 +
581 +
582 + /**
583 + * Remove the cache item for a single plugin
584 + */
585 + private function clear_cache_item( $slug ) {
586 + if ( isset( $slug ) ) {
449 587 $cache_key = $this->create_cache_key( $slug );
450 588 delete_site_transient( $cache_key );
451 589 }
452 590 }
453 591
592 +
593 + /**
594 + * Selectively delete cache for plugins that have been updated.
595 + */
596 + public function upgrade_delete_cache_items( $upgrader, $data ) {
597 + // Check if plugins have been upgraded by WP.
598 + if ( isset( $data ) && isset( $data['plugins'] ) && is_array( $data['plugins'] ) ) {
599 + // Loop through the plugins, and delete the associated cache items.
600 + foreach ( $data['plugins'] as $key => $value ) {
601 + $slug = $this->get_plugin_slug( $value );
602 + $this->clear_cache_item( $slug );
603 + }
604 + }
605 + }
606 +
454 607 }
455 608
456 609 // Instantiate the class.
457 - $rt_plugin_report_instance = new RT_Plugin_Report();
458 - $rt_plugin_report_instance->init();
610 + $plugin_report_instance = new RT_Plugin_Report();
611 + $plugin_report_instance->init();
459 612
460 613 }