diff --git a/assets/js/admin.js b/assets/js/admin.js
index fc0f5b7f..bc1d9756 100644
--- a/assets/js/admin.js
+++ b/assets/js/admin.js
@@ -449,9 +449,12 @@
function ( event ) {
event.preventDefault();
+ var $parent = $( this ).parent();
+
$.post( ajaxurl, {
- notice: $( this ).parent().attr( 'data-dismissible' ),
+ notice: $parent.data( 'dismissible' ),
action: 'roc_dismiss_notice',
+ _ajax_nonce: $parent.data( 'nonce' ),
} );
}
);
diff --git a/includes/class-plugin.php b/includes/class-plugin.php
index 801503b0..c376d4a3 100644
--- a/includes/class-plugin.php
+++ b/includes/class-plugin.php
@@ -12,12 +12,30 @@
defined( '\\ABSPATH' ) || exit;
+/**
+ * Main plugin class definition
+ */
class Plugin {
- private $page;
+ /**
+ * Settings page uri
+ *
+ * @var string $page
+ */
+ private $page = '';
+ /**
+ * Settings page slug
+ *
+ * @var string $screen
+ */
private $screen = '';
+ /**
+ * Allowed setting page actions
+ *
+ * @var string[] $actions
+ */
private $actions = array(
'enable-cache',
'disable-cache',
@@ -26,14 +44,14 @@ class Plugin {
);
/**
- * Plugin instance property.
+ * Plugin instance property
*
* @var Plugin
*/
private static $instance;
/**
- * Plugin instanciation method.
+ * Plugin instanciation method
*
* @return Plugin
*/
@@ -45,6 +63,9 @@ public static function instance() {
return self::$instance;
}
+ /**
+ * Constructor
+ */
private function __construct() {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
@@ -66,6 +87,11 @@ private function __construct() {
}
}
+ /**
+ * Adds all necessary hooks
+ *
+ * @return void
+ */
public function add_actions_and_filters() {
add_action( 'deactivate_plugin', array( $this, 'on_deactivation' ) );
add_action( 'admin_init', array( $this, 'maybe_update_dropin' ) );
@@ -97,8 +123,12 @@ public function add_actions_and_filters() {
add_filter( 'qm/outputter/html', array( $this, 'register_qm_output' ) );
}
+ /**
+ * Adds a submenu page to "Settings"
+ *
+ * @return void
+ */
public function add_admin_menu_page() {
- // add sub-page to "Settings"
add_submenu_page(
is_multisite() ? 'settings.php' : 'options-general.php',
__( 'Redis Object Cache', 'redis-cache' ),
@@ -109,18 +139,24 @@ public function add_admin_menu_page() {
);
}
+ /**
+ * Displays the settings page
+ *
+ * @return void
+ */
public function show_admin_page() {
- // request filesystem credentials?
+ // Request filesystem credentials?
if ( isset( $_GET['_wpnonce'], $_GET['action'] ) ) {
- $action = $_GET['action'];
+ $action = sanitize_key( $_GET['action'] );
+ $nonce = sanitize_key( $_GET['_wpnonce'] );
foreach ( $this->actions as $name ) {
- // verify nonce
- if ( $action === $name && wp_verify_nonce( $_GET['_wpnonce'], $action ) ) {
+ // Nonce verification.
+ if ( $action === $name && wp_verify_nonce( $nonce, $action ) ) {
$url = $this->action_link( $action );
if ( $this->initialize_filesystem( $url ) === false ) {
- return; // request filesystem credentials
+ return; // Request filesystem credentials.
}
}
}
@@ -147,10 +183,15 @@ public function show_admin_page() {
__( 'Diagnostics', 'redis-cache' )
);
- // show admin page
+ // Show the admin page.
require_once WP_REDIS_PLUGIN_PATH . '/includes/ui/settings.php';
}
+ /**
+ * Adds the dashboard metrics widget
+ *
+ * @return void
+ */
public function setup_dashboard_widget() {
if ( defined( 'WP_REDIS_DISABLE_METRICS' ) && WP_REDIS_DISABLE_METRICS ) {
return;
@@ -163,18 +204,33 @@ public function setup_dashboard_widget() {
);
}
+ /**
+ * Displays the dashboard widget
+ *
+ * @return void
+ */
public function show_dashboard_widget() {
require_once WP_REDIS_PLUGIN_PATH . '/includes/ui/widget.php';
}
+ /**
+ * Adds the settings page to the plugin action links on the plugin page
+ *
+ * @param string[] $links The current plugin action links.
+ * @return string[]
+ */
public function add_plugin_actions_links( $links ) {
- // add settings link to plugin actions
return array_merge(
[ sprintf( '%s', network_admin_url( $this->page ), esc_html__( 'Settings', 'redis-cache' ) ) ],
$links
);
}
+ /**
+ * Enqueues admin style resources
+ *
+ * @return void
+ */
public function enqueue_admin_styles() {
$screen = get_current_screen();
@@ -188,13 +244,18 @@ public function enqueue_admin_styles() {
'dashboard-network',
);
- if ( ! in_array( $screen->id, $screens ) ) {
+ if ( ! in_array( $screen->id, $screens, true ) ) {
return;
}
wp_enqueue_style( 'redis-cache', WP_REDIS_DIR . '/assets/css/admin.css', null, WP_REDIS_VERSION );
}
+ /**
+ * Enqueues admin script resources
+ *
+ * @return void
+ */
public function enqueue_admin_scripts() {
$screen = get_current_screen();
@@ -211,7 +272,7 @@ public function enqueue_admin_scripts() {
'woocommerce_page_wc-admin',
);
- if ( ! in_array( $screen->id, $screens ) ) {
+ if ( ! in_array( $screen->id, $screens, true ) ) {
return;
}
@@ -219,7 +280,8 @@ public function enqueue_admin_scripts() {
'redis-cache',
plugins_url( 'assets/js/admin.js', WP_REDIS_FILE ),
array( 'jquery', 'underscore' ),
- WP_REDIS_VERSION
+ WP_REDIS_VERSION,
+ true
);
wp_localize_script(
@@ -242,6 +304,11 @@ public function enqueue_admin_scripts() {
);
}
+ /**
+ * Enqueues scripts to display recorded metrics
+ *
+ * @return void
+ */
public function enqueue_redis_metrics() {
global $wp_object_cache;
@@ -255,7 +322,7 @@ public function enqueue_redis_metrics() {
return;
}
- if ( ! in_array( $screen->id, array( $this->screen, 'dashboard', 'dashboard-network' ) ) ) {
+ if ( ! in_array( $screen->id, array( $this->screen, 'dashboard', 'dashboard-network' ), true ) ) {
return;
}
@@ -263,7 +330,8 @@ public function enqueue_redis_metrics() {
'redis-cache-charts',
plugins_url( 'assets/js/apexcharts.min.js', WP_REDIS_FILE ),
null,
- WP_REDIS_VERSION
+ WP_REDIS_VERSION,
+ true
);
if ( ! method_exists( $wp_object_cache, 'redis_instance' ) ) {
@@ -279,17 +347,29 @@ public function enqueue_redis_metrics() {
);
wp_localize_script( 'redis-cache', 'rediscache_metrics', $metrics );
- } catch (Exception $exception) {
- error_log($exception);
+ } catch ( Exception $exception ) {
+ error_log( $exception ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
}
}
+ /**
+ * Registers a new cache collector for the Query Monitor plugin
+ *
+ * @param array $collectors Array of currently registered collectors.
+ * @return array
+ */
public function register_qm_collector( array $collectors ) {
$collectors['cache'] = new QM_Collector();
return $collectors;
}
+ /**
+ * Registers a new cache output using our collector for the Query Monitor plugin
+ *
+ * @param array $output Array of current QM_Output handlers.
+ * @return array
+ */
public function register_qm_output( $output ) {
$collector = \QM_Collectors::get( 'cache' );
@@ -303,10 +383,20 @@ public function register_qm_output( $output ) {
return $output;
}
+ /**
+ * Checks if the `object-cache.php` drop-in exists
+ *
+ * @return bool
+ */
public function object_cache_dropin_exists() {
return file_exists( WP_CONTENT_DIR . '/object-cache.php' );
}
+ /**
+ * Validates the `object-cache.php` drop-in
+ *
+ * @return bool
+ */
public function validate_object_cache_dropin() {
if ( ! $this->object_cache_dropin_exists() ) {
return false;
@@ -318,6 +408,11 @@ public function validate_object_cache_dropin() {
return $dropin['PluginURI'] === $plugin['PluginURI'];
}
+ /**
+ * Checks if the `object-cache.php` drop-in is outdated
+ *
+ * @return bool
+ */
public function object_cache_dropin_outdated() {
if ( ! $this->object_cache_dropin_exists() ) {
return false;
@@ -333,6 +428,11 @@ public function object_cache_dropin_outdated() {
return false;
}
+ /**
+ * Retrieves the current human-readable status
+ *
+ * @return string
+ */
public function get_status() {
global $wp_object_cache;
@@ -380,6 +480,12 @@ public function get_redis_status() {
return $wp_object_cache->redis_status();
}
+ /**
+ * Returns the redis version if possible
+ *
+ * @see WP_Object_Cache::redis_version()
+ * @return null|string
+ */
public function get_redis_version() {
global $wp_object_cache;
@@ -392,6 +498,11 @@ public function get_redis_version() {
}
}
+ /**
+ * Returns the currently used redis client (if any)
+ *
+ * @return null|string
+ */
public function get_redis_client_name() {
global $wp_object_cache;
@@ -404,6 +515,11 @@ public function get_redis_client_name() {
}
}
+ /**
+ * Fetches the redis diagnostics data
+ *
+ * @return null|array
+ */
public function get_diagnostics() {
global $wp_object_cache;
@@ -412,21 +528,36 @@ public function get_diagnostics() {
}
}
+ /**
+ * Retrieves the redis prefix
+ *
+ * @return null|mixed
+ */
public function get_redis_prefix() {
return defined( 'WP_REDIS_PREFIX' ) ? WP_REDIS_PREFIX : null;
}
+ /**
+ * Retrieves the redis maximum time to live
+ *
+ * @return null|mixed
+ */
public function get_redis_maxttl() {
return defined( 'WP_REDIS_MAXTTL' ) ? WP_REDIS_MAXTTL : null;
}
+ /**
+ * Displays admin notices
+ *
+ * @return void
+ */
public function show_admin_notices() {
if ( ! defined( 'WP_REDIS_DISABLE_BANNERS' ) || ! WP_REDIS_DISABLE_BANNERS ) {
$this->pro_notice();
$this->wc_pro_notice();
}
- // only show admin notices to users with the right capability
+ // Only show admin notices to users with the right capability.
if ( ! current_user_can( is_multisite() ? 'manage_network_options' : 'manage_options' ) ) {
return;
}
@@ -436,34 +567,40 @@ public function show_admin_notices() {
if ( $this->validate_object_cache_dropin() ) {
if ( $this->object_cache_dropin_outdated() ) {
- // translators: %s = Action link to update the drop-in
+ // translators: %s = Action link to update the drop-in.
$message = sprintf( __( 'The Redis object cache drop-in is outdated. Please update the drop-in.', 'redis-cache' ), $url );
}
} else {
- // translators: %s = Action link to update the drop-in
+ // translators: %s = Action link to update the drop-in.
$message = sprintf( __( 'A foreign object cache drop-in was found. To use Redis for object caching, please enable the drop-in.', 'redis-cache' ), $url );
}
if ( isset( $message ) ) {
- printf( '
%s
', $message );
+ printf( '%s
', wp_kses_post( $message ) );
}
}
}
+ /**
+ * Executes admin actions
+ *
+ * @return void
+ */
public function do_admin_actions() {
global $wp_filesystem;
if ( isset( $_GET['_wpnonce'], $_GET['action'] ) ) {
- $action = $_GET['action'];
+ $action = sanitize_key( $_GET['action'] );
+ $nonce = sanitize_key( $_GET['_wpnonce'] );
- // verify nonce
+ // Nonce verification.
foreach ( $this->actions as $name ) {
- if ( $action === $name && ! wp_verify_nonce( $_GET['_wpnonce'], $action ) ) {
+ if ( $action === $name && ! wp_verify_nonce( $nonce, $action ) ) {
return;
}
}
- if ( in_array( $action, $this->actions ) ) {
+ if ( in_array( $action, $this->actions, true ) ) {
$url = $this->action_link( $action );
if ( $action === 'flush-cache' ) {
@@ -518,12 +655,14 @@ public function do_admin_actions() {
$result
? add_settings_error(
'redis-cache',
- 'dropin', __( 'Object cache disabled.', 'redis-cache' ),
+ 'dropin',
+ __( 'Object cache disabled.', 'redis-cache' ),
'updated'
)
: add_settings_error(
'redis-cache',
- 'dropin', __( 'Object cache could not be disabled.', 'redis-cache' ),
+ 'dropin',
+ __( 'Object cache could not be disabled.', 'redis-cache' ),
'error'
);
}
@@ -552,7 +691,6 @@ public function do_admin_actions() {
'error'
);
}
-
}
$messages = get_settings_errors( 'redis-cache' );
@@ -569,17 +707,31 @@ public function do_admin_actions() {
}
}
+ /**
+ * Dismisses the admin notice for the current user
+ *
+ * @return void
+ */
public function dismiss_notice() {
- $notice = sprintf(
- 'roc_dismissed_%s',
- sanitize_key( $_POST['notice'] )
- );
+ if ( isset( $_POST['notice'] ) ) {
+ check_ajax_referer( 'roc_dismiss_notice' );
+
+ $notice = sprintf(
+ 'roc_dismissed_%s',
+ sanitize_key( $_POST['notice'] )
+ );
- update_user_meta( get_current_user_id(), $notice, '1' );
+ update_user_meta( get_current_user_id(), $notice, '1' );
+ }
wp_die();
}
+ /**
+ * Displays a redis cache pro admin notice
+ *
+ * @return void
+ */
public function pro_notice() {
$screen = get_current_screen();
@@ -587,7 +739,7 @@ public function pro_notice() {
return;
}
- if ( ! in_array( $screen->id, array( 'dashboard', 'dashboard-network' ) ) ) {
+ if ( ! in_array( $screen->id, array( 'dashboard', 'dashboard-network' ), true ) ) {
return;
}
@@ -595,21 +747,27 @@ public function pro_notice() {
return;
}
- if ( get_user_meta( get_current_user_id(), 'roc_dismissed_pro_release_notice', true ) == '1' ) {
+ if ( 1 === intval( get_user_meta( get_current_user_id(), 'roc_dismissed_pro_release_notice', true ) ) ) {
return;
}
printf(
- '',
- __( 'Object Cache Pro is out!', 'redis-cache' ),
+ '',
+ esc_attr( wp_create_nonce( 'roc_dismiss_notice' ) ),
+ esc_html__( 'Object Cache Pro is out!', 'redis-cache' ),
sprintf(
- // translators: %s = Link to the plugin setting screen
- __( 'A business class object cache backend. Truly reliable, highly-optimized and fully customizable, with a dedicated engineer when you most need it. Learn more »', 'redis-cache' ),
- network_admin_url( $this->page )
+ // translators: %s = Link to the plugin setting screen.
+ wp_kses_post( __( 'A business class object cache backend. Truly reliable, highly-optimized and fully customizable, with a dedicated engineer when you most need it. Learn more »', 'redis-cache' ) ),
+ esc_url( network_admin_url( $this->page ) )
)
);
}
+ /**
+ * Displays a redis cache pro admin notice specifically for WooCommerce
+ *
+ * @return void
+ */
public function wc_pro_notice() {
if ( ! class_exists( 'WooCommerce' ) ) {
return;
@@ -621,7 +779,7 @@ public function wc_pro_notice() {
return;
}
- if ( ! in_array( $screen->id, array( 'edit-shop_order', 'edit-product', 'woocommerce_page_wc-admin' ) ) ) {
+ if ( ! in_array( $screen->id, array( 'edit-shop_order', 'edit-product', 'woocommerce_page_wc-admin' ), true ) ) {
return;
}
@@ -629,27 +787,38 @@ public function wc_pro_notice() {
return;
}
- if ( get_user_meta( get_current_user_id(), 'roc_dismissed_wc_pro_notice', true ) == '1' ) {
+ if ( 1 === intval( get_user_meta( get_current_user_id(), 'roc_dismissed_wc_pro_notice', true ) ) ) {
return;
}
printf(
- '',
- __( 'Object Cache Pro + WooCommerce = ❤️', 'redis-cache' ),
+ '',
+ esc_attr( wp_create_nonce( 'roc_dismiss_notice' ) ),
+ esc_html__( 'Object Cache Pro + WooCommerce = ❤️', 'redis-cache' ),
sprintf(
- // translators: %s = Link to the plugin's settings screen
- __( 'Object Cache Pro is a business class object cache that’s highly-optimized for WooCommerce to provide true reliability, peace of mind and faster load times for your store. Learn more »', 'redis-cache' ),
- network_admin_url( $this->page )
+ // translators: %s = Link to the plugin's settings screen.
+ wp_kses_post( __( 'Object Cache Pro is a business class object cache that’s highly-optimized for WooCommerce to provide true reliability, peace of mind and faster load times for your store. Learn more »', 'redis-cache' ) ),
+ esc_url( network_admin_url( $this->page ) )
)
);
}
+ /**
+ * Registers all hooks associated with the shutdown hook
+ *
+ * @return void
+ */
public function register_shutdown_hooks() {
if ( ! defined( 'WP_REDIS_DISABLE_COMMENT' ) || ! WP_REDIS_DISABLE_COMMENT ) {
add_action( 'shutdown', array( $this, 'maybe_print_comment' ), 0 );
}
}
+ /**
+ * Adds the recorded metrics to redis
+ *
+ * @return void
+ */
public function record_metrics() {
global $wp_object_cache;
@@ -683,11 +852,16 @@ public function record_metrics() {
time(),
http_build_query( $metrics, null, ';' )
);
- } catch (Exception $exception) {
- error_log($exception);
+ } catch ( Exception $exception ) {
+ error_log( $exception ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
}
}
+ /**
+ * Removes recorded metrics after an hour
+ *
+ * @return void
+ */
public function discard_metrics() {
global $wp_object_cache;
@@ -709,11 +883,16 @@ public function discard_metrics() {
0,
time() - HOUR_IN_SECONDS
);
- } catch (Exception $exception) {
- error_log($exception);
+ } catch ( Exception $exception ) {
+ error_log( $exception ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
}
}
+ /**
+ * Displays the redis cache html comment
+ *
+ * @return void
+ */
public function maybe_print_comment() {
global $wp_object_cache;
@@ -747,12 +926,13 @@ public function maybe_print_comment() {
);
if ( ! WP_DEBUG ) {
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
printf( "\n\n", $message );
return;
}
- $bytes = strlen( serialize( $wp_object_cache->cache ) );
+ $bytes = strlen( serialize( $wp_object_cache->cache ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
$debug = sprintf(
// translators: %1$d = number of objects. %2$s = human-readable size of cache. %3$s = name of the used client.
@@ -762,15 +942,28 @@ function_exists( 'size_format' ) ? size_format( $bytes ) : "{$bytes} bytes",
$wp_object_cache->diagnostics['client']
);
- printf( "\n", $message, $debug );
+ printf(
+ "\n",
+ $message, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ esc_html( $debug )
+ );
}
+ /**
+ * Initializes the WP filesystem API to be ready for use
+ *
+ * @param string $url The URL to post the form to.
+ * @param bool $silent Wheather to ask the user for credentials if necessary or not.
+ * @return bool
+ */
public function initialize_filesystem( $url, $silent = false ) {
if ( $silent ) {
ob_start();
}
- if ( ( $credentials = request_filesystem_credentials( $url ) ) === false ) {
+ $credentials = request_filesystem_credentials( $url );
+
+ if ( false === $credentials ) {
if ( $silent ) {
ob_end_clean();
}
@@ -791,8 +984,12 @@ public function initialize_filesystem( $url, $silent = false ) {
return true;
}
- public function test_filesystem_writing()
- {
+ /**
+ * Test if we can write in the WP_CONTENT_DIR and modify the `object-cache.php` drop-in
+ *
+ * @return true|WP_Error
+ */
+ public function test_filesystem_writing() {
global $wp_filesystem;
if ( ! $this->initialize_filesystem( '', true ) ) {
@@ -833,6 +1030,11 @@ public function test_filesystem_writing()
return true;
}
+ /**
+ * Calls the drop-in update method if necessary
+ *
+ * @return void
+ */
public function maybe_update_dropin() {
if ( defined( 'WP_REDIS_DISABLE_DROPIN_AUTOUPDATE' ) && WP_REDIS_DISABLE_DROPIN_AUTOUPDATE ) {
return;
@@ -843,6 +1045,11 @@ public function maybe_update_dropin() {
}
}
+ /**
+ * Updates the `object-cache.php` drop-in
+ *
+ * @return void
+ */
public function update_dropin() {
global $wp_filesystem;
@@ -862,13 +1069,21 @@ public function update_dropin() {
}
}
+ /**
+ * Plugin deactivation hook
+ *
+ * @param string $plugin Plugin basename.
+ * @return void
+ */
public function on_deactivation( $plugin ) {
global $wp_filesystem;
ob_start();
if ( $plugin === WP_REDIS_BASENAME ) {
- if ( $timestamp = wp_next_scheduled( 'rediscache_discard_metrics' ) ) {
+ $timestamp = wp_next_scheduled( 'rediscache_discard_metrics' );
+
+ if ( $timestamp ) {
wp_unschedule_event( $timestamp, 'rediscache_discard_metrics' );
}
@@ -882,7 +1097,17 @@ public function on_deactivation( $plugin ) {
ob_end_clean();
}
+ /**
+ * Helper method to retrieve a nonced plugin action link
+ *
+ * @param string $action The action to be executed once the link is followed.
+ * @return string
+ */
public function action_link( $action ) {
+ if ( ! in_array( $action, $this->actions, true ) ) {
+ return '';
+ }
+
return wp_nonce_url(
network_admin_url( add_query_arg( 'action', $action, $this->page ) ),
$action
diff --git a/includes/class-qm-collector.php b/includes/class-qm-collector.php
index 1cda3af4..32829a77 100644
--- a/includes/class-qm-collector.php
+++ b/includes/class-qm-collector.php
@@ -11,24 +11,42 @@
defined( '\\ABSPATH' ) || exit;
+/**
+ * Query Monitor data collector class definition
+ */
class QM_Collector extends Base_Collector {
+ /**
+ * Collector id
+ *
+ * @var string $id
+ */
public $id = 'cache';
+ /**
+ * Retrieves the collector name
+ *
+ * @return string
+ */
public function name() {
return __( 'Object Cache', 'redis-cache' );
}
+ /**
+ * Fills the collector with data
+ *
+ * @return void
+ */
public function process() {
- global $wp_object_cache;
+ global $wp_object_cache;
$this->process_defaults();
- $plugin = Plugin::instance();
+ $roc = Plugin::instance();
- $this->data['status'] = $plugin->get_status();
- $this->data['has_dropin'] = $plugin->object_cache_dropin_exists();
- $this->data['valid_dropin'] = $plugin->validate_object_cache_dropin();
+ $this->data['status'] = $roc->get_status();
+ $this->data['has_dropin'] = $roc->object_cache_dropin_exists();
+ $this->data['valid_dropin'] = $roc->validate_object_cache_dropin();
if ( ! method_exists( $wp_object_cache, 'info' ) ) {
return;
@@ -54,12 +72,17 @@ public function process() {
'unflushable' => $info->groups->unflushable,
];
- // these are used by Query Monitor
+ // These are used by Query Monitor.
$this->data['stats']['cache_hits'] = $info->hits;
$this->data['stats']['cache_misses'] = $info->misses;
$this->data['cache_hit_percentage'] = $info->ratio;
}
+ /**
+ * Sets collector defaults
+ *
+ * @return void
+ */
public function process_defaults() {
$this->data['hits'] = 0;
$this->data['misses'] = 0;
diff --git a/includes/class-qm-output.php b/includes/class-qm-output.php
index 17978479..f44534b5 100644
--- a/includes/class-qm-output.php
+++ b/includes/class-qm-output.php
@@ -11,8 +11,16 @@
defined( '\\ABSPATH' ) || exit;
+/**
+ * Query Monitor output logic class definition
+ */
class QM_Output extends QM_Output_Html {
+ /**
+ * Contructor
+ *
+ * @param QM_Collector $collector The corresponding collector instance.
+ */
public function __construct( QM_Collector $collector ) {
parent::__construct( $collector );
@@ -20,10 +28,20 @@ public function __construct( QM_Collector $collector ) {
add_filter( 'qm/output/panel_menus', [ $this, 'panel_menu' ] );
}
+ /**
+ * Output class name
+ *
+ * @return string
+ */
public function name() {
return __( 'Object Cache', 'redis cache' );
}
+ /**
+ * Adds a menu to the panel navigation menu in Query Monitor's output
+ *
+ * @param array $menu Array of menus.
+ */
public function admin_menu( array $menu ) {
$data = $this->collector->get_data();
@@ -48,6 +66,11 @@ public function admin_menu( array $menu ) {
return $menu;
}
+ /**
+ * Adds a menu item in the panel navigation menu in Query Monitor's output.
+ *
+ * @param array $menu Array of menus.
+ */
public function panel_menu( array $menu ) {
$ids = array_keys( $menu );
$request = array_search( 'qm-request', $ids, true );
@@ -64,12 +87,20 @@ public function panel_menu( array $menu ) {
);
}
+ /**
+ * Renders the output
+ *
+ * @return void
+ */
public function output() {
$data = $this->collector->get_data();
if ( ! $data['has_dropin'] ) {
$this->before_non_tabular_output();
- echo $this->build_notice( __( 'The Redis Object Cache drop-in is not installed. Use WP CLI or go to "Settings -> Redis" to enable drop-in.', 'redis-cache' ) );
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ echo $this->build_notice(
+ esc_html__( 'The Redis Object Cache drop-in is not installed. Use WP CLI or go to "Settings -> Redis" to enable drop-in.', 'redis-cache' )
+ );
$this->after_non_tabular_output();
return;
@@ -77,7 +108,10 @@ public function output() {
if ( ! $data['valid_dropin'] ) {
$this->before_non_tabular_output();
- echo $this->build_notice( __( 'WordPress is using a foreign object cache drop-in and Redis Object Cache is not being used. Use WP CLI or go to "Settings -> Redis" to enable drop-in.', 'redis-cache' ) );
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
+ echo $this->build_notice(
+ esc_html__( 'WordPress is using a foreign object cache drop-in and Redis Object Cache is not being used. Use WP CLI or go to "Settings -> Redis" to enable drop-in.', 'redis-cache' )
+ );
$this->after_non_tabular_output();
return;
diff --git a/includes/class-ui.php b/includes/class-ui.php
index 4d338807..b251dcce 100644
--- a/includes/class-ui.php
+++ b/includes/class-ui.php
@@ -30,13 +30,7 @@ class UI {
* @return void
*/
public static function register_tab( $slug, $label, $args = [] ) {
- self::$tabs[ $slug ] = (object) wp_parse_args( $args, [
- 'label' => $label,
- 'file' => WP_REDIS_PLUGIN_PATH . "/includes/ui/tabs/{$slug}.php",
- 'slug' => $slug,
- 'default' => false,
- 'disabled' => false,
- ] );
+ self::$tabs[ $slug ] = new UI\Tab( $slug, $label, $args );
}
/**
diff --git a/includes/object-cache.php b/includes/object-cache.php
index b47bc984..6aa88ab1 100644
--- a/includes/object-cache.php
+++ b/includes/object-cache.php
@@ -1,4 +1,4 @@
-add_non_persistent_groups( $groups );
}
+/**
+ * Object cache class definition
+ */
class WP_Object_Cache {
/**
@@ -380,7 +386,7 @@ class WP_Object_Cache {
/**
* Instantiate the Redis class.
*
- * @param bool $fail_gracefully
+ * @param bool $fail_gracefully Handles and logs errors if true throws exceptions otherwise.
*/
public function __construct( $fail_gracefully = true ) {
global $blog_id, $table_prefix;
@@ -405,17 +411,17 @@ public function __construct( $fail_gracefully = true ) {
try {
switch ( $client ) {
case 'hhvm':
- $this->connectUsingHHVM( $parameters );
+ $this->connect_using_hhvm( $parameters );
break;
case 'phpredis':
- $this->connectUsingPhpRedis( $parameters );
+ $this->connect_using_phpredis( $parameters );
break;
case 'credis':
- $this->connectUsingCredis( $parameters );
+ $this->connect_using_credis( $parameters );
break;
case 'predis':
default:
- $this->connectUsingPredis( $parameters );
+ $this->connect_using_predis( $parameters );
break;
}
@@ -432,7 +438,7 @@ public function __construct( $fail_gracefully = true ) {
$this->handle_exception( $exception );
}
- // Assign global and blog prefixes for use with keys
+ // Assign global and blog prefixes for use with keys.
if ( function_exists( 'is_multisite' ) ) {
$this->global_prefix = is_multisite() ? '' : $table_prefix;
$this->blog_prefix = is_multisite() ? $blog_id : $table_prefix;
@@ -509,10 +515,10 @@ protected function build_parameters() {
/**
* Connect to Redis using the PhpRedis (PECL) extention.
*
- * @param array $parameters
+ * @param array $parameters Connection parameters built by the `build_parameters` method.
* @return void
*/
- protected function connectUsingPhpRedis( $parameters ) {
+ protected function connect_using_phpredis( $parameters ) {
$version = phpversion( 'redis' );
$this->diagnostics[ 'client' ] = sprintf( 'PhpRedis (v%s)', $version );
@@ -593,25 +599,20 @@ protected function connectUsingPhpRedis( $parameters ) {
/**
* Connect to Redis using the Predis library.
*
- * @param array $parameters
+ * @param array $parameters Connection parameters built by the `build_parameters` method.
+ * @throws \Exception If the Predis library was not found or is unreadable.
* @return void
*/
- protected function connectUsingPredis( $parameters ) {
+ protected function connect_using_predis( $parameters ) {
$client = 'Predis';
- // Require PHP 5.4 or greater
- if ( version_compare( PHP_VERSION, '5.4.0', '<' ) ) {
- throw new Exception( 'Predis requires PHP 5.4 or newer.' );
- }
-
- // Load bundled Predis library
+ // Load bundled Predis library.
if ( ! class_exists( 'Predis\Client' ) ) {
$predis = sprintf(
'%s/redis-cache/dependencies/predis/predis/autoload.php',
defined( 'WP_PLUGIN_DIR' ) ? WP_PLUGIN_DIR : WP_CONTENT_DIR . '/plugins'
);
-
if ( is_readable( $predis ) ) {
require_once $predis;
} else {
@@ -666,17 +667,15 @@ protected function connectUsingPredis( $parameters ) {
/**
* Connect to Redis using the Credis library.
*
- * @param array $parameters
+ * @param array $parameters Connection parameters built by the `build_parameters` method.
+ * @throws \Exception If the Credis library was not found or is unreadable.
+ * @throws \Exception If redis sharding should be configured as Credis does not support sharding.
+ * @throws \Exception If more than one seninel is configured as Credis does not support multiple sentinel servers.
* @return void
*/
- protected function connectUsingCredis( $parameters ) {
+ protected function connect_using_credis( $parameters ) {
$client = 'Credis';
- // Require PHP 5.4 or greater
- if ( version_compare( PHP_VERSION, '5.4.0', '<' ) ) {
- throw new Exception( 'Predis requires PHP 5.4 or newer.' );
- }
-
$creds_path = sprintf(
'%s/redis-cache/dependencies/colinmollenhour/credis/',
defined( 'WP_PLUGIN_DIR' ) ? WP_PLUGIN_DIR : WP_CONTENT_DIR . '/plugins'
@@ -689,8 +688,8 @@ protected function connectUsingCredis( $parameters ) {
}
if (
- ( defined( 'WP_REDIS_SHARDS' ) || defined( 'WP_REDIS_SENTINEL' ) || defined( 'WP_REDIS_SERVERS' ) || defined( 'WP_REDIS_CLUSTER' ) ) &&
- ! class_exists( 'Credis_Cluster' )
+ ( defined( 'WP_REDIS_SHARDS' ) || defined( 'WP_REDIS_SENTINEL' ) || defined( 'WP_REDIS_SERVERS' ) || defined( 'WP_REDIS_CLUSTER' ) ) &&
+ ! class_exists( 'Credis_Cluster' )
) {
$to_load[] = 'Cluster.php';
@@ -720,7 +719,7 @@ protected function connectUsingCredis( $parameters ) {
if ( defined( 'WP_REDIS_SENTINEL' ) ) {
if ( is_array( WP_REDIS_SERVERS ) && count( WP_REDIS_SERVERS ) > 1 ) {
throw new Exception(
- 'Multipe sentinel servers are not supported by the bundled Credis library. Please review your Redis Cache configurations.'
+ 'Multipe sentinel servers are not supported by the bundled Credis library. Please review your Redis Cache configuration.'
);
}
@@ -735,7 +734,7 @@ protected function connectUsingCredis( $parameters ) {
$clients = $is_cluster ? WP_REDIS_CLUSTER : WP_REDIS_SERVERS;
foreach ( $clients as $index => &$connection_string ) {
- $url_components = parse_url( $connection_string );
+ $url_components = wp_parse_url( $connection_string );
parse_str( $url_components['query'], $add_params );
if ( ! $is_cluster && isset( $add_params['alias'] ) ) {
@@ -767,7 +766,7 @@ protected function connectUsingCredis( $parameters ) {
$this->redis = new Credis_Client( ...array_values( $args ) );
}
- // Don't use PhpRedis
+ // Don't use PhpRedis if it is available.
$this->redis->forceStandalone();
$this->redis->connect();
@@ -786,13 +785,13 @@ protected function connectUsingCredis( $parameters ) {
/**
* Connect to Redis using HHVM's Redis extention.
*
- * @param array $parameters
+ * @param array $parameters Connection parameters built by the `build_parameters` method.
* @return void
*/
- protected function connectUsingHHVM( $parameters ) {
+ protected function connect_using_hhvm( $parameters ) {
$this->redis = new Redis();
- // Adjust host and port, if the scheme is `unix`
+ // Adjust host and port if the scheme is `unix`.
if ( strcasecmp( 'unix', $parameters['scheme'] ) === 0 ) {
$parameters['host'] = 'unix://' . $parameters['path'];
$parameters['port'] = 0;
@@ -863,7 +862,7 @@ public function fetch_info() {
* @return bool
*/
public function redis_status() {
- return (bool) $this->redis_connected;
+ return (bool) $this->redis_connected;
}
/**
@@ -872,7 +871,7 @@ public function redis_status() {
* @return mixed
*/
public function redis_instance() {
- return $this->redis;
+ return $this->redis;
}
/**
@@ -881,7 +880,7 @@ public function redis_instance() {
* @return null|string
*/
public function redis_version() {
- return $this->redis_version;
+ return $this->redis_version;
}
/**
@@ -921,7 +920,7 @@ public function replace( $key, $value, $group = 'default', $expiration = 0 ) {
*
* Add does not set the value if the key exists; replace does not replace if the value doesn't exist.
*
- * @param bool $add True if should only add if value doesn't exist, false to only add when value already exists
+ * @param bool $add True if should only add if value doesn't exist, false to only add when value already exists.
* @param string $key The key under which to store the value.
* @param mixed $value The value to store.
* @param string $group The group value appended to the $key.
@@ -940,7 +939,7 @@ protected function add_or_replace( $add, $key, $value, $group = 'default', $expi
$result = true;
$derived_key = $this->build_key( $key, $group );
- // save if group not excluded and redis is up
+ // Save if group not excluded and redis is up.
if ( ! $this->is_ignored_group( $group ) && $this->redis_status() ) {
try {
$expiration = apply_filters( 'redis_cache_expiration', $this->validate_expiration( $expiration ), $key, $group );
@@ -993,7 +992,7 @@ protected function add_or_replace( $add, $key, $value, $group = 'default', $expi
$exists = isset( $this->cache[ $derived_key ] );
- if ( $add == $exists ) {
+ if ( (bool) $add === $exists ) {
return false;
}
@@ -1148,6 +1147,12 @@ protected function get_flush_closure( $salt ) {
}
}
+ /**
+ * Quotes a string for usage in the `glob` function
+ *
+ * @param string $string The string to quote.
+ * @return string
+ */
protected function glob_quote( $string ) {
$characters = [ '*', '+', '?', '!', '{', '}', '[', ']', '(', ')', '|', '@' ];
@@ -1174,20 +1179,20 @@ protected function lua_flush_closure( $salt ) {
return function () use ( $salt ) {
$script = <<redis_version(), '5', '<' ) && version_compare( $this->redis_version(), '3.2', '>=' ) ) {
@@ -1222,27 +1227,27 @@ function ( $group ) {
);
$script = <<redis_version(), '5', '<' ) && version_compare( $this->redis_version(), '3.2', '>=' ) ) {
$script = 'redis.replicate_commands()' . "\n" . $script;
@@ -1265,7 +1270,7 @@ function ( $group ) {
* @param string $group The group value appended to the $key.
* @param string $force Optional. Whether to force a refetch rather than relying on the local
* cache. Default false.
- * @param bool &$found Optional. Whether the key was found in the cache. Disambiguates a return of
+ * @param bool $found Optional. Whether the key was found in the cache. Disambiguates a return of
* false, a storable value. Passed by reference. Default null.
* @return bool|mixed Cached object value.
*/
@@ -1368,9 +1373,12 @@ public function get_multiple( $keys, $group = 'default', $force = false ) {
}
}
- $remaining_keys = array_filter( $keys, function ( $key ) use ( $cache ) {
- return ! isset( $cache[ $key ] );
- } );
+ $remaining_keys = array_filter(
+ $keys,
+ function ( $key ) use ( $cache ) {
+ return ! isset( $cache[ $key ] );
+ }
+ );
if ( empty( $remaining_keys ) ) {
return $cache;
@@ -1379,9 +1387,12 @@ public function get_multiple( $keys, $group = 'default', $force = false ) {
$start_time = microtime( true );
try {
- $remaining_ids = array_map( function ( $key ) use ( $derived_keys ) {
- return $derived_keys[ $key ];
- }, $remaining_keys );
+ $remaining_ids = array_map(
+ function ( $key ) use ( $derived_keys ) {
+ return $derived_keys[ $key ];
+ },
+ $remaining_keys
+ );
$results = array_combine(
$remaining_keys,
@@ -1442,7 +1453,7 @@ public function set( $key, $value, $group = 'default', $expiration = 0 ) {
$start_time = microtime( true );
- // save if group not excluded from redis and redis is up
+ // Save if group not excluded from redis and redis is up.
if ( ! $this->is_ignored_group( $group ) && $this->redis_status() ) {
$expiration = apply_filters( 'redis_cache_expiration', $this->validate_expiration( $expiration ), $key, $group );
@@ -1462,7 +1473,7 @@ public function set( $key, $value, $group = 'default', $expiration = 0 ) {
$this->cache_time += ( microtime( true ) - $start_time );
}
- // if the set was successful, or we didn't go to redis
+ // If the set was successful, or we didn't go to redis.
if ( $result ) {
$this->add_to_internal_cache( $derived_key, $value );
}
@@ -1479,16 +1490,16 @@ public function set( $key, $value, $group = 'default', $expiration = 0 ) {
/**
* Increment a Redis counter by the amount specified
*
- * @param string $key
- * @param int $offset
- * @param string $group
+ * @param string $key The key name.
+ * @param int $offset Optional. The increment. Defaults to 1.
+ * @param string $group Optional. The key group. Default is 'default'.
* @return int|bool
*/
public function increment( $key, $offset = 1, $group = 'default' ) {
$offset = (int) $offset;
$derived_key = $this->build_key( $key, $group );
- // If group is a non-Redis group, save to internal cache, not Redis
+ // If group is a non-Redis group, save to internal cache, not Redis.
if ( $this->is_ignored_group( $group ) || ! $this->redis_status() ) {
$value = $this->get_from_internal_cache( $derived_key );
$value += $offset;
@@ -1520,10 +1531,11 @@ public function increment( $key, $offset = 1, $group = 'default' ) {
/**
* Alias of `increment()`.
*
- * @param string $key
- * @param int $offset
- * @param string $group
- * @return bool
+ * @see self::increment()
+ * @param string $key The key name.
+ * @param int $offset Optional. The increment. Defaults to 1.
+ * @param string $group Optional. The key group. Default is 'default'.
+ * @return int|bool
*/
public function incr( $key, $offset = 1, $group = 'default' ) {
return $this->increment( $key, $offset, $group );
@@ -1532,16 +1544,16 @@ public function incr( $key, $offset = 1, $group = 'default' ) {
/**
* Decrement a Redis counter by the amount specified
*
- * @param string $key
- * @param int $offset
- * @param string $group
+ * @param string $key The key name.
+ * @param int $offset Optional. The decrement. Defaults to 1.
+ * @param string $group Optional. The key group. Default is 'default'.
* @return int|bool
*/
public function decrement( $key, $offset = 1, $group = 'default' ) {
$derived_key = $this->build_key( $key, $group );
$offset = (int) $offset;
- // If group is a non-Redis group, save to internal cache, not Redis
+ // If group is a non-Redis group, save to internal cache, not Redis.
if ( $this->is_ignored_group( $group ) || ! $this->redis_status() ) {
$value = $this->get_from_internal_cache( $derived_key );
$value -= $offset;
@@ -1553,7 +1565,7 @@ public function decrement( $key, $offset = 1, $group = 'default' ) {
$start_time = microtime( true );
try {
- // Save to Redis
+ // Save to Redis.
$result = $this->parse_redis_response( $this->redis->decrBy( $derived_key, $offset ) );
$this->add_to_internal_cache( $derived_key, (int) $this->redis->get( $derived_key ) );
@@ -1573,33 +1585,30 @@ public function decrement( $key, $offset = 1, $group = 'default' ) {
/**
* Render data about current cache requests
+ * Used by the Debug bar plugin
*
- * @return string
+ * @return void
*/
public function stats() {
- $bytes = array_map(
- function ( $key ) {
- return strlen( serialize( $key ) );
- },
- $this->cache
- );
-
- ?>
- Redis Status:
- redis_status() ? 'Connected' : 'Not connected'; ?>
-
- Redis Client:
- diagnostics['client'] ?: 'Unknown'; ?>
-
- Cache Hits:
- cache_hits; ?>
-
- Cache Misses:
- cache_misses; ?>
-
- Cache Size:
- kB
-
+ $bytes = strlen( serialize( $wp_object_cache->cache ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
+
+ ?>
+
+ Redis Status:
+ redis_status() ? 'Connected' : 'Not connected'; ?>
+
+ Redis Client:
+ diagnostics['client'] ?: 'Unknown'; ?>
+
+ Cache Hits:
+ cache_hits ); ?>
+
+ Cache Misses:
+ cache_misses ); ?>
+
+ Cache Size:
+ kB
+
cache
@@ -1669,13 +1679,13 @@ public function build_key( $key, $group = 'default' ) {
* @return string Sanitized string.
*/
protected function sanitize_key_part( $part ) {
- return str_replace( ':', '-', $part );
+ return str_replace( ':', '-', $part );
}
/**
* Checks if the given group is part the ignored group array
*
- * @param string $group Name of the group to check
+ * @param string $group Name of the group to check.
* @return bool
*/
protected function is_ignored_group( $group ) {
@@ -1685,7 +1695,7 @@ protected function is_ignored_group( $group ) {
/**
* Checks if the given group is part the global group array
*
- * @param string $group Name of the group to check
+ * @param string $group Name of the group to check.
* @return bool
*/
protected function is_global_group( $group ) {
@@ -1695,7 +1705,7 @@ protected function is_global_group( $group ) {
/**
* Checks if the given group is part the unflushable group array
*
- * @param string $group Name of the group to check
+ * @param string $group Name of the group to check.
* @return bool
*/
protected function is_unflushable_group( $group ) {
@@ -1705,7 +1715,7 @@ protected function is_unflushable_group( $group ) {
/**
* Convert Redis responses into something meaningful
*
- * @param mixed $response
+ * @param mixed $response Response sent from the redis instance.
* @return mixed
*/
protected function parse_redis_response( $response ) {
@@ -1760,7 +1770,7 @@ public function get_from_internal_cache( $derived_key ) {
/**
* In multisite, switch blog prefix when switching blogs
*
- * @param int $_blog_id
+ * @param int $_blog_id Blog ID.
* @return bool
*/
public function switch_to_blog( $_blog_id ) {
@@ -1813,7 +1823,7 @@ public function add_unflushable_groups( $groups ) {
/**
* Wrapper to validate the cache keys expiration value
*
- * @param mixed $expiration Incoming expiration value (whatever it is)
+ * @param mixed $expiration Incoming expiration value (whatever it is).
*/
protected function validate_expiration( $expiration ) {
$expiration = is_int( $expiration ) || ctype_digit( $expiration ) ? (int) $expiration : 0;
@@ -1844,8 +1854,9 @@ protected function maybe_unserialize( $original ) {
return igbinary_unserialize( $original );
}
- // don't attempt to unserialize data that wasn't serialized going in
+ // Don't attempt to unserialize data that wasn't serialized going in.
if ( $this->is_serialized( $original ) ) {
+ // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
$value = @unserialize( $original );
return is_object( $value ) ? clone $value : $value;
@@ -1874,10 +1885,12 @@ protected function maybe_serialize( $data ) {
}
if ( is_array( $data ) || is_object( $data ) ) {
+ // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
return serialize( $data );
}
if ( $this->is_serialized( $data, false ) ) {
+ // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
return serialize( $data );
}
@@ -1902,7 +1915,7 @@ protected function is_serialized( $data, $strict = true ) {
$data = trim( $data );
- if ( 'N;' == $data ) {
+ if ( 'N;' === $data ) {
return true;
}
@@ -1949,8 +1962,8 @@ protected function is_serialized( $data, $strict = true ) {
} elseif ( false === strpos( $data, '"' ) ) {
return false;
}
- // or else fall through
- // no break
+ // Or else fall through.
+ // No break!
case 'a':
case 'O':
return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
@@ -1969,11 +1982,13 @@ protected function is_serialized( $data, $strict = true ) {
* Handle the redis failure gracefully or throw an exception.
*
* @param \Exception $exception Exception thrown.
+ * @throws \Exception If `fail_gracefully` flag is set to a falsy value.
+ * @return void
*/
protected function handle_exception( $exception ) {
$this->redis_connected = false;
- // When Redis is unavailable, fall back to the internal cache by forcing all groups to be "no redis" groups
+ // When Redis is unavailable, fall back to the internal cache by forcing all groups to be "no redis" groups.
$this->ignored_groups = array_unique( array_merge( $this->ignored_groups, $this->global_groups ) );
if ( ! $this->fail_gracefully ) {
@@ -1982,7 +1997,7 @@ protected function handle_exception( $exception ) {
$this->errors[] = $exception->getMessage();
- error_log( $exception );
+ error_log( $exception ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
if ( function_exists( 'do_action' ) ) {
do_action( 'redis_object_cache_error', $exception );
@@ -1992,12 +2007,13 @@ protected function handle_exception( $exception ) {
/**
* Allows access to private properties for backwards compatibility.
*
- * @param string $name
+ * @param string $name Name of the property.
* @return mixed
*/
public function __get( $name ) {
- return isset($this->{$name}) ? $this->{$name} : null;
+ return isset( $this->{$name} ) ? $this->{$name} : null;
}
}
endif;
+// phpcs:enable Generic.WhiteSpace.ScopeIndent.IncorrectExact, Generic.WhiteSpace.ScopeIndent.Incorrect
diff --git a/includes/ui/class-tab.php b/includes/ui/class-tab.php
new file mode 100644
index 00000000..7759cd12
--- /dev/null
+++ b/includes/ui/class-tab.php
@@ -0,0 +1,219 @@
+ $slug,
+ 'label' => $label,
+ 'file' => WP_REDIS_PLUGIN_PATH . "/includes/ui/tabs/{$slug}.php",
+ ]
+ );
+ foreach ( $args ?: [] as $property => $value ) {
+ if ( property_exists( $this, $property ) ) {
+ $this->{$property} = $value;
+ } else {
+ $this->custom[ $property ] = $value;
+ }
+ }
+ }
+
+ /**
+ * Getter for tab slug
+ *
+ * @return string
+ */
+ public function slug() {
+ return $this->slug;
+ }
+
+ /**
+ * Getter for tab label
+ *
+ * @return string
+ */
+ public function label() {
+ return $this->label;
+ }
+
+ /**
+ * Getter for tab file
+ *
+ * @return string
+ */
+ public function file() {
+ return $this->file;
+ }
+
+ /**
+ * Getter for tab disabled state
+ *
+ * @return bool
+ */
+ public function is_disabled() {
+ return $this->disabled;
+ }
+
+ /**
+ * Getter for tab default state
+ *
+ * @return bool
+ */
+ public function is_default() {
+ return $this->default;
+ }
+
+ /**
+ * Getter for tab custom data
+ *
+ * @param $string $key Custom data key.
+ * @return mixed
+ */
+ public function custom( $key ) {
+ if ( ! isset( $this->custom[ $key ] ) ) {
+ return null;
+ }
+ return $this->custom[ $key ];
+ }
+
+ /**
+ * Disabled notice for tab
+ *
+ * @return string
+ */
+ public function disabled_notice() {
+ return sprintf(
+ // translators: %s = Tab label.
+ __( '%s are disabled for this site.', 'redis-cache' ),
+ $this->label
+ );
+ }
+
+ /**
+ * Displays the tab template
+ *
+ * @return void
+ */
+ public function display() {
+ $roc = Plugin::instance();
+ include $this->file;
+ }
+
+ /**
+ * Returns the tab nav id attribute
+ *
+ * @return string
+ */
+ public function nav_id() {
+ return apply_filters( 'roc_tab_nav_id', "{$this->slug}-tab", $this );
+ }
+
+ /**
+ * Returns the tab nav css classes
+ *
+ * @return string
+ */
+ public function nav_classes() {
+ $classes = [
+ 'nav-tab',
+ ];
+ if ( $this->default ) {
+ $classes[] = 'nav-tab-active';
+ }
+ if ( $this->disabled ) {
+ $classes[] = 'nav-tab-disabled';
+ }
+ return implode( ' ', apply_filters( 'roc_tab_nav_classes', $classes, $this ) );
+ }
+
+ /**
+ * Returns the tab id attribute
+ *
+ * @return string
+ */
+ public function id() {
+ return apply_filters( 'roc_tab_id', "{$this->slug}-pane", $this );
+ }
+
+ /**
+ * Returns the tab css classes
+ *
+ * @return string
+ */
+ public function classes() {
+ $classes = [
+ 'tab-pane',
+ "tab-pane-{$this->slug}",
+ ];
+ if ( $this->default ) {
+ $classes[] = 'active';
+ }
+ return implode( ' ', apply_filters( 'roc_tab_classes', $classes, $this ) );
+ }
+
+}
diff --git a/includes/ui/diagnostics.php b/includes/ui/diagnostics.php
index ce3cb1a0..d9620056 100644
--- a/includes/ui/diagnostics.php
+++ b/includes/ui/diagnostics.php
@@ -10,14 +10,14 @@
global $wp_object_cache;
$info = [];
-$filesystem = $plugin->test_filesystem_writing();
-$dropin = $plugin->validate_object_cache_dropin();
+$filesystem = $roc->test_filesystem_writing();
+$dropin = $roc->validate_object_cache_dropin();
$disabled = defined( 'WP_REDIS_DISABLED' ) && WP_REDIS_DISABLED;
-$info['Status'] = $plugin->get_status();
-$info['Client'] = $plugin->get_redis_client_name();
-$info['Drop-in'] = $plugin->object_cache_dropin_exists()
- ? ($dropin ? 'Valid' : 'Invalid')
+$info['Status'] = $roc->get_status();
+$info['Client'] = $roc->get_redis_client_name();
+$info['Drop-in'] = $roc->object_cache_dropin_exists()
+ ? ( $dropin ? 'Valid' : 'Invalid' )
: 'Not installed';
$info['Disabled'] = $disabled ? 'Yes' : 'No';
$info['Filesystem'] = is_wp_error( $filesystem ) ? $filesystem->get_error_message() : 'Working';
@@ -52,7 +52,7 @@
}
$info['Plugin Version'] = WP_REDIS_VERSION;
-$info['Redis Version'] = $plugin->get_redis_version() ?: 'Unknown';
+$info['Redis Version'] = $roc->get_redis_version() ?: 'Unknown';
$info['Multisite'] = is_multisite() ? 'Yes' : 'No';
@@ -140,6 +140,6 @@
if ( defined( 'WP_CLI' ) && WP_CLI ) {
WP_CLI::line( "{$name}: $value" );
} else {
- echo "{$name}: {$value}\r\n";
+ echo esc_textarea( "{$name}: {$value}\r\n" );
}
}
diff --git a/includes/ui/settings.php b/includes/ui/settings.php
index 2632a36d..9ba99cd7 100644
--- a/includes/ui/settings.php
+++ b/includes/ui/settings.php
@@ -26,28 +26,24 @@
- disabled ) : ?>
+ is_disabled() ) : ?>
- label ); ?>
+ label() ); ?>
- label ); ?>
+ label() ); ?>
@@ -56,11 +52,11 @@ class="nav-tab default ? 'nav-tab-active' : ''; ?>"
- disabled ) : ?>
-
is_disabled() ) : ?>
+
- file; ?>
+ display(); ?>
diff --git a/includes/ui/tabs/diagnostics.php b/includes/ui/tabs/diagnostics.php
index 4509e0c3..4a4e9a91 100644
--- a/includes/ui/tabs/diagnostics.php
+++ b/includes/ui/tabs/diagnostics.php
@@ -7,8 +7,6 @@
defined( '\\ABSPATH' ) || exit;
-$plugin = $this;
-
?>
diff --git a/includes/ui/tabs/overview.php b/includes/ui/tabs/overview.php
index 6f1bf029..eb3bd2a8 100644
--- a/includes/ui/tabs/overview.php
+++ b/includes/ui/tabs/overview.php
@@ -7,14 +7,12 @@
defined( '\\ABSPATH' ) || exit;
-$plugin = redis_object_cache();
+$redis_client = $roc->get_redis_client_name();
+$redis_prefix = $roc->get_redis_prefix();
+$redis_maxttl = $roc->get_redis_maxttl();
+$redis_version = $roc->get_redis_version();
-$redis_client = $plugin->get_redis_client_name();
-$redis_prefix = $plugin->get_redis_prefix();
-$redis_maxttl = $plugin->get_redis_maxttl();
-$redis_version = $plugin->get_redis_version();
-
-$diagnostics = $plugin->get_diagnostics();
+$diagnostics = $roc->get_diagnostics();
?>
@@ -37,14 +35,15 @@
|
- object_cache_dropin_exists() ) : ?>
+ object_cache_dropin_exists() ) : ?>
- object_cache_dropin_outdated() ) : ?>
+ object_cache_dropin_outdated() ) : ?>
- validate_object_cache_dropin()
- ? esc_html_e( 'Valid', 'redis-cache' )
- : esc_html_e( 'Invalid', 'redis-cache' );
+ validate_object_cache_dropin()
+ ? esc_html_e( 'Valid', 'redis-cache' )
+ : esc_html_e( 'Invalid', 'redis-cache' );
?>
@@ -94,7 +93,7 @@
|
|
- get_status() ); ?> |
+ get_status() ); ?> |
@@ -161,7 +160,7 @@
|
-
+ ••••••••
|
@@ -235,18 +234,18 @@
- get_redis_status() ) : ?>
-
+ get_redis_status() ) : ?>
+
- validate_object_cache_dropin() ) : ?>
-
+ validate_object_cache_dropin() ) : ?>
+
-
+
diff --git a/phpcs.xml b/phpcs.xml
index 45832e8c..9bd6882a 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -18,6 +18,7 @@
+