Skip to content

Commit 3c365d4

Browse files
authored
Merge pull request #466 from newfold-labs/fix/object-cache-connection-constants
Update Redis connection constants for availability check
2 parents b5a10bf + 9a5507d commit 3c365d4

File tree

6 files changed

+133
-70
lines changed

6 files changed

+133
-70
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
"newfold-labs/wp-module-features": "^1.5",
4141
"newfold-labs/wp-module-installer": "^1.7",
4242
"newfold-labs/wp-module-htaccess": "^1.0",
43-
"predis/predis": "^3.4"
43+
"predis/predis": "^3.4",
44+
"wp-cli/wp-config-transformer": "^1.4"
4445
},
4546
"require-dev": {
4647
"newfold-labs/wp-php-standards": "^1.2",

composer.lock

Lines changed: 50 additions & 50 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

includes/Cache/CachePurgingService.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,10 @@ public function manual_purge_request() {
9090
}
9191

9292
/**
93-
* Purge everything.
93+
* Purge page caches only (File, Browser). Does not flush object cache.
94+
* Use when enabling object cache so session/auth data is not flushed.
9495
*/
95-
public function purge_all() {
96+
public function purge_page_caches() {
9697
foreach ( $this->cache_types as $instance ) {
9798
if ( array_key_exists( Purgeable::class, class_implements( $instance ) ) ) {
9899
/**
@@ -103,6 +104,13 @@ public function purge_all() {
103104
$instance->purge_all();
104105
}
105106
}
107+
}
108+
109+
/**
110+
* Purge everything (page caches and object cache).
111+
*/
112+
public function purge_all() {
113+
$this->purge_page_caches();
106114
ObjectCache::flush_object_cache();
107115
}
108116

includes/Cache/Types/ObjectCache.php

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,8 @@ class ObjectCache {
3838
* @var string[]
3939
*/
4040
const REDIS_CONNECTION_CONSTANTS = array(
41-
'WP_REDIS_HOST',
42-
'WP_REDIS_SERVERS',
43-
'WP_REDIS_CLUSTER',
44-
'WP_REDIS_SHARDS',
45-
'WP_REDIS_SENTINEL',
41+
'WP_REDIS_PREFIX',
42+
'WP_REDIS_PASSWORD',
4643
);
4744

4845
/**
@@ -61,11 +58,49 @@ class ObjectCache {
6158
*/
6259
public static function is_available() {
6360
foreach ( self::REDIS_CONNECTION_CONSTANTS as $constant ) {
64-
if ( defined( $constant ) ) {
65-
return true;
61+
if ( ! defined( $constant ) ) {
62+
return false;
6663
}
6764
}
68-
return false;
65+
return true;
66+
}
67+
68+
/**
69+
* Whether Redis is configured in wp-config.php (at least one connection constant is defined there).
70+
* Used for removal: we remove the drop-in when wp-config no longer has Redis config, even if the
71+
* drop-in has already defined a constant (e.g. WP_REDIS_PREFIX from WP_CACHE_KEY_SALT or env).
72+
* Uses WP-CLI's wp-config-transformer so commented-out defines are not counted as present.
73+
* Result is cached per request to avoid repeated file reads and parsing.
74+
*
75+
* @return bool
76+
*/
77+
public static function is_configured_in_wp_config() {
78+
static $result = null;
79+
if ( null !== $result ) {
80+
return $result;
81+
}
82+
$path = defined( 'WP_CONFIG_FILE' ) ? constant( 'WP_CONFIG_FILE' ) : ( ABSPATH . 'wp-config.php' );
83+
if ( ! file_exists( $path ) ) {
84+
$path = dirname( ABSPATH ) . '/wp-config.php';
85+
}
86+
if ( ! file_exists( $path ) || ! is_readable( $path ) ) {
87+
$result = false;
88+
return $result;
89+
}
90+
try {
91+
$transformer = new \WPConfigTransformer( $path, true );
92+
foreach ( self::REDIS_CONNECTION_CONSTANTS as $constant ) {
93+
if ( ! $transformer->exists( 'constant', $constant ) ) {
94+
$result = false;
95+
return $result;
96+
}
97+
}
98+
} catch ( \Exception $e ) {
99+
$result = false;
100+
return $result;
101+
}
102+
$result = true;
103+
return $result;
69104
}
70105

71106
/**
@@ -308,18 +343,20 @@ public static function maybe_restore_on_activation() {
308343
/**
309344
* If Redis config is no longer present (e.g. constants commented out in wp-config) but our drop-in
310345
* is still in place, remove the drop-in so WordPress does not load a broken object cache.
311-
* Also clears the enabled preference so state stays consistent.
346+
* Uses wp-config content (not defined()) so we still remove when the drop-in has already defined
347+
* a constant (e.g. WP_REDIS_PREFIX from WP_CACHE_KEY_SALT or env). Also clears the enabled preference.
348+
* Checks for the drop-in file first so we skip wp-config read/parse on most requests (no drop-in).
312349
*
313350
* @return void
314351
*/
315352
public static function maybe_remove_dropin_if_unavailable() {
316-
if ( self::is_available() ) {
317-
return;
318-
}
319353
$path = self::get_drop_in_path();
320354
if ( ! file_exists( $path ) || ! self::is_our_drop_in( $path ) ) {
321355
return;
322356
}
357+
if ( self::is_configured_in_wp_config() ) {
358+
return;
359+
}
323360
if ( ! function_exists( 'WP_Filesystem' ) ) {
324361
require_once ABSPATH . 'wp-admin/includes/file.php';
325362
}

includes/PerformanceLifecycleHooks.php

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,9 @@ public function hooks() {
115115
* @return void
116116
*/
117117
public function on_activation() {
118-
// Purge object cache on shutdown so the next request reads active_plugins from DB (not Redis).
119-
add_action( 'shutdown', array( $this, 'purge_object_cache_on_shutdown' ), PHP_INT_MAX );
118+
// Clear plugin list from object cache on shutdown so the next request reads active_plugins from DB (not Redis).
119+
// Only clears options group — avoids full flush which would destroy session/auth data and log the user out.
120+
add_action( 'shutdown', array( $this, 'clear_plugin_cache_on_shutdown' ), PHP_INT_MAX );
120121
// Cache feature bits.
121122
File::on_activation();
122123
Browser::on_activation();
@@ -146,7 +147,17 @@ protected function delete_plugin_list_option_cache() {
146147
}
147148

148149
/**
149-
* Purge object cache (options + full flush + runtime) on shutdown after activate/deactivate.
150+
* Clear only the plugin list from object cache on shutdown after activation.
151+
* Ensures the next request reads active_plugins from DB without destroying session/auth data.
152+
*
153+
* @return void
154+
*/
155+
public function clear_plugin_cache_on_shutdown() {
156+
$this->delete_plugin_list_option_cache();
157+
}
158+
159+
/**
160+
* Purge object cache (options + full flush + runtime) on shutdown after deactivation.
150161
* Ensures the next request reads active_plugins from DB even if something re-cached after our hooks.
151162
*
152163
* @return void

includes/RestApi/CacheController.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,14 @@ public function update_settings( \WP_REST_Request $request ) {
130130
$out = ObjectCache::disable();
131131
}
132132
if ( $out['success'] ) {
133-
// Purge page cache and object cache (purge_all includes flush_object_cache).
134-
container()->get( 'cachePurger' )->purge_all();
133+
// When enabling: only purge page caches so we don't flush object cache (avoids logging out the user).
134+
// When disabling: purge everything including object cache.
135+
$purger = container()->get( 'cachePurger' );
136+
if ( $enable ) {
137+
$purger->purge_page_caches();
138+
} else {
139+
$purger->purge_all();
140+
}
135141
return new \WP_REST_Response( array( 'result' => true ), 200 );
136142
}
137143
return new \WP_REST_Response(

0 commit comments

Comments
 (0)