-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtelex.php
More file actions
330 lines (305 loc) · 12.6 KB
/
telex.php
File metadata and controls
330 lines (305 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
<?php
/**
* Plugin Name: Dispatch for Telex
* Plugin URI: https://telex.automattic.ai
* Description: Telex builds the block. Dispatch ships it. Install, update, and remove Telex-generated blocks and themes from wp-admin — no zip files, no upload forms.
* Version: 1.6.2
* Requires at least: 6.7
* Tested up to: 6.8
* Requires PHP: 8.2
* Author: Regionally Famous
* Author URI: https://regionallyfamous.com
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: dispatch
*
* @package Dispatch_For_Telex
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Guard against double-loading.
if ( defined( 'TELEX_LOADED' ) ) {
return;
}
define( 'TELEX_LOADED', true );
define( 'TELEX_PLUGIN_VERSION', '1.6.2' );
define( 'TELEX_PLUGIN_FILE', __FILE__ );
define( 'TELEX_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'TELEX_PUBLIC_URL', 'https://telex.automattic.ai' );
define( 'TELEX_API_BASE_URL', TELEX_PUBLIC_URL . '/api' );
define( 'TELEX_DEVICE_AUTH_URL', TELEX_PUBLIC_URL . '/auth/device' );
// =============================================================================
// PRE-FLIGHT CHECKS
//
// Every hard requirement is verified before a single class file is loaded.
// On failure: show an actionable admin notice and deactivate cleanly.
// A white screen or PHP fatal is never an acceptable outcome.
// =============================================================================
/**
* Registers an admin error notice and schedules immediate deactivation.
*
* Stored as a variable rather than a named function to avoid polluting the
* global function namespace. Unset after the pre-flight block completes.
*
* @param string $message HTML-safe message shown inside the notice (wp_kses_post applied).
*/
$telex_bail = static function ( string $message ): void {
add_action(
'admin_notices',
static function () use ( $message ): void {
printf(
'<div class="notice notice-error"><p>%s</p></div>',
wp_kses_post( '<strong>Dispatch for Telex</strong> cannot start: ' . $message )
);
}
);
// Deactivate on the very next admin_init so the plugin does not sit in a
// permanently broken state. Also suppress the "Plugin activated." banner
// that would otherwise appear alongside the error notice.
add_action(
'admin_init',
static function (): void {
deactivate_plugins( plugin_basename( TELEX_PLUGIN_FILE ) );
if ( isset( $_GET['activate'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
unset( $_GET['activate'] );
}
}
);
};
// -----------------------------------------------------------------------------
// 1. PHP version
// Backed enums, readonly classes, named arguments, and first-class callables
// all require PHP 8.2+. WordPress checks Requires PHP before activation, but
// that can be bypassed via WP-CLI or direct DB manipulation.
// -----------------------------------------------------------------------------
if ( version_compare( PHP_VERSION, '8.2', '<' ) ) {
$telex_bail(
sprintf(
/* translators: %s: current PHP version */
__( 'Dispatch needs PHP 8.2 or later. Your server is running PHP %s — ask your host to upgrade.', 'dispatch' ),
esc_html( PHP_VERSION )
)
);
unset( $telex_bail );
return;
}
// -----------------------------------------------------------------------------
// 2. WordPress version
// Checked here as defence-in-depth; WP normally enforces Requires At Least
// from the plugin header before activation.
// -----------------------------------------------------------------------------
global $wp_version;
if ( version_compare( $wp_version, '6.7', '<' ) ) {
$telex_bail(
sprintf(
/* translators: %s: current WordPress version */
__( 'Dispatch needs WordPress 6.7 or later. You\'re on %s — time to update!', 'dispatch' ),
esc_html( $wp_version )
)
);
unset( $telex_bail );
return;
}
// -----------------------------------------------------------------------------
// 3. OpenSSL extension
// Required by Telex_Auth for AES-256-GCM token encryption/decryption and
// for generating random IVs via openssl_random_pseudo_bytes().
// -----------------------------------------------------------------------------
if ( ! extension_loaded( 'openssl' ) ) {
$telex_bail(
__( 'The PHP <code>openssl</code> extension is missing. Ask your host to enable it — Dispatch needs it for secure token storage.', 'dispatch' )
);
unset( $telex_bail );
return;
}
// -----------------------------------------------------------------------------
// 4. ZipArchive class
// Required by Telex_Installer to package build files before handing them
// to the WordPress Upgrader API.
// -----------------------------------------------------------------------------
if ( ! class_exists( 'ZipArchive' ) ) {
$telex_bail(
__( 'The PHP <code>zip</code> extension is missing. Ask your host to enable it — Dispatch needs it to install projects.', 'dispatch' )
);
unset( $telex_bail );
return;
}
// -----------------------------------------------------------------------------
// 5. Composer autoloader
// Not present when the plugin is installed by cloning the repository without
// running composer install.
// -----------------------------------------------------------------------------
if ( ! file_exists( TELEX_PLUGIN_DIR . 'vendor/autoload.php' ) ) {
$telex_bail(
sprintf(
/* translators: %s: composer install command */
__( 'Composer dependencies are missing. Run %s in the plugin directory, or install from the pre-built release ZIP rather than cloning the repository directly.', 'dispatch' ),
'<code>composer install --no-dev --optimize-autoloader</code>'
)
);
unset( $telex_bail );
return;
}
// -----------------------------------------------------------------------------
// 6. Required plugin files
// Guards against partial uploads via FTP, truncated ZIP extractions, or
// any other incomplete installation. Every file loaded below is listed here.
// -----------------------------------------------------------------------------
$telex_required = [
'includes/Enums/AuditAction.php',
'includes/Enums/AuthStatus.php',
'includes/Enums/ProjectType.php',
'includes/class-telex-activator.php',
'includes/class-telex-admin.php',
'includes/class-telex-utils.php',
'includes/class-telex-audit-log.php',
'includes/class-telex-audit-log-table.php',
'includes/class-telex-auth.php',
'includes/class-telex-cache.php',
'includes/class-telex-circuit-breaker.php',
'includes/class-telex-dtos.php',
'includes/class-telex-fatal-handler.php',
'includes/class-telex-installer.php',
'includes/class-telex-privacy.php',
'includes/class-telex-rest.php',
'includes/class-telex-tracker.php',
'includes/class-telex-updater.php',
'includes/class-telex-wp-http-client.php',
'includes/class-telex-version-pin.php',
'includes/class-telex-auto-update.php',
'includes/class-telex-project-groups.php',
'includes/class-telex-snapshot.php',
'includes/class-telex-notifications.php',
'includes/class-telex-analytics.php',
'includes/class-telex-health.php',
];
$telex_missing = array_values(
array_filter(
$telex_required,
static fn( string $path ) => ! file_exists( TELEX_PLUGIN_DIR . $path )
)
);
if ( ! empty( $telex_missing ) ) {
$telex_bail(
sprintf(
/* translators: %s: comma-separated list of missing file paths */
__( 'The plugin installation is incomplete — the following files are missing. Please reinstall from the release ZIP: <code>%s</code>', 'dispatch' ),
esc_html( implode( '</code>, <code>', $telex_missing ) )
)
);
unset( $telex_bail, $telex_required, $telex_missing );
return;
}
unset( $telex_bail, $telex_required, $telex_missing );
// =============================================================================
// BOOTSTRAP
//
// All pre-flight checks passed. Load dependencies and register hooks.
// The plugins_loaded and rest_api_init callbacks are wrapped in try/catch as
// a last-resort safety net for any unexpected runtime errors.
// =============================================================================
require_once TELEX_PLUGIN_DIR . 'vendor/autoload.php';
// Enums (loaded before any class that uses them).
require_once TELEX_PLUGIN_DIR . 'includes/Enums/ProjectType.php';
require_once TELEX_PLUGIN_DIR . 'includes/Enums/AuthStatus.php';
require_once TELEX_PLUGIN_DIR . 'includes/Enums/AuditAction.php';
// DTOs (readonly classes — loaded after enums, before services).
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-dtos.php';
// Core service classes.
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-audit-log.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-circuit-breaker.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-auth.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-cache.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-tracker.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-wp-http-client.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-utils.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-installer.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-updater.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-audit-log-table.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-admin.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-privacy.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-rest.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-fatal-handler.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-version-pin.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-auto-update.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-project-groups.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-snapshot.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-notifications.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-analytics.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-health.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-favorites.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-tags.php';
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-failed-installs.php';
// Activation/deactivation handlers.
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-activator.php';
register_activation_hook( __FILE__, Telex_Activator::activate( ... ) );
register_deactivation_hook( __FILE__, Telex_Activator::deactivate( ... ) );
// WP-CLI commands — only load in CLI context and only if the file is present.
if ( defined( 'WP_CLI' ) && WP_CLI && file_exists( TELEX_PLUGIN_DIR . 'includes/class-telex-cli.php' ) ) {
require_once TELEX_PLUGIN_DIR . 'includes/class-telex-cli.php';
WP_CLI::add_command( 'telex', 'Telex_CLI' );
}
// Bootstrap all services after all plugins have loaded.
// Wrapped in try/catch: maybe_upgrade() writes to the DB, Auth::init() adds
// multisite filters — any unexpected exception here must not produce a fatal.
add_action(
'plugins_loaded',
static function (): void {
try {
Telex_Fatal_Handler::register();
Telex_Activator::maybe_upgrade();
Telex_Auth::init();
Telex_Admin::init();
Telex_Updater::init();
// Cron callbacks for new features.
add_action( Telex_Auto_Update::CRON_HOOK, Telex_Auto_Update::run( ... ) );
add_action( Telex_Analytics::CRON_HOOK, Telex_Analytics::scan( ... ) );
// Piggyback on the existing hourly cache-warm cron to evaluate notification triggers.
add_action( 'telex_cache_warm', Telex_Notifications::evaluate_cron_triggers( ... ) );
} catch ( \Throwable $e ) {
add_action(
'admin_notices',
static function () use ( $e ): void {
printf(
'<div class="notice notice-error"><p>%s</p></div>',
wp_kses_post(
sprintf(
/* translators: %s: error message */
__( '<strong>Dispatch for Telex</strong> encountered an unexpected error during startup and could not initialise: %s', 'dispatch' ),
'<code>' . esc_html( $e->getMessage() ) . '</code>'
)
)
);
}
);
}
}
);
// REST API routes.
// Wrapped in try/catch: route registration is non-critical — a failure here
// should surface as an admin notice, not a fatal that breaks the entire admin.
add_action(
'rest_api_init',
static function (): void {
try {
Telex_REST::register_routes();
} catch ( \Throwable $e ) {
add_action(
'admin_notices',
static function () use ( $e ): void {
printf(
'<div class="notice notice-warning"><p>%s</p></div>',
wp_kses_post(
sprintf(
/* translators: %s: error message */
__( '<strong>Dispatch for Telex</strong> could not register its REST API routes: %s', 'dispatch' ),
'<code>' . esc_html( $e->getMessage() ) . '</code>'
)
)
);
}
);
}
}
);