ache Pro + WooCommerce = ❤️', 'redis-cache' ),
sprintf(
// 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', [ $this, 'maybe_print_comment' ], 0 );
}
}
/**
* Displays the redis cache html comment
*
* @return void
*/
public function maybe_print_comment() {
/** @var \WP_Object_Cache $wp_object_cache */
global $wp_object_cache;
if (
( defined( 'WP_CLI' ) && WP_CLI ) ||
( defined( 'DOING_CRON' ) && DOING_CRON ) ||
( defined( 'DOING_AJAX' ) && DOING_AJAX ) ||
( defined( 'REST_REQUEST' ) && REST_REQUEST ) ||
( defined( 'JSON_REQUEST' ) && JSON_REQUEST ) ||
( defined( 'IFRAME_REQUEST' ) && IFRAME_REQUEST ) ||
( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) ||
( defined( 'WC_API_REQUEST' ) && WC_API_REQUEST )
) {
return;
}
if ( function_exists( 'wp_is_json_request' ) && wp_is_json_request() ) {
return;
}
if (
! isset( $wp_object_cache->cache, $wp_object_cache->diagnostics ) ||
! is_array( $wp_object_cache->cache )
) {
return;
}
if ($this->incompatible_content_type()) {
return;
}
$message = sprintf(
'Performance optimized by Redis Object Cache. Learn more: %s',
'https://wprediscache.com'
);
if ( ! WP_DEBUG_DISPLAY ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
printf( "\n\n", $message );
return;
}
$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.
__( 'Retrieved %1$d objects (%2$s) from Redis using %3$s.', 'redis-cache' ),
$wp_object_cache->cache_hits,
function_exists( 'size_format' ) ? size_format( $bytes ) : "{$bytes} bytes",
$wp_object_cache->diagnostics['client']
);
printf(
"\n",
$message, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
esc_html( $debug )
);
}
/**
* Whether incompatible content type headers were sent.
*
* @return bool
*/
protected function incompatible_content_type()
{
$jsonContentType = static function ($headers) {
foreach ($headers as $header => $value) {
if (stripos((string) $header, 'content-type') === false) {
continue;
}
if (stripos((string) $value, '/json') === false) {
continue;
}
return true;
}
return false;
};
if (function_exists('headers_list')) {
$headers = [];
foreach (headers_list() as $header) {
[$name, $value] = explode(':', $header);
$headers[$name] = $value;
}
if ($jsonContentType($headers)) {
return true;
}
}
if (function_exists('apache_response_headers')) {
if ($headers = apache_response_headers()) {
return $jsonContentType($headers);
}
}
return false;
}
/**
* Initializes the WP filesystem API to be ready for use
*
* @param string $url The URL to post the form to.
* @param bool $silent Whether to ask the user for credentials if necessary or not.
* @return bool
*/
public function initialize_filesystem( $url, $silent = false ) {
if ( $silent ) {
ob_start();
}
$credentials = request_filesystem_credentials( $url );
if ( false === $credentials ) {
if ( $silent ) {
ob_end_clean();
}
return false;
}
if ( ! WP_Filesystem( $credentials ) ) {
request_filesystem_credentials( $url );
if ( $silent ) {
ob_end_clean();
}
return false;
}
return true;
}
/**
* Determines whether object cache file modifications are allowed.
*
* @return bool
*/
function is_file_mod_allowed() {
return apply_filters(
'file_mod_allowed',
! defined( 'DISALLOW_FILE_MODS' ) || ! DISALLOW_FILE_MODS,
'object_cache_dropin'
);
}
/**
* 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() {
/** @var \WP_Filesystem_Base $wp_filesystem */
global $wp_filesystem;
if ( ! $this->is_file_mod_allowed() ) {
return new WP_Error( 'disallowed', __( 'File modifications are not allowed.', 'redis-cache' ) );
}
if ( ! $this->initialize_filesystem( '', true ) ) {
return new WP_Error( 'fs', __( 'Could not initialize filesystem.', 'redis-cache' ) );
}
$dropin_check = ! defined( 'WP_REDIS_DISABLE_DROPIN_CHECK' ) || ! WP_REDIS_DISABLE_DROPIN_CHECK;
if ( ! $dropin_check ) {
if ( ! $wp_filesystem->exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
return true;
}
if ( ! $wp_filesystem->is_writable( WP_CONTENT_DIR . '/object-cache.php' ) ) {
return new WP_Error( 'writable', __( 'Object cache drop-in is not writable.', 'redis-cache' ) );
}
return true;
}
$cachefile = WP_REDIS_PLUGIN_PATH . '/includes/object-cache.php';
$testfile = WP_CONTENT_DIR . '/object-cache.tmp';
if ( ! $wp_filesystem->exists( $cachefile ) ) {
return new WP_Error( 'exists', __( 'Object cache file doesn’t exist.', 'redis-cache' ) );
}
if ( $wp_filesystem->exists( $testfile ) ) {
if ( ! $wp_filesystem->delete( $testfile ) ) {
return new WP_Error( 'delete', __( 'Test file exists, but couldn’t be deleted.', 'redis-cache' ) );
}
}
if ( ! $wp_filesystem->is_writable( WP_CONTENT_DIR ) ) {
return new WP_Error( 'writable', __( 'Content directory is not writable.', 'redis-cache' ) );
}
if ( ! $wp_filesystem->copy( $cachefile, $testfile, true, FS_CHMOD_FILE ) ) {
return new WP_Error( 'copy', __( 'Failed to copy test file.', 'redis-cache' ) );
}
if ( ! $wp_filesystem->exists( $testfile ) ) {
return new WP_Error( 'exists', __( 'Copied test file doesn’t exist.', 'redis-cache' ) );
}
$meta = get_file_data( $testfile, [ 'Version' => 'Version' ] );
if ( $meta['Version'] !== WP_REDIS_VERSION ) {
return new WP_Error( 'version', __( 'Couldn’t verify test file contents.', 'redis-cache' ) );
}
if ( ! $wp_filesystem->delete( $testfile ) ) {
return new WP_Error( 'delete', __( 'Copied test file couldn’t be deleted.', 'redis-cache' ) );
}
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;
}
if ( $this->object_cache_dropin_outdated() ) {
add_action( 'shutdown', [ $this, 'update_dropin' ] );
}
}
/**
* Redirects to the plugin settings if the plugin was just activated
*
* @return void
*/
public function maybe_redirect() {
if ( ! get_transient( '_rediscache_activation_redirect' ) ) {
return;
}
if ( ! $this->current_user_can_manage_redis() ) {
return;
}
delete_transient( '_rediscache_activation_redirect' );
wp_safe_redirect( network_admin_url( $this->page ) );
}
/**
* Updates the `object-cache.php` drop-in
*
* @return void
*/
public function update_dropin() {
global $wp_filesystem;
if ( ! $this->validate_object_cache_dropin() ) {
return;
}
if ( $this->initialize_filesystem( '', true ) ) {
$result = $wp_filesystem->copy(
WP_REDIS_PLUGIN_PATH . '/includes/object-cache.php',
WP_CONTENT_DIR . '/object-cache.php',
true,
FS_CHMOD_FILE
);
/**
* Fires on cache enable event
*
* @since 1.3.5
* @param bool $result Whether the filesystem event (copy of the `object-cache.php` file) was successful.
*/
do_action( 'redis_object_cache_update_dropin', $result );
}
}
/**
* Plugin activation hook
*
* @return void
*/
public static function on_activation() {
set_transient( '_rediscache_activation_redirect', 1, 30 );
}
/**
* 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 ) {
$timestamp = wp_next_scheduled( 'rediscache_discard_metrics' );
if ( $timestamp ) {
wp_unschedule_event( $timestamp, 'rediscache_discard_metrics' );
}
(new Predis)->flush();
if ( $this->validate_object_cache_dropin() && $this->initialize_filesystem( '', true ) ) {
$wp_filesystem->delete( WP_CONTENT_DIR . '/object-cache.php' );
}
}
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
);
}
/**
* Obscure `password` URL parameter.
*
* @param string $url
* @return string
*/
public function obscure_url_secrets( $url ) {
return preg_replace(
'/password=[^&]+/',
'password=*****',
(string) $url
);
}
/**
* The capability required to manage Redis.
*
* @return string
*/
public function manage_redis_capability() {
return is_multisite() ? 'manage_network_options' : 'manage_options';
}
/**
* Does the current user have the capability to manage Redis?
*
* @return bool
*/
public function current_user_can_manage_redis() {
return current_user_can( $this->manage_redis_capability() );
}
/**
* Prevent LiteSpeed Cache from overwriting the `object-cache.php` drop-in.
*
* @return void
*/
public function litespeed_disable_objectcache()
{
if ( isset( $_POST['LSCWP_CTRL'], $_POST['LSCWP_NONCE'], $_POST['object'] ) ) {
$_POST['object'] = '0';
}
}
/**
* Returns `true` if the plugin was installed by AccelerateWP from CloudLinux.
*
* @param bool $ignore_banner_constant
* @return bool
*/
public static function acceleratewp_install( $ignore_banner_constant = false ) {
$path = defined( 'WP_REDIS_PATH' ) ? WP_REDIS_PATH : null;
$scheme = defined( 'WP_REDIS_SCHEME' ) ? WP_REDIS_SCHEME : null;
if ( $scheme === 'unix' && strpos( (string) $path, '.clwpos/redis.sock' ) !== false ) {
if ( $ignore_banner_constant ) {
return true;
} else {
return defined( 'WP_REDIS_DISABLE_BANNERS' ) && WP_REDIS_DISABLE_BANNERS;
}
}
return false;
}
}