PluginProbe
MxChat – AI Chatbot & Content Generation for WordPress / 3.2.25
MxChat – AI Chatbot & Content Generation for WordPress v3.2.25
3.2.25 3.2.24 3.2.23 3.2.22 3.2.21 3.2.20 3.2.19 3.2.18 3.2.17 3.2.16 3.2.15 3.2.14 3.2.12 3.2.13 3.2.11 3.2.10 3.2.9 3.2.8 3.2.7 3.2.6 3.2.5 3.2.4 3.2.3 3.2.2 3.2.1 All 156 releases
mxchat-basic / includes / class-mxchat-cache-purge.php

class-mxchat-cache-purge.php in MxChat – AI Chatbot & Content Generation for WordPress 3.2.25, at includes/class-mxchat-cache-purge.php

171 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) {
3 exit;
4 }
5
6 /**
7 * MxChat_Cache_Purge — purges known full-page caches when MxChat settings save.
8 *
9 * Widget settings are printed inline into page HTML (wp_localize_script in
10 * class-mxchat-integrator.php), so a full-page cache keeps serving the old
11 * snapshot after an admin changes a setting — toggles look broken until the
12 * cache is cleared by hand. This module clears the page caches we can reach
13 * from PHP the moment mxchat_options is written, using each cache plugin's
14 * own public purge API (guarded by existence checks, so absent plugins are
15 * a no-op). Companion to the 3.2.6 page-cache compatibility filters in
16 * mxchat-basic.php, which keep the chat AJAX endpoints out of those same
17 * caches; this handles the cached page HTML itself.
18 *
19 * Host-level caches and CDNs (Cloudflare APO etc.) cannot be purged from
20 * PHP — for those, the widget re-fetches its behavior settings when opened
21 * (see MxChat_Integrator::get_dynamic_widget_settings()).
22 *
23 * Debounce: the admin screen autosaves per field, so a settings session can
24 * write mxchat_options many times in a minute. We purge at most once per
25 * DEBOUNCE_SECONDS; writes that land inside the window schedule one deferred
26 * purge via wp-cron so the final state always gets flushed.
27 *
28 * @since 3.2.9 (plan-32db95)
29 */
30 class MxChat_Cache_Purge {
31
32 const DEBOUNCE_TRANSIENT = 'mxchat_cache_purge_debounce';
33 const DEBOUNCE_SECONDS = 30;
34 const DEFERRED_EVENT = 'mxchat_deferred_cache_purge';
35
36 /**
37 * Owner switch (plan b76ed6, Support Ticket 468: a 1,400-page FlyingPress
38 * site lost its whole preload on every settings save). Standalone option,
39 * 'on' / 'off'; absent means ON so existing sites keep today's behaviour.
40 * Rendered on Settings → Optimization → Page Cache Compatibility and saved
41 * by the mxchat_cache_purge_enabled case in class-ajax-handler.php.
42 *
43 * The switch is read when a watched option is actually written (and when
44 * a deferred purge fires), not at plugin load: the hooks below cost
45 * nothing until a save happens, and a site that never touches the switch
46 * never pays a get_option() for it on a visitor request.
47 */
48 const OPTION_NAME = 'mxchat_cache_purge_enabled';
49
50 private static $instance = null;
51
52 /**
53 * Whether this request already queued a shutdown purge (one per request).
54 *
55 * @var bool
56 */
57 private $purge_queued = false;
58
59 public static function init() {
60 if (self::$instance === null) {
61 self::$instance = new self();
62 }
63 return self::$instance;
64 }
65
66 /**
67 * Whether MxChat clears page caches when its settings are saved.
68 * Default ON; only an explicit 'off' switches it off.
69 *
70 * @return bool
71 */
72 public static function is_enabled() {
73 return get_option(self::OPTION_NAME, 'on') !== 'off';
74 }
75
76 private function __construct() {
77 foreach ($this->watched_options() as $option_name) {
78 add_action('update_option_' . $option_name, array($this, 'queue_purge'), 10, 0);
79 add_action('add_option_' . $option_name, array($this, 'queue_purge'), 10, 0);
80 }
81 add_action(self::DEFERRED_EVENT, array($this, 'purge_page_caches'));
82 }
83
84 /**
85 * Option names whose writes trigger a page-cache purge.
86 *
87 * Defaults cover every option whose values reach the cached page's inline
88 * widget payload: mxchat_options (settings/behavior gates),
89 * mxchat_theme_options (active AI theme CSS + bot theme assignments —
90 * written only by the MxChat Theme add-on's admin AJAX actions), and
91 * mxchat_prompts_options (Pinecone toggle — written only by the prompts
92 * autosave). All write sites are admin-action-driven; the debounce
93 * absorbs back-to-back writes like apply-and-save.
94 *
95 * @return string[]
96 */
97 private function watched_options() {
98 $defaults = array('mxchat_options', 'mxchat_theme_options', 'mxchat_prompts_options');
99 $options = apply_filters('mxchat_cache_purge_watched_options', $defaults);
100 return is_array($options) ? array_filter(array_map('strval', $options)) : $defaults;
101 }
102
103 /**
104 * Coalesce all option writes in this request into one shutdown purge.
105 */
106 public function queue_purge() {
107 if ($this->purge_queued || !self::is_enabled()) {
108 return;
109 }
110 $this->purge_queued = true;
111 add_action('shutdown', array($this, 'run_queued_purge'), 5);
112 }
113
114 /**
115 * Shutdown handler: purge unless one ran inside the debounce window; in
116 * that case schedule a single deferred purge so the last write still wins.
117 */
118 public function run_queued_purge() {
119 if (get_transient(self::DEBOUNCE_TRANSIENT)) {
120 if (!wp_next_scheduled(self::DEFERRED_EVENT)) {
121 wp_schedule_single_event(time() + self::DEBOUNCE_SECONDS, self::DEFERRED_EVENT);
122 }
123 return;
124 }
125 set_transient(self::DEBOUNCE_TRANSIENT, 1, self::DEBOUNCE_SECONDS);
126 $this->purge_page_caches();
127 }
128
129 /**
130 * Purge every supported page cache via its own public API. Each call is
131 * guarded so installs without that plugin skip it silently.
132 */
133 public function purge_page_caches() {
134 // The owner may have switched the purge off after a deferred purge was
135 // scheduled; off means off.
136 if (!self::is_enabled()) {
137 return;
138 }
139
140 // WP Rocket — public helper, clears the whole domain's page cache.
141 if (function_exists('rocket_clean_domain')) {
142 rocket_clean_domain();
143 }
144
145 // LiteSpeed Cache — documented third-party purge API.
146 if (defined('LSCWP_V') || class_exists('LiteSpeed\Core')) {
147 do_action('litespeed_purge_all');
148 }
149
150 // W3 Total Cache — page-cache flush helper.
151 if (function_exists('w3tc_pgcache_flush')) {
152 w3tc_pgcache_flush();
153 }
154
155 // WP Super Cache — global cache clear.
156 if (function_exists('wp_cache_clear_cache')) {
157 wp_cache_clear_cache();
158 }
159
160 // FlyingPress — documented programmatic purge (purge_pages clears the
161 // HTML page cache without rebuilding optimized assets):
162 // https://docs.flyingpress.com/en/articles/11406092-programmatically-purge-and-preload-cache
163 if (class_exists('\FlyingPress\Purge') && method_exists('\FlyingPress\Purge', 'purge_pages')) {
164 \FlyingPress\Purge::purge_pages();
165 }
166
167 // Extension point for CDNs / host caches / custom setups.
168 do_action('mxchat_purge_page_caches');
169 }
170 }
171