PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.3.3
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.3.3
1.3.3 1.3.2 1.3.1 1.3.0 1.2.4 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 All 29 releases
← All changes | includes/class-activity-log.php +48 -7 1.1.11.3.3 View file →
@@ -30,12 +30,25 @@
30 30 defined( 'ABSPATH' ) || exit;
31 31
32 32 final class Activity_Log {
33 33
34 + /**
35 + * Storage key. An OPTION, not a transient — with a persistent object
36 + * cache a transient lives in Redis/Memcached, and `Cache::purge_all()`
37 + * calls `wp_cache_flush()` before it records the purge. The log was
38 + * therefore erased by the very event it exists to record: on any
39 + * Redis/Memcached site "Last purge" could never show more than the one
40 + * row written after the flush. A history a flush can evaporate is not a
41 + * history. Autoload is off — the log is read in admin contexts only.
42 + */
43 + public const OPTION_KEY = 'xspeed_activity_log';
44 +
45 + /** Legacy transient the log used to live in; drained once on read. */
34 46 public const TRANSIENT_KEY = 'xspeed_activity_log';
35 - public const TTL = 2592000; // 30 days
36 - public const MAX_ENTRIES = 50;
37 47
48 + public const TTL = 2592000; // 30 days — legacy transient only.
49 + public const MAX_ENTRIES = 50;
50 +
38 51 public const INFO = 'info';
39 52 public const WARN = 'warn';
40 53 public const ERROR = 'error';
41 54 public const SUCCESS = 'success';
@@ -53,12 +66,26 @@
53 66 );
54 67 if ( count( $entries ) > self::MAX_ENTRIES ) {
55 68 $entries = array_slice( $entries, 0, self::MAX_ENTRIES );
56 69 }
57 - set_transient( self::TRANSIENT_KEY, $entries, self::TTL );
70 + self::store( $entries );
58 71 }
59 72
60 73 /**
74 + * Persist the log with autoload disabled, so it never joins
75 + * `wp_load_alloptions()` on frontend requests.
76 + *
77 + * @param array<int,array<string,mixed>> $entries Newest-first entries.
78 + */
79 + private static function store( array $entries ): void {
80 + if ( false === get_option( self::OPTION_KEY, false ) ) {
81 + add_option( self::OPTION_KEY, $entries, '', 'no' );
82 + return;
83 + }
84 + update_option( self::OPTION_KEY, $entries );
85 + }
86 +
87 + /**
61 88 * Newest-first entries (up to MAX_ENTRIES). Defensive shape coercion
62 89 * so a malformed transient never breaks the dashboard.
63 90 *
64 91 * @return array<int,array{ts:int,type:string,message:string,severity:string}>
@@ -63,10 +90,23 @@
63 90 *
64 91 * @return array<int,array{ts:int,type:string,message:string,severity:string}>
65 92 */
66 93 public static function entries(): array {
67 - $raw = get_transient( self::TRANSIENT_KEY );
94 + $raw = get_option( self::OPTION_KEY, null );
95 +
96 + // One-time migration off the old transient. Done lazily on read so
97 + // no upgrade routine has to run first, and so history written by a
98 + // previous version isn't thrown away.
68 99 if ( ! is_array( $raw ) ) {
100 + $legacy = get_transient( self::TRANSIENT_KEY );
101 + if ( is_array( $legacy ) ) {
102 + self::store( $legacy );
103 + delete_transient( self::TRANSIENT_KEY );
104 + $raw = $legacy;
105 + }
106 + }
107 +
108 + if ( ! is_array( $raw ) ) {
69 109 return array();
70 110 }
71 111 $out = array();
72 112 foreach ( $raw as $e ) {
@@ -82,8 +122,9 @@
82 122 return $out;
83 123 }
84 124
85 125 public static function clear(): void {
126 + delete_option( self::OPTION_KEY );
86 127 delete_transient( self::TRANSIENT_KEY );
87 128 }
88 129
89 130 /**
@@ -98,10 +139,10 @@
98 139 * Rewrites any `<secret_key> old→new` fragment to `<secret_key> changed`,
99 140 * preserving the rest of the entry so the causal history survives.
100 141 */
101 142 public static function redact_legacy_secrets(): void {
102 - $entries = get_transient( self::TRANSIENT_KEY );
103 - if ( ! is_array( $entries ) || empty( $entries ) ) {
143 + $entries = self::entries();
144 + if ( empty( $entries ) ) {
104 145 return;
105 146 }
106 147
107 148 $changed = false;
@@ -126,8 +167,8 @@
126 167 }
127 168 }
128 169
129 170 if ( $changed ) {
130 - set_transient( self::TRANSIENT_KEY, $entries, self::TTL );
171 + self::store( $entries );
131 172 }
132 173 }
133 174 }