PluginProbe
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN / 1.0.7
xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN v1.0.7
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
xspeed / includes / modules / Cloudflare / CloudflareModule.php

CloudflareModule.php in xSpeed Cache: AI-Powered Performance Hub with MCP, Caching & CDN 1.0.7, at includes/modules/Cloudflare/CloudflareModule.php

226 lines 6.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Cloudflare module — connect a CF zone for purge + dev-mode toggles.
4 *
5 * Free tier (this module): API token / global key auth, zone
6 * verification, manual purge, auto purge on xSpeed's own purge, dev
7 * mode toggle.
8 *
9 * Pro tier (xspeed-pro): APO toggle, edge cache rules, edge cache TTL.
10 * Per FEATURES.md "Cloudflare Integration" §8-10.
11 *
12 * @package XSpeed
13 */
14
15 declare(strict_types=1);
16
17 namespace XSpeed\Modules\Cloudflare;
18
19 defined( 'ABSPATH' ) || exit;
20
21 use XSpeed\Cloudflare;
22 use XSpeed\Module;
23
24 final class CloudflareModule extends Module {
25
26 public const SLUG = 'cloudflare';
27 public const TIER = self::TIER_FREE;
28 public const VERSION = '1.0.0';
29
30 public function ui_metadata(): array {
31 return array(
32 'label' => 'Cloudflare',
33 'icon' => 'Cloud',
34 'description' => 'Connect a Cloudflare zone for automatic edge purging when xSpeed clears its cache, plus a dev-mode toggle.',
35 'custom_panel' => 'CloudflarePanel',
36 );
37 }
38
39 public function settings_schema(): array {
40 return array(
41 'enabled' => array(
42 'type' => 'bool',
43 'default' => false,
44 'label' => 'Enable Cloudflare integration',
45 'description' => 'Use the credentials below to verify your zone and run purges.',
46 ),
47 'auth_method' => array(
48 'type' => 'enum',
49 'default' => 'token',
50 'options' => array( 'token', 'key' ),
51 'option_labels' => array(
52 'token' => 'API Token',
53 'key' => 'Global API Key',
54 ),
55 'label' => 'Authentication',
56 'description' => 'API Tokens (scoped, recommended) or the legacy Global API Key with your account email.',
57 'dependsOn' => array( 'field' => 'enabled' ),
58 ),
59 'api_token' => array(
60 'type' => 'string',
61 'default' => '',
62 'label' => 'API Token',
63 'description' => 'Create a token at dash.cloudflare.com → My Profile → API Tokens. Needs "Zone → Cache Purge" + "Zone Settings" permissions.',
64 // Only the token auth branch (and only while CF is enabled, via
65 // the transitive gate on auth_method → enabled).
66 'dependsOn' => array( 'field' => 'auth_method', 'value' => 'token' ),
67 ),
68 'email' => array(
69 'type' => 'string',
70 'default' => '',
71 'label' => 'Account Email',
72 'description' => 'Only used when Authentication is set to Global API Key.',
73 'dependsOn' => array( 'field' => 'auth_method', 'value' => 'key' ),
74 ),
75 'api_key' => array(
76 'type' => 'string',
77 'default' => '',
78 'label' => 'Global API Key',
79 'description' => 'Found at dash.cloudflare.com → My Profile → API Tokens → Global API Key.',
80 'dependsOn' => array( 'field' => 'auth_method', 'value' => 'key' ),
81 ),
82 'zone_id' => array(
83 'type' => 'string',
84 'default' => '',
85 'label' => 'Zone ID',
86 'description' => 'The 32-character hex Zone ID from your domain overview page.',
87 'dependsOn' => array( 'field' => 'enabled' ),
88 ),
89 'auto_purge_on_update' => array(
90 'type' => 'bool',
91 'default' => true,
92 'label' => 'Auto-purge Cloudflare on xSpeed purge',
93 'description' => 'When xSpeed clears its own cache (post save, settings change, manual purge), trigger a Cloudflare purge too.',
94 'dependsOn' => array( 'field' => 'enabled' ),
95 ),
96 );
97 }
98
99 public function rest_routes(): array {
100 $default = parent::rest_routes();
101 return array_merge(
102 $default,
103 array(
104 array(
105 'path' => '/verify',
106 'methods' => 'POST',
107 'callback' => array( $this, 'rest_verify' ),
108 ),
109 array(
110 'path' => '/purge',
111 'methods' => 'POST',
112 'callback' => array( $this, 'rest_purge' ),
113 ),
114 array(
115 'path' => '/dev-mode',
116 'methods' => 'POST',
117 'callback' => array( $this, 'rest_dev_mode' ),
118 ),
119 )
120 );
121 }
122
123 public function conflicts(): array {
124 return array(
125 array(
126 'plugin' => 'cloudflare/cloudflare.php',
127 'feature' => 'cloudflare.purge',
128 'strategy' => \XSpeed\Conflict_Registry::STRATEGY_WARN,
129 'reason' => 'The official Cloudflare plugin also auto-purges; keep auto-purge enabled in only one to avoid double API calls.',
130 ),
131 );
132 }
133
134 public function boot(): void {
135 $opts = $this->get_settings();
136 if ( empty( $opts['enabled'] ) ) {
137 return;
138 }
139 if ( ! empty( $opts['auto_purge_on_update'] ) ) {
140 // xSpeed fires this action whenever it purges its own
141 // cache (see Cache::purge_all). Listening here keeps
142 // CF in sync without any new wiring elsewhere.
143 add_action( 'xspeed_after_purge_all', array( $this, 'on_xspeed_purge' ), 10, 0 );
144 }
145 }
146
147 public function on_xspeed_purge(): void {
148 $opts = $this->get_settings();
149 if ( empty( $opts['enabled'] ) || empty( $opts['zone_id'] ) ) {
150 return;
151 }
152 $result = Cloudflare::purge_all( $opts );
153 if ( ! $result['ok'] && class_exists( '\\XSpeed\\Activity_Log' ) ) {
154 \XSpeed\Activity_Log::record(
155 'cloudflare_purge_failed',
156 'Cloudflare auto-purge failed: ' . ( $result['body']['message'] ?? 'unknown error' ),
157 \XSpeed\Activity_Log::WARN
158 );
159 }
160 }
161
162 public function rest_verify( \WP_REST_Request $request ) {
163 return rest_ensure_response( Cloudflare::verify( $this->get_settings() ) );
164 }
165
166 public function rest_purge( \WP_REST_Request $request ) {
167 $params = $request->get_json_params();
168 if ( ! is_array( $params ) ) {
169 $params = array();
170 }
171 $opts = $this->get_settings();
172 if ( isset( $params['urls'] ) && is_array( $params['urls'] ) && ! empty( $params['urls'] ) ) {
173 return rest_ensure_response( Cloudflare::purge_urls( $opts, $params['urls'] ) );
174 }
175 return rest_ensure_response( Cloudflare::purge_all( $opts ) );
176 }
177
178 public function rest_dev_mode( \WP_REST_Request $request ) {
179 $params = $request->get_json_params();
180 $on = ! empty( $params['on'] );
181 return rest_ensure_response( Cloudflare::set_dev_mode( $this->get_settings(), $on ) );
182 }
183
184 public function cli_commands(): array {
185 return array(
186 array(
187 'name' => 'xspeed cf',
188 'callback' => array( $this, 'cli_handler' ),
189 'shortdesc' => 'Cloudflare verify / purge / dev-mode helpers.',
190 'synopsis' => array(
191 array(
192 'type' => 'positional',
193 'name' => 'action',
194 'options' => array( 'verify', 'purge', 'dev-on', 'dev-off' ),
195 'optional' => false,
196 ),
197 ),
198 ),
199 );
200 }
201
202 public function cli_handler( array $args, array $assoc ): void {
203 $opts = $this->get_settings();
204 $action = $args[0] ?? 'verify';
205 switch ( $action ) {
206 case 'verify':
207 $res = Cloudflare::verify( $opts );
208 break;
209 case 'purge':
210 $res = Cloudflare::purge_all( $opts );
211 break;
212 case 'dev-on':
213 $res = Cloudflare::set_dev_mode( $opts, true );
214 break;
215 case 'dev-off':
216 $res = Cloudflare::set_dev_mode( $opts, false );
217 break;
218 default:
219 \WP_CLI::error( "Unknown action: $action" );
220 return;
221 }
222 \WP_CLI::log( 'HTTP ' . $res['status'] . '' . ( $res['ok'] ? 'ok' : 'failed' ) );
223 \WP_CLI::log( wp_json_encode( $res['body'] ) );
224 }
225 }
226