@wp-playground/wordpress 3.1.20 → 3.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,8 +1,2253 @@
1
- import { phpVars as $, joinPaths as s, dirname as y, basename as b, phpVar as d } from "@php-wasm/util";
2
- import { createMemoizedFetch as P, unzipFile as p } from "@wp-playground/common";
3
- import { logger as g } from "@php-wasm/logger";
4
- import { sandboxedSpawnHandlerFactory as T, PHPRequestHandler as E, PHP as v, setPhpIniEntries as S, writeFiles as f, withPHPIniValues as R } from "@php-wasm/universal";
5
- const m = `<?php
1
+ import { isLegacyPHPVersion as w, setPhpIniEntries as P, withPHPIniValues as N, sandboxedSpawnHandlerFactory as F, PHPRequestHandler as C, PHP as q, writeFiles as b } from "@php-wasm/universal";
2
+ import { joinPaths as _, phpVar as $, phpVars as A, dirname as W, basename as G } from "@php-wasm/util";
3
+ import { unzipFile as m, createMemoizedFetch as M } from "@wp-playground/common";
4
+ import { logger as h } from "@php-wasm/logger";
5
+ async function S(e) {
6
+ await e.writeFile(
7
+ "/internal/shared/mu-plugins/0-playground.php",
8
+ `<?php
9
+
10
+ // Save WordPress environment information to a file.
11
+ // Named function (not a closure) so this file parses on PHP 5.2.
12
+ function playground_save_wp_env_info() {
13
+ if (defined('DB_ENGINE') && DB_ENGINE === 'sqlite') {
14
+ $db_info = array(
15
+ 'type' => 'sqlite',
16
+ 'path' => FQDB,
17
+ 'driver_path' => defined('WP_MYSQL_ON_SQLITE_LOADER_PATH')
18
+ ? WP_MYSQL_ON_SQLITE_LOADER_PATH
19
+ : dirname(SQLITE_MAIN_FILE) . '/wp-pdo-mysql-on-sqlite.php',
20
+ );
21
+ } else {
22
+ $db_info = array(
23
+ 'type' => 'mysql',
24
+ // TODO: Save MySQL connection config.
25
+ );
26
+ }
27
+ $wp_env = array('db' => $db_info);
28
+ $wp_env_php = sprintf('<?php return %s;', var_export($wp_env, true));
29
+ $wp_env_file = '/internal/shared/wp-env.php';
30
+ if (!file_exists($wp_env_file) || file_get_contents($wp_env_file) !== $wp_env_php ) {
31
+ file_put_contents($wp_env_file, $wp_env_php);
32
+ }
33
+ }
34
+ add_action('wp_loaded', 'playground_save_wp_env_info');
35
+
36
+ // Needed because gethostbyname( 'wordpress.org' ) returns
37
+ // a private network IP address for some reason.
38
+ function playground_allowed_redirect_hosts( $deprecated = '' ) {
39
+ return array(
40
+ 'wordpress.org',
41
+ 'api.wordpress.org',
42
+ 'downloads.wordpress.org',
43
+ );
44
+ }
45
+ add_filter( 'allowed_redirect_hosts', 'playground_allowed_redirect_hosts' );
46
+
47
+ /**
48
+ * Prevents wp_http_validate_url() from universally failing.
49
+ *
50
+ * wp_http_validate_url() calls gethostbyname() to verify whether the host
51
+ * is external. If it is internal, the URL validation fails and WordPress
52
+ * refuses to make a request.
53
+ *
54
+ * However, in EMscripten, gethostbyname() returns a private network IP address.
55
+ * This causes wp_http_validate_url() to return false for all URLs.
56
+ *
57
+ * This filter ensures that all URLs are considered external. In production
58
+ * environments, this would be considered a security risk. However, Playground
59
+ * already provides multiple code execution vectors as features (e.g. Blueprints).
60
+ *
61
+ * If someone wants to poke around local IP addresses, they already have multiple
62
+ * tools at their disposal. Therefore, this is not a real security risk in context
63
+ * of WordPress Playground or Playground CLI.
64
+ */
65
+ add_filter('http_request_host_is_external', '__return_true');
66
+
67
+ // Support pretty permalinks
68
+ add_filter( 'got_url_rewrite', '__return_true' );
69
+
70
+ /**
71
+ * Flush rewrite rules on the first real WordPress request.
72
+ *
73
+ * During boot, we set permalink_structure in the database
74
+ * but can't flush rewrite rules at that point because WordPress
75
+ * isn't fully bootstrapped — post types and taxonomies haven't
76
+ * been registered yet, so the generated rules are incomplete.
77
+ *
78
+ * This hook fires on 'init' at a very late priority, after all
79
+ * post types and taxonomies are registered. It checks if the
80
+ * rewrite_rules option is empty (meaning rules were never
81
+ * flushed) and if permalink_structure is set, then flushes once.
82
+ * A flag file prevents repeated flushes on subsequent requests.
83
+ */
84
+ function playground_maybe_flush_rewrite_rules() {
85
+ $flag = '/internal/shared/.rewrite-rules-flushed';
86
+ if (file_exists($flag)) {
87
+ return;
88
+ }
89
+ if (!function_exists('get_option')) {
90
+ return;
91
+ }
92
+ $structure = get_option('permalink_structure');
93
+ if (empty($structure)) {
94
+ return;
95
+ }
96
+ $rules = get_option('rewrite_rules');
97
+ if (!empty($rules)) {
98
+ @file_put_contents($flag, '1');
99
+ return;
100
+ }
101
+ global $wp_rewrite;
102
+ if (!isset($wp_rewrite) && class_exists('WP_Rewrite')) {
103
+ $wp_rewrite = new WP_Rewrite();
104
+ }
105
+ if (isset($wp_rewrite) && method_exists($wp_rewrite, 'flush_rules')) {
106
+ $wp_rewrite->flush_rules();
107
+ }
108
+ @file_put_contents($flag, '1');
109
+ }
110
+ add_action('init', 'playground_maybe_flush_rewrite_rules', 99999);
111
+
112
+ // Create the fonts directory if missing
113
+ if(!file_exists(WP_CONTENT_DIR . '/fonts')) {
114
+ mkdir(WP_CONTENT_DIR . '/fonts');
115
+ }
116
+
117
+ $log_file = WP_CONTENT_DIR . '/debug.log';
118
+ if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
119
+ if ( is_string( WP_DEBUG_LOG ) ) {
120
+ $log_file = WP_DEBUG_LOG;
121
+ }
122
+ ini_set('error_log', $log_file);
123
+ } else {
124
+ ini_set('log_errors', '0');
125
+ }
126
+ define('ERROR_LOG_FILE', $log_file);
127
+ ?>`
128
+ ), await e.writeFile(
129
+ "/internal/shared/mu-plugins/sitemap-redirect.php",
130
+ `<?php
131
+ /**
132
+ * Redirect sitemap.xml to wp-sitemap.xml for non-root installations.
133
+ *
134
+ * WordPress seems to only generate the sitemap.xml → wp-sitemap.xml rewrite
135
+ * rule when installed at the domain root. This mu-plugin handles the
136
+ * redirect for non-root installations.
137
+ */
138
+ if (isset($_SERVER['REQUEST_URI'])) {
139
+ $site_url = site_url();
140
+ $parsed = parse_url($site_url);
141
+ $base_path = isset($parsed['path']) ? rtrim($parsed['path'], '/') : '';
142
+
143
+ $request_uri = $_SERVER['REQUEST_URI'];
144
+ if (
145
+ $request_uri === $base_path . '/sitemap.xml' ||
146
+ strpos($request_uri, $base_path . '/sitemap.xml?') === 0 ||
147
+ strpos($request_uri, $base_path . '/sitemap.xml/') === 0
148
+ ) {
149
+ $query_string = strpos($request_uri, '?') !== false ? substr($request_uri, strpos($request_uri, '?')) : '';
150
+ header('Location: ' . $base_path . '/wp-sitemap.xml' . $query_string, true, 301);
151
+ exit;
152
+ }
153
+ }
154
+ `
155
+ ), await e.writeFile(
156
+ "/internal/shared/mu-plugins/inline-tinymce-content-css.php",
157
+ `<?php
158
+ function playground_inline_tinymce_content_css($settings) {
159
+ if (empty($settings['content_css'])) return $settings;
160
+ $css_urls = explode(',', $settings['content_css']);
161
+ $inline_css = '';
162
+ $doc_root = isset($_SERVER['DOCUMENT_ROOT'])
163
+ ? $_SERVER['DOCUMENT_ROOT'] : '/wordpress';
164
+ foreach ($css_urls as $url) {
165
+ $url = trim($url);
166
+ if (!$url) continue;
167
+ $parsed = parse_url($url);
168
+ if (!isset($parsed['path'])) continue;
169
+ $path = preg_replace('#^/scope:[^/]+#', '', $parsed['path']);
170
+ $file = $doc_root . $path;
171
+ if (file_exists($file)) {
172
+ $inline_css .= @file_get_contents($file) . "\\n";
173
+ }
174
+ }
175
+ if ($inline_css !== '') {
176
+ if (!empty($settings['content_style'])) {
177
+ $inline_css = $settings['content_style'] . "\\n" . $inline_css;
178
+ }
179
+ $settings['content_style'] = $inline_css;
180
+ $settings['content_css'] = '';
181
+ }
182
+ return $settings;
183
+ }
184
+ add_filter('tiny_mce_before_init', 'playground_inline_tinymce_content_css');
185
+ `
186
+ );
187
+ }
188
+ function v(e) {
189
+ return `
190
+ /**
191
+ * Loads the SQLite integration plugin before WordPress is loaded
192
+ * and without creating a drop-in "db.php" file.
193
+ *
194
+ * Technically, it creates a global $wpdb object whose only two
195
+ * purposes are to:
196
+ *
197
+ * * Exist – because the require_wp_db() WordPress function won't
198
+ * connect to MySQL if $wpdb is already set.
199
+ * * Load the SQLite integration plugin the first time it's used
200
+ * and replace the global $wpdb reference with the SQLite one.
201
+ *
202
+ * This lets Playground keep the WordPress installation clean and
203
+ * solves dillemas like:
204
+ *
205
+ * * Should we include db.php in Playground exports?
206
+ * * Should we remove db.php from Playground imports?
207
+ * * How should we treat stale db.php from long-lived OPFS sites?
208
+ *
209
+ * @see https://github.com/WordPress/wordpress-playground/discussions/1379 for
210
+ * more context.
211
+ */
212
+ class Playground_SQLite_Integration_Loader {
213
+ public function __call($name, $arguments) {
214
+ $this->load_sqlite_integration();
215
+ if($GLOBALS['wpdb'] === $this) {
216
+ throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
217
+ }
218
+ return call_user_func_array(
219
+ array($GLOBALS['wpdb'], $name),
220
+ $arguments
221
+ );
222
+ }
223
+ public function __get($name) {
224
+ $this->load_sqlite_integration();
225
+ if($GLOBALS['wpdb'] === $this) {
226
+ throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
227
+ }
228
+ return $GLOBALS['wpdb']->$name;
229
+ }
230
+ public function __set($name, $value) {
231
+ $this->load_sqlite_integration();
232
+ if($GLOBALS['wpdb'] === $this) {
233
+ throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
234
+ }
235
+ $GLOBALS['wpdb']->$name = $value;
236
+ }
237
+ protected function load_sqlite_integration() {
238
+ ${e}
239
+ }
240
+ }
241
+ /**
242
+ * The Query Monitor plugin short-circuits in the CLI SAPI. However, in Playground,
243
+ * the SAPI is always "cli" at the moment. Let's set a constant to disable the CLI
244
+ * detection.
245
+ *
246
+ * @see https://github.com/WordPress/sqlite-database-integration/pull/212
247
+ * @see https://github.com/WordPress/sqlite-database-integration/pull/215
248
+ */
249
+ define('QM_TESTS', true);
250
+ $wpdb = $GLOBALS['wpdb'] = new Playground_SQLite_Integration_Loader();
251
+
252
+ /**
253
+ * WordPress is capable of using a preloaded global $wpdb. However, if
254
+ * it cannot find the drop-in db.php plugin it still checks whether
255
+ * the mysqli_connect() function exists even though it's not used.
256
+ *
257
+ * What WordPress demands, Playground shall provide.
258
+ */
259
+ `;
260
+ }
261
+ const H = `
262
+ if (function_exists('is_user_logged_in') && is_user_logged_in()) {
263
+ return;
264
+ }
265
+ if (headers_sent()) {
266
+ return;
267
+ }
268
+
269
+ // Legacy auto-login never redirects; it populates $_COOKIE
270
+ // in-process for the current request and relies on
271
+ // setcookie() / wp_set_auth_cookie() to persist across
272
+ // requests via HttpCookieStore.
273
+
274
+ // WP 2.5+
275
+ if (function_exists('wp_set_current_user') && function_exists('wp_set_auth_cookie')) {
276
+ $user = function_exists('get_user_by')
277
+ ? get_user_by('login', $user_name)
278
+ : (function_exists('get_userdatabylogin')
279
+ ? get_userdatabylogin($user_name) : null);
280
+ if (!$user) return;
281
+
282
+ wp_set_current_user($user->ID, $user->user_login);
283
+ // Populate $_COOKIE in-process so auth_redirect() and
284
+ // wp_verify_nonce() see the session for the remainder
285
+ // of this request; wp_set_auth_cookie() also emits
286
+ // Set-Cookie for subsequent requests.
287
+ wp_set_auth_cookie($user->ID);
288
+ if (function_exists('wp_generate_auth_cookie')) {
289
+ $_pg_exp = time() + 172800;
290
+ if (defined('AUTH_COOKIE'))
291
+ $_COOKIE[AUTH_COOKIE] = wp_generate_auth_cookie($user->ID, $_pg_exp, 'auth');
292
+ if (defined('SECURE_AUTH_COOKIE'))
293
+ $_COOKIE[SECURE_AUTH_COOKIE] = wp_generate_auth_cookie($user->ID, $_pg_exp, 'secure_auth');
294
+ if (defined('LOGGED_IN_COOKIE'))
295
+ $_COOKIE[LOGGED_IN_COOKIE] = wp_generate_auth_cookie($user->ID, $_pg_exp, 'logged_in');
296
+ }
297
+ return;
298
+ }
299
+
300
+ // WP 1.5–2.4
301
+ if (defined('USER_COOKIE') && defined('PASS_COOKIE')) {
302
+ $_pg_pass_cookie = md5(md5('password'));
303
+ $_COOKIE[USER_COOKIE] = $user_name;
304
+ $_COOKIE[PASS_COOKIE] = $_pg_pass_cookie;
305
+ if (!headers_sent()) {
306
+ $_pg_exp = time() + 172800;
307
+ setcookie(USER_COOKIE, $user_name, $_pg_exp, '/');
308
+ setcookie(PASS_COOKIE, $_pg_pass_cookie, $_pg_exp, '/');
309
+ }
310
+ $GLOBALS['current_user'] = null;
311
+ if (function_exists('get_currentuserinfo')) {
312
+ get_currentuserinfo();
313
+ }
314
+ return;
315
+ }
316
+
317
+ // WP 1.0–1.2: cookies are usually already set by
318
+ // playground_legacy_set_auth_cookies_early() in env.php,
319
+ // but WP 1.0–1.2 reads its user state from globals (no
320
+ // WP_User), so populate those explicitly here.
321
+ $cookiehash = defined('COOKIEHASH')
322
+ ? COOKIEHASH
323
+ : (isset($GLOBALS['cookiehash']) && $GLOBALS['cookiehash']
324
+ ? $GLOBALS['cookiehash']
325
+ : (function_exists('get_settings')
326
+ ? md5(get_settings('siteurl'))
327
+ : ''));
328
+ if ($cookiehash) {
329
+ $_pg_user_cookie_name = 'wordpressuser_' . $cookiehash;
330
+ $_pg_pass_cookie_name = 'wordpresspass_' . $cookiehash;
331
+ $_pg_pass_cookie_value = md5(md5('password'));
332
+ $_COOKIE[$_pg_user_cookie_name] = $user_name;
333
+ $_COOKIE[$_pg_pass_cookie_name] = $_pg_pass_cookie_value;
334
+ if (!headers_sent()) {
335
+ $_pg_exp = time() + 172800;
336
+ setcookie($_pg_user_cookie_name, $user_name, $_pg_exp, '/');
337
+ setcookie($_pg_pass_cookie_name, $_pg_pass_cookie_value, $_pg_exp, '/');
338
+ }
339
+ if (function_exists('get_userdatabylogin')) {
340
+ $userdata = get_userdatabylogin($user_name);
341
+ if ($userdata) {
342
+ $GLOBALS['user_login'] = $user_name;
343
+ $GLOBALS['userdata'] = $userdata;
344
+ $GLOBALS['user_level'] = isset($userdata->user_level) ? (int) $userdata->user_level : 10;
345
+ $GLOBALS['user_ID'] = $userdata->ID;
346
+ $GLOBALS['user_email'] = isset($userdata->user_email) ? $userdata->user_email : '';
347
+ $GLOBALS['user_url'] = isset($userdata->user_url) ? $userdata->user_url : '';
348
+ $GLOBALS['user_nickname'] = isset($userdata->user_nickname) ? $userdata->user_nickname : $user_name;
349
+ $GLOBALS['user_pass_md5'] = md5(isset($userdata->user_pass) ? $userdata->user_pass : '');
350
+ }
351
+ }
352
+ return;
353
+ }
354
+ `;
355
+ async function B(e) {
356
+ await e.mkdir("/internal/shared/mu-plugins"), await e.writeFile(
357
+ "/internal/shared/auto_prepend_file.php",
358
+ `<?php
359
+ // Polyfill the PHP 4 superglobals WP 1.0–2.5 still reads (removed
360
+ // in PHP 5.4). Bind by reference so later writes to $_COOKIE
361
+ // reach $HTTP_COOKIE_VARS, which WP 1.0's get_currentuserinfo()
362
+ // consults.
363
+ $GLOBALS['HTTP_GET_VARS'] = &$_GET;
364
+ $GLOBALS['HTTP_POST_VARS'] = &$_POST;
365
+ $GLOBALS['HTTP_COOKIE_VARS'] = &$_COOKIE;
366
+ $GLOBALS['HTTP_SERVER_VARS'] = &$_SERVER;
367
+ if (isset($_FILES)) $GLOBALS['HTTP_POST_FILES'] = &$_FILES;
368
+ if (isset($_ENV)) $GLOBALS['HTTP_ENV_VARS'] = &$_ENV;
369
+ if (isset($_SESSION)) $GLOBALS['HTTP_SESSION_VARS'] = &$_SESSION;
370
+ // Top-level names register_globals=On used to expose. WP 1.0
371
+ // reads $PHP_SELF / $REMOTE_ADDR directly instead of $_SERVER.
372
+ if (isset($_SERVER['PHP_SELF'])) $GLOBALS['PHP_SELF'] = $_SERVER['PHP_SELF'];
373
+ if (isset($_SERVER['REMOTE_ADDR'])) $GLOBALS['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
374
+ if (isset($_SERVER['REQUEST_URI'])) $GLOBALS['REQUEST_URI'] = $_SERVER['REQUEST_URI'];
375
+ // Default SERVER_PROTOCOL for scripts invoked outside an HTTP
376
+ // request (e.g. php.run() during boot/fixups) — legacy WP reads
377
+ // it unconditionally in places like wp_redirect().
378
+ if (!isset($_SERVER['SERVER_PROTOCOL'])) {
379
+ $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
380
+ }
381
+ if(file_exists('/internal/shared/consts.json')) {
382
+ $consts = json_decode(file_get_contents('/internal/shared/consts.json'), true);
383
+ if ($consts) {
384
+ foreach ($consts as $const => $value) {
385
+ if (!defined($const) && is_scalar($value)) {
386
+ define($const, $value);
387
+ }
388
+ }
389
+ }
390
+ }
391
+ foreach (glob('/internal/shared/preload/*.php') as $file) {
392
+ require_once $file;
393
+ }
394
+ // Buffer early output so a stray PHP notice doesn't commit the
395
+ // response headers before the auto-login mu-plugin gets a chance
396
+ // to call wp_set_auth_cookie() / setcookie() on the init hook —
397
+ // otherwise nonce validation breaks on POST requests. PHP flushes
398
+ // the buffer at script end so output still reaches the browser.
399
+ ob_start();
400
+ `
401
+ ), await e.writeFile(
402
+ "/internal/shared/preload/env.php",
403
+ `<?php
404
+ // Reads $wp_version from the WordPress install on disk. Falls back
405
+ // to '1.0' so callers can use version_compare() unconditionally.
406
+ function _playground_detect_wp_version() {
407
+ static $version = null;
408
+ if ($version !== null) return $version;
409
+ $doc_root = isset($_SERVER['DOCUMENT_ROOT'])
410
+ ? $_SERVER['DOCUMENT_ROOT'] : '/wordpress';
411
+ $version_path = $doc_root . '/wp-includes/version.php';
412
+ $wp_version = '1.0';
413
+ if (file_exists($version_path)) {
414
+ include $version_path;
415
+ }
416
+ $version = $wp_version;
417
+ return $version;
418
+ }
419
+
420
+ // Returns 'wp10', 'wp12', or 'wp15' based on the WP version on
421
+ // disk — the three $wp_filter shapes apply_filters() understands.
422
+ function _playground_detect_wp_hook_format() {
423
+ static $format = null;
424
+ if ($format !== null) return $format;
425
+ $wp_version = _playground_detect_wp_version();
426
+ if (version_compare($wp_version, '1.5', '>=')) {
427
+ $format = 'wp15';
428
+ } elseif (version_compare($wp_version, '1.2', '>=')) {
429
+ $format = 'wp12';
430
+ } else {
431
+ $format = 'wp10';
432
+ }
433
+ return $format;
434
+ }
435
+
436
+ // Adds filters/actions before WordPress is loaded by writing the
437
+ // $wp_filter shape the target version expects. $function_to_add
438
+ // MUST be a string (no closures).
439
+ function playground_add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
440
+ global $wp_filter;
441
+ $fmt = _playground_detect_wp_hook_format();
442
+ if ($fmt === 'wp10') {
443
+ $wp_filter[$tag][] = $function_to_add;
444
+ } elseif ($fmt === 'wp12') {
445
+ $wp_filter[$tag][$priority][] = $function_to_add;
446
+ } else {
447
+ $wp_filter[$tag][$priority][$function_to_add] = array(
448
+ 'function' => $function_to_add,
449
+ 'accepted_args' => $accepted_args
450
+ );
451
+ }
452
+ }
453
+ function playground_add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
454
+ playground_add_filter( $tag, $function_to_add, $priority, $accepted_args );
455
+ }
456
+
457
+ // Set WP 1.0–2.4 auth cookies before WordPress loads — by the time
458
+ // the init hook fires (and on WP 1.0–1.2 it may not fire at all on
459
+ // the front page) WordPress has already read $_COOKIE. setcookie()
460
+ // also persists them across requests via HttpCookieStore.
461
+ // WP 2.5+ uses the HMAC auth cookie scheme and doesn't read these
462
+ // wordpressuser_/wordpresspass_ cookies at all — bail there so we
463
+ // don't write inert cookies the runtime would have to clean up.
464
+ function playground_legacy_set_auth_cookies_early() {
465
+ if (!defined('PLAYGROUND_AUTO_LOGIN_AS_USER')) return;
466
+ if (isset($_COOKIE['playground_auto_login_already_logged_out'])) return;
467
+ if (version_compare(_playground_detect_wp_version(), '2.5', '>=')) return;
468
+
469
+ foreach ($_COOKIE as $name => $_) {
470
+ if (strncmp($name, 'wordpressuser_', 14) === 0) return;
471
+ }
472
+
473
+ $user_name = PLAYGROUND_AUTO_LOGIN_AS_USER;
474
+ $pass_md5 = md5(md5('password'));
475
+
476
+ // Read siteurl from SQLite so the cookie hash matches what
477
+ // WP 1.0–2.4 derives from get_settings('siteurl').
478
+ $siteurl = null;
479
+ $db_path = defined('DB_DIR') ? DB_DIR . '.ht.sqlite' : '';
480
+ if ($db_path && class_exists('PDO') && file_exists($db_path)) {
481
+ try {
482
+ $pdo = new PDO('sqlite:' . $db_path);
483
+ $stmt = $pdo->query("SELECT option_value FROM wp_options WHERE option_name = 'siteurl' LIMIT 1");
484
+ if ($stmt) $siteurl = $stmt->fetchColumn();
485
+ $pdo = null;
486
+ } catch (Exception $e) {}
487
+ }
488
+ if (!$siteurl && defined('WP_SITEURL')) $siteurl = WP_SITEURL;
489
+ if (!$siteurl) return;
490
+
491
+ $cookiehash = md5($siteurl);
492
+ $user_cookie_name = 'wordpressuser_' . $cookiehash;
493
+ $pass_cookie_name = 'wordpresspass_' . $cookiehash;
494
+ $_COOKIE[$user_cookie_name] = $user_name;
495
+ $_COOKIE[$pass_cookie_name] = $pass_md5;
496
+
497
+ if (!headers_sent()) {
498
+ $exp = time() + 172800;
499
+ setcookie($user_cookie_name, $user_name, $exp, '/');
500
+ setcookie($pass_cookie_name, $pass_md5, $exp, '/');
501
+ }
502
+ }
503
+ playground_legacy_set_auth_cookies_early();
504
+
505
+ // WP < 4.0 emits YEAR(post_date)='2026' AND MONTH(post_date)='4'
506
+ // against MySQL's loose type coercion. The SQLite driver's UDFs
507
+ // return integers and SQLite is strictly typed (4 != '4'), so
508
+ // strip quotes around numeric RHS values to keep both sides ints.
509
+ function playground_fix_sqlite_date_comparisons($query) {
510
+ if (
511
+ stripos($query, 'YEAR') === false &&
512
+ stripos($query, 'MONTH') === false &&
513
+ stripos($query, 'DAY') === false
514
+ ) {
515
+ return $query;
516
+ }
517
+ return preg_replace(
518
+ '/\\b(YEAR|MONTH|DAYOFMONTH|DAY)\\s*\\(([^)]+)\\)\\s*=\\s*\\'(\\d+)\\'/i',
519
+ '$1($2) = $3',
520
+ $query
521
+ );
522
+ }
523
+ playground_add_filter( 'query', 'playground_fix_sqlite_date_comparisons' );
524
+
525
+ // WP 2.2+ checks WP_SITEURL/WP_HOME inside get_option(); WP <2.2
526
+ // doesn't, so backfill the same behaviour via the option filters
527
+ // to keep admin links on the Playground-scoped URL.
528
+ function playground_override_siteurl($value) {
529
+ if (defined('WP_SITEURL')) {
530
+ return WP_SITEURL;
531
+ }
532
+ return $value;
533
+ }
534
+ function playground_override_home($value) {
535
+ if (defined('WP_HOME')) {
536
+ return WP_HOME;
537
+ }
538
+ return $value;
539
+ }
540
+ playground_add_filter( 'option_siteurl', 'playground_override_siteurl' );
541
+ playground_add_filter( 'option_home', 'playground_override_home' );
542
+
543
+ // Load mu-plugins last so customer mu-plugins win — and so they
544
+ // can't depend on muplugins_loaded. WP < 2.8 doesn't fire that
545
+ // action at all, so init -1000 acts as a fallback (the $loaded
546
+ // flag keeps it idempotent).
547
+ playground_add_action( 'muplugins_loaded', 'playground_load_mu_plugins', 0 );
548
+ playground_add_action( 'init', 'playground_load_mu_plugins', -1000 );
549
+ function playground_load_mu_plugins() {
550
+ static $loaded = false;
551
+ if ($loaded) return;
552
+ $loaded = true;
553
+ $mu_plugins_dir = '/internal/shared/mu-plugins';
554
+ if(!is_dir($mu_plugins_dir)){
555
+ return;
556
+ }
557
+ $mu_plugins = glob( $mu_plugins_dir . '/*.php' );
558
+ sort( $mu_plugins );
559
+ global $wp_version;
560
+ $is_legacy_wp = isset($wp_version) && version_compare($wp_version, '2.8', '<');
561
+ foreach ( $mu_plugins as $mu_plugin ) {
562
+ // Loaded separately by the preload lazy loader or db.php.
563
+ if (strpos($mu_plugin, 'sqlite-database-integration') !== false) {
564
+ continue;
565
+ }
566
+ // WP < 2.8 crashes on closures in hooks and lacks
567
+ // site_url() (added 2.6). 1-auto-login.php is written
568
+ // without either, so it's the only mu-plugin we load
569
+ // on legacy WP.
570
+ if ($is_legacy_wp) {
571
+ if (strpos($mu_plugin, '1-auto-login.php') === false) {
572
+ continue;
573
+ }
574
+ }
575
+ require_once $mu_plugin;
576
+ }
577
+
578
+ // PHP 5.x's foreach over $wp_filter['init'] iterates a copy,
579
+ // so add_action() calls made by the mu-plugin we just loaded
580
+ // won't fire on this same init run. Call them directly.
581
+ if ($is_legacy_wp) {
582
+ if (function_exists('playground_auto_login_redirect_target')) {
583
+ playground_auto_login_redirect_target();
584
+ }
585
+ if (function_exists('playground_auto_login')) {
586
+ playground_auto_login();
587
+ }
588
+ }
589
+ }
590
+ `
591
+ ), await e.writeFile(
592
+ "/internal/shared/mu-plugins/1-auto-login.php",
593
+ `<?php
594
+ /**
595
+ * Returns the username to auto-login as, if any.
596
+ * @return string|false
597
+ */
598
+ function playground_get_username_for_auto_login() {
599
+ if ( defined('PLAYGROUND_AUTO_LOGIN_AS_USER') && !isset($_COOKIE['playground_auto_login_already_happened']) ) {
600
+ return PLAYGROUND_AUTO_LOGIN_AS_USER;
601
+ }
602
+ if ( defined('PLAYGROUND_FORCE_AUTO_LOGIN_ENABLED') && isset($_GET['playground_force_auto_login_as_user']) ) {
603
+ return $_GET['playground_force_auto_login_as_user'];
604
+ }
605
+ return false;
606
+ }
607
+
608
+ function playground_auto_login() {
609
+ if (empty($_SERVER['REQUEST_URI'])) {
610
+ return;
611
+ }
612
+ $user_name = playground_get_username_for_auto_login();
613
+ if ( false === $user_name ) {
614
+ return;
615
+ }
616
+ if ((function_exists('wp_doing_ajax') && wp_doing_ajax()) || defined('REST_REQUEST')) {
617
+ return;
618
+ }
619
+ ${H}
620
+ }
621
+ add_action('init', 'playground_auto_login', 1);
622
+
623
+ function playground_auto_login_redirect_target() {
624
+ if(strpos($_SERVER['REQUEST_URI'], '?playground-redirection-handler') !== false) {
625
+ $next = $_GET['next'];
626
+ header('Location: ' . $next, true, 302);
627
+ exit;
628
+ }
629
+ }
630
+ add_action('init', 'playground_auto_login_redirect_target', 1);
631
+
632
+ /**
633
+ * Disable the Site Admin Email Verification Screen for any session started
634
+ * via autologin.
635
+ */
636
+ if (function_exists('add_filter')) {
637
+ add_filter('admin_email_check_interval', 'playground_disable_admin_email_check');
638
+ }
639
+ function playground_disable_admin_email_check($interval) {
640
+ if(false === playground_get_username_for_auto_login()) {
641
+ return 0;
642
+ }
643
+ return $interval;
644
+ }
645
+ `
646
+ ), await S(e), await e.writeFile(
647
+ "/internal/shared/preload/error-handler.php",
648
+ `<?php
649
+ $GLOBALS['_playground_consts'] = array();
650
+ if (file_exists('/internal/shared/consts.json')) {
651
+ $GLOBALS['_playground_consts'] = @json_decode(file_get_contents('/internal/shared/consts.json'), true);
652
+ if (!is_array($GLOBALS['_playground_consts'])) { $GLOBALS['_playground_consts'] = array(); }
653
+ $GLOBALS['_playground_consts'] = array_keys($GLOBALS['_playground_consts']);
654
+ }
655
+ function _playground_error_handler($severity, $message, $file, $line) {
656
+ $playground_consts = $GLOBALS['_playground_consts'];
657
+ ${V}
658
+ return false;
659
+ }
660
+ set_error_handler('_playground_error_handler');`
661
+ );
662
+ }
663
+ const V = `
664
+ // http_api_transports is deprecated since 6.4.0 but Playground's
665
+ // networking layer still registers it for wp_http_supports().
666
+ // @see https://core.trac.wordpress.org/ticket/37708
667
+ if (
668
+ strpos($message, "http_api_transports") !== false &&
669
+ strpos($message, "since version 6.4.0 with no alternative available") !== false
670
+ ) {
671
+ return;
672
+ }
673
+ // Playground predefines constants (SITE_URL, WP_DEBUG, …) that
674
+ // wp-config.php is allowed to redefine; ours take precedence.
675
+ if (strpos($message, "already defined") !== false) {
676
+ foreach($playground_consts as $const) {
677
+ if(strpos($message, "Constant $const already defined") !== false) {
678
+ return;
679
+ }
680
+ }
681
+ }
682
+ // Legacy WP (2.0–3.5) assigns props on uninitialised vars,
683
+ // valid in PHP 4 but E_WARNING since 5.x. Unfixable in core —
684
+ // Playground ships unmodified WordPress releases.
685
+ if (strpos($message, "Creating default object from empty value") !== false) {
686
+ return;
687
+ }
688
+ // WP 2.8's dashboard widget calls get_error_string() on a
689
+ // null SimplePie when feed HTTP requests fail in WASM.
690
+ if (strpos($message, "get_error_string() on null") !== false ||
691
+ strpos($message, "get_error_string() on a non-object") !== false) {
692
+ return;
693
+ }
694
+ // Don't complain about WordPress.org connection errors when
695
+ // the runtime isn't using fetch().
696
+ if (
697
+ (
698
+ ! defined('USE_FETCH_FOR_REQUESTS') ||
699
+ ! USE_FETCH_FOR_REQUESTS
700
+ ) &&
701
+ strpos($message, "WordPress could not establish a secure connection to WordPress.org") !== false)
702
+ {
703
+ return;
704
+ }
705
+ `;
706
+ async function X(e, t) {
707
+ const i = T(e, t);
708
+ if (i === null) return;
709
+ const n = parseFloat(i);
710
+ if (!Number.isFinite(n) || n < 5 || n >= 6.2)
711
+ return;
712
+ const s = _(t, "wp-includes/load.php");
713
+ if (!e.fileExists(s)) return;
714
+ const r = e.readFileAsText(s), a = r.replace(
715
+ "extension_loaded( 'mysqli' )",
716
+ "function_exists( 'mysqli_connect' )"
717
+ );
718
+ a !== r && await e.writeFile(s, a);
719
+ }
720
+ function T(e, t) {
721
+ const i = _(t, "wp-includes/version.php");
722
+ if (!e.fileExists(i)) return null;
723
+ const s = e.readFileAsText(i).match(/\$wp_version\s*=\s*['"]([^'"]+)['"]/);
724
+ return s ? s[1] : null;
725
+ }
726
+ const Y = 22527, L = "E_ALL & ~8192 & ~2048";
727
+ async function K(e, t) {
728
+ await se(e, t), await ae(e, t), await oe(e, t), await ue(e, t), await de(e, t), await Le(e, t), await fe(e, t), await we(e, t), await Z(e, t), await z(e, t);
729
+ const i = T(e, t);
730
+ if (i === null) return;
731
+ const n = parseFloat(i);
732
+ Number.isFinite(n) && (n < 1.2 && (await re(e, t), await ie(e, t)), n < 1.5 && await J(e, t), 1.5 <= n && n < 2 && await ge(e, t), n < 2 && (await ee(e, t), await ce(e, t)), 2.1 <= n && n < 2.3 && await ne(e, t), n < 2.5 && await $e(e, t), n < 2.8 && (await Ee(e, t), await Te(e, t)), 2.9 <= n && n < 3.6 && await j(e, t), 3.3 <= n && n < 3.4 && await te(e, t), n >= 4.7 && await Q(e, t));
733
+ }
734
+ async function Q(e, t) {
735
+ const i = _(t, "wp-content/themes");
736
+ if (e.isDir(i))
737
+ for (const n of e.listFiles(i)) {
738
+ const s = _(i, n, "searchform.php");
739
+ e.fileExists(s) && e.unlink(s);
740
+ }
741
+ }
742
+ async function j(e, t) {
743
+ const i = _(t, "wp-admin/includes/dashboard.php");
744
+ if (e.fileExists(i)) {
745
+ let r = e.readFileAsText(i);
746
+ if (r.includes("function wp_dashboard_primary()") && !r.includes("/* pg_no_rss */")) {
747
+ for (const a of [
748
+ "wp_dashboard_primary",
749
+ "wp_dashboard_secondary",
750
+ "wp_dashboard_plugins"
751
+ ])
752
+ r = r.replace(
753
+ new RegExp(`function ${a}\\(\\)\\s*\\{`),
754
+ `function ${a}() { /* pg_no_rss */ return;`
755
+ );
756
+ await e.writeFile(i, r);
757
+ }
758
+ }
759
+ const n = _(t, "wp-admin/admin.php");
760
+ if (e.fileExists(n)) {
761
+ let r = e.readFileAsText(n);
762
+ r.includes("do_action('admin_init');") && !r.includes("/* pg_admin_init_cleanup */") && (r = r.replace(
763
+ "do_action('admin_init');",
764
+ `/* pg_admin_init_cleanup */
765
+ if (function_exists('remove_action')) {
766
+ @remove_action('admin_init', '_maybe_update_plugins');
767
+ @remove_action('admin_init', '_maybe_update_themes');
768
+ @remove_action('admin_init', '_maybe_update_core');
769
+ @remove_action('admin_init', 'wp_version_check');
770
+ @remove_action('admin_init', 'wp_update_plugins');
771
+ @remove_action('admin_init', 'wp_update_themes');
772
+ }
773
+ do_action('admin_init');`
774
+ ), await e.writeFile(n, r));
775
+ }
776
+ const s = _(
777
+ t,
778
+ "wp-admin/includes/update.php"
779
+ );
780
+ if (e.fileExists(s)) {
781
+ let r = e.readFileAsText(s);
782
+ if (!r.includes("/* pg_admin_no_updates */")) {
783
+ for (const a of [
784
+ "wp_plugin_update_rows",
785
+ "wp_plugin_update_row",
786
+ "wp_theme_update_rows",
787
+ "wp_theme_update_row",
788
+ "wp_update_plugins",
789
+ "wp_update_themes"
790
+ ]) {
791
+ const o = new RegExp(
792
+ `function ${a}\\s*\\([^)]*\\)\\s*\\{`
793
+ );
794
+ o.test(r) && (r = r.replace(
795
+ o,
796
+ (l) => l + " /* pg_admin_no_updates */ return;"
797
+ ));
798
+ }
799
+ await e.writeFile(s, r);
800
+ }
801
+ }
802
+ for (const r of [
803
+ _(t, "wp-includes/SimplePie/File.php"),
804
+ _(t, "wp-includes/class-simplepie.php")
805
+ ]) {
806
+ if (!e.fileExists(r)) continue;
807
+ let a = e.readFileAsText(r);
808
+ a.includes("function SimplePie_File(") && !a.includes("/* pg_no_fetch */") && (a = a.replace(
809
+ /function SimplePie_File\([^)]*\)\s*\{/,
810
+ (o) => o + `
811
+ /* pg_no_fetch */
812
+ $this->error = 'Network requests disabled in Playground';
813
+ $this->success = false;
814
+ return;`
815
+ ), await e.writeFile(r, a));
816
+ }
817
+ }
818
+ async function z(e, t) {
819
+ const i = [
820
+ ["function wp_new_blog_notification", "pg_no_blog_notification"],
821
+ [
822
+ "function wp_install_maybe_enable_pretty_permalinks",
823
+ "pg_no_permalink_check"
824
+ ]
825
+ ], n = [
826
+ _(t, "wp-admin/includes/upgrade.php"),
827
+ _(t, "wp-admin/upgrade-functions.php")
828
+ ];
829
+ for (const s of n) {
830
+ if (!e.fileExists(s)) continue;
831
+ let r = e.readFileAsText(s), a = !1;
832
+ for (const [o, l] of i) {
833
+ if (r.includes(`/* ${l} */`)) continue;
834
+ const c = r.indexOf(o);
835
+ if (c === -1) continue;
836
+ const u = r.indexOf("{", c);
837
+ u !== -1 && (r = r.substring(0, u + 1) + ` /* ${l} */ return;` + r.substring(u + 1), a = !0);
838
+ }
839
+ a && await e.writeFile(s, r);
840
+ }
841
+ }
842
+ async function Z(e, t) {
843
+ const i = _(t, "wp-load.php");
844
+ if (!e.fileExists(i)) return;
845
+ const n = e.readFileAsText(i);
846
+ if (!n.includes("error_reporting(") || n.includes("~8192") && n.includes("~2048")) return;
847
+ const s = n.replace(
848
+ /error_reporting\(([^)]+)\)/g,
849
+ (r, a) => `error_reporting((${a}) & ~8192 & ~2048)`
850
+ );
851
+ await e.writeFile(i, s);
852
+ }
853
+ async function J(e, t) {
854
+ const i = _(t, "wp-admin/menu.php");
855
+ if (e.fileExists(i)) {
856
+ const r = e.readFileAsText(i);
857
+ if (!r.includes("/* pg_wp10_logo_link */")) {
858
+ const a = '<h1 id="wphead"><a href="http://wordpress.org" rel="external">WordPress</a></h1>';
859
+ if (r.includes(a)) {
860
+ const o = r.replace(
861
+ a,
862
+ '<h1 id="wphead"><a href="#" rel="external">WordPress</a></h1> <!-- pg_wp10_logo_link -->'
863
+ );
864
+ o !== r && await e.writeFile(i, o);
865
+ }
866
+ }
867
+ }
868
+ const n = _(
869
+ t,
870
+ "wp-admin/admin-header.php"
871
+ );
872
+ if (e.fileExists(n)) {
873
+ const r = e.readFileAsText(n);
874
+ if (!r.includes("/* pg_wp12_logo_link */")) {
875
+ const a = '<a href="http://wordpress.org" rel="external"', o = "</a>", l = r.indexOf(a);
876
+ if (l !== -1) {
877
+ const c = r.indexOf(o, l);
878
+ if (c !== -1) {
879
+ const u = r.substring(0, l) + '<a href="#">WordPress</a><!-- pg_wp12_logo_link -->' + r.substring(c + o.length);
880
+ u !== r && await e.writeFile(n, u);
881
+ }
882
+ }
883
+ }
884
+ }
885
+ const s = _(
886
+ t,
887
+ "wp-admin/admin-footer.php"
888
+ );
889
+ if (e.fileExists(s)) {
890
+ const r = e.readFileAsText(s);
891
+ if (!r.includes("/* pg_wp10_footer_link */")) {
892
+ const a = r.replace(
893
+ '<a href="http://wordpress.org">WordPress</a>',
894
+ "WordPress<!-- pg_wp10_footer_link -->"
895
+ ).replace(
896
+ '<a href="http://wordpress.org/">WordPress</a>',
897
+ "WordPress<!-- pg_wp10_footer_link -->"
898
+ );
899
+ a !== r && await e.writeFile(s, a);
900
+ }
901
+ }
902
+ }
903
+ async function ee(e, t) {
904
+ const i = _(t, "wp-admin/edit.php");
905
+ if (!e.fileExists(i)) return;
906
+ const n = e.readFileAsText(i);
907
+ if (n.includes("/* pg_wp10_post_title_edit */")) return;
908
+ let s = n;
909
+ const r = '<strong><a href="<?php permalink_link(); ?>" rel="permalink"><?php the_title() ?></a></strong>';
910
+ s.includes(r) && (s = s.replace(
911
+ r,
912
+ '<strong><a href="post.php?action=edit&amp;post=<?php echo $id /* pg_wp10_post_title_edit */ ?>"><?php the_title() ?></a></strong>'
913
+ ));
914
+ const a = '<td><a href="<?php the_permalink(); ?>" rel="permalink">';
915
+ s.includes(a) && (s = s.replace(
916
+ a,
917
+ '<td><a href="post.php?action=edit&amp;post=<?php echo $id /* pg_wp10_post_title_edit */ ?>">'
918
+ ));
919
+ const o = `<td><?php the_title() ?>
920
+ <?php if ('private' == $post->post_status) _e(' - <strong>Private</strong>'); ?></td>`;
921
+ s.includes(o) && (s = s.replace(
922
+ o,
923
+ `<td><a href="post.php?action=edit&amp;post=<?php echo $id /* pg_wp10_post_title_edit */ ?>"><?php the_title() ?></a>
924
+ <?php if ('private' == $post->post_status) _e(' - <strong>Private</strong>'); ?></td>`
925
+ )), s !== n && await e.writeFile(i, s);
926
+ }
927
+ async function te(e, t) {
928
+ const i = _(t, "wp-admin/includes/screen.php");
929
+ if (!e.fileExists(i)) return;
930
+ const n = e.readFileAsText(i);
931
+ if (!n.includes("self::$this->_help_sidebar")) return;
932
+ const s = n.replace(
933
+ /self::\$this->_help_sidebar/g,
934
+ "$this->_help_sidebar"
935
+ );
936
+ s !== n && await e.writeFile(i, s);
937
+ }
938
+ async function ne(e, t) {
939
+ const i = _(t, "wp-admin/plugins.php");
940
+ if (!e.fileExists(i)) return;
941
+ const n = e.readFileAsText(i);
942
+ if (n.includes("/* pg_wp21_active_plugins_array */")) return;
943
+ const s = "$current = get_option('active_plugins');";
944
+ if (!n.includes(s)) return;
945
+ const r = n.replace(
946
+ s,
947
+ s + `
948
+ if (!is_array($current)) $current = array(); /* pg_wp21_active_plugins_array */`
949
+ );
950
+ r !== n && await e.writeFile(i, r);
951
+ }
952
+ async function ie(e, t) {
953
+ const i = _(t, "wp-login.php");
954
+ if (!e.fileExists(i)) return;
955
+ const n = e.readFileAsText(i), s = "AND user_pass = '$password'";
956
+ if (!n.includes(s) || n.includes("pg_wp10_plain_or_md5")) return;
957
+ let r = n.replace(
958
+ s,
959
+ "AND (user_pass = '$password' OR user_pass = MD5('$password')) /* pg_wp10_plain_or_md5 */"
960
+ );
961
+ r = r.replace(
962
+ "$login->user_pass == $password",
963
+ "($login->user_pass == $password || $login->user_pass == md5($password))"
964
+ ), r !== n && await e.writeFile(i, r);
965
+ }
966
+ async function se(e, t) {
967
+ const i = _(t, "wp-includes");
968
+ if (!e.isDir(i)) return;
969
+ const n = _(i, "version.php");
970
+ e.fileExists(n) || await e.writeFile(n, "<?php $wp_version = '1.0';");
971
+ }
972
+ async function re(e, t) {
973
+ const i = _(t, "wp-blog-header.php");
974
+ if (e.fileExists(i)) {
975
+ const s = e.readFileAsText(i), r = `$where .= ' AND (post_status = "publish"';`;
976
+ s.includes(r) && await e.writeFile(
977
+ i,
978
+ s.replace(
979
+ r,
980
+ `$where .= " AND (post_status = 'publish'";`
981
+ )
982
+ );
983
+ }
984
+ const n = _(t, "wp-includes/vars.php");
985
+ if (e.fileExists(n)) {
986
+ const s = e.readFileAsText(n), r = "add_filter('all', 'wptexturize');";
987
+ s.includes(r) && await e.writeFile(
988
+ n,
989
+ s.replace(
990
+ r,
991
+ `// ${r} // Disabled by Playground: mangles SQL literals.`
992
+ )
993
+ );
994
+ }
995
+ }
996
+ async function ae(e, t) {
997
+ const i = _(t, "wp-load.php");
998
+ e.fileExists(i) || await e.writeFile(
999
+ i,
1000
+ `<?php
1001
+ if ( !defined('ABSPATH') ) {
1002
+ define('ABSPATH', dirname(__FILE__) . '/');
1003
+ }
1004
+ require_once(ABSPATH . 'wp-config.php');
1005
+ `
1006
+ );
1007
+ }
1008
+ async function oe(e, t) {
1009
+ const i = _(t, "wp-settings.php");
1010
+ if (!e.fileExists(i)) return;
1011
+ const n = e.readFileAsText(i);
1012
+ let s = n;
1013
+ s = s.replace(
1014
+ /if\s*\(\s*!extension_loaded\('mysql'\)\s*\)\s*\n\s*die/,
1015
+ `if ( false ) // Patched for SQLite
1016
+ die`
1017
+ ), s = s.replace(
1018
+ /error_reporting\(([^)]+)\)/g,
1019
+ (r, a) => a.includes("~8192") && a.includes("~2048") ? r : `error_reporting((${a}) & ~8192 & ~2048)`
1020
+ ), s = s.replace(
1021
+ /set_magic_quotes_runtime\(\s*0\s*\)\s*;/g,
1022
+ "// set_magic_quotes_runtime(0); // Removed"
1023
+ ), s.includes("function_exists('get_magic_quotes_gpc')") || (s = s.replace(
1024
+ /get_magic_quotes_gpc\(\)/g,
1025
+ "(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc())"
1026
+ )), s = s.replace(/=\s*&\s*new\b/g, "= new"), s = s.replace(/\$HTTP_SERVER_VARS/g, "$_SERVER"), !s.includes("WP_CONTENT_DIR") && s.includes("define('WPINC'") && (s = s.replace(
1027
+ /define\('WPINC',\s*'wp-includes'\);/,
1028
+ `define('WPINC', 'wp-includes');
1029
+ if (!defined('WP_CONTENT_DIR')) define('WP_CONTENT_DIR', ABSPATH . 'wp-content');`
1030
+ )), s = s.replace(/unset\(\s*\$wp_filter\s*,/, "unset("), s = _e(s), s = le(s), s !== n && await e.writeFile(i, s);
1031
+ }
1032
+ function _e(e) {
1033
+ const t = e.indexOf("installed WP");
1034
+ if (t === -1) return e;
1035
+ const i = e.lastIndexOf("die(", t);
1036
+ if (i === -1) return e;
1037
+ let n = 0;
1038
+ for (let s = i + 3; s < e.length; s++)
1039
+ if (e[s] === "(") n++;
1040
+ else if (e[s] === ")" && (n--, n === 0)) {
1041
+ let r = s + 1;
1042
+ return e[r] === ";" && r++, e.substring(0, i) + "true; /* die removed by Playground */" + e.substring(r);
1043
+ }
1044
+ return e;
1045
+ }
1046
+ function le(e) {
1047
+ return e.replace(
1048
+ "do_action('init');",
1049
+ `// Remove hooks that make outbound HTTP requests (crash WASM).
1050
+ if (function_exists('remove_action')) {
1051
+ @remove_action('init', 'wp_cron');
1052
+ @remove_action('init', 'wp_version_check');
1053
+ @remove_action('init', 'wp_update_plugins');
1054
+ @remove_action('init', 'wp_update_themes');
1055
+ @remove_action('admin_init', '_maybe_update_plugins');
1056
+ @remove_action('admin_init', '_maybe_update_themes');
1057
+ @remove_action('admin_init', 'wp_version_check');
1058
+ @remove_action('admin_init', 'wp_update_plugins');
1059
+ @remove_action('admin_init', 'wp_update_themes');
1060
+ @remove_action('load-plugins.php', 'wp_update_plugins');
1061
+ @remove_action('load-update.php', 'wp_update_plugins');
1062
+ @remove_action('load-update.php', 'wp_update_themes');
1063
+ @remove_action('load-themes.php', 'wp_update_themes');
1064
+ @remove_action('wp_update_plugins', 'wp_update_plugins');
1065
+ @remove_action('wp_version_check', 'wp_version_check');
1066
+ }
1067
+ if (function_exists('add_filter')) {
1068
+ function _pg_disable_curl() { return false; }
1069
+ function _pg_disable_streams() { return false; }
1070
+ @add_filter('use_curl_transport', '_pg_disable_curl');
1071
+ @add_filter('use_streams_transport', '_pg_disable_streams');
1072
+ @add_filter('use_ftp_transport', '_pg_disable_curl');
1073
+ @add_filter('use_fsockopen_transport', '_pg_disable_streams');
1074
+ }
1075
+ do_action('init');`
1076
+ );
1077
+ }
1078
+ async function ce(e, t) {
1079
+ const i = _(
1080
+ t,
1081
+ "wp-includes/functions.php"
1082
+ );
1083
+ if (!e.fileExists(i)) return;
1084
+ let n = e.readFileAsText(i), s = !1;
1085
+ n.includes("$all_options->{$option->option_name}") && !n.includes("$all_options = new stdClass") && (n = n.replace(
1086
+ "foreach ($options as $option) {",
1087
+ `$all_options = new stdClass;
1088
+ foreach ($options as $option) {`
1089
+ ), s = !0), s && await e.writeFile(i, n);
1090
+ }
1091
+ async function ue(e, t) {
1092
+ const i = _(t, "wp-admin/install.php");
1093
+ if (!e.fileExists(i)) return;
1094
+ const n = e.readFileAsText(i);
1095
+ let s = n;
1096
+ const r = _(t, "wp-admin");
1097
+ s = s.replace(/'\.\.\/(wp-config\.php)'/g, `'${t}/$1'`).replace(/'\.\.\/(wp-load\.php)'/g, `'${t}/$1'`).replace(/'\.\/(upgrade-functions\.php)'/g, `'${r}/$1'`).replace(/'(upgrade-functions\.php)'/g, `'${r}/$1'`).replace(/'\.\/(includes\/upgrade\.php)'/g, `'${r}/$1'`).replace(/'\.\.\/(wp-includes\/[^']+)'/g, `'${t}/$1'`), s = s.replace(/\$HTTP_GET_VARS/g, "$_GET").replace(/\$HTTP_POST_VARS/g, "$_POST"), s !== n && await e.writeFile(i, s);
1098
+ }
1099
+ async function de(e, t) {
1100
+ const i = _(t, "wp-includes/wp-db.php");
1101
+ if (!e.fileExists(i)) return;
1102
+ const n = e.readFileAsText(i);
1103
+ let s = n;
1104
+ s.includes("isset($wpdb)") || (s = s.replace(
1105
+ "$wpdb = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);",
1106
+ "if ( !isset($wpdb) ) { $wpdb = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST); }"
1107
+ )), s.includes("db_connect") || (s = s.replace(
1108
+ /\$this->dbh\s*=\s*@mysql_connect\(\$dbhost\s*,\s*\$dbuser\s*,\s*\$dbpassword(?:\s*,\s*true)?\);/,
1109
+ 'if (method_exists($this, "db_connect")) { $this->dbname = $dbname; $this->db_connect(); } else { $this->dbh = @mysql_connect($dbhost, $dbuser, $dbpassword); }'
1110
+ )), s = pe(s), s !== n && await e.writeFile(i, s);
1111
+ }
1112
+ function pe(e) {
1113
+ const t = [];
1114
+ if (e.includes("function set_prefix") || t.push(`
1115
+ function set_prefix($prefix) {
1116
+ $this->prefix = $prefix;
1117
+ $tables = array('posts', 'users', 'categories', 'post2cat', 'comments', 'link2cat', 'links', 'options', 'postmeta', 'usermeta', 'terms', 'term_taxonomy', 'term_relationships');
1118
+ foreach ($tables as $t) {
1119
+ $this->$t = $prefix . $t;
1120
+ }
1121
+ return $prefix;
1122
+ }`), e.includes("function timer_start") || t.push(`
1123
+ function timer_start() {
1124
+ $this->time_start = microtime(true);
1125
+ return true;
1126
+ }`), e.includes("function timer_stop") || t.push(`
1127
+ function timer_stop() {
1128
+ return microtime(true) - $this->time_start;
1129
+ }`), e.includes("function init_charset") || t.push(`
1130
+ function init_charset() {
1131
+ if (defined('DB_CHARSET')) $this->charset = DB_CHARSET;
1132
+ if (defined('DB_COLLATE')) $this->collate = DB_COLLATE;
1133
+ }`), e.includes("function bail") || t.push(`
1134
+ function bail($message, $error_code = '500') {
1135
+ die($message);
1136
+ }`), e.includes("function check_connection") || t.push(`
1137
+ function check_connection($allow_bail = true) {
1138
+ return true;
1139
+ }`), t.length === 0) return e;
1140
+ const i = e.match(
1141
+ /^(\s*})\s*\n+(\$wpdb|\?>\s*$|if\s*\(\s*!\s*isset\(\s*\$wpdb\s*\))/m
1142
+ );
1143
+ if (!i || i.index === void 0) return e;
1144
+ const n = `
1145
+ // Polyfills added by WordPress Playground.
1146
+ ` + t.join(`
1147
+ `) + `
1148
+
1149
+ `;
1150
+ return e.substring(0, i.index) + n + e.substring(i.index);
1151
+ }
1152
+ async function fe(e, t) {
1153
+ const i = (a) => {
1154
+ let o = a, l = 0;
1155
+ for (; o.startsWith("../"); )
1156
+ l++, o = o.slice(3);
1157
+ for (; o.startsWith("./"); )
1158
+ o = o.slice(2);
1159
+ let c = "dirname(__FILE__)";
1160
+ for (let u = 0; u < l; u++)
1161
+ c = `dirname(${c})`;
1162
+ return `${c} . '/${o}'`;
1163
+ }, n = _(t, "wp-admin");
1164
+ if (e.isDir(n))
1165
+ for (const a of e.listFiles(n)) {
1166
+ if (!a.endsWith(".php")) continue;
1167
+ const o = _(n, a), l = e.readFileAsText(o), c = l.replace(
1168
+ /((?:require|include)(?:_once)?)\s*\(\s*(['"])(\.\.\/[^'"]+)\2\s*\)/g,
1169
+ (u, d, f, p) => `${d}(${i(p)})`
1170
+ ).replace(
1171
+ /((?:require|include)(?:_once)?)\s*\(\s*(['"])(\.\/[^'"]+)\2\s*\)/g,
1172
+ (u, d, f, p) => `${d}(${i(p)})`
1173
+ ).replace(
1174
+ /((?:require|include)(?:_once)?)\s*\(\s*(['"])([a-z][\w-]*\.php)\2\s*\)/g,
1175
+ (u, d, f, p) => `${d}(${i(p)})`
1176
+ ).replace(
1177
+ /((?:require|include)(?:_once)?)\s+(['"])(\.\.\/[^'"]+)\2/g,
1178
+ (u, d, f, p) => `${d}(${i(p)})`
1179
+ ).replace(
1180
+ /((?:require|include)(?:_once)?)\s+(['"])(\.\/[^'"]+)\2/g,
1181
+ (u, d, f, p) => `${d}(${i(p)})`
1182
+ ).replace(
1183
+ /((?:require|include)(?:_once)?)\s+(['"])([a-z][\w-]*\.php)\2/g,
1184
+ (u, d, f, p) => `${d}(${i(p)})`
1185
+ ).replace(/ABSPATH\s*\.\s*'\/wp-/g, "ABSPATH . 'wp-");
1186
+ c !== l && await e.writeFile(o, c);
1187
+ }
1188
+ const s = _(t, "wp-admin/index.php");
1189
+ if (e.fileExists(s)) {
1190
+ let a = e.readFileAsText(s);
1191
+ a.includes("get_settings('siteurl')") && (a = a.replace(
1192
+ /get_settings\('siteurl'\)\s*\.\s*'\/wp-admin\//g,
1193
+ "'"
1194
+ ), await e.writeFile(s, a));
1195
+ }
1196
+ const r = _(t, "wp-admin/menu.php");
1197
+ if (e.fileExists(r)) {
1198
+ const a = e.readFileAsText(r), o = "file('./menu.txt')";
1199
+ a.includes(o) && await e.writeFile(
1200
+ r,
1201
+ a.replace(o, "file(dirname(__FILE__) . '/menu.txt')")
1202
+ );
1203
+ }
1204
+ }
1205
+ async function $e(e, t) {
1206
+ const i = _(
1207
+ t,
1208
+ "wp-admin/admin-functions.php"
1209
+ );
1210
+ if (!e.fileExists(i)) return;
1211
+ const n = e.readFileAsText(i);
1212
+ if (!n.includes("function check_admin_referer()") || !n.includes("$_SERVER['HTTP_REFERER']"))
1213
+ return;
1214
+ const s = he(
1215
+ n,
1216
+ "check_admin_referer",
1217
+ `
1218
+ do_action('check_admin_referer', '');
1219
+ `
1220
+ );
1221
+ s !== n && await e.writeFile(i, s);
1222
+ }
1223
+ function he(e, t, i) {
1224
+ const n = `function ${t}()`, s = e.indexOf(n);
1225
+ if (s === -1) return e;
1226
+ const r = e.indexOf("{", s + n.length);
1227
+ if (r === -1) return e;
1228
+ let a = 1;
1229
+ for (let o = r + 1; o < e.length; o++) {
1230
+ const l = e[o];
1231
+ if (l === "{") a++;
1232
+ else if (l === "}" && (a--, a === 0))
1233
+ return e.substring(0, r + 1) + i + e.substring(o);
1234
+ }
1235
+ return e;
1236
+ }
1237
+ async function ge(e, t) {
1238
+ const i = _(t, "wp-admin/index.php");
1239
+ if (e.fileExists(i)) {
1240
+ const n = e.readFileAsText(i), s = n.replace(/AND post_date_gmt < '\$today'/, "");
1241
+ s !== n && await e.writeFile(i, s);
1242
+ }
1243
+ await me(e, t);
1244
+ }
1245
+ async function me(e, t) {
1246
+ const i = _(t, "wp-includes/rss-functions.php");
1247
+ if (!e.fileExists(i)) return;
1248
+ let n = e.readFileAsText(i);
1249
+ !/^\s*error\s*\(/m.test(n) || /^function\s+error\s*\(/m.test(n) || (n = n.replace(
1250
+ /^(<\?php\s*)/,
1251
+ `$1
1252
+ if (!function_exists('error')) {
1253
+ function error($msg = '', $lvl = E_USER_WARNING) {
1254
+ if (defined('MAGPIE_DEBUG') && MAGPIE_DEBUG) {
1255
+ trigger_error($msg, $lvl);
1256
+ }
1257
+ }
1258
+ }
1259
+ `
1260
+ ), await e.writeFile(i, n));
1261
+ }
1262
+ async function we(e, t) {
1263
+ const i = _(t, "wp-login.php");
1264
+ if (!e.fileExists(i)) return;
1265
+ let n = e.readFileAsText(i), s = !1;
1266
+ for (const r of ["log", "pwd"]) {
1267
+ const a = new RegExp(
1268
+ `(\\bname=(['"])${r}\\2)(?![^>]*data-1p-ignore)`
1269
+ );
1270
+ a.test(n) && (n = n.replace(a, "$1 data-1p-ignore"), s = !0);
1271
+ }
1272
+ s && await e.writeFile(i, n);
1273
+ }
1274
+ async function Ee(e, t) {
1275
+ const i = _(t, "wp-admin/admin.php");
1276
+ if (e.fileExists(i)) {
1277
+ const s = e.readFileAsText(i);
1278
+ if (s.includes("auth_redirect()")) {
1279
+ const r = `
1280
+ // Playground: populate auth cookies and force admin user before auth_redirect.
1281
+ if (defined('PLAYGROUND_AUTO_LOGIN_AS_USER')) {
1282
+ if (function_exists('is_user_logged_in') && is_user_logged_in()) {
1283
+ // On WP < 4.0, wp_set_auth_cookie() does not update $_COOKIE
1284
+ // in-process — auth_redirect() reads $_COOKIE, so re-emit.
1285
+ if (function_exists('wp_generate_auth_cookie') && defined('LOGGED_IN_COOKIE') && empty($_COOKIE[LOGGED_IN_COOKIE])) {
1286
+ $_pg_uid = wp_get_current_user()->ID;
1287
+ $_pg_exp = time() + 172800;
1288
+ $_COOKIE[AUTH_COOKIE] = wp_generate_auth_cookie($_pg_uid, $_pg_exp, 'auth');
1289
+ if (defined('SECURE_AUTH_COOKIE'))
1290
+ $_COOKIE[SECURE_AUTH_COOKIE] = wp_generate_auth_cookie($_pg_uid, $_pg_exp, 'secure_auth');
1291
+ $_COOKIE[LOGGED_IN_COOKIE] = wp_generate_auth_cookie($_pg_uid, $_pg_exp, 'logged_in');
1292
+ }
1293
+ } else {
1294
+ ${x("PLAYGROUND_AUTO_LOGIN_AS_USER")}
1295
+ // WP 2.0-2.4: kses_init() runs during do_action('init') inside
1296
+ // wp-settings.php and caches $current_user as WP_User(0) when
1297
+ // no cookies were set yet. Reset and re-evaluate so capability
1298
+ // checks see the user we just authenticated.
1299
+ if (!function_exists('wp_generate_auth_cookie')) {
1300
+ $GLOBALS['current_user'] = null;
1301
+ if (function_exists('get_currentuserinfo')) {
1302
+ get_currentuserinfo();
1303
+ }
1304
+ }
1305
+ }
1306
+ // Force admin caps in-memory: if populate_roles() never ran
1307
+ // (e.g. WP 2.0, or WP 2.5 installs that crashed before writing
1308
+ // roles), the user has no caps and every current_user_can() fails.
1309
+ $_pg_cu = isset($GLOBALS['current_user']) ? $GLOBALS['current_user'] : null;
1310
+ if ($_pg_cu && isset($_pg_cu->ID) && $_pg_cu->ID > 0 && empty($_pg_cu->allcaps['read'])) {
1311
+ // Respect a DB-stored user_level so a blueprint that auto-logs
1312
+ // in as a lower-privilege user doesn't silently get level 10.
1313
+ $_pg_db_level = isset($_pg_cu->user_level)
1314
+ ? (int) $_pg_cu->user_level
1315
+ : null;
1316
+ if ($_pg_db_level === null && isset($_pg_user) && $_pg_user) {
1317
+ $_pg_db_level = isset($_pg_user->user_level)
1318
+ ? (int) $_pg_user->user_level
1319
+ : null;
1320
+ }
1321
+ $_pg_cu->user_level = $_pg_db_level !== null ? $_pg_db_level : 10;
1322
+ $_pg_effective_level = $_pg_cu->user_level;
1323
+ $_pg_caps = array('read');
1324
+ for ($_pg_i = 0; $_pg_i <= $_pg_effective_level; $_pg_i++) {
1325
+ $_pg_caps[] = 'level_' . $_pg_i;
1326
+ }
1327
+ if ($_pg_effective_level >= 10) {
1328
+ $_pg_caps = array_merge($_pg_caps, array(
1329
+ 'switch_themes','edit_themes','activate_plugins',
1330
+ 'edit_plugins','edit_users','edit_files','manage_options',
1331
+ 'moderate_comments','manage_categories','manage_links',
1332
+ 'upload_files','import','unfiltered_html','edit_posts',
1333
+ 'edit_others_posts','edit_published_posts','publish_posts',
1334
+ 'edit_pages'));
1335
+ }
1336
+ foreach ($_pg_caps as $_pg_c) {
1337
+ $_pg_cu->allcaps[$_pg_c] = true;
1338
+ }
1339
+ if ($_pg_effective_level >= 10) {
1340
+ $_pg_cu->caps = array('administrator' => true);
1341
+ }
1342
+ }
1343
+ }
1344
+ `, a = s.replace(
1345
+ "auth_redirect();",
1346
+ r + "auth_redirect();"
1347
+ );
1348
+ a !== s && await e.writeFile(i, a);
1349
+ }
1350
+ }
1351
+ const n = _(t, "wp-admin/auth.php");
1352
+ if (e.fileExists(n)) {
1353
+ const s = e.readFileAsText(n);
1354
+ if (s.includes("$cookiehash") && !s.includes("Playground: bypass auth")) {
1355
+ const r = `<?php
1356
+ require_once(ABSPATH . 'wp-config.php');
1357
+ // Playground: bypass auth and manually populate user globals.
1358
+ global $user_login, $userdata, $user_level, $user_ID,
1359
+ $user_nickname, $user_email, $user_url, $user_pass_md5, $cookiehash;
1360
+ $__pg_user_login = defined('PLAYGROUND_AUTO_LOGIN_AS_USER')
1361
+ ? PLAYGROUND_AUTO_LOGIN_AS_USER
1362
+ : 'admin';
1363
+ $__pg_cookiehash = defined('COOKIEHASH')
1364
+ ? COOKIEHASH
1365
+ : (isset($cookiehash) && $cookiehash
1366
+ ? $cookiehash
1367
+ : md5(function_exists('get_settings') ? get_settings('siteurl') : ''));
1368
+ if ($__pg_cookiehash) {
1369
+ $_COOKIE['wordpressuser_' . $__pg_cookiehash] = $__pg_user_login;
1370
+ }
1371
+ if (function_exists('get_userdatabylogin')) {
1372
+ $__pg_userdata = get_userdatabylogin($__pg_user_login);
1373
+ if ($__pg_userdata) {
1374
+ $user_login = $__pg_user_login;
1375
+ $userdata = $__pg_userdata;
1376
+ $user_level = isset($__pg_userdata->user_level)
1377
+ ? (int) $__pg_userdata->user_level
1378
+ : 10;
1379
+ $user_ID = $__pg_userdata->ID;
1380
+ $user_nickname = isset($__pg_userdata->user_nickname)
1381
+ ? $__pg_userdata->user_nickname
1382
+ : $__pg_user_login;
1383
+ $user_email = isset($__pg_userdata->user_email)
1384
+ ? $__pg_userdata->user_email
1385
+ : '';
1386
+ $user_url = isset($__pg_userdata->user_url)
1387
+ ? $__pg_userdata->user_url
1388
+ : '';
1389
+ $user_pass_md5 = md5(
1390
+ isset($__pg_userdata->user_pass) ? $__pg_userdata->user_pass : ''
1391
+ );
1392
+ }
1393
+ }
1394
+ ?>`;
1395
+ r !== s && await e.writeFile(n, r);
1396
+ }
1397
+ }
1398
+ }
1399
+ async function Te(e, t) {
1400
+ const i = _(t, "wp-admin/admin-ajax.php");
1401
+ if (!e.fileExists(i)) return;
1402
+ let n = e.readFileAsText(i);
1403
+ if (!n.includes("is_user_logged_in")) return;
1404
+ const s = `
1405
+ // Playground: authenticate admin user for AJAX requests on WP < 2.8.
1406
+ if (defined('PLAYGROUND_AUTO_LOGIN_AS_USER')) {
1407
+ ${x("PLAYGROUND_AUTO_LOGIN_AS_USER")}
1408
+ }
1409
+ `;
1410
+ n = n.replace(
1411
+ /if\s*\(\s*!\s*is_user_logged_in\(\)\s*\)/,
1412
+ s + "if ( !is_user_logged_in() )"
1413
+ ), await e.writeFile(i, n);
1414
+ }
1415
+ function x(e) {
1416
+ return `
1417
+ $_pg_user = null;
1418
+ if (function_exists('wp_generate_auth_cookie')) {
1419
+ $_pg_user = function_exists('get_user_by')
1420
+ ? get_user_by('login', ${e})
1421
+ : (function_exists('get_userdatabylogin')
1422
+ ? get_userdatabylogin(${e}) : null);
1423
+ if ($_pg_user) {
1424
+ wp_set_current_user($_pg_user->ID, $_pg_user->user_login);
1425
+ $_pg_exp = time() + 172800;
1426
+ if (defined('AUTH_COOKIE'))
1427
+ $_COOKIE[AUTH_COOKIE] = wp_generate_auth_cookie($_pg_user->ID, $_pg_exp, 'auth');
1428
+ if (defined('SECURE_AUTH_COOKIE'))
1429
+ $_COOKIE[SECURE_AUTH_COOKIE] = wp_generate_auth_cookie($_pg_user->ID, $_pg_exp, 'secure_auth');
1430
+ if (defined('LOGGED_IN_COOKIE'))
1431
+ $_COOKIE[LOGGED_IN_COOKIE] = wp_generate_auth_cookie($_pg_user->ID, $_pg_exp, 'logged_in');
1432
+ }
1433
+ }
1434
+ `;
1435
+ }
1436
+ async function Le(e, t) {
1437
+ const i = T(e, t);
1438
+ if (i === null) return;
1439
+ const n = parseFloat(i);
1440
+ if (!Number.isFinite(n) || n >= 3.3) return;
1441
+ const s = _(
1442
+ t,
1443
+ "wp-admin/includes/schema.php"
1444
+ );
1445
+ if (!e.fileExists(s)) return;
1446
+ const r = e.readFileAsText(s);
1447
+ /\$wp_queries\s*=\s*"CREATE TABLE/.test(r) && !r.includes("function wp_get_db_schema") && await ye(e, t, s, r);
1448
+ }
1449
+ async function ye(e, t, i, n) {
1450
+ const s = n.match(/\$wp_queries\s*=\s*"CREATE TABLE/);
1451
+ if (!s || s.index === void 0)
1452
+ return;
1453
+ const r = s.index, a = '";', o = n.indexOf(a, r);
1454
+ if (o === -1)
1455
+ return;
1456
+ const l = o + a.length, u = `function wp_get_db_schema( $scope = 'all', $blog_id = null ) {
1457
+ global $wpdb, $wp_queries, $charset_collate;
1458
+ $charset_collate = '';
1459
+ if ( ! empty($wpdb->charset) )
1460
+ $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
1461
+ if ( ! empty($wpdb->collate) )
1462
+ $charset_collate .= " COLLATE $wpdb->collate";
1463
+ ${n.substring(r, l)}
1464
+ return $wp_queries;
1465
+ }`, d = n.substring(0, r) + u + n.substring(l);
1466
+ await e.writeFile(i, d);
1467
+ const f = _(
1468
+ t,
1469
+ "wp-admin/includes/upgrade.php"
1470
+ );
1471
+ if (e.fileExists(f)) {
1472
+ const p = e.readFileAsText(f), y = p.replace(
1473
+ /(\$alterations\s*=\s*dbDelta\(\s*\$wp_queries\s*\))/g,
1474
+ "if ( function_exists('wp_get_db_schema') ) { $wp_queries = wp_get_db_schema(); } $1"
1475
+ );
1476
+ y !== p && await e.writeFile(f, y);
1477
+ }
1478
+ }
1479
+ function be() {
1480
+ return `<?php
1481
+ // @playground-managed — Playground-generated db.php.
1482
+ // WP < 3.0 loads only db.php and skips wp-db.php, so we pull
1483
+ // in the wpdb class definition explicitly.
1484
+ if (defined('ABSPATH') && defined('WPINC') && !class_exists('wpdb', false)) {
1485
+ require_once(ABSPATH . WPINC . '/wp-db.php');
1486
+ }
1487
+ // Old wpdb (WP < 3.0) has no db_connect() and calls mysql_connect()
1488
+ // inline, so the SQLite driver never gets a chance to attach. Load
1489
+ // the integration here and reinitialise to swap the dbh in place.
1490
+ if (
1491
+ class_exists('wpdb', false) &&
1492
+ isset($GLOBALS['wpdb']) &&
1493
+ !($GLOBALS['wpdb'] instanceof wpdb) &&
1494
+ !method_exists('wpdb', 'db_connect') &&
1495
+ file_exists('/internal/shared/mu-plugins/sqlite-database-integration.php')
1496
+ ) {
1497
+ require_once '/internal/shared/mu-plugins/sqlite-database-integration.php';
1498
+ if (
1499
+ isset($GLOBALS['wpdb']) &&
1500
+ $GLOBALS['wpdb'] instanceof wpdb &&
1501
+ method_exists($GLOBALS['wpdb'], 'reinitialize_sqlite')
1502
+ ) {
1503
+ $GLOBALS['wpdb']->reinitialize_sqlite();
1504
+ }
1505
+ }
1506
+ // Remaining mysqli_* stubs not covered by the 0-sqlite.php preload.
1507
+ // WP 4.x's extension_loaded('mysqli') check expects these to exist.
1508
+ if (!function_exists('mysqli_real_connect')) {
1509
+ function mysqli_real_connect() { return true; }
1510
+ }
1511
+ if (!function_exists('mysqli_error')) {
1512
+ function mysqli_error() { return ''; }
1513
+ }
1514
+ if (!function_exists('mysqli_errno')) {
1515
+ function mysqli_errno() { return 0; }
1516
+ }
1517
+ if (!function_exists('mysqli_query')) {
1518
+ function mysqli_query() { return false; }
1519
+ }
1520
+ if (!function_exists('mysqli_set_charset')) {
1521
+ function mysqli_set_charset() { return true; }
1522
+ }
1523
+ if (!function_exists('mysqli_select_db')) {
1524
+ function mysqli_select_db() { return true; }
1525
+ }
1526
+ if (!function_exists('mysqli_close')) {
1527
+ function mysqli_close() { return true; }
1528
+ }
1529
+ `;
1530
+ }
1531
+ async function Oe(e, t) {
1532
+ let i = null;
1533
+ const n = _(e.documentRoot, "wp-includes/version.php");
1534
+ if (e.fileExists(n)) {
1535
+ const r = e.readFileAsText(n).match(/\$wp_version\s*=\s*['"]([^'"]+)['"]/);
1536
+ r && (i = r[1]);
1537
+ }
1538
+ const s = i !== null && parseFloat(i) < 3.5;
1539
+ try {
1540
+ await e.run({
1541
+ code: `<?php
1542
+ // WP_INSTALLING bypasses WP 1.x's "not installed" die() in wp-settings.php.
1543
+ define('WP_INSTALLING', true);
1544
+ error_reporting(${L});
1545
+ ini_set('display_errors', '0');
1546
+ ob_start();
1547
+ $_pg_db_path = getenv('DOCUMENT_ROOT') . '/wp-content/database/.ht.sqlite';
1548
+ if (!file_exists($_pg_db_path)) { exit; }
1549
+ $_pg_pdo = new PDO('sqlite:' . $_pg_db_path);
1550
+ $_pg_check = $_pg_pdo->query("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='wp_users'")->fetchColumn();
1551
+ $_pg_pdo = null;
1552
+ if (!$_pg_check) { exit; }
1553
+ $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
1554
+ if (!file_exists($wp_load)) { exit; }
1555
+ require $wp_load;
1556
+ ob_clean();
1557
+ global $wpdb;
1558
+ if (!isset($wpdb) || !method_exists($wpdb, 'query')) { exit; }
1559
+
1560
+ // Persist the scoped siteurl/home to the DB so parse_request()
1561
+ // strips the scope prefix from REQUEST_URI. Filters alone
1562
+ // (env.php) aren't enough on WP < 2.2.
1563
+ $_pg_opts = !empty($wpdb->options) ? $wpdb->options : $GLOBALS['table_prefix'] . 'options';
1564
+ try {
1565
+ $_pg_url = getenv('PLAYGROUND_SITE_URL');
1566
+ if ($_pg_url) {
1567
+ $_pg_current = $wpdb->get_var("SELECT option_value FROM {$_pg_opts} WHERE option_name = 'siteurl'");
1568
+ if ($_pg_current !== $_pg_url) {
1569
+ $wpdb->query("UPDATE {$_pg_opts} SET option_value = '{$_pg_url}' WHERE option_name = 'siteurl'");
1570
+ $wpdb->query("UPDATE {$_pg_opts} SET option_value = '{$_pg_url}' WHERE option_name = 'home'");
1571
+ }
1572
+ }
1573
+ } catch (Exception $e) {}
1574
+
1575
+ // $wpdb->users exists on WP 1.5+; older WP needs the prefix.
1576
+ $users_table = !empty($wpdb->users) ? $wpdb->users : $GLOBALS['table_prefix'] . 'users';
1577
+
1578
+ // WP 1.0/1.2 installers often leave the users table or admin row missing.
1579
+ $wpdb->query("CREATE TABLE IF NOT EXISTS {$users_table} (
1580
+ ID int(10) unsigned NOT NULL auto_increment,
1581
+ user_login varchar(20) NOT NULL default '',
1582
+ user_pass varchar(64) NOT NULL default '',
1583
+ user_firstname varchar(50) NOT NULL default '',
1584
+ user_lastname varchar(50) NOT NULL default '',
1585
+ user_nickname varchar(50) NOT NULL default '',
1586
+ user_icq int(10) unsigned NOT NULL default '0',
1587
+ user_email varchar(100) NOT NULL default '',
1588
+ user_url varchar(100) NOT NULL default '',
1589
+ user_ip varchar(15) NOT NULL default '',
1590
+ user_domain varchar(200) NOT NULL default '',
1591
+ user_browser varchar(200) NOT NULL default '',
1592
+ dateYMDhour datetime NOT NULL default '0000-00-00 00:00:00',
1593
+ user_level int(2) unsigned NOT NULL default '0',
1594
+ user_aim varchar(50) NOT NULL default '',
1595
+ user_msn varchar(100) NOT NULL default '',
1596
+ user_yim varchar(50) NOT NULL default '',
1597
+ user_idmode varchar(20) NOT NULL default '',
1598
+ PRIMARY KEY (ID),
1599
+ UNIQUE KEY user_login (user_login)
1600
+ )");
1601
+ if (!$wpdb->get_var("SELECT COUNT(*) FROM {$users_table}")) {
1602
+ $now = date('Y-m-d H:i:s');
1603
+ $wpdb->query(
1604
+ "INSERT INTO {$users_table} (ID, user_login, user_pass, user_email, user_level, dateYMDhour, user_nickname) " .
1605
+ "VALUES (1, 'admin', MD5('password'), 'admin@localhost.com', 10, '{$now}', 'admin')"
1606
+ );
1607
+ }
1608
+ $wpdb->query(
1609
+ "UPDATE {$users_table} SET user_pass = MD5('password') WHERE user_login = 'admin'"
1610
+ );
1611
+
1612
+ // populate_roles() can fail on SQLite; seed the admin role and caps directly.
1613
+ $p = $GLOBALS['table_prefix'];
1614
+ $roles_key = $p . 'user_roles';
1615
+ try {
1616
+ $has_roles = $wpdb->get_var(
1617
+ "SELECT COUNT(*) FROM {$p}options WHERE option_name = '{$roles_key}'"
1618
+ );
1619
+ } catch (Exception $e) {
1620
+ $has_roles = 0;
1621
+ }
1622
+ if (!$has_roles) {
1623
+ $roles = array('administrator' => array(
1624
+ 'name' => 'Administrator',
1625
+ 'capabilities' => array(
1626
+ 'switch_themes'=>true, 'edit_themes'=>true,
1627
+ 'activate_plugins'=>true, 'edit_plugins'=>true,
1628
+ 'edit_users'=>true, 'edit_files'=>true,
1629
+ 'manage_options'=>true, 'moderate_comments'=>true,
1630
+ 'manage_categories'=>true, 'manage_links'=>true,
1631
+ 'upload_files'=>true, 'import'=>true,
1632
+ 'unfiltered_html'=>true, 'edit_posts'=>true,
1633
+ 'edit_others_posts'=>true, 'edit_published_posts'=>true,
1634
+ 'publish_posts'=>true, 'edit_pages'=>true,
1635
+ 'read'=>true, 'level_10'=>true, 'level_9'=>true,
1636
+ 'level_8'=>true, 'level_7'=>true, 'level_6'=>true,
1637
+ 'level_5'=>true, 'level_4'=>true, 'level_3'=>true,
1638
+ 'level_2'=>true, 'level_1'=>true, 'level_0'=>true,
1639
+ 'edit_others_pages'=>true, 'edit_published_pages'=>true,
1640
+ 'publish_pages'=>true, 'delete_pages'=>true,
1641
+ 'delete_others_pages'=>true, 'delete_published_pages'=>true,
1642
+ 'delete_posts'=>true, 'delete_others_posts'=>true,
1643
+ 'delete_published_posts'=>true, 'delete_private_posts'=>true,
1644
+ 'edit_private_posts'=>true, 'read_private_posts'=>true,
1645
+ 'delete_private_pages'=>true, 'edit_private_pages'=>true,
1646
+ 'read_private_pages'=>true,
1647
+ )
1648
+ ));
1649
+ $wpdb->query("INSERT INTO {$p}options (option_name, option_value, autoload) VALUES ('{$roles_key}', '" . addslashes(serialize($roles)) . "', 'yes')");
1650
+ }
1651
+ $um = isset($wpdb->usermeta) ? $wpdb->usermeta : $p . 'usermeta';
1652
+ try {
1653
+ $has_cap = $wpdb->get_var("SELECT COUNT(*) FROM {$um} WHERE user_id=1 AND meta_key='{$p}capabilities'");
1654
+ if (!$has_cap) {
1655
+ $cap_val = addslashes(serialize(array('administrator' => true)));
1656
+ $wpdb->query("INSERT INTO {$um} (user_id, meta_key, meta_value) VALUES (1, '{$p}capabilities', '{$cap_val}')");
1657
+ }
1658
+ $has_level = $wpdb->get_var("SELECT COUNT(*) FROM {$um} WHERE user_id=1 AND meta_key='{$p}user_level'");
1659
+ if (!$has_level) {
1660
+ $wpdb->query("INSERT INTO {$um} (user_id, meta_key, meta_value) VALUES (1, '{$p}user_level', '10')");
1661
+ }
1662
+ } catch (Exception $e) {}
1663
+
1664
+ // Seed default content when the install left the posts table empty.
1665
+ $posts_table = !empty($wpdb->posts) ? $wpdb->posts : $GLOBALS['table_prefix'] . 'posts';
1666
+ $has_posts = false;
1667
+ try { $has_posts = (bool)$wpdb->get_var("SELECT COUNT(*) FROM {$posts_table}"); } catch (Exception $e) {}
1668
+ if (!$has_posts) {
1669
+ $now = date('Y-m-d H:i:s');
1670
+ $now_gmt = gmdate('Y-m-d H:i:s');
1671
+ if (isset($wpdb->categories)) {
1672
+ $wpdb->query("INSERT INTO {$wpdb->categories} (cat_ID, cat_name, category_nicename, category_description, category_parent) VALUES (1, 'Uncategorized', 'uncategorized', '', 0)");
1673
+ }
1674
+ // Columns common to WP 1.0+.
1675
+ $wpdb->query("INSERT INTO {$posts_table} (ID, post_author, post_date, post_date_gmt, post_content, post_title, post_excerpt, post_status, comment_status, ping_status, post_password, post_name, to_ping, pinged, post_modified, post_modified_gmt, post_content_filtered) VALUES (1, 1, '{$now}', '{$now_gmt}', 'Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!', 'Hello world!', '', 'publish', 'open', 'open', '', 'hello-world', '', '', '{$now}', '{$now_gmt}', '')");
1676
+ if (isset($wpdb->comments)) {
1677
+ $wpdb->query("INSERT INTO {$wpdb->comments} (comment_post_ID, comment_author, comment_author_email, comment_author_url, comment_author_IP, comment_date, comment_date_gmt, comment_content, comment_karma, comment_approved, comment_agent, comment_type, comment_parent, user_id) VALUES (1, 'Mr WordPress', '', 'http://wordpress.org', '127.0.0.1', '{$now}', '{$now_gmt}', 'Hi, this is a comment. To delete a comment, just log in and view the post comments. There you will have the option to edit or delete them.', 0, '1', '', '', 0, 0)");
1678
+ }
1679
+ if (isset($wpdb->post2cat)) {
1680
+ $wpdb->query("INSERT INTO {$wpdb->post2cat} (rel_id, post_id, category_id) VALUES (1, 1, 1)");
1681
+ }
1682
+ }
1683
+ `,
1684
+ env: {
1685
+ DOCUMENT_ROOT: e.documentRoot,
1686
+ PLAYGROUND_SITE_URL: t || ""
1687
+ }
1688
+ });
1689
+ } catch (r) {
1690
+ h.warn("Legacy WP post-install fixups failed (non-fatal):", r);
1691
+ }
1692
+ if (s)
1693
+ try {
1694
+ await e.run({
1695
+ code: `<?php
1696
+ $db_dir = getenv('DOCUMENT_ROOT') . '/wp-content/database/';
1697
+ if (!is_dir($db_dir)) { @mkdir($db_dir, 0777, true); }
1698
+ $db_path = $db_dir . '.ht.sqlite';
1699
+ $pdo = new PDO('sqlite:' . $db_path);
1700
+ $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
1701
+
1702
+ $prefix = 'wp_';
1703
+ $table = $prefix . 'users';
1704
+ try {
1705
+ $count = $pdo->query("SELECT COUNT(*) FROM {$table}")->fetchColumn();
1706
+ } catch (Exception $e) {
1707
+ $pdo->exec("CREATE TABLE IF NOT EXISTS {$table} (
1708
+ ID INTEGER PRIMARY KEY AUTOINCREMENT,
1709
+ user_login TEXT NOT NULL DEFAULT '',
1710
+ user_pass TEXT NOT NULL DEFAULT '',
1711
+ user_nickname TEXT NOT NULL DEFAULT '',
1712
+ user_email TEXT NOT NULL DEFAULT '',
1713
+ user_url TEXT NOT NULL DEFAULT '',
1714
+ user_ip TEXT NOT NULL DEFAULT '',
1715
+ user_domain TEXT NOT NULL DEFAULT '',
1716
+ user_browser TEXT NOT NULL DEFAULT '',
1717
+ dateYMDhour TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1718
+ user_level INTEGER NOT NULL DEFAULT 0,
1719
+ user_idmode TEXT NOT NULL DEFAULT '',
1720
+ user_firstname TEXT NOT NULL DEFAULT '',
1721
+ user_lastname TEXT NOT NULL DEFAULT '',
1722
+ user_icq INTEGER NOT NULL DEFAULT 0,
1723
+ user_aim TEXT NOT NULL DEFAULT '',
1724
+ user_msn TEXT NOT NULL DEFAULT '',
1725
+ user_yim TEXT NOT NULL DEFAULT ''
1726
+ )");
1727
+ $count = 0;
1728
+ }
1729
+ if ($count == 0) {
1730
+ $now = date('Y-m-d H:i:s');
1731
+ // SECURITY: md5('password') matches WP 1.0-1.2's single-md5
1732
+ // scheme so auto-login works without a blueprint password.
1733
+ // Safe only inside the Playground WASM sandbox.
1734
+ $pass = md5('password');
1735
+ try {
1736
+ $col_info = $pdo->query("PRAGMA table_info({$table})")->fetchAll(PDO::FETCH_ASSOC);
1737
+ $known = array(
1738
+ 'ID' => '1', 'user_login' => "'admin'",
1739
+ 'user_pass' => "'{$pass}'", 'user_email' => "'admin@localhost.com'",
1740
+ 'user_level' => '10', 'dateYMDhour' => "'{$now}'",
1741
+ 'user_nickname' => "'admin'", 'user_nicename' => "'admin'",
1742
+ 'user_registered' => "'{$now}'", 'user_status' => '0',
1743
+ );
1744
+ $ins_cols = array(); $ins_vals = array();
1745
+ foreach ($col_info as $ci) {
1746
+ $cn = $ci['name'];
1747
+ $ins_cols[] = $cn;
1748
+ if (isset($known[$cn])) {
1749
+ $ins_vals[] = $known[$cn];
1750
+ } elseif ($ci['dflt_value'] !== null) {
1751
+ $ins_vals[] = $ci['dflt_value'];
1752
+ } elseif (stripos($ci['type'], 'int') !== false) {
1753
+ $ins_vals[] = '0';
1754
+ } else {
1755
+ $ins_vals[] = "''";
1756
+ }
1757
+ }
1758
+ $pdo->exec("INSERT INTO {$table} (" . implode(',', $ins_cols) . ") VALUES (" . implode(',', $ins_vals) . ")");
1759
+ } catch (Exception $e) {}
1760
+ } else {
1761
+ // See SECURITY note above.
1762
+ $pass = md5('password');
1763
+ try { $pdo->exec("UPDATE {$table} SET user_pass = '{$pass}' WHERE user_login = 'admin'"); } catch (Exception $e) {}
1764
+ }
1765
+
1766
+ // WP 1.0-1.2 install often leaves these tables missing because
1767
+ // the SQLite driver can't translate the old-style CREATE TABLEs.
1768
+ $now = date('Y-m-d H:i:s');
1769
+ $now_gmt = gmdate('Y-m-d H:i:s');
1770
+ $tables_sql = array(
1771
+ 'posts' => "CREATE TABLE IF NOT EXISTS {$prefix}posts (
1772
+ ID INTEGER PRIMARY KEY AUTOINCREMENT,
1773
+ post_author INTEGER NOT NULL DEFAULT 0,
1774
+ post_date TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1775
+ post_date_gmt TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1776
+ post_content TEXT NOT NULL DEFAULT '',
1777
+ post_title TEXT NOT NULL DEFAULT '',
1778
+ post_category INTEGER NOT NULL DEFAULT 0,
1779
+ post_excerpt TEXT NOT NULL DEFAULT '',
1780
+ post_status TEXT NOT NULL DEFAULT 'publish',
1781
+ comment_status TEXT NOT NULL DEFAULT 'open',
1782
+ ping_status TEXT NOT NULL DEFAULT 'open',
1783
+ post_password TEXT NOT NULL DEFAULT '',
1784
+ post_name TEXT NOT NULL DEFAULT '',
1785
+ to_ping TEXT NOT NULL DEFAULT '',
1786
+ pinged TEXT NOT NULL DEFAULT '',
1787
+ post_modified TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1788
+ post_modified_gmt TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1789
+ post_content_filtered TEXT NOT NULL DEFAULT '',
1790
+ post_parent INTEGER NOT NULL DEFAULT 0,
1791
+ menu_order INTEGER NOT NULL DEFAULT 0,
1792
+ post_mime_type TEXT NOT NULL DEFAULT ''
1793
+ )",
1794
+ 'categories' => "CREATE TABLE IF NOT EXISTS {$prefix}categories (
1795
+ cat_ID INTEGER PRIMARY KEY AUTOINCREMENT,
1796
+ cat_name TEXT NOT NULL DEFAULT '',
1797
+ category_nicename TEXT NOT NULL DEFAULT '',
1798
+ category_description TEXT NOT NULL DEFAULT '',
1799
+ category_parent INTEGER NOT NULL DEFAULT 0
1800
+ )",
1801
+ 'post2cat' => "CREATE TABLE IF NOT EXISTS {$prefix}post2cat (
1802
+ rel_id INTEGER PRIMARY KEY AUTOINCREMENT,
1803
+ post_id INTEGER NOT NULL DEFAULT 0,
1804
+ category_id INTEGER NOT NULL DEFAULT 0
1805
+ )",
1806
+ 'comments' => "CREATE TABLE IF NOT EXISTS {$prefix}comments (
1807
+ comment_ID INTEGER PRIMARY KEY AUTOINCREMENT,
1808
+ comment_post_ID INTEGER NOT NULL DEFAULT 0,
1809
+ comment_author TEXT NOT NULL DEFAULT '',
1810
+ comment_author_email TEXT NOT NULL DEFAULT '',
1811
+ comment_author_url TEXT NOT NULL DEFAULT '',
1812
+ comment_author_IP TEXT NOT NULL DEFAULT '',
1813
+ comment_date TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1814
+ comment_date_gmt TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1815
+ comment_content TEXT NOT NULL DEFAULT '',
1816
+ comment_karma INTEGER NOT NULL DEFAULT 0,
1817
+ comment_approved TEXT NOT NULL DEFAULT '1',
1818
+ comment_agent TEXT NOT NULL DEFAULT '',
1819
+ comment_type TEXT NOT NULL DEFAULT '',
1820
+ comment_parent INTEGER NOT NULL DEFAULT 0,
1821
+ user_id INTEGER NOT NULL DEFAULT 0
1822
+ )",
1823
+ 'options' => "CREATE TABLE IF NOT EXISTS {$prefix}options (
1824
+ option_id INTEGER PRIMARY KEY AUTOINCREMENT,
1825
+ blog_id INTEGER NOT NULL DEFAULT 0,
1826
+ option_name TEXT NOT NULL DEFAULT '',
1827
+ option_can_override TEXT NOT NULL DEFAULT 'Y',
1828
+ option_type INTEGER NOT NULL DEFAULT 1,
1829
+ option_value TEXT NOT NULL DEFAULT '',
1830
+ option_width INTEGER NOT NULL DEFAULT 20,
1831
+ option_height INTEGER NOT NULL DEFAULT 8,
1832
+ option_description TEXT NOT NULL DEFAULT '',
1833
+ option_admin_level INTEGER NOT NULL DEFAULT 1,
1834
+ autoload TEXT NOT NULL DEFAULT 'yes'
1835
+ )",
1836
+ 'postmeta' => "CREATE TABLE IF NOT EXISTS {$prefix}postmeta (
1837
+ meta_id INTEGER PRIMARY KEY AUTOINCREMENT,
1838
+ post_id INTEGER NOT NULL DEFAULT 0,
1839
+ meta_key TEXT NOT NULL DEFAULT '',
1840
+ meta_value TEXT NOT NULL DEFAULT ''
1841
+ )",
1842
+ 'links' => "CREATE TABLE IF NOT EXISTS {$prefix}links (
1843
+ link_id INTEGER PRIMARY KEY AUTOINCREMENT,
1844
+ link_url TEXT NOT NULL DEFAULT '',
1845
+ link_name TEXT NOT NULL DEFAULT '',
1846
+ link_image TEXT NOT NULL DEFAULT '',
1847
+ link_target TEXT NOT NULL DEFAULT '',
1848
+ link_category INTEGER NOT NULL DEFAULT 0,
1849
+ link_description TEXT NOT NULL DEFAULT '',
1850
+ link_visible TEXT NOT NULL DEFAULT 'Y',
1851
+ link_owner INTEGER NOT NULL DEFAULT 1,
1852
+ link_rating INTEGER NOT NULL DEFAULT 0,
1853
+ link_updated TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1854
+ link_rel TEXT NOT NULL DEFAULT '',
1855
+ link_notes TEXT NOT NULL DEFAULT '',
1856
+ link_rss TEXT NOT NULL DEFAULT ''
1857
+ )",
1858
+ 'linkcategories' => "CREATE TABLE IF NOT EXISTS {$prefix}linkcategories (
1859
+ cat_id INTEGER PRIMARY KEY AUTOINCREMENT,
1860
+ cat_name TEXT NOT NULL DEFAULT '',
1861
+ auto_toggle TEXT NOT NULL DEFAULT 'N',
1862
+ show_images TEXT NOT NULL DEFAULT 'Y',
1863
+ show_description TEXT NOT NULL DEFAULT 'N',
1864
+ show_rating TEXT NOT NULL DEFAULT 'Y',
1865
+ show_updated TEXT NOT NULL DEFAULT 'Y',
1866
+ sort_order TEXT NOT NULL DEFAULT 'name',
1867
+ sort_desc TEXT NOT NULL DEFAULT 'ASC',
1868
+ text_before_link TEXT NOT NULL DEFAULT '<li>',
1869
+ text_after_link TEXT NOT NULL DEFAULT '<br />',
1870
+ text_after_all TEXT NOT NULL DEFAULT '</li>',
1871
+ list_limit INTEGER NOT NULL DEFAULT -1
1872
+ )",
1873
+ 'optiongroups' => "CREATE TABLE IF NOT EXISTS {$prefix}optiongroups (
1874
+ group_id INTEGER PRIMARY KEY AUTOINCREMENT,
1875
+ group_name TEXT NOT NULL DEFAULT '',
1876
+ group_desc TEXT DEFAULT '',
1877
+ group_longdesc TEXT DEFAULT ''
1878
+ )",
1879
+ 'optiongroup_options' => "CREATE TABLE IF NOT EXISTS {$prefix}optiongroup_options (
1880
+ group_id INTEGER NOT NULL DEFAULT 0,
1881
+ option_id INTEGER NOT NULL DEFAULT 0,
1882
+ seq INTEGER NOT NULL DEFAULT 0,
1883
+ PRIMARY KEY (group_id, option_id)
1884
+ )"
1885
+ );
1886
+ foreach ($tables_sql as $t => $sql) {
1887
+ try { $pdo->exec($sql); } catch (Exception $e) {}
1888
+ }
1889
+ // Backfill columns that WP 1.0-1.2 installs leave off but later code paths read.
1890
+ $alter_cols = array(
1891
+ 'categories' => array(
1892
+ 'category_nicename' => "TEXT NOT NULL DEFAULT ''",
1893
+ 'category_description' => "TEXT NOT NULL DEFAULT ''",
1894
+ 'category_parent' => "INTEGER NOT NULL DEFAULT 0",
1895
+ 'category_count' => "INTEGER NOT NULL DEFAULT 0",
1896
+ ),
1897
+ // WP 1.5+ get_comments_number() reads comment_count off wp_posts.
1898
+ 'posts' => array(
1899
+ 'comment_count' => "INTEGER NOT NULL DEFAULT 0",
1900
+ ),
1901
+ );
1902
+ foreach ($alter_cols as $t => $cols_to_add) {
1903
+ try {
1904
+ $existing = $pdo->query("PRAGMA table_info({$prefix}{$t})")->fetchAll(PDO::FETCH_COLUMN, 1);
1905
+ foreach ($cols_to_add as $col => $type) {
1906
+ if (!in_array($col, $existing)) {
1907
+ $pdo->exec("ALTER TABLE {$prefix}{$t} ADD COLUMN {$col} {$type}");
1908
+ }
1909
+ }
1910
+ } catch (Exception $e) {}
1911
+ }
1912
+ // Dynamic column detection because the schema differs across WP 1.x.
1913
+ try {
1914
+ if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}posts")->fetchColumn()) {
1915
+ $post_cols = $pdo->query("PRAGMA table_info({$prefix}posts)")->fetchAll(PDO::FETCH_COLUMN, 1);
1916
+ $post_vals = array(
1917
+ 'ID' => '1', 'post_author' => '1',
1918
+ 'post_date' => "'{$now}'", 'post_date_gmt' => "'{$now_gmt}'",
1919
+ 'post_content' => "'Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!'",
1920
+ 'post_title' => "'Hello world!'", 'post_excerpt' => "''",
1921
+ 'post_status' => "'publish'", 'comment_status' => "'open'",
1922
+ 'ping_status' => "'open'", 'post_password' => "''",
1923
+ 'post_name' => "'hello-world'", 'to_ping' => "''", 'pinged' => "''",
1924
+ 'post_modified' => "'{$now}'", 'post_modified_gmt' => "'{$now_gmt}'",
1925
+ 'post_content_filtered' => "''",
1926
+ );
1927
+ $ins_c = array(); $ins_v = array();
1928
+ foreach ($post_vals as $c => $v) {
1929
+ if (in_array($c, $post_cols)) { $ins_c[] = $c; $ins_v[] = $v; }
1930
+ }
1931
+ if ($ins_c) $pdo->exec("INSERT INTO {$prefix}posts (" . implode(',', $ins_c) . ") VALUES (" . implode(',', $ins_v) . ")");
1932
+ }
1933
+ } catch (Exception $e) {}
1934
+ try {
1935
+ if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}categories")->fetchColumn()) {
1936
+ $pdo->exec("INSERT INTO {$prefix}categories (cat_ID, cat_name, category_nicename, category_description, category_parent) VALUES (1, 'Uncategorized', 'uncategorized', '', 0)");
1937
+ }
1938
+ } catch (Exception $e) {}
1939
+ try {
1940
+ $env_site = getenv('PLAYGROUND_SITE_URL');
1941
+ $site = $env_site ? $env_site : 'http://localhost';
1942
+ if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}options WHERE option_name='siteurl'")->fetchColumn()) {
1943
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('siteurl', '{$site}')");
1944
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('blogname', 'My WordPress Website')");
1945
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('blogdescription', 'Just another WordPress weblog')");
1946
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('home', '{$site}')");
1947
+ }
1948
+ // Overwrite the placeholder 'http://localhost' with the scoped URL.
1949
+ if ($env_site) {
1950
+ $pdo->exec("UPDATE {$prefix}options SET option_value = '{$env_site}' WHERE option_name = 'siteurl'");
1951
+ $pdo->exec("UPDATE {$prefix}options SET option_value = '{$env_site}' WHERE option_name = 'home'");
1952
+ }
1953
+ // populate_options() sets template/stylesheet; backfill if it crashed.
1954
+ if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}options WHERE option_name='template'")->fetchColumn()) {
1955
+ $themes_dir = getenv('DOCUMENT_ROOT') . '/wp-content/themes/';
1956
+ $tpl = 'default';
1957
+ if (is_dir($themes_dir)) {
1958
+ $entries = glob($themes_dir . '*', GLOB_ONLYDIR);
1959
+ if ($entries) {
1960
+ foreach ($entries as $e) {
1961
+ $name = basename($e);
1962
+ if ($name === '.' || $name === '..') continue;
1963
+ if (file_exists($e . '/style.css')) {
1964
+ $tpl = $name;
1965
+ break;
1966
+ }
1967
+ }
1968
+ }
1969
+ }
1970
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value, autoload) VALUES ('template', '{$tpl}', 'yes')");
1971
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value, autoload) VALUES ('stylesheet', '{$tpl}', 'yes')");
1972
+ }
1973
+ // Without a correct db_version, WP 2.0-2.5 admin redirects to upgrade.php.
1974
+ $version_path = getenv('DOCUMENT_ROOT') . '/wp-includes/version.php';
1975
+ if (file_exists($version_path)) {
1976
+ $wp_db_version = 0;
1977
+ include $version_path;
1978
+ if ($wp_db_version > 0) {
1979
+ $has_dbv = $pdo->query("SELECT COUNT(*) FROM {$prefix}options WHERE option_name='db_version'")->fetchColumn();
1980
+ if (!$has_dbv) {
1981
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value, autoload) VALUES ('db_version', '{$wp_db_version}', 'yes')");
1982
+ } else {
1983
+ $pdo->exec("UPDATE {$prefix}options SET option_value = '{$wp_db_version}' WHERE option_name = 'db_version'");
1984
+ }
1985
+ }
1986
+ }
1987
+ } catch (Exception $e) {}
1988
+ `,
1989
+ env: {
1990
+ DOCUMENT_ROOT: e.documentRoot,
1991
+ PLAYGROUND_SITE_URL: t || ""
1992
+ }
1993
+ });
1994
+ } catch (r) {
1995
+ h.warn("Legacy WP PDO fallback failed (non-fatal):", r);
1996
+ }
1997
+ }
1998
+ const Pe = `
1999
+ // Connection stubs — wpdb::__construct bails on a falsy return.
2000
+ if (!function_exists('mysqli_connect')) {
2001
+ function mysqli_connect() { return true; }
2002
+ }
2003
+ if (!function_exists('mysqli_init')) {
2004
+ function mysqli_init() { return true; }
2005
+ }
2006
+ if (!function_exists('mysql_connect')) {
2007
+ function mysql_connect() { return true; }
2008
+ }
2009
+ if (!function_exists('mysql_select_db')) {
2010
+ function mysql_select_db() { return true; }
2011
+ }
2012
+ // WordPress < 3.0 wpdb::__construct calls mysql_set_charset directly.
2013
+ if (!function_exists('mysql_set_charset')) {
2014
+ function mysql_set_charset() { return true; }
2015
+ }
2016
+ // Functional mysql_* stubs that delegate to $wpdb (SQLite driver).
2017
+ $GLOBALS['_mysql_results'] = array();
2018
+ $GLOBALS['_mysql_result_id'] = 0;
2019
+ if (!function_exists('mysql_query')) {
2020
+ function mysql_query($query, $link = null) {
2021
+ global $wpdb;
2022
+ if (isset($wpdb) && method_exists($wpdb, 'query')) {
2023
+ $wpdb->query($query);
2024
+ if (preg_match('/^\\s*(SELECT|SHOW|DESCRIBE|EXPLAIN)/i', $query)) {
2025
+ $rows = isset($wpdb->last_result) ? $wpdb->last_result : array();
2026
+ $id = ++$GLOBALS['_mysql_result_id'];
2027
+ $GLOBALS['_mysql_results'][$id] = array(
2028
+ 'rows' => $rows,
2029
+ 'index' => 0,
2030
+ );
2031
+ return $id;
2032
+ }
2033
+ return true;
2034
+ }
2035
+ return false;
2036
+ }
2037
+ }
2038
+ if (!function_exists('mysql_error')) {
2039
+ function mysql_error($link = null) {
2040
+ global $wpdb;
2041
+ if (isset($wpdb) && isset($wpdb->last_error)) {
2042
+ return $wpdb->last_error;
2043
+ }
2044
+ return '';
2045
+ }
2046
+ }
2047
+ if (!function_exists('mysql_list_tables')) {
2048
+ function mysql_list_tables($db = '', $link = null) {
2049
+ global $wpdb;
2050
+ if (isset($wpdb) && method_exists($wpdb, 'get_results')) {
2051
+ $tables = $wpdb->get_results(
2052
+ "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
2053
+ );
2054
+ $rows = array();
2055
+ if ($tables) {
2056
+ foreach ($tables as $t) {
2057
+ $obj = new stdClass();
2058
+ $obj->name = is_object($t) ? $t->name : $t['name'];
2059
+ $rows[] = $obj;
2060
+ }
2061
+ }
2062
+ $id = ++$GLOBALS['_mysql_result_id'];
2063
+ $GLOBALS['_mysql_results'][$id] = array(
2064
+ 'rows' => $rows,
2065
+ 'index' => 0,
2066
+ );
2067
+ return $id;
2068
+ }
2069
+ return false;
2070
+ }
2071
+ }
2072
+ if (!function_exists('mysql_fetch_row')) {
2073
+ function mysql_fetch_row($result) {
2074
+ if (!isset($GLOBALS['_mysql_results'][$result])) return null;
2075
+ $r = &$GLOBALS['_mysql_results'][$result];
2076
+ if ($r['index'] >= count($r['rows'])) return null;
2077
+ $row = $r['rows'][$r['index']++];
2078
+ return array_values((array)$row);
2079
+ }
2080
+ }
2081
+ if (!function_exists('mysql_fetch_object')) {
2082
+ function mysql_fetch_object($result) {
2083
+ if (!isset($GLOBALS['_mysql_results'][$result])) return null;
2084
+ $r = &$GLOBALS['_mysql_results'][$result];
2085
+ if ($r['index'] >= count($r['rows'])) return null;
2086
+ return (object)(array)$r['rows'][$r['index']++];
2087
+ }
2088
+ }
2089
+ if (!function_exists('mysql_num_rows')) {
2090
+ function mysql_num_rows($result) {
2091
+ if (isset($GLOBALS['_mysql_results'][$result])) {
2092
+ return count($GLOBALS['_mysql_results'][$result]['rows']);
2093
+ }
2094
+ return 0;
2095
+ }
2096
+ }
2097
+ if (!function_exists('mysql_get_server_info')) {
2098
+ function mysql_get_server_info() { return '8.0.0'; }
2099
+ }
2100
+ if (!function_exists('mysql_affected_rows')) {
2101
+ function mysql_affected_rows() {
2102
+ global $wpdb;
2103
+ if (isset($wpdb) && isset($wpdb->rows_affected)) {
2104
+ return $wpdb->rows_affected;
2105
+ }
2106
+ return 0;
2107
+ }
2108
+ }
2109
+ if (!function_exists('mysql_insert_id')) {
2110
+ function mysql_insert_id() {
2111
+ global $wpdb;
2112
+ if (isset($wpdb) && isset($wpdb->insert_id)) {
2113
+ return $wpdb->insert_id;
2114
+ }
2115
+ return 0;
2116
+ }
2117
+ }
2118
+ if (!function_exists('mysql_free_result')) {
2119
+ function mysql_free_result($result) {
2120
+ unset($GLOBALS['_mysql_results'][$result]);
2121
+ return true;
2122
+ }
2123
+ }
2124
+ if (!function_exists('mysql_num_fields')) {
2125
+ function mysql_num_fields($result) {
2126
+ if (isset($GLOBALS['_mysql_results'][$result])
2127
+ && !empty($GLOBALS['_mysql_results'][$result]['rows'])) {
2128
+ return count((array)$GLOBALS['_mysql_results'][$result]['rows'][0]);
2129
+ }
2130
+ return 0;
2131
+ }
2132
+ }
2133
+ if (!function_exists('mysql_real_escape_string')) {
2134
+ function mysql_real_escape_string($s) { return addslashes($s); }
2135
+ }
2136
+ if (!function_exists('mysql_escape_string')) {
2137
+ function mysql_escape_string($s) { return addslashes($s); }
2138
+ }`;
2139
+ async function Ne(e, t, i = {}) {
2140
+ await e.isDir("/tmp/sqlite-database-integration") && await e.rmdir("/tmp/sqlite-database-integration", {
2141
+ recursive: !0
2142
+ }), await e.mkdir("/tmp/sqlite-database-integration"), await m(e, t, "/tmp/sqlite-database-integration");
2143
+ const n = "/internal/shared/sqlite-database-integration", s = `/tmp/sqlite-database-integration/${(await e.listFiles("/tmp/sqlite-database-integration"))[0]}`;
2144
+ await e.mv(s, n), await Ae(e, n), await e.defineConstant("SQLITE_MAIN_FILE", "1");
2145
+ let a = (await e.readFileAsText(
2146
+ _(n, "db.copy")
2147
+ )).replace(
2148
+ "'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",
2149
+ $(n)
2150
+ ).replace(
2151
+ "'{SQLITE_PLUGIN}'",
2152
+ $(_(n, "load.php"))
2153
+ );
2154
+ a = a.replace(
2155
+ /^add_action\(/gm,
2156
+ 'function_exists("add_action") && add_action('
2157
+ );
2158
+ const o = _(await e.documentRoot, "wp-content/db.php"), l = "/internal/shared/mu-plugins/sqlite-database-integration.php", c = `
2159
+ if(file_exists(${$(o)})) {
2160
+ $_pg_db_php = @file_get_contents(${$(o)});
2161
+ if (strpos($_pg_db_php, '@playground-managed') === false) {
2162
+ return;
2163
+ }
2164
+ unset($_pg_db_php);
2165
+ }
2166
+ `;
2167
+ await e.writeFile(l, `<?php
2168
+ ${c}?>` + a), await e.writeFile(
2169
+ "/internal/shared/preload/0-sqlite.php",
2170
+ Se(c, l)
2171
+ ), await e.writeFile(
2172
+ "/internal/shared/mu-plugins/sqlite-test.php",
2173
+ `<?php
2174
+ global $wpdb;
2175
+ if(!($wpdb instanceof WP_SQLite_DB)) {
2176
+ var_dump(isset($wpdb));
2177
+ die("SQLite integration not loaded " . get_class($wpdb));
2178
+ }
2179
+ `
2180
+ );
2181
+ }
2182
+ async function Ae(e, t) {
2183
+ const i = _(
2184
+ t,
2185
+ "wp-includes/database/sqlite/class-wp-pdo-mysql-on-sqlite.php"
2186
+ );
2187
+ if (!await e.fileExists(i)) return;
2188
+ const n = await e.readFileAsText(i), s = n.replace(
2189
+ /\$active_sql_modes\s*=\s*array\s*\([^)]*\)\s*;/,
2190
+ "$active_sql_modes = array();"
2191
+ );
2192
+ s !== n && await e.writeFile(i, s);
2193
+ }
2194
+ function Se(e, t) {
2195
+ return `<?php
2196
+ ${e}?>
2197
+ <?php
2198
+ // Shim __() etc. only for WP < 1.2 (no l10n layer; the SQLite
2199
+ // plugin calls __() from print_error()). WP 1.2–1.4 ship
2200
+ // wp-l10n.php and WP 1.5+ ships l10n.php — defining the shims
2201
+ // then would fatal on redeclare.
2202
+ $_pg_doc_root = isset($_SERVER['DOCUMENT_ROOT'])
2203
+ ? $_SERVER['DOCUMENT_ROOT'] : '/wordpress';
2204
+ if (
2205
+ !file_exists($_pg_doc_root . '/wp-includes/l10n.php')
2206
+ && !file_exists($_pg_doc_root . '/wp-includes/wp-l10n.php')
2207
+ ) {
2208
+ if (!function_exists('__')) {
2209
+ function __($text, $domain = null) { return $text; }
2210
+ }
2211
+ if (!function_exists('_e')) {
2212
+ function _e($text, $domain = null) { echo $text; }
2213
+ }
2214
+ if (!function_exists('esc_html__')) {
2215
+ function esc_html__($text, $domain = null) {
2216
+ return htmlspecialchars($text, ENT_QUOTES);
2217
+ }
2218
+ }
2219
+ if (!function_exists('esc_html_e')) {
2220
+ function esc_html_e($text, $domain = null) {
2221
+ echo htmlspecialchars($text, ENT_QUOTES);
2222
+ }
2223
+ }
2224
+ }
2225
+ ?>
2226
+ <?php
2227
+ ${v(
2228
+ // WP < 3.0's wpdb does mysql_connect() inline so the SQLite
2229
+ // plugin's db_connect() never runs; reinitialize_sqlite()
2230
+ // swaps the dbh in place after the integration is loaded.
2231
+ `require_once ${$(t)};
2232
+ if (
2233
+ isset($GLOBALS['wpdb']) &&
2234
+ method_exists($GLOBALS['wpdb'], 'reinitialize_sqlite')
2235
+ ) {
2236
+ $GLOBALS['wpdb']->reinitialize_sqlite();
2237
+ }`
2238
+ )}
2239
+ ${Pe}
2240
+ if (PHP_MAJOR_VERSION < 7) {
2241
+ // E_DEPRECATED (8192) / E_STRICT (2048) are PHP 5.3+ symbols;
2242
+ // LEGACY_WP_ERROR_REPORTING_PHP_EXPR uses numeric literals.
2243
+ $level = ${L};
2244
+ error_reporting($level);
2245
+ ini_set('error_reporting', $level);
2246
+ }
2247
+
2248
+ `;
2249
+ }
2250
+ const U = `<?php
6
2251
 
7
2252
  /**
8
2253
  * Transforms the "wp-config.php" file.
@@ -474,133 +2719,327 @@ class WP_Config_Transformer {
474
2719
  }
475
2720
  }
476
2721
  `;
477
- async function I(t, e) {
478
- const n = s(e, "wp-config.php");
479
- !t.fileExists(n) && t.fileExists(s(e, "wp-config-sample.php")) && await t.writeFile(
480
- n,
481
- await t.readFileAsBuffer(
482
- s(e, "wp-config-sample.php")
2722
+ async function ve(e, t) {
2723
+ const i = _(t, "wp-config.php");
2724
+ !e.fileExists(i) && e.fileExists(_(t, "wp-config-sample.php")) && await e.writeFile(
2725
+ i,
2726
+ await e.readFileAsBuffer(
2727
+ _(t, "wp-config-sample.php")
483
2728
  )
484
- ), t.fileExists(n) && await x(t, n, {
2729
+ ), e.fileExists(i) && await xe(e, i, {
485
2730
  DB_NAME: "wordpress"
486
2731
  });
487
2732
  }
488
- async function V(t, e, n) {
489
- const i = $({ wpConfigPath: e, constants: n });
490
- if ((await t.run({
491
- code: `${m}
492
- $wp_config_path = ${i.wpConfigPath};
493
- $transformer = WP_Config_Transformer::from_file($wp_config_path);
494
- $transformer->define_constants(${i.constants});
495
- $transformer->to_file($wp_config_path);
496
- `
497
- })).errors.length > 0)
498
- throw new Error("Failed to rewrite constants in wp-config.php.");
2733
+ async function st(e, t, i) {
2734
+ const n = A({ wpConfigPath: t, constants: i });
2735
+ if ((await e.run({
2736
+ code: `${U}
2737
+ $wp_config_path = ${n.wpConfigPath};
2738
+ $transformer = WP_Config_Transformer::from_file($wp_config_path);
2739
+ $transformer->define_constants(${n.constants});
2740
+ $transformer->to_file($wp_config_path);
2741
+ `
2742
+ })).errors.length > 0)
2743
+ throw new Error("Failed to rewrite constants in wp-config.php.");
2744
+ }
2745
+ async function xe(e, t, i) {
2746
+ const n = Object.keys(i), s = A({ wpConfigPath: t, constantNames: n }), r = await e.run({
2747
+ code: `${U}
2748
+ $transformer = WP_Config_Transformer::from_file(${s.wpConfigPath});
2749
+ $missing = [];
2750
+ foreach (${s.constantNames} as $name) {
2751
+ if (!$transformer->constant_exists($name)) {
2752
+ $missing[] = $name;
2753
+ }
2754
+ }
2755
+ echo json_encode($missing);
2756
+ `
2757
+ });
2758
+ if (r.errors.length > 0)
2759
+ throw new Error("Failed to check wp-config.php for constants.");
2760
+ let a;
2761
+ try {
2762
+ a = JSON.parse(r.text);
2763
+ } catch {
2764
+ throw new Error(
2765
+ `Failed to parse wp-config.php constant check output: ${r.text}`
2766
+ );
2767
+ }
2768
+ for (const o of a)
2769
+ await e.defineConstant(o, i[o]);
2770
+ }
2771
+ async function E(e, {
2772
+ usesSqlite: t,
2773
+ hasCustomDatabasePath: i
2774
+ }) {
2775
+ const n = await e.getPrimaryPhp();
2776
+ if (n.isFile("/internal/shared/preload/0-sqlite.php"))
2777
+ return;
2778
+ const s = _(
2779
+ e.documentRoot,
2780
+ "wp-content/mu-plugins/sqlite-database-integration"
2781
+ );
2782
+ if (!n.isDir(s) && !t && !i && !Ue(n))
2783
+ throw new Error("Error connecting to the MySQL database.");
2784
+ }
2785
+ function Ue(e) {
2786
+ const t = _(e.documentRoot, "wp-config.php");
2787
+ if (!e.isFile(t)) return !1;
2788
+ const i = e.readFileAsText(t), n = i.match(
2789
+ /define\s*\(\s*['"]DB_NAME['"]\s*,\s*['"]([^'"]*)['"]/
2790
+ ), s = i.match(
2791
+ /define\s*\(\s*['"]DB_USER['"]\s*,\s*['"]([^'"]*)['"]/
2792
+ );
2793
+ return !n || !s ? !1 : n[1] !== "database_name_here" && s[1] !== "username_here";
2794
+ }
2795
+ const R = [
2796
+ "fsockopen",
2797
+ "pfsockopen",
2798
+ "curl_init",
2799
+ "curl_exec",
2800
+ "curl_multi_exec",
2801
+ "mail"
2802
+ ];
2803
+ function Re(e, t) {
2804
+ var r, a;
2805
+ if (!w(t.phpVersion)) return;
2806
+ const i = (((r = t.phpIniEntries) == null ? void 0 : r.disable_functions) ?? "").split(",").map((o) => o.trim()).filter((o) => o), s = {
2807
+ disable_functions: Array.from(
2808
+ /* @__PURE__ */ new Set([...i, ...R])
2809
+ ).join(","),
2810
+ allow_url_fopen: "0"
2811
+ };
2812
+ (a = t.phpIniEntries) != null && a["date.timezone"] || (s["date.timezone"] = "UTC"), P(e, s);
2813
+ }
2814
+ async function ke(e, t) {
2815
+ var a, o;
2816
+ const i = await e.getPrimaryPhp();
2817
+ if ((a = t.hooks) != null && a.beforeWordPressFiles && await t.hooks.beforeWordPressFiles(i), t.wordPressZip && await D(i, await t.wordPressZip), t.constants)
2818
+ for (const l in t.constants)
2819
+ i.defineConstant(l, t.constants[l]);
2820
+ i.defineConstant("WP_HOME", t.siteUrl), i.defineConstant("WP_SITEURL", t.siteUrl), await Ie(i, e.documentRoot), await K(i, e.documentRoot), (o = t.hooks) != null && o.beforeDatabaseSetup && await t.hooks.beforeDatabaseSetup(i);
2821
+ let n = !1;
2822
+ t.sqliteIntegrationPluginZip && (n = !0, await I(
2823
+ i,
2824
+ await t.sqliteIntegrationPluginZip,
2825
+ { phpVersion: t.phpVersion }
2826
+ ), await De(i, e.documentRoot));
2827
+ const s = t.wordpressInstallMode ?? "download-and-install", r = !!t.dataSqlPath;
2828
+ return (s === "download-and-install" || s === "install-from-existing-files" || // Legacy PHP: isWordPressInstalled() can trigger a WASM trap
2829
+ // (not a PHP exception) on old WordPress (< 3.0) and corrupt
2830
+ // the runtime beyond recovery. Always run the installer; it
2831
+ // is idempotent and its post-install fixups short-circuit
2832
+ // cheaply when the schema already exists.
2833
+ s === "install-from-existing-files-if-needed") && (await E(e, {
2834
+ usesSqlite: n,
2835
+ hasCustomDatabasePath: r
2836
+ }), await Fe(i, e)), e;
2837
+ }
2838
+ async function Ie(e, t) {
2839
+ const i = _(t, "wp-config.php"), n = _(t, "wp-config-sample.php");
2840
+ !e.fileExists(i) && e.fileExists(n) && await e.writeFile(
2841
+ i,
2842
+ await e.readFileAsBuffer(n)
2843
+ );
499
2844
  }
500
- async function x(t, e, n) {
501
- const i = Object.keys(n), a = $({ wpConfigPath: e, constantNames: i }), o = await t.run({
502
- code: `${m}
503
- $transformer = WP_Config_Transformer::from_file(${a.wpConfigPath});
504
- $missing = [];
505
- foreach (${a.constantNames} as $name) {
506
- if (!$transformer->constant_exists($name)) {
507
- $missing[] = $name;
508
- }
509
- }
510
- echo json_encode($missing);
511
- `
512
- });
513
- if (o.errors.length > 0)
514
- throw new Error("Failed to check wp-config.php for constants.");
515
- let l;
2845
+ async function De(e, t) {
2846
+ const i = _(t, "wp-content"), n = _(i, "db.php");
2847
+ e.isDir(i) && !e.fileExists(n) && await e.writeFile(n, be());
2848
+ }
2849
+ async function Fe(e, t) {
516
2850
  try {
517
- l = JSON.parse(o.text);
518
- } catch {
2851
+ await Ce(e);
2852
+ } catch (i) {
2853
+ h.warn("Legacy PHP WordPress installation error:", i);
2854
+ }
2855
+ await Oe(e, t.absoluteUrl);
2856
+ }
2857
+ async function Ce(e) {
2858
+ var r, a, o, l, c, u;
2859
+ const t = Ge(e, e.documentRoot);
2860
+ if (t !== null) {
2861
+ const d = parseFloat(t);
2862
+ if (d < 2.1)
2863
+ return;
2864
+ if (d <= 3) {
2865
+ await We(e);
2866
+ return;
2867
+ }
2868
+ }
2869
+ const i = {
2870
+ disable_functions: R.join(","),
2871
+ allow_url_fopen: "0",
2872
+ error_reporting: String(Y)
2873
+ }, n = await N(
2874
+ e,
2875
+ i,
2876
+ async () => await e.request({
2877
+ url: "/wp-admin/install.php?step=2",
2878
+ method: "POST",
2879
+ body: {
2880
+ language: "en",
2881
+ prefix: "wp_",
2882
+ weblog_title: "My WordPress Website",
2883
+ user_name: "admin",
2884
+ admin_password: "password",
2885
+ admin_password2: "password",
2886
+ Submit: "Install WordPress",
2887
+ pw_weak: "1",
2888
+ admin_email: "admin@localhost.com"
2889
+ }
2890
+ })
2891
+ );
2892
+ if (!(((r = n.text) == null ? void 0 : r.includes("Success")) || ((a = n.text) == null ? void 0 : a.includes("successful")) || ((o = n.text) == null ? void 0 : o.includes("Finished")) || ((l = n.text) == null ? void 0 : l.includes("Already Installed")) || ((c = n.text) == null ? void 0 : c.includes("already have WordPress installed")) || !1))
519
2893
  throw new Error(
520
- `Failed to parse wp-config.php constant check output: ${o.text}`
2894
+ `Failed to install WordPress installer responded with "${(u = n.text) == null ? void 0 : u.substring(
2895
+ 0,
2896
+ 100
2897
+ )}"`
2898
+ );
2899
+ await qe(e);
2900
+ }
2901
+ async function qe(e) {
2902
+ try {
2903
+ (await e.run({
2904
+ code: `<?php
2905
+ $db_dir = getenv('DOCUMENT_ROOT') . '/wp-content/database/';
2906
+ $db_path = $db_dir . '.ht.sqlite';
2907
+ if (!file_exists($db_path)) { echo '0'; exit; }
2908
+ $pdo = new PDO('sqlite:' . $db_path);
2909
+ $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
2910
+ $nice_permalinks = '/%year%/%monthnum%/%day%/%postname%/';
2911
+ $stmt = $pdo->prepare(
2912
+ "UPDATE wp_options SET option_value = :val WHERE option_name = 'permalink_structure'"
2913
+ );
2914
+ $stmt->execute(array(':val' => $nice_permalinks));
2915
+ if ($stmt->rowCount() === 0) {
2916
+ $stmt = $pdo->prepare(
2917
+ "INSERT INTO wp_options (option_name, option_value, autoload) VALUES ('permalink_structure', :val, 'yes')"
2918
+ );
2919
+ $stmt->execute(array(':val' => $nice_permalinks));
2920
+ }
2921
+ $check = $pdo->query(
2922
+ "SELECT option_value FROM wp_options WHERE option_name = 'permalink_structure'"
2923
+ )->fetchColumn();
2924
+ echo $check === $nice_permalinks ? '1' : '0';
2925
+ `,
2926
+ env: { DOCUMENT_ROOT: e.documentRoot }
2927
+ })).text !== "1" && h.warn(
2928
+ "Failed to default to pretty permalinks after WP install."
2929
+ );
2930
+ } catch {
2931
+ h.warn(
2932
+ "Failed to set pretty permalinks after WP install (non-fatal)."
521
2933
  );
522
2934
  }
523
- for (const r of l)
524
- await t.defineConstant(r, n[r]);
525
- }
526
- async function Z(t) {
527
- const e = await C(t);
528
- return await L(e, t), e;
529
- }
530
- async function L(t, e) {
531
- var l, r;
532
- const n = await t.getPrimaryPhp();
533
- if ((l = e.hooks) != null && l.beforeWordPressFiles && await e.hooks.beforeWordPressFiles(n), e.wordPressZip && await M(n, await e.wordPressZip), e.constants)
534
- for (const c in e.constants)
535
- n.defineConstant(c, e.constants[c]);
536
- e.dataSqlPath && (n.defineConstant("DB_DIR", y(e.dataSqlPath)), n.defineConstant("DB_FILE", b(e.dataSqlPath))), n.defineConstant("WP_HOME", e.siteUrl), n.defineConstant("WP_SITEURL", e.siteUrl), await I(n, t.documentRoot), (r = e.hooks) != null && r.beforeDatabaseSetup && await e.hooks.beforeDatabaseSetup(n);
537
- let i = !1;
538
- e.sqliteIntegrationPluginZip && (i = !0, await D(
539
- n,
540
- await e.sqliteIntegrationPluginZip
541
- ));
542
- const a = e.wordpressInstallMode ?? "download-and-install", o = !!e.dataSqlPath;
2935
+ }
2936
+ async function We(e) {
2937
+ try {
2938
+ await e.run({
2939
+ code: `<?php
2940
+ define('WP_INSTALLING', true);
2941
+ error_reporting(${L});
2942
+ ini_set('display_errors', '0');
2943
+ ob_start();
2944
+ require getenv('DOCUMENT_ROOT') . '/wp-load.php';
2945
+ ob_clean();
2946
+ if (file_exists(ABSPATH . 'wp-admin/includes/upgrade.php')) {
2947
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
2948
+ } elseif (file_exists(ABSPATH . 'wp-admin/upgrade-functions.php')) {
2949
+ require_once ABSPATH . 'wp-admin/upgrade-functions.php';
2950
+ }
2951
+ if (function_exists('make_db_current_silent')) {
2952
+ make_db_current_silent();
2953
+ }
2954
+ // Seed essential options/roles when the loader exposes
2955
+ // them. The PDO fallback in runPostInstallLegacyFixups
2956
+ // backfills anything missing if either call dies.
2957
+ if (function_exists('populate_options')) populate_options();
2958
+ if (function_exists('populate_roles')) populate_roles();
2959
+ echo 'OK';
2960
+ `,
2961
+ env: { DOCUMENT_ROOT: e.documentRoot }
2962
+ });
2963
+ } catch (t) {
2964
+ h.warn("runDbDeltaOnly failed (non-fatal):", t);
2965
+ }
2966
+ }
2967
+ function Ge(e, t) {
2968
+ const i = _(t, "wp-includes/version.php");
2969
+ if (!e.fileExists(i)) return null;
2970
+ const s = e.readFileAsText(i).match(/\$wp_version\s*=\s*['"]([^'"]+)['"]/);
2971
+ return s ? s[1] : null;
2972
+ }
2973
+ async function rt(e) {
2974
+ const t = await He(e);
2975
+ return await Me(t, e), t;
2976
+ }
2977
+ async function Me(e, t) {
2978
+ var a, o;
2979
+ if (w(t.phpVersion))
2980
+ return ke(e, t);
2981
+ const i = await e.getPrimaryPhp();
2982
+ if ((a = t.hooks) != null && a.beforeWordPressFiles && await t.hooks.beforeWordPressFiles(i), t.wordPressZip && await D(i, await t.wordPressZip), t.constants)
2983
+ for (const l in t.constants)
2984
+ i.defineConstant(l, t.constants[l]);
2985
+ t.dataSqlPath && (i.defineConstant("DB_DIR", W(t.dataSqlPath)), i.defineConstant("DB_FILE", G(t.dataSqlPath))), i.defineConstant("WP_HOME", t.siteUrl), i.defineConstant("WP_SITEURL", t.siteUrl), await ve(i, e.documentRoot), (o = t.hooks) != null && o.beforeDatabaseSetup && await t.hooks.beforeDatabaseSetup(i);
2986
+ let n = !1;
2987
+ t.sqliteIntegrationPluginZip && (n = !0, await I(
2988
+ i,
2989
+ await t.sqliteIntegrationPluginZip,
2990
+ { phpVersion: t.phpVersion }
2991
+ ), await X(i, e.documentRoot));
2992
+ const s = t.wordpressInstallMode ?? "download-and-install", r = !!t.dataSqlPath;
543
2993
  if (["download-and-install", "install-from-existing-files"].includes(
544
- a
2994
+ s
545
2995
  )) {
546
- await _(t, {
547
- usesSqlite: i,
548
- hasCustomDatabasePath: o
2996
+ await E(e, {
2997
+ usesSqlite: n,
2998
+ hasCustomDatabasePath: r
549
2999
  });
550
3000
  try {
551
- await h(n);
552
- } catch (c) {
553
- throw o || await u(t), c;
3001
+ await O(i);
3002
+ } catch (l) {
3003
+ throw r || await g(e), l;
554
3004
  }
555
- o || await u(t);
556
- } else if (a === "install-from-existing-files-if-needed") {
557
- if (await _(t, {
558
- usesSqlite: i,
559
- hasCustomDatabasePath: o
560
- }), !await w(n))
3005
+ r || await g(e);
3006
+ } else if (s === "install-from-existing-files-if-needed") {
3007
+ if (await E(e, {
3008
+ usesSqlite: n,
3009
+ hasCustomDatabasePath: r
3010
+ }), !await k(i))
561
3011
  try {
562
- await h(n);
563
- } catch (c) {
564
- throw o || await u(t), c;
3012
+ await O(i);
3013
+ } catch (l) {
3014
+ throw r || await g(e), l;
565
3015
  }
566
- o || await u(t);
3016
+ r || await g(e);
567
3017
  }
568
- return t;
569
- }
570
- async function _(t, {
571
- usesSqlite: e,
572
- hasCustomDatabasePath: n
573
- }) {
574
- const i = await t.getPrimaryPhp();
575
- if (i.isFile("/internal/shared/preload/0-sqlite.php"))
576
- return;
577
- const a = s(
578
- t.documentRoot,
579
- "wp-content/mu-plugins/sqlite-database-integration"
580
- );
581
- if (!i.isDir(a) && !e && !n && !A(i))
582
- throw new Error("Error connecting to the MySQL database.");
3018
+ return e;
583
3019
  }
584
- async function u(t) {
585
- const e = await t.getPrimaryPhp();
586
- if (await W(e))
3020
+ async function g(e) {
3021
+ const t = await e.getPrimaryPhp();
3022
+ if (await Ve(t))
587
3023
  return;
588
- if (e.isFile("/internal/shared/preload/0-sqlite.php"))
3024
+ if (t.isFile("/internal/shared/preload/0-sqlite.php"))
589
3025
  throw new Error("Error connecting to the SQLite database.");
590
- const i = s(
591
- t.documentRoot,
3026
+ const n = _(
3027
+ e.documentRoot,
592
3028
  "wp-content/mu-plugins/sqlite-database-integration"
593
3029
  );
594
- throw e.isDir(i) ? new Error("Error connecting to the SQLite database.") : new Error("Error connecting to the MySQL database.");
595
- }
596
- async function C(t) {
597
- const e = t.spawnHandler ?? T;
598
- async function n(a, o = !1) {
599
- const l = await t.createPhpRuntime(o), r = new v(l);
600
- if (t.sapiName && r.setSapiName(t.sapiName), a && (r.requestHandler = a), t.phpIniEntries && S(r, t.phpIniEntries), r.defineConstant("WP_SQLITE_AST_DRIVER", !0), t.constants)
601
- for (const c in t.constants)
602
- r.defineConstant(c, t.constants[c]);
603
- return o && /**
3030
+ throw t.isDir(n) ? new Error("Error connecting to the SQLite database.") : new Error("Error connecting to the MySQL database.");
3031
+ }
3032
+ async function He(e) {
3033
+ const t = e.spawnHandler ?? F;
3034
+ async function i(s, r = !1) {
3035
+ const a = await e.createPhpRuntime(r), o = new q(a);
3036
+ if (e.sapiName && o.setSapiName(e.sapiName), s && (o.requestHandler = s), e.phpIniEntries && P(o, e.phpIniEntries), Re(o, {
3037
+ phpVersion: e.phpVersion,
3038
+ phpIniEntries: e.phpIniEntries
3039
+ }), o.defineConstant("WP_SQLITE_AST_DRIVER", !0), e.constants)
3040
+ for (const l in e.constants)
3041
+ o.defineConstant(l, e.constants[l]);
3042
+ return r && /**
604
3043
  * Only the first PHP instance of the first worker created
605
3044
  * during WordPress boot writes these files – otherwise we'll keep
606
3045
  * overwriting them with concurrent writers living in other worker
@@ -610,45 +3049,47 @@ async function C(t) {
610
3049
  * mechanism. It works, because secondary workers are only booted
611
3050
  * once the primary worker has fully booted.
612
3051
  */
613
- !r.isFile("/internal/.boot-files-written") && (await N(r), await f(r, "/", t.createFiles || {}), await F(
614
- r,
615
- s(new URL(t.siteUrl).pathname, "phpinfo.php")
616
- ), await f(r, "/internal", {
3052
+ !o.isFile("/internal/.boot-files-written") && (await Ke(o, {
3053
+ phpVersion: e.phpVersion
3054
+ }), await b(o, "/", e.createFiles || {}), await Qe(
3055
+ o,
3056
+ _(new URL(e.siteUrl).pathname, "phpinfo.php")
3057
+ ), await b(o, "/internal", {
617
3058
  ".boot-files-written": ""
618
- })), e && await r.setSpawnHandler(
619
- e(
620
- a ? () => a.instanceManager.acquirePHPInstance() : void 0
3059
+ })), t && await o.setSpawnHandler(
3060
+ t(
3061
+ s ? () => s.instanceManager.acquirePHPInstance() : void 0
621
3062
  )
622
- ), r.enableRuntimeRotation({
623
- recreateRuntime: t.createPhpRuntime,
3063
+ ), o.enableRuntimeRotation({
3064
+ recreateRuntime: e.createPhpRuntime,
624
3065
  maxRequests: 400
625
- }), t.onPHPInstanceCreated && await t.onPHPInstanceCreated(r, { isPrimary: o }), r;
3066
+ }), e.onPHPInstanceCreated && await e.onPHPInstanceCreated(o, { isPrimary: r }), o;
626
3067
  }
627
- const i = new E({
628
- documentRoot: t.documentRoot || "/wordpress",
629
- absoluteUrl: t.siteUrl,
630
- rewriteRules: q,
631
- pathAliases: t.pathAliases,
632
- getFileNotFoundAction: t.getFileNotFoundAction ?? O,
633
- cookieStore: t.cookieStore,
3068
+ const n = new C({
3069
+ documentRoot: e.documentRoot || "/wordpress",
3070
+ absoluteUrl: e.siteUrl,
3071
+ rewriteRules: Ye,
3072
+ pathAliases: e.pathAliases,
3073
+ getFileNotFoundAction: e.getFileNotFoundAction ?? Be,
3074
+ cookieStore: e.cookieStore,
634
3075
  /**
635
3076
  * If maxPhpInstances is 1, the PHPRequestHandler constructor needs
636
3077
  * a PHP instance. Internally, it creates a SinglePHPInstanceManager
637
3078
  * and uses the same PHP instance to handle all requests.
638
3079
  */
639
- php: t.maxPhpInstances === 1 ? await n(void 0, !0) : void 0,
3080
+ php: e.maxPhpInstances === 1 ? await i(void 0, !0) : void 0,
640
3081
  /**
641
3082
  * If maxPhpInstances is not 1, the PHPRequestHandler constructor needs
642
3083
  * a PHP factory function. Internally, it creates a PHPProcessManager that
643
3084
  * maintains a pool of reusable PHP instances.
644
3085
  */
645
- phpFactory: t.maxPhpInstances !== 1 ? async ({ isPrimary: a }) => n(i, a) : void 0,
646
- maxPhpInstances: t.maxPhpInstances
3086
+ phpFactory: e.maxPhpInstances !== 1 ? async ({ isPrimary: s }) => i(n, s) : void 0,
3087
+ maxPhpInstances: e.maxPhpInstances
647
3088
  });
648
- return i;
3089
+ return n;
649
3090
  }
650
- async function w(t) {
651
- return (await t.run({
3091
+ async function k(e) {
3092
+ return (await e.run({
652
3093
  code: `<?php
653
3094
  ob_start();
654
3095
  $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
@@ -662,19 +3103,19 @@ async function w(t) {
662
3103
  ob_end_flush();
663
3104
  `,
664
3105
  env: {
665
- DOCUMENT_ROOT: t.documentRoot
3106
+ DOCUMENT_ROOT: e.documentRoot
666
3107
  }
667
3108
  })).text === "1";
668
3109
  }
669
- async function h(t) {
670
- var i;
671
- const e = await R(
672
- t,
3110
+ async function O(e) {
3111
+ var n;
3112
+ const t = await N(
3113
+ e,
673
3114
  {
674
3115
  disable_functions: "fsockopen",
675
3116
  allow_url_fopen: "0"
676
3117
  },
677
- async () => await t.request({
3118
+ async () => await e.request({
678
3119
  url: "/wp-admin/install.php?step=2",
679
3120
  method: "POST",
680
3121
  body: {
@@ -691,14 +3132,14 @@ async function h(t) {
691
3132
  }
692
3133
  })
693
3134
  );
694
- if (!await w(t))
3135
+ if (!await k(e))
695
3136
  throw new Error(
696
- `Failed to install WordPress – installer responded with "${(i = e.text) == null ? void 0 : i.substring(
3137
+ `Failed to install WordPress – installer responded with "${(n = t.text) == null ? void 0 : n.substring(
697
3138
  0,
698
3139
  100
699
3140
  )}"`
700
3141
  );
701
- (await t.run({
3142
+ (await e.run({
702
3143
  code: `<?php
703
3144
  ob_start();
704
3145
  $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
@@ -721,28 +3162,18 @@ async function h(t) {
721
3162
  ob_end_flush();
722
3163
  `,
723
3164
  env: {
724
- DOCUMENT_ROOT: t.documentRoot
3165
+ DOCUMENT_ROOT: e.documentRoot
725
3166
  }
726
- })).text !== "1" && g.warn("Failed to default to pretty permalinks after WP install.");
3167
+ })).text !== "1" && h.warn("Failed to default to pretty permalinks after WP install.");
727
3168
  }
728
- function O(t) {
3169
+ function Be(e) {
729
3170
  return {
730
3171
  type: "internal-redirect",
731
3172
  uri: "/index.php"
732
3173
  };
733
3174
  }
734
- function A(t) {
735
- const e = s(t.documentRoot, "wp-config.php");
736
- if (!t.isFile(e)) return !1;
737
- const n = t.readFileAsText(e), i = n.match(
738
- /define\s*\(\s*['"]DB_NAME['"]\s*,\s*['"]([^'"]*)['"]/
739
- ), a = n.match(
740
- /define\s*\(\s*['"]DB_USER['"]\s*,\s*['"]([^'"]*)['"]/
741
- );
742
- return !i || !a ? !1 : i[1] !== "database_name_here" && a[1] !== "username_here";
743
- }
744
- async function W(t) {
745
- return (await t.run({
3175
+ async function Ve(e) {
3176
+ return (await e.run({
746
3177
  code: `<?php
747
3178
  ob_start();
748
3179
  $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
@@ -756,35 +3187,35 @@ async function W(t) {
756
3187
  ob_end_flush();
757
3188
  `,
758
3189
  env: {
759
- DOCUMENT_ROOT: t.documentRoot
3190
+ DOCUMENT_ROOT: e.documentRoot
760
3191
  }
761
3192
  })).text === "1";
762
3193
  }
763
- async function Y(t) {
764
- const { php: e, reap: n } = await t.instanceManager.acquirePHPInstance();
3194
+ async function at(e) {
3195
+ const { php: t, reap: i } = await e.instanceManager.acquirePHPInstance();
765
3196
  try {
766
- const a = (await e.run({
3197
+ const s = (await t.run({
767
3198
  code: `<?php
768
- require '${t.documentRoot}/wp-includes/version.php';
3199
+ require '${e.documentRoot}/wp-includes/version.php';
769
3200
  echo $wp_version;
770
3201
  `
771
3202
  })).text;
772
- if (!a)
3203
+ if (!s)
773
3204
  throw new Error("Unable to read loaded WordPress version.");
774
- return U(a);
3205
+ return Xe(s);
775
3206
  } finally {
776
- n();
3207
+ i();
777
3208
  }
778
3209
  }
779
- function U(t) {
780
- if (/-(alpha|beta|RC)\d*-\d+$/.test(t))
3210
+ function Xe(e) {
3211
+ if (/-(alpha|beta|RC)\d*-\d+$/.test(e))
781
3212
  return "trunk";
782
- if (/-(beta|RC)\d*$/.test(t))
3213
+ if (/-(beta|RC)\d*$/.test(e))
783
3214
  return "beta";
784
- const i = t.match(/^(\d+\.\d+)(?:\.\d+)?$/);
785
- return i !== null ? i[1] : t;
3215
+ const n = e.match(/^(\d+\.\d+)(?:\.\d+)?$/);
3216
+ return n !== null ? n[1] : e;
786
3217
  }
787
- const q = [
3218
+ const Ye = [
788
3219
  /**
789
3220
  * Substitutes the multisite WordPress rewrite rule:
790
3221
  *
@@ -800,8 +3231,10 @@ const q = [
800
3231
  replacement: "$2"
801
3232
  }
802
3233
  ];
803
- async function N(t) {
804
- await t.mkdir("/internal/shared/mu-plugins"), await t.writeFile(
3234
+ async function Ke(e, t = {}) {
3235
+ if (w(t.phpVersion))
3236
+ return B(e);
3237
+ await e.mkdir("/internal/shared/mu-plugins"), await e.writeFile(
805
3238
  "/internal/shared/preload/env.php",
806
3239
  `<?php
807
3240
 
@@ -831,7 +3264,7 @@ async function N(t) {
831
3264
  }
832
3265
  }
833
3266
  `
834
- ), await t.writeFile(
3267
+ ), await e.writeFile(
835
3268
  "/internal/shared/mu-plugins/1-auto-login.php",
836
3269
  `<?php
837
3270
  /**
@@ -988,111 +3421,7 @@ async function N(t) {
988
3421
  return $interval;
989
3422
  });
990
3423
  `
991
- ), await t.writeFile(
992
- "/internal/shared/mu-plugins/0-playground.php",
993
- `<?php
994
-
995
- // Save WordPress environment information to a file.
996
- add_action('wp_loaded', function() {
997
- if (defined('DB_ENGINE') && DB_ENGINE === 'sqlite') {
998
- $db_info = array(
999
- 'type' => 'sqlite',
1000
- 'path' => FQDB,
1001
- 'driver_path' => defined('WP_MYSQL_ON_SQLITE_LOADER_PATH')
1002
- ? WP_MYSQL_ON_SQLITE_LOADER_PATH
1003
- : dirname(SQLITE_MAIN_FILE) . '/wp-pdo-mysql-on-sqlite.php',
1004
- );
1005
- } else {
1006
- $db_info = array(
1007
- 'type' => 'mysql',
1008
- // TODO: Save MySQL connection config.
1009
- );
1010
- }
1011
- $wp_env = array('db' => $db_info);
1012
- $wp_env_php = sprintf('<?php return %s;', var_export($wp_env, true));
1013
- $wp_env_file = '/internal/shared/wp-env.php';
1014
- if (!file_exists($wp_env_file) || file_get_contents($wp_env_file) !== $wp_env_php ) {
1015
- file_put_contents($wp_env_file, $wp_env_php);
1016
- }
1017
- });
1018
-
1019
- // Needed because gethostbyname( 'wordpress.org' ) returns
1020
- // a private network IP address for some reason.
1021
- add_filter( 'allowed_redirect_hosts', function( $deprecated = '' ) {
1022
- return array(
1023
- 'wordpress.org',
1024
- 'api.wordpress.org',
1025
- 'downloads.wordpress.org',
1026
- );
1027
- } );
1028
-
1029
- /**
1030
- * Prevents wp_http_validate_url() from universally failing.
1031
- *
1032
- * wp_http_validate_url() calls gethostbyname() to verify whether the host
1033
- * is external. If it is internal, the URL validation fails and WordPress
1034
- * refuses to make a request.
1035
- *
1036
- * However, in EMscripten, gethostbyname() returns a private network IP address.
1037
- * This causes wp_http_validate_url() to return false for all URLs.
1038
- *
1039
- * This filter ensures that all URLs are considered external. In production
1040
- * environments, this would be considered a security risk. However, Playground
1041
- * already provides multiple code execution vectors as features (e.g. Blueprints).
1042
- *
1043
- * If someone wants to poke around local IP addresses, they already have multiple
1044
- * tools at their disposal. Therefore, this is not a real security risk in context
1045
- * of WordPress Playground or Playground CLI.
1046
- */
1047
- add_filter('http_request_host_is_external', '__return_true');
1048
-
1049
- // Support pretty permalinks
1050
- add_filter( 'got_url_rewrite', '__return_true' );
1051
-
1052
- // Create the fonts directory if missing
1053
- if(!file_exists(WP_CONTENT_DIR . '/fonts')) {
1054
- mkdir(WP_CONTENT_DIR . '/fonts');
1055
- }
1056
-
1057
- $log_file = WP_CONTENT_DIR . '/debug.log';
1058
- if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
1059
- if ( is_string( WP_DEBUG_LOG ) ) {
1060
- $log_file = WP_DEBUG_LOG;
1061
- }
1062
- ini_set('error_log', $log_file);
1063
- } else {
1064
- ini_set('log_errors', '0');
1065
- }
1066
- define('ERROR_LOG_FILE', $log_file);
1067
- ?>`
1068
- ), await t.writeFile(
1069
- "/internal/shared/mu-plugins/sitemap-redirect.php",
1070
- `<?php
1071
- /**
1072
- * Redirect sitemap.xml to wp-sitemap.xml for non-root installations.
1073
- *
1074
- * WordPress seems to only generate the sitemap.xml → wp-sitemap.xml rewrite
1075
- * rule when installed at the domain root. This mu-plugin handles the
1076
- * redirect for non-root installations.
1077
- */
1078
- if (isset($_SERVER['REQUEST_URI'])) {
1079
- $site_url = site_url();
1080
- $parsed = parse_url($site_url);
1081
- $base_path = isset($parsed['path']) ? rtrim($parsed['path'], '/') : '';
1082
-
1083
- $request_uri = $_SERVER['REQUEST_URI'];
1084
- if (
1085
- $request_uri === $base_path . '/sitemap.xml' ||
1086
- strpos($request_uri, $base_path . '/sitemap.xml?') === 0 ||
1087
- strpos($request_uri, $base_path . '/sitemap.xml/') === 0
1088
- ) {
1089
- $query_string = strpos($request_uri, '?') !== false ? substr($request_uri, strpos($request_uri, '?')) : '';
1090
- header('Location: ' . $base_path . '/wp-sitemap.xml' . $query_string, true, 301);
1091
- exit;
1092
- }
1093
- }
1094
- `
1095
- ), await t.writeFile(
3424
+ ), await S(e), await e.writeFile(
1096
3425
  "/internal/shared/preload/error-handler.php",
1097
3426
  `<?php
1098
3427
  (function() {
@@ -1145,13 +3474,13 @@ async function N(t) {
1145
3474
  })();`
1146
3475
  );
1147
3476
  }
1148
- async function F(t, e = "/phpinfo.php") {
1149
- await t.writeFile(
3477
+ async function Qe(e, t = "/phpinfo.php") {
3478
+ await e.writeFile(
1150
3479
  "/internal/shared/preload/phpinfo.php",
1151
3480
  `<?php
1152
3481
  // Render PHPInfo if the requested page is /phpinfo.php
1153
- if ( isset($_SERVER['REQUEST_URI']) && ${d(
1154
- e
3482
+ if ( isset($_SERVER['REQUEST_URI']) && ${$(
3483
+ t
1155
3484
  )} === $_SERVER['REQUEST_URI'] ) {
1156
3485
  phpinfo();
1157
3486
  exit;
@@ -1159,105 +3488,44 @@ async function F(t, e = "/phpinfo.php") {
1159
3488
  `
1160
3489
  );
1161
3490
  }
1162
- async function D(t, e) {
1163
- await t.isDir("/tmp/sqlite-database-integration") && await t.rmdir("/tmp/sqlite-database-integration", {
3491
+ async function I(e, t, i = {}) {
3492
+ if (w(i.phpVersion))
3493
+ return Ne(e, t, i);
3494
+ await e.isDir("/tmp/sqlite-database-integration") && await e.rmdir("/tmp/sqlite-database-integration", {
1164
3495
  recursive: !0
1165
- }), await t.mkdir("/tmp/sqlite-database-integration"), await p(t, e, "/tmp/sqlite-database-integration");
1166
- const n = "/internal/shared/sqlite-database-integration", i = `/tmp/sqlite-database-integration/${(await t.listFiles("/tmp/sqlite-database-integration"))[0]}`;
1167
- await t.mv(i, n), await t.defineConstant("SQLITE_MAIN_FILE", "1");
1168
- const o = (await t.readFileAsText(
1169
- s(n, "db.copy")
3496
+ }), await e.mkdir("/tmp/sqlite-database-integration"), await m(e, t, "/tmp/sqlite-database-integration");
3497
+ const n = "/internal/shared/sqlite-database-integration", s = `/tmp/sqlite-database-integration/${(await e.listFiles("/tmp/sqlite-database-integration"))[0]}`;
3498
+ await e.mv(s, n);
3499
+ const r = _(
3500
+ n,
3501
+ "wp-includes/sqlite/class-wp-sqlite-db.php"
3502
+ );
3503
+ if (await e.fileExists(r)) {
3504
+ const d = await e.readFileAsText(r), f = d.replace(
3505
+ "private $allow_unsafe_unquoted_parameters",
3506
+ "protected $allow_unsafe_unquoted_parameters"
3507
+ );
3508
+ f !== d && await e.writeFile(r, f);
3509
+ }
3510
+ await e.defineConstant("SQLITE_MAIN_FILE", "1");
3511
+ const o = (await e.readFileAsText(
3512
+ _(n, "db.copy")
1170
3513
  )).replace(
1171
3514
  "'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",
1172
- d(n)
3515
+ $(n)
1173
3516
  ).replace(
1174
3517
  "'{SQLITE_PLUGIN}'",
1175
- d(s(n, "load.php"))
1176
- ), l = s(await t.documentRoot, "wp-content/db.php"), r = `<?php
3518
+ $(_(n, "load.php"))
3519
+ ), l = _(await e.documentRoot, "wp-content/db.php"), c = `<?php
1177
3520
  // Do not preload this if WordPress comes with a custom db.php file.
1178
- if(file_exists(${d(l)})) {
3521
+ if(file_exists(${$(l)})) {
1179
3522
  return;
1180
3523
  }
1181
- ?>`, c = "/internal/shared/mu-plugins/sqlite-database-integration.php";
1182
- await t.writeFile(c, r + o), await t.writeFile(
3524
+ ?>`, u = "/internal/shared/mu-plugins/sqlite-database-integration.php";
3525
+ await e.writeFile(u, c + o), await e.writeFile(
1183
3526
  "/internal/shared/preload/0-sqlite.php",
1184
- r + `<?php
1185
-
1186
- /**
1187
- * Loads the SQLite integration plugin before WordPress is loaded
1188
- * and without creating a drop-in "db.php" file.
1189
- *
1190
- * Technically, it creates a global $wpdb object whose only two
1191
- * purposes are to:
1192
- *
1193
- * * Exist – because the require_wp_db() WordPress function won't
1194
- * connect to MySQL if $wpdb is already set.
1195
- * * Load the SQLite integration plugin the first time it's used
1196
- * and replace the global $wpdb reference with the SQLite one.
1197
- *
1198
- * This lets Playground keep the WordPress installation clean and
1199
- * solves dillemas like:
1200
- *
1201
- * * Should we include db.php in Playground exports?
1202
- * * Should we remove db.php from Playground imports?
1203
- * * How should we treat stale db.php from long-lived OPFS sites?
1204
- *
1205
- * @see https://github.com/WordPress/wordpress-playground/discussions/1379 for
1206
- * more context.
1207
- */
1208
- class Playground_SQLite_Integration_Loader {
1209
- public function __call($name, $arguments) {
1210
- $this->load_sqlite_integration();
1211
- if($GLOBALS['wpdb'] === $this) {
1212
- throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
1213
- }
1214
- return call_user_func_array(
1215
- array($GLOBALS['wpdb'], $name),
1216
- $arguments
1217
- );
1218
- }
1219
- public function __get($name) {
1220
- $this->load_sqlite_integration();
1221
- if($GLOBALS['wpdb'] === $this) {
1222
- throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
1223
- }
1224
- return $GLOBALS['wpdb']->$name;
1225
- }
1226
- public function __set($name, $value) {
1227
- $this->load_sqlite_integration();
1228
- if($GLOBALS['wpdb'] === $this) {
1229
- throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
1230
- }
1231
- $GLOBALS['wpdb']->$name = $value;
1232
- }
1233
- protected function load_sqlite_integration() {
1234
- require_once ${d(c)};
1235
- }
1236
- }
1237
- /**
1238
- * The Query Monitor plugin short-circuits in the CLI SAPI. However, in Playground,
1239
- * the SAPI is always "cli" at the moment. Let's set a constant to disable the CLI
1240
- * detection.
1241
- *
1242
- * @see https://github.com/WordPress/sqlite-database-integration/pull/212
1243
- * @see https://github.com/WordPress/sqlite-database-integration/pull/215
1244
- */
1245
- define('QM_TESTS', true);
1246
- $wpdb = $GLOBALS['wpdb'] = new Playground_SQLite_Integration_Loader();
1247
-
1248
- /**
1249
- * WordPress is capable of using a preloaded global $wpdb. However, if
1250
- * it cannot find the drop-in db.php plugin it still checks whether
1251
- * the mysqli_connect() function exists even though it's not used.
1252
- *
1253
- * What WordPress demands, Playground shall provide.
1254
- */
1255
- if(!function_exists('mysqli_connect')) {
1256
- function mysqli_connect() {}
1257
- }
1258
-
1259
- `
1260
- ), await t.writeFile(
3527
+ je(c, u)
3528
+ ), await e.writeFile(
1261
3529
  "/internal/shared/mu-plugins/sqlite-test.php",
1262
3530
  `<?php
1263
3531
  global $wpdb;
@@ -1268,117 +3536,127 @@ if(!function_exists('mysqli_connect')) {
1268
3536
  `
1269
3537
  );
1270
3538
  }
1271
- async function M(t, e) {
1272
- t.mkdir("/tmp/unzipped-wordpress"), await p(t, e, "/tmp/unzipped-wordpress"), t.fileExists("/tmp/unzipped-wordpress/wordpress.zip") && await p(
1273
- t,
3539
+ function je(e, t) {
3540
+ return e + `<?php
3541
+
3542
+ ${v(`require_once ${$(t)};`)}
3543
+ if(!function_exists('mysqli_connect')) {
3544
+ function mysqli_connect() {}
3545
+ }
3546
+
3547
+ `;
3548
+ }
3549
+ async function D(e, t) {
3550
+ e.mkdir("/tmp/unzipped-wordpress"), await m(e, t, "/tmp/unzipped-wordpress"), e.fileExists("/tmp/unzipped-wordpress/wordpress.zip") && await m(
3551
+ e,
1274
3552
  "/tmp/unzipped-wordpress/wordpress.zip",
1275
3553
  "/tmp/unzipped-wordpress"
1276
3554
  );
1277
- let n = t.fileExists("/tmp/unzipped-wordpress/wordpress") ? "/tmp/unzipped-wordpress/wordpress" : t.fileExists("/tmp/unzipped-wordpress/build") ? "/tmp/unzipped-wordpress/build" : "/tmp/unzipped-wordpress";
1278
- if (!t.fileExists(s(n, "wp-config-sample.php"))) {
1279
- const a = t.listFiles(n);
1280
- if (a.length) {
1281
- const o = a[0];
1282
- t.fileExists(
1283
- s(n, o, "wp-config-sample.php")
1284
- ) && (n = s(n, o));
3555
+ let i = e.fileExists("/tmp/unzipped-wordpress/wordpress") ? "/tmp/unzipped-wordpress/wordpress" : e.fileExists("/tmp/unzipped-wordpress/build") ? "/tmp/unzipped-wordpress/build" : "/tmp/unzipped-wordpress";
3556
+ if (!e.fileExists(_(i, "wp-config-sample.php"))) {
3557
+ const s = e.listFiles(i);
3558
+ if (s.length) {
3559
+ const r = s[0];
3560
+ e.fileExists(
3561
+ _(i, r, "wp-config-sample.php")
3562
+ ) && (i = _(i, r));
1285
3563
  }
1286
3564
  }
1287
- const i = (a, o, l) => {
1288
- if (l.isDir(a) && l.isDir(o))
1289
- for (const r of l.listFiles(a)) {
1290
- const c = s(a, r), k = s(o, r);
1291
- i(c, k, l);
3565
+ const n = (s, r, a) => {
3566
+ if (a.isDir(s) && a.isDir(r))
3567
+ for (const o of a.listFiles(s)) {
3568
+ const l = _(s, o), c = _(r, o);
3569
+ n(l, c, a);
1292
3570
  }
1293
3571
  else {
1294
- if (l.fileExists(o)) {
1295
- const r = a.replace(
3572
+ if (a.fileExists(r)) {
3573
+ const o = s.replace(
1296
3574
  /^\/tmp\/unzipped-wordpress\//,
1297
3575
  "/"
1298
3576
  );
1299
- g.warn(
1300
- `Cannot unzip WordPress files at ${o}: ${r} already exists.`
3577
+ h.warn(
3578
+ `Cannot unzip WordPress files at ${r}: ${o} already exists.`
1301
3579
  );
1302
3580
  return;
1303
3581
  }
1304
- l.mv(a, o);
3582
+ a.mv(s, r);
1305
3583
  }
1306
3584
  };
1307
- i(n, t.documentRoot, t), t.fileExists(n) && t.rmdir(n, { recursive: !0 }), !t.fileExists(s(t.documentRoot, "wp-config.php")) && t.fileExists(s(t.documentRoot, "wp-config-sample.php")) && t.writeFile(
1308
- s(t.documentRoot, "wp-config.php"),
1309
- t.readFileAsText(
1310
- s(t.documentRoot, "/wp-config-sample.php")
3585
+ n(i, e.documentRoot, e), e.fileExists(i) && e.rmdir(i, { recursive: !0 }), !e.fileExists(_(e.documentRoot, "wp-config.php")) && e.fileExists(_(e.documentRoot, "wp-config-sample.php")) && e.writeFile(
3586
+ _(e.documentRoot, "wp-config.php"),
3587
+ e.readFileAsText(
3588
+ _(e.documentRoot, "/wp-config-sample.php")
1311
3589
  )
1312
3590
  );
1313
3591
  }
1314
- const G = P(fetch), H = "https://github.com/WordPress/WordPress/archive/refs/heads/master.zip";
1315
- async function K(t = "latest") {
1316
- if (t === null)
1317
- t = "latest";
1318
- else if (t.startsWith("https://") || t.startsWith("http://")) {
1319
- const i = await crypto.subtle.digest(
3592
+ const ze = M(fetch), Ze = "https://github.com/WordPress/WordPress/archive/refs/heads/master.zip";
3593
+ async function ot(e = "latest") {
3594
+ if (e === null)
3595
+ e = "latest";
3596
+ else if (e.startsWith("https://") || e.startsWith("http://")) {
3597
+ const n = await crypto.subtle.digest(
1320
3598
  "SHA-1",
1321
- new TextEncoder().encode(t)
1322
- ), a = Array.from(new Uint8Array(i)).map((o) => o.toString(16).padStart(2, "0")).join("");
3599
+ new TextEncoder().encode(e)
3600
+ ), s = Array.from(new Uint8Array(n)).map((r) => r.toString(16).padStart(2, "0")).join("");
1323
3601
  return {
1324
- releaseUrl: t,
1325
- version: "custom-" + a.substring(0, 8),
3602
+ releaseUrl: e,
3603
+ version: "custom-" + s.substring(0, 8),
1326
3604
  source: "inferred"
1327
3605
  };
1328
- } else if (t === "trunk" || t === "nightly") {
1329
- const i = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
3606
+ } else if (e === "trunk" || e === "nightly") {
3607
+ const n = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1330
3608
  return {
1331
- releaseUrl: `${H}?ts=${i}`,
3609
+ releaseUrl: `${Ze}?ts=${n}`,
1332
3610
  version: "trunk",
1333
3611
  source: "inferred"
1334
3612
  };
1335
3613
  }
1336
- let n = await (await G(
3614
+ let i = await (await ze(
1337
3615
  "https://api.wordpress.org/core/version-check/1.7/?channel=beta"
1338
3616
  )).json();
1339
- n = n.offers.filter(
1340
- (i) => i.response === "autoupdate"
3617
+ i = i.offers.filter(
3618
+ (n) => n.response === "autoupdate"
1341
3619
  );
1342
- for (const i of n) {
1343
- if (t === "beta" && (i.version.includes("beta") || i.version.includes("RC")))
3620
+ for (const n of i) {
3621
+ if (e === "beta" && (n.version.includes("beta") || n.version.includes("RC")))
1344
3622
  return {
1345
- releaseUrl: i.download,
1346
- version: i.version,
3623
+ releaseUrl: n.download,
3624
+ version: n.version,
1347
3625
  source: "api"
1348
3626
  };
1349
- if (t === "latest" && !i.version.includes("beta") && !i.version.includes("RC"))
3627
+ if (e === "latest" && !n.version.includes("beta") && !n.version.includes("RC"))
1350
3628
  return {
1351
- releaseUrl: i.download,
1352
- version: i.version,
3629
+ releaseUrl: n.download,
3630
+ version: n.version,
1353
3631
  source: "api"
1354
3632
  };
1355
- if (i.version.substring(0, t.length) === t)
3633
+ if (n.version.substring(0, e.length) === e)
1356
3634
  return {
1357
- releaseUrl: i.download,
1358
- version: i.version,
3635
+ releaseUrl: n.download,
3636
+ version: n.version,
1359
3637
  source: "api"
1360
3638
  };
1361
3639
  }
1362
- return t.match(/^\d+\.\d+\.0$/) && (t = t.split(".").slice(0, 2).join(".")), {
1363
- releaseUrl: `https://wordpress.org/wordpress-${t}.zip`,
1364
- version: t,
3640
+ return e.match(/^\d+\.\d+\.0$/) && (e = e.split(".").slice(0, 2).join(".")), {
3641
+ releaseUrl: `https://wordpress.org/wordpress-${e}.zip`,
3642
+ version: e,
1365
3643
  source: "inferred"
1366
3644
  };
1367
3645
  }
1368
3646
  export {
1369
- C as bootRequestHandler,
1370
- L as bootWordPress,
1371
- Z as bootWordPressAndRequestHandler,
1372
- V as defineWpConfigConstants,
1373
- I as ensureWpConfig,
1374
- O as getFileNotFoundActionForWordPress,
1375
- Y as getLoadedWordPressVersion,
1376
- F as preloadPhpInfoRoute,
1377
- D as preloadSqliteIntegration,
1378
- K as resolveWordPressRelease,
1379
- N as setupPlatformLevelMuPlugins,
1380
- M as unzipWordPress,
1381
- U as versionStringToLoadedWordPressVersion,
1382
- q as wordPressRewriteRules
3647
+ He as bootRequestHandler,
3648
+ Me as bootWordPress,
3649
+ rt as bootWordPressAndRequestHandler,
3650
+ st as defineWpConfigConstants,
3651
+ ve as ensureWpConfig,
3652
+ Be as getFileNotFoundActionForWordPress,
3653
+ at as getLoadedWordPressVersion,
3654
+ Qe as preloadPhpInfoRoute,
3655
+ I as preloadSqliteIntegration,
3656
+ ot as resolveWordPressRelease,
3657
+ Ke as setupPlatformLevelMuPlugins,
3658
+ D as unzipWordPress,
3659
+ Xe as versionStringToLoadedWordPressVersion,
3660
+ Ye as wordPressRewriteRules
1383
3661
  };
1384
3662
  //# sourceMappingURL=index.js.map