@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.cjs CHANGED
@@ -1,4 +1,1586 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("@php-wasm/util"),p=require("@wp-playground/common"),_=require("@php-wasm/logger"),d=require("@php-wasm/universal"),$=`<?php
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const f=require("@php-wasm/universal"),o=require("@php-wasm/util"),g=require("@wp-playground/common"),h=require("@php-wasm/logger");async function O(e){await e.writeFile("/internal/shared/mu-plugins/0-playground.php",`<?php
2
+
3
+ // Save WordPress environment information to a file.
4
+ // Named function (not a closure) so this file parses on PHP 5.2.
5
+ function playground_save_wp_env_info() {
6
+ if (defined('DB_ENGINE') && DB_ENGINE === 'sqlite') {
7
+ $db_info = array(
8
+ 'type' => 'sqlite',
9
+ 'path' => FQDB,
10
+ 'driver_path' => defined('WP_MYSQL_ON_SQLITE_LOADER_PATH')
11
+ ? WP_MYSQL_ON_SQLITE_LOADER_PATH
12
+ : dirname(SQLITE_MAIN_FILE) . '/wp-pdo-mysql-on-sqlite.php',
13
+ );
14
+ } else {
15
+ $db_info = array(
16
+ 'type' => 'mysql',
17
+ // TODO: Save MySQL connection config.
18
+ );
19
+ }
20
+ $wp_env = array('db' => $db_info);
21
+ $wp_env_php = sprintf('<?php return %s;', var_export($wp_env, true));
22
+ $wp_env_file = '/internal/shared/wp-env.php';
23
+ if (!file_exists($wp_env_file) || file_get_contents($wp_env_file) !== $wp_env_php ) {
24
+ file_put_contents($wp_env_file, $wp_env_php);
25
+ }
26
+ }
27
+ add_action('wp_loaded', 'playground_save_wp_env_info');
28
+
29
+ // Needed because gethostbyname( 'wordpress.org' ) returns
30
+ // a private network IP address for some reason.
31
+ function playground_allowed_redirect_hosts( $deprecated = '' ) {
32
+ return array(
33
+ 'wordpress.org',
34
+ 'api.wordpress.org',
35
+ 'downloads.wordpress.org',
36
+ );
37
+ }
38
+ add_filter( 'allowed_redirect_hosts', 'playground_allowed_redirect_hosts' );
39
+
40
+ /**
41
+ * Prevents wp_http_validate_url() from universally failing.
42
+ *
43
+ * wp_http_validate_url() calls gethostbyname() to verify whether the host
44
+ * is external. If it is internal, the URL validation fails and WordPress
45
+ * refuses to make a request.
46
+ *
47
+ * However, in EMscripten, gethostbyname() returns a private network IP address.
48
+ * This causes wp_http_validate_url() to return false for all URLs.
49
+ *
50
+ * This filter ensures that all URLs are considered external. In production
51
+ * environments, this would be considered a security risk. However, Playground
52
+ * already provides multiple code execution vectors as features (e.g. Blueprints).
53
+ *
54
+ * If someone wants to poke around local IP addresses, they already have multiple
55
+ * tools at their disposal. Therefore, this is not a real security risk in context
56
+ * of WordPress Playground or Playground CLI.
57
+ */
58
+ add_filter('http_request_host_is_external', '__return_true');
59
+
60
+ // Support pretty permalinks
61
+ add_filter( 'got_url_rewrite', '__return_true' );
62
+
63
+ /**
64
+ * Flush rewrite rules on the first real WordPress request.
65
+ *
66
+ * During boot, we set permalink_structure in the database
67
+ * but can't flush rewrite rules at that point because WordPress
68
+ * isn't fully bootstrapped — post types and taxonomies haven't
69
+ * been registered yet, so the generated rules are incomplete.
70
+ *
71
+ * This hook fires on 'init' at a very late priority, after all
72
+ * post types and taxonomies are registered. It checks if the
73
+ * rewrite_rules option is empty (meaning rules were never
74
+ * flushed) and if permalink_structure is set, then flushes once.
75
+ * A flag file prevents repeated flushes on subsequent requests.
76
+ */
77
+ function playground_maybe_flush_rewrite_rules() {
78
+ $flag = '/internal/shared/.rewrite-rules-flushed';
79
+ if (file_exists($flag)) {
80
+ return;
81
+ }
82
+ if (!function_exists('get_option')) {
83
+ return;
84
+ }
85
+ $structure = get_option('permalink_structure');
86
+ if (empty($structure)) {
87
+ return;
88
+ }
89
+ $rules = get_option('rewrite_rules');
90
+ if (!empty($rules)) {
91
+ @file_put_contents($flag, '1');
92
+ return;
93
+ }
94
+ global $wp_rewrite;
95
+ if (!isset($wp_rewrite) && class_exists('WP_Rewrite')) {
96
+ $wp_rewrite = new WP_Rewrite();
97
+ }
98
+ if (isset($wp_rewrite) && method_exists($wp_rewrite, 'flush_rules')) {
99
+ $wp_rewrite->flush_rules();
100
+ }
101
+ @file_put_contents($flag, '1');
102
+ }
103
+ add_action('init', 'playground_maybe_flush_rewrite_rules', 99999);
104
+
105
+ // Create the fonts directory if missing
106
+ if(!file_exists(WP_CONTENT_DIR . '/fonts')) {
107
+ mkdir(WP_CONTENT_DIR . '/fonts');
108
+ }
109
+
110
+ $log_file = WP_CONTENT_DIR . '/debug.log';
111
+ if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
112
+ if ( is_string( WP_DEBUG_LOG ) ) {
113
+ $log_file = WP_DEBUG_LOG;
114
+ }
115
+ ini_set('error_log', $log_file);
116
+ } else {
117
+ ini_set('log_errors', '0');
118
+ }
119
+ define('ERROR_LOG_FILE', $log_file);
120
+ ?>`),await e.writeFile("/internal/shared/mu-plugins/sitemap-redirect.php",`<?php
121
+ /**
122
+ * Redirect sitemap.xml to wp-sitemap.xml for non-root installations.
123
+ *
124
+ * WordPress seems to only generate the sitemap.xml → wp-sitemap.xml rewrite
125
+ * rule when installed at the domain root. This mu-plugin handles the
126
+ * redirect for non-root installations.
127
+ */
128
+ if (isset($_SERVER['REQUEST_URI'])) {
129
+ $site_url = site_url();
130
+ $parsed = parse_url($site_url);
131
+ $base_path = isset($parsed['path']) ? rtrim($parsed['path'], '/') : '';
132
+
133
+ $request_uri = $_SERVER['REQUEST_URI'];
134
+ if (
135
+ $request_uri === $base_path . '/sitemap.xml' ||
136
+ strpos($request_uri, $base_path . '/sitemap.xml?') === 0 ||
137
+ strpos($request_uri, $base_path . '/sitemap.xml/') === 0
138
+ ) {
139
+ $query_string = strpos($request_uri, '?') !== false ? substr($request_uri, strpos($request_uri, '?')) : '';
140
+ header('Location: ' . $base_path . '/wp-sitemap.xml' . $query_string, true, 301);
141
+ exit;
142
+ }
143
+ }
144
+ `),await e.writeFile("/internal/shared/mu-plugins/inline-tinymce-content-css.php",`<?php
145
+ function playground_inline_tinymce_content_css($settings) {
146
+ if (empty($settings['content_css'])) return $settings;
147
+ $css_urls = explode(',', $settings['content_css']);
148
+ $inline_css = '';
149
+ $doc_root = isset($_SERVER['DOCUMENT_ROOT'])
150
+ ? $_SERVER['DOCUMENT_ROOT'] : '/wordpress';
151
+ foreach ($css_urls as $url) {
152
+ $url = trim($url);
153
+ if (!$url) continue;
154
+ $parsed = parse_url($url);
155
+ if (!isset($parsed['path'])) continue;
156
+ $path = preg_replace('#^/scope:[^/]+#', '', $parsed['path']);
157
+ $file = $doc_root . $path;
158
+ if (file_exists($file)) {
159
+ $inline_css .= @file_get_contents($file) . "\\n";
160
+ }
161
+ }
162
+ if ($inline_css !== '') {
163
+ if (!empty($settings['content_style'])) {
164
+ $inline_css = $settings['content_style'] . "\\n" . $inline_css;
165
+ }
166
+ $settings['content_style'] = $inline_css;
167
+ $settings['content_css'] = '';
168
+ }
169
+ return $settings;
170
+ }
171
+ add_filter('tiny_mce_before_init', 'playground_inline_tinymce_content_css');
172
+ `)}function N(e){return`
173
+ /**
174
+ * Loads the SQLite integration plugin before WordPress is loaded
175
+ * and without creating a drop-in "db.php" file.
176
+ *
177
+ * Technically, it creates a global $wpdb object whose only two
178
+ * purposes are to:
179
+ *
180
+ * * Exist – because the require_wp_db() WordPress function won't
181
+ * connect to MySQL if $wpdb is already set.
182
+ * * Load the SQLite integration plugin the first time it's used
183
+ * and replace the global $wpdb reference with the SQLite one.
184
+ *
185
+ * This lets Playground keep the WordPress installation clean and
186
+ * solves dillemas like:
187
+ *
188
+ * * Should we include db.php in Playground exports?
189
+ * * Should we remove db.php from Playground imports?
190
+ * * How should we treat stale db.php from long-lived OPFS sites?
191
+ *
192
+ * @see https://github.com/WordPress/wordpress-playground/discussions/1379 for
193
+ * more context.
194
+ */
195
+ class Playground_SQLite_Integration_Loader {
196
+ public function __call($name, $arguments) {
197
+ $this->load_sqlite_integration();
198
+ if($GLOBALS['wpdb'] === $this) {
199
+ throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
200
+ }
201
+ return call_user_func_array(
202
+ array($GLOBALS['wpdb'], $name),
203
+ $arguments
204
+ );
205
+ }
206
+ public function __get($name) {
207
+ $this->load_sqlite_integration();
208
+ if($GLOBALS['wpdb'] === $this) {
209
+ throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
210
+ }
211
+ return $GLOBALS['wpdb']->$name;
212
+ }
213
+ public function __set($name, $value) {
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
+ $GLOBALS['wpdb']->$name = $value;
219
+ }
220
+ protected function load_sqlite_integration() {
221
+ ${e}
222
+ }
223
+ }
224
+ /**
225
+ * The Query Monitor plugin short-circuits in the CLI SAPI. However, in Playground,
226
+ * the SAPI is always "cli" at the moment. Let's set a constant to disable the CLI
227
+ * detection.
228
+ *
229
+ * @see https://github.com/WordPress/sqlite-database-integration/pull/212
230
+ * @see https://github.com/WordPress/sqlite-database-integration/pull/215
231
+ */
232
+ define('QM_TESTS', true);
233
+ $wpdb = $GLOBALS['wpdb'] = new Playground_SQLite_Integration_Loader();
234
+
235
+ /**
236
+ * WordPress is capable of using a preloaded global $wpdb. However, if
237
+ * it cannot find the drop-in db.php plugin it still checks whether
238
+ * the mysqli_connect() function exists even though it's not used.
239
+ *
240
+ * What WordPress demands, Playground shall provide.
241
+ */
242
+ `}const W=`
243
+ if (function_exists('is_user_logged_in') && is_user_logged_in()) {
244
+ return;
245
+ }
246
+ if (headers_sent()) {
247
+ return;
248
+ }
249
+
250
+ // Legacy auto-login never redirects; it populates $_COOKIE
251
+ // in-process for the current request and relies on
252
+ // setcookie() / wp_set_auth_cookie() to persist across
253
+ // requests via HttpCookieStore.
254
+
255
+ // WP 2.5+
256
+ if (function_exists('wp_set_current_user') && function_exists('wp_set_auth_cookie')) {
257
+ $user = function_exists('get_user_by')
258
+ ? get_user_by('login', $user_name)
259
+ : (function_exists('get_userdatabylogin')
260
+ ? get_userdatabylogin($user_name) : null);
261
+ if (!$user) return;
262
+
263
+ wp_set_current_user($user->ID, $user->user_login);
264
+ // Populate $_COOKIE in-process so auth_redirect() and
265
+ // wp_verify_nonce() see the session for the remainder
266
+ // of this request; wp_set_auth_cookie() also emits
267
+ // Set-Cookie for subsequent requests.
268
+ wp_set_auth_cookie($user->ID);
269
+ if (function_exists('wp_generate_auth_cookie')) {
270
+ $_pg_exp = time() + 172800;
271
+ if (defined('AUTH_COOKIE'))
272
+ $_COOKIE[AUTH_COOKIE] = wp_generate_auth_cookie($user->ID, $_pg_exp, 'auth');
273
+ if (defined('SECURE_AUTH_COOKIE'))
274
+ $_COOKIE[SECURE_AUTH_COOKIE] = wp_generate_auth_cookie($user->ID, $_pg_exp, 'secure_auth');
275
+ if (defined('LOGGED_IN_COOKIE'))
276
+ $_COOKIE[LOGGED_IN_COOKIE] = wp_generate_auth_cookie($user->ID, $_pg_exp, 'logged_in');
277
+ }
278
+ return;
279
+ }
280
+
281
+ // WP 1.5–2.4
282
+ if (defined('USER_COOKIE') && defined('PASS_COOKIE')) {
283
+ $_pg_pass_cookie = md5(md5('password'));
284
+ $_COOKIE[USER_COOKIE] = $user_name;
285
+ $_COOKIE[PASS_COOKIE] = $_pg_pass_cookie;
286
+ if (!headers_sent()) {
287
+ $_pg_exp = time() + 172800;
288
+ setcookie(USER_COOKIE, $user_name, $_pg_exp, '/');
289
+ setcookie(PASS_COOKIE, $_pg_pass_cookie, $_pg_exp, '/');
290
+ }
291
+ $GLOBALS['current_user'] = null;
292
+ if (function_exists('get_currentuserinfo')) {
293
+ get_currentuserinfo();
294
+ }
295
+ return;
296
+ }
297
+
298
+ // WP 1.0–1.2: cookies are usually already set by
299
+ // playground_legacy_set_auth_cookies_early() in env.php,
300
+ // but WP 1.0–1.2 reads its user state from globals (no
301
+ // WP_User), so populate those explicitly here.
302
+ $cookiehash = defined('COOKIEHASH')
303
+ ? COOKIEHASH
304
+ : (isset($GLOBALS['cookiehash']) && $GLOBALS['cookiehash']
305
+ ? $GLOBALS['cookiehash']
306
+ : (function_exists('get_settings')
307
+ ? md5(get_settings('siteurl'))
308
+ : ''));
309
+ if ($cookiehash) {
310
+ $_pg_user_cookie_name = 'wordpressuser_' . $cookiehash;
311
+ $_pg_pass_cookie_name = 'wordpresspass_' . $cookiehash;
312
+ $_pg_pass_cookie_value = md5(md5('password'));
313
+ $_COOKIE[$_pg_user_cookie_name] = $user_name;
314
+ $_COOKIE[$_pg_pass_cookie_name] = $_pg_pass_cookie_value;
315
+ if (!headers_sent()) {
316
+ $_pg_exp = time() + 172800;
317
+ setcookie($_pg_user_cookie_name, $user_name, $_pg_exp, '/');
318
+ setcookie($_pg_pass_cookie_name, $_pg_pass_cookie_value, $_pg_exp, '/');
319
+ }
320
+ if (function_exists('get_userdatabylogin')) {
321
+ $userdata = get_userdatabylogin($user_name);
322
+ if ($userdata) {
323
+ $GLOBALS['user_login'] = $user_name;
324
+ $GLOBALS['userdata'] = $userdata;
325
+ $GLOBALS['user_level'] = isset($userdata->user_level) ? (int) $userdata->user_level : 10;
326
+ $GLOBALS['user_ID'] = $userdata->ID;
327
+ $GLOBALS['user_email'] = isset($userdata->user_email) ? $userdata->user_email : '';
328
+ $GLOBALS['user_url'] = isset($userdata->user_url) ? $userdata->user_url : '';
329
+ $GLOBALS['user_nickname'] = isset($userdata->user_nickname) ? $userdata->user_nickname : $user_name;
330
+ $GLOBALS['user_pass_md5'] = md5(isset($userdata->user_pass) ? $userdata->user_pass : '');
331
+ }
332
+ }
333
+ return;
334
+ }
335
+ `;async function G(e){await e.mkdir("/internal/shared/mu-plugins"),await e.writeFile("/internal/shared/auto_prepend_file.php",`<?php
336
+ // Polyfill the PHP 4 superglobals WP 1.0–2.5 still reads (removed
337
+ // in PHP 5.4). Bind by reference so later writes to $_COOKIE
338
+ // reach $HTTP_COOKIE_VARS, which WP 1.0's get_currentuserinfo()
339
+ // consults.
340
+ $GLOBALS['HTTP_GET_VARS'] = &$_GET;
341
+ $GLOBALS['HTTP_POST_VARS'] = &$_POST;
342
+ $GLOBALS['HTTP_COOKIE_VARS'] = &$_COOKIE;
343
+ $GLOBALS['HTTP_SERVER_VARS'] = &$_SERVER;
344
+ if (isset($_FILES)) $GLOBALS['HTTP_POST_FILES'] = &$_FILES;
345
+ if (isset($_ENV)) $GLOBALS['HTTP_ENV_VARS'] = &$_ENV;
346
+ if (isset($_SESSION)) $GLOBALS['HTTP_SESSION_VARS'] = &$_SESSION;
347
+ // Top-level names register_globals=On used to expose. WP 1.0
348
+ // reads $PHP_SELF / $REMOTE_ADDR directly instead of $_SERVER.
349
+ if (isset($_SERVER['PHP_SELF'])) $GLOBALS['PHP_SELF'] = $_SERVER['PHP_SELF'];
350
+ if (isset($_SERVER['REMOTE_ADDR'])) $GLOBALS['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
351
+ if (isset($_SERVER['REQUEST_URI'])) $GLOBALS['REQUEST_URI'] = $_SERVER['REQUEST_URI'];
352
+ // Default SERVER_PROTOCOL for scripts invoked outside an HTTP
353
+ // request (e.g. php.run() during boot/fixups) — legacy WP reads
354
+ // it unconditionally in places like wp_redirect().
355
+ if (!isset($_SERVER['SERVER_PROTOCOL'])) {
356
+ $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
357
+ }
358
+ if(file_exists('/internal/shared/consts.json')) {
359
+ $consts = json_decode(file_get_contents('/internal/shared/consts.json'), true);
360
+ if ($consts) {
361
+ foreach ($consts as $const => $value) {
362
+ if (!defined($const) && is_scalar($value)) {
363
+ define($const, $value);
364
+ }
365
+ }
366
+ }
367
+ }
368
+ foreach (glob('/internal/shared/preload/*.php') as $file) {
369
+ require_once $file;
370
+ }
371
+ // Buffer early output so a stray PHP notice doesn't commit the
372
+ // response headers before the auto-login mu-plugin gets a chance
373
+ // to call wp_set_auth_cookie() / setcookie() on the init hook —
374
+ // otherwise nonce validation breaks on POST requests. PHP flushes
375
+ // the buffer at script end so output still reaches the browser.
376
+ ob_start();
377
+ `),await e.writeFile("/internal/shared/preload/env.php",`<?php
378
+ // Reads $wp_version from the WordPress install on disk. Falls back
379
+ // to '1.0' so callers can use version_compare() unconditionally.
380
+ function _playground_detect_wp_version() {
381
+ static $version = null;
382
+ if ($version !== null) return $version;
383
+ $doc_root = isset($_SERVER['DOCUMENT_ROOT'])
384
+ ? $_SERVER['DOCUMENT_ROOT'] : '/wordpress';
385
+ $version_path = $doc_root . '/wp-includes/version.php';
386
+ $wp_version = '1.0';
387
+ if (file_exists($version_path)) {
388
+ include $version_path;
389
+ }
390
+ $version = $wp_version;
391
+ return $version;
392
+ }
393
+
394
+ // Returns 'wp10', 'wp12', or 'wp15' based on the WP version on
395
+ // disk — the three $wp_filter shapes apply_filters() understands.
396
+ function _playground_detect_wp_hook_format() {
397
+ static $format = null;
398
+ if ($format !== null) return $format;
399
+ $wp_version = _playground_detect_wp_version();
400
+ if (version_compare($wp_version, '1.5', '>=')) {
401
+ $format = 'wp15';
402
+ } elseif (version_compare($wp_version, '1.2', '>=')) {
403
+ $format = 'wp12';
404
+ } else {
405
+ $format = 'wp10';
406
+ }
407
+ return $format;
408
+ }
409
+
410
+ // Adds filters/actions before WordPress is loaded by writing the
411
+ // $wp_filter shape the target version expects. $function_to_add
412
+ // MUST be a string (no closures).
413
+ function playground_add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
414
+ global $wp_filter;
415
+ $fmt = _playground_detect_wp_hook_format();
416
+ if ($fmt === 'wp10') {
417
+ $wp_filter[$tag][] = $function_to_add;
418
+ } elseif ($fmt === 'wp12') {
419
+ $wp_filter[$tag][$priority][] = $function_to_add;
420
+ } else {
421
+ $wp_filter[$tag][$priority][$function_to_add] = array(
422
+ 'function' => $function_to_add,
423
+ 'accepted_args' => $accepted_args
424
+ );
425
+ }
426
+ }
427
+ function playground_add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
428
+ playground_add_filter( $tag, $function_to_add, $priority, $accepted_args );
429
+ }
430
+
431
+ // Set WP 1.0–2.4 auth cookies before WordPress loads — by the time
432
+ // the init hook fires (and on WP 1.0–1.2 it may not fire at all on
433
+ // the front page) WordPress has already read $_COOKIE. setcookie()
434
+ // also persists them across requests via HttpCookieStore.
435
+ // WP 2.5+ uses the HMAC auth cookie scheme and doesn't read these
436
+ // wordpressuser_/wordpresspass_ cookies at all — bail there so we
437
+ // don't write inert cookies the runtime would have to clean up.
438
+ function playground_legacy_set_auth_cookies_early() {
439
+ if (!defined('PLAYGROUND_AUTO_LOGIN_AS_USER')) return;
440
+ if (isset($_COOKIE['playground_auto_login_already_logged_out'])) return;
441
+ if (version_compare(_playground_detect_wp_version(), '2.5', '>=')) return;
442
+
443
+ foreach ($_COOKIE as $name => $_) {
444
+ if (strncmp($name, 'wordpressuser_', 14) === 0) return;
445
+ }
446
+
447
+ $user_name = PLAYGROUND_AUTO_LOGIN_AS_USER;
448
+ $pass_md5 = md5(md5('password'));
449
+
450
+ // Read siteurl from SQLite so the cookie hash matches what
451
+ // WP 1.0–2.4 derives from get_settings('siteurl').
452
+ $siteurl = null;
453
+ $db_path = defined('DB_DIR') ? DB_DIR . '.ht.sqlite' : '';
454
+ if ($db_path && class_exists('PDO') && file_exists($db_path)) {
455
+ try {
456
+ $pdo = new PDO('sqlite:' . $db_path);
457
+ $stmt = $pdo->query("SELECT option_value FROM wp_options WHERE option_name = 'siteurl' LIMIT 1");
458
+ if ($stmt) $siteurl = $stmt->fetchColumn();
459
+ $pdo = null;
460
+ } catch (Exception $e) {}
461
+ }
462
+ if (!$siteurl && defined('WP_SITEURL')) $siteurl = WP_SITEURL;
463
+ if (!$siteurl) return;
464
+
465
+ $cookiehash = md5($siteurl);
466
+ $user_cookie_name = 'wordpressuser_' . $cookiehash;
467
+ $pass_cookie_name = 'wordpresspass_' . $cookiehash;
468
+ $_COOKIE[$user_cookie_name] = $user_name;
469
+ $_COOKIE[$pass_cookie_name] = $pass_md5;
470
+
471
+ if (!headers_sent()) {
472
+ $exp = time() + 172800;
473
+ setcookie($user_cookie_name, $user_name, $exp, '/');
474
+ setcookie($pass_cookie_name, $pass_md5, $exp, '/');
475
+ }
476
+ }
477
+ playground_legacy_set_auth_cookies_early();
478
+
479
+ // WP < 4.0 emits YEAR(post_date)='2026' AND MONTH(post_date)='4'
480
+ // against MySQL's loose type coercion. The SQLite driver's UDFs
481
+ // return integers and SQLite is strictly typed (4 != '4'), so
482
+ // strip quotes around numeric RHS values to keep both sides ints.
483
+ function playground_fix_sqlite_date_comparisons($query) {
484
+ if (
485
+ stripos($query, 'YEAR') === false &&
486
+ stripos($query, 'MONTH') === false &&
487
+ stripos($query, 'DAY') === false
488
+ ) {
489
+ return $query;
490
+ }
491
+ return preg_replace(
492
+ '/\\b(YEAR|MONTH|DAYOFMONTH|DAY)\\s*\\(([^)]+)\\)\\s*=\\s*\\'(\\d+)\\'/i',
493
+ '$1($2) = $3',
494
+ $query
495
+ );
496
+ }
497
+ playground_add_filter( 'query', 'playground_fix_sqlite_date_comparisons' );
498
+
499
+ // WP 2.2+ checks WP_SITEURL/WP_HOME inside get_option(); WP <2.2
500
+ // doesn't, so backfill the same behaviour via the option filters
501
+ // to keep admin links on the Playground-scoped URL.
502
+ function playground_override_siteurl($value) {
503
+ if (defined('WP_SITEURL')) {
504
+ return WP_SITEURL;
505
+ }
506
+ return $value;
507
+ }
508
+ function playground_override_home($value) {
509
+ if (defined('WP_HOME')) {
510
+ return WP_HOME;
511
+ }
512
+ return $value;
513
+ }
514
+ playground_add_filter( 'option_siteurl', 'playground_override_siteurl' );
515
+ playground_add_filter( 'option_home', 'playground_override_home' );
516
+
517
+ // Load mu-plugins last so customer mu-plugins win — and so they
518
+ // can't depend on muplugins_loaded. WP < 2.8 doesn't fire that
519
+ // action at all, so init -1000 acts as a fallback (the $loaded
520
+ // flag keeps it idempotent).
521
+ playground_add_action( 'muplugins_loaded', 'playground_load_mu_plugins', 0 );
522
+ playground_add_action( 'init', 'playground_load_mu_plugins', -1000 );
523
+ function playground_load_mu_plugins() {
524
+ static $loaded = false;
525
+ if ($loaded) return;
526
+ $loaded = true;
527
+ $mu_plugins_dir = '/internal/shared/mu-plugins';
528
+ if(!is_dir($mu_plugins_dir)){
529
+ return;
530
+ }
531
+ $mu_plugins = glob( $mu_plugins_dir . '/*.php' );
532
+ sort( $mu_plugins );
533
+ global $wp_version;
534
+ $is_legacy_wp = isset($wp_version) && version_compare($wp_version, '2.8', '<');
535
+ foreach ( $mu_plugins as $mu_plugin ) {
536
+ // Loaded separately by the preload lazy loader or db.php.
537
+ if (strpos($mu_plugin, 'sqlite-database-integration') !== false) {
538
+ continue;
539
+ }
540
+ // WP < 2.8 crashes on closures in hooks and lacks
541
+ // site_url() (added 2.6). 1-auto-login.php is written
542
+ // without either, so it's the only mu-plugin we load
543
+ // on legacy WP.
544
+ if ($is_legacy_wp) {
545
+ if (strpos($mu_plugin, '1-auto-login.php') === false) {
546
+ continue;
547
+ }
548
+ }
549
+ require_once $mu_plugin;
550
+ }
551
+
552
+ // PHP 5.x's foreach over $wp_filter['init'] iterates a copy,
553
+ // so add_action() calls made by the mu-plugin we just loaded
554
+ // won't fire on this same init run. Call them directly.
555
+ if ($is_legacy_wp) {
556
+ if (function_exists('playground_auto_login_redirect_target')) {
557
+ playground_auto_login_redirect_target();
558
+ }
559
+ if (function_exists('playground_auto_login')) {
560
+ playground_auto_login();
561
+ }
562
+ }
563
+ }
564
+ `),await e.writeFile("/internal/shared/mu-plugins/1-auto-login.php",`<?php
565
+ /**
566
+ * Returns the username to auto-login as, if any.
567
+ * @return string|false
568
+ */
569
+ function playground_get_username_for_auto_login() {
570
+ if ( defined('PLAYGROUND_AUTO_LOGIN_AS_USER') && !isset($_COOKIE['playground_auto_login_already_happened']) ) {
571
+ return PLAYGROUND_AUTO_LOGIN_AS_USER;
572
+ }
573
+ if ( defined('PLAYGROUND_FORCE_AUTO_LOGIN_ENABLED') && isset($_GET['playground_force_auto_login_as_user']) ) {
574
+ return $_GET['playground_force_auto_login_as_user'];
575
+ }
576
+ return false;
577
+ }
578
+
579
+ function playground_auto_login() {
580
+ if (empty($_SERVER['REQUEST_URI'])) {
581
+ return;
582
+ }
583
+ $user_name = playground_get_username_for_auto_login();
584
+ if ( false === $user_name ) {
585
+ return;
586
+ }
587
+ if ((function_exists('wp_doing_ajax') && wp_doing_ajax()) || defined('REST_REQUEST')) {
588
+ return;
589
+ }
590
+ ${W}
591
+ }
592
+ add_action('init', 'playground_auto_login', 1);
593
+
594
+ function playground_auto_login_redirect_target() {
595
+ if(strpos($_SERVER['REQUEST_URI'], '?playground-redirection-handler') !== false) {
596
+ $next = $_GET['next'];
597
+ header('Location: ' . $next, true, 302);
598
+ exit;
599
+ }
600
+ }
601
+ add_action('init', 'playground_auto_login_redirect_target', 1);
602
+
603
+ /**
604
+ * Disable the Site Admin Email Verification Screen for any session started
605
+ * via autologin.
606
+ */
607
+ if (function_exists('add_filter')) {
608
+ add_filter('admin_email_check_interval', 'playground_disable_admin_email_check');
609
+ }
610
+ function playground_disable_admin_email_check($interval) {
611
+ if(false === playground_get_username_for_auto_login()) {
612
+ return 0;
613
+ }
614
+ return $interval;
615
+ }
616
+ `),await O(e),await e.writeFile("/internal/shared/preload/error-handler.php",`<?php
617
+ $GLOBALS['_playground_consts'] = array();
618
+ if (file_exists('/internal/shared/consts.json')) {
619
+ $GLOBALS['_playground_consts'] = @json_decode(file_get_contents('/internal/shared/consts.json'), true);
620
+ if (!is_array($GLOBALS['_playground_consts'])) { $GLOBALS['_playground_consts'] = array(); }
621
+ $GLOBALS['_playground_consts'] = array_keys($GLOBALS['_playground_consts']);
622
+ }
623
+ function _playground_error_handler($severity, $message, $file, $line) {
624
+ $playground_consts = $GLOBALS['_playground_consts'];
625
+ ${M}
626
+ return false;
627
+ }
628
+ set_error_handler('_playground_error_handler');`)}const M=`
629
+ // http_api_transports is deprecated since 6.4.0 but Playground's
630
+ // networking layer still registers it for wp_http_supports().
631
+ // @see https://core.trac.wordpress.org/ticket/37708
632
+ if (
633
+ strpos($message, "http_api_transports") !== false &&
634
+ strpos($message, "since version 6.4.0 with no alternative available") !== false
635
+ ) {
636
+ return;
637
+ }
638
+ // Playground predefines constants (SITE_URL, WP_DEBUG, …) that
639
+ // wp-config.php is allowed to redefine; ours take precedence.
640
+ if (strpos($message, "already defined") !== false) {
641
+ foreach($playground_consts as $const) {
642
+ if(strpos($message, "Constant $const already defined") !== false) {
643
+ return;
644
+ }
645
+ }
646
+ }
647
+ // Legacy WP (2.0–3.5) assigns props on uninitialised vars,
648
+ // valid in PHP 4 but E_WARNING since 5.x. Unfixable in core —
649
+ // Playground ships unmodified WordPress releases.
650
+ if (strpos($message, "Creating default object from empty value") !== false) {
651
+ return;
652
+ }
653
+ // WP 2.8's dashboard widget calls get_error_string() on a
654
+ // null SimplePie when feed HTTP requests fail in WASM.
655
+ if (strpos($message, "get_error_string() on null") !== false ||
656
+ strpos($message, "get_error_string() on a non-object") !== false) {
657
+ return;
658
+ }
659
+ // Don't complain about WordPress.org connection errors when
660
+ // the runtime isn't using fetch().
661
+ if (
662
+ (
663
+ ! defined('USE_FETCH_FOR_REQUESTS') ||
664
+ ! USE_FETCH_FOR_REQUESTS
665
+ ) &&
666
+ strpos($message, "WordPress could not establish a secure connection to WordPress.org") !== false)
667
+ {
668
+ return;
669
+ }
670
+ `;async function H(e,t){const i=E(e,t);if(i===null)return;const n=parseFloat(i);if(!Number.isFinite(n)||n<5||n>=6.2)return;const s=o.joinPaths(t,"wp-includes/load.php");if(!e.fileExists(s))return;const r=e.readFileAsText(s),a=r.replace("extension_loaded( 'mysqli' )","function_exists( 'mysqli_connect' )");a!==r&&await e.writeFile(s,a)}function E(e,t){const i=o.joinPaths(t,"wp-includes/version.php");if(!e.fileExists(i))return null;const s=e.readFileAsText(i).match(/\$wp_version\s*=\s*['"]([^'"]+)['"]/);return s?s[1]:null}const B=22527,T="E_ALL & ~8192 & ~2048";async function j(e,t){await te(e,t),await ie(e,t),await se(e,t),await le(e,t),await _e(e,t),await we(e,t),await ue(e,t),await he(e,t),await K(e,t),await Y(e,t);const i=E(e,t);if(i===null)return;const n=parseFloat(i);Number.isFinite(n)&&(n<1.2&&(await ne(e,t),await ee(e,t)),n<1.5&&await Q(e,t),1.5<=n&&n<2&&await fe(e,t),n<2&&(await z(e,t),await oe(e,t)),2.1<=n&&n<2.3&&await J(e,t),n<2.5&&await de(e,t),n<2.8&&(await ge(e,t),await me(e,t)),2.9<=n&&n<3.6&&await X(e,t),3.3<=n&&n<3.4&&await Z(e,t),n>=4.7&&await V(e,t))}async function V(e,t){const i=o.joinPaths(t,"wp-content/themes");if(e.isDir(i))for(const n of e.listFiles(i)){const s=o.joinPaths(i,n,"searchform.php");e.fileExists(s)&&e.unlink(s)}}async function X(e,t){const i=o.joinPaths(t,"wp-admin/includes/dashboard.php");if(e.fileExists(i)){let r=e.readFileAsText(i);if(r.includes("function wp_dashboard_primary()")&&!r.includes("/* pg_no_rss */")){for(const a of["wp_dashboard_primary","wp_dashboard_secondary","wp_dashboard_plugins"])r=r.replace(new RegExp(`function ${a}\\(\\)\\s*\\{`),`function ${a}() { /* pg_no_rss */ return;`);await e.writeFile(i,r)}}const n=o.joinPaths(t,"wp-admin/admin.php");if(e.fileExists(n)){let r=e.readFileAsText(n);r.includes("do_action('admin_init');")&&!r.includes("/* pg_admin_init_cleanup */")&&(r=r.replace("do_action('admin_init');",`/* pg_admin_init_cleanup */
671
+ if (function_exists('remove_action')) {
672
+ @remove_action('admin_init', '_maybe_update_plugins');
673
+ @remove_action('admin_init', '_maybe_update_themes');
674
+ @remove_action('admin_init', '_maybe_update_core');
675
+ @remove_action('admin_init', 'wp_version_check');
676
+ @remove_action('admin_init', 'wp_update_plugins');
677
+ @remove_action('admin_init', 'wp_update_themes');
678
+ }
679
+ do_action('admin_init');`),await e.writeFile(n,r))}const s=o.joinPaths(t,"wp-admin/includes/update.php");if(e.fileExists(s)){let r=e.readFileAsText(s);if(!r.includes("/* pg_admin_no_updates */")){for(const a of["wp_plugin_update_rows","wp_plugin_update_row","wp_theme_update_rows","wp_theme_update_row","wp_update_plugins","wp_update_themes"]){const l=new RegExp(`function ${a}\\s*\\([^)]*\\)\\s*\\{`);l.test(r)&&(r=r.replace(l,_=>_+" /* pg_admin_no_updates */ return;"))}await e.writeFile(s,r)}}for(const r of[o.joinPaths(t,"wp-includes/SimplePie/File.php"),o.joinPaths(t,"wp-includes/class-simplepie.php")]){if(!e.fileExists(r))continue;let a=e.readFileAsText(r);a.includes("function SimplePie_File(")&&!a.includes("/* pg_no_fetch */")&&(a=a.replace(/function SimplePie_File\([^)]*\)\s*\{/,l=>l+`
680
+ /* pg_no_fetch */
681
+ $this->error = 'Network requests disabled in Playground';
682
+ $this->success = false;
683
+ return;`),await e.writeFile(r,a))}}async function Y(e,t){const i=[["function wp_new_blog_notification","pg_no_blog_notification"],["function wp_install_maybe_enable_pretty_permalinks","pg_no_permalink_check"]],n=[o.joinPaths(t,"wp-admin/includes/upgrade.php"),o.joinPaths(t,"wp-admin/upgrade-functions.php")];for(const s of n){if(!e.fileExists(s))continue;let r=e.readFileAsText(s),a=!1;for(const[l,_]of i){if(r.includes(`/* ${_} */`))continue;const c=r.indexOf(l);if(c===-1)continue;const u=r.indexOf("{",c);u!==-1&&(r=r.substring(0,u+1)+` /* ${_} */ return;`+r.substring(u+1),a=!0)}a&&await e.writeFile(s,r)}}async function K(e,t){const i=o.joinPaths(t,"wp-load.php");if(!e.fileExists(i))return;const n=e.readFileAsText(i);if(!n.includes("error_reporting(")||n.includes("~8192")&&n.includes("~2048"))return;const s=n.replace(/error_reporting\(([^)]+)\)/g,(r,a)=>`error_reporting((${a}) & ~8192 & ~2048)`);await e.writeFile(i,s)}async function Q(e,t){const i=o.joinPaths(t,"wp-admin/menu.php");if(e.fileExists(i)){const r=e.readFileAsText(i);if(!r.includes("/* pg_wp10_logo_link */")){const a='<h1 id="wphead"><a href="http://wordpress.org" rel="external">WordPress</a></h1>';if(r.includes(a)){const l=r.replace(a,'<h1 id="wphead"><a href="#" rel="external">WordPress</a></h1> <!-- pg_wp10_logo_link -->');l!==r&&await e.writeFile(i,l)}}}const n=o.joinPaths(t,"wp-admin/admin-header.php");if(e.fileExists(n)){const r=e.readFileAsText(n);if(!r.includes("/* pg_wp12_logo_link */")){const a='<a href="http://wordpress.org" rel="external"',l="</a>",_=r.indexOf(a);if(_!==-1){const c=r.indexOf(l,_);if(c!==-1){const u=r.substring(0,_)+'<a href="#">WordPress</a><!-- pg_wp12_logo_link -->'+r.substring(c+l.length);u!==r&&await e.writeFile(n,u)}}}}const s=o.joinPaths(t,"wp-admin/admin-footer.php");if(e.fileExists(s)){const r=e.readFileAsText(s);if(!r.includes("/* pg_wp10_footer_link */")){const a=r.replace('<a href="http://wordpress.org">WordPress</a>',"WordPress<!-- pg_wp10_footer_link -->").replace('<a href="http://wordpress.org/">WordPress</a>',"WordPress<!-- pg_wp10_footer_link -->");a!==r&&await e.writeFile(s,a)}}}async function z(e,t){const i=o.joinPaths(t,"wp-admin/edit.php");if(!e.fileExists(i))return;const n=e.readFileAsText(i);if(n.includes("/* pg_wp10_post_title_edit */"))return;let s=n;const r='<strong><a href="<?php permalink_link(); ?>" rel="permalink"><?php the_title() ?></a></strong>';s.includes(r)&&(s=s.replace(r,'<strong><a href="post.php?action=edit&amp;post=<?php echo $id /* pg_wp10_post_title_edit */ ?>"><?php the_title() ?></a></strong>'));const a='<td><a href="<?php the_permalink(); ?>" rel="permalink">';s.includes(a)&&(s=s.replace(a,'<td><a href="post.php?action=edit&amp;post=<?php echo $id /* pg_wp10_post_title_edit */ ?>">'));const l=`<td><?php the_title() ?>
684
+ <?php if ('private' == $post->post_status) _e(' - <strong>Private</strong>'); ?></td>`;s.includes(l)&&(s=s.replace(l,`<td><a href="post.php?action=edit&amp;post=<?php echo $id /* pg_wp10_post_title_edit */ ?>"><?php the_title() ?></a>
685
+ <?php if ('private' == $post->post_status) _e(' - <strong>Private</strong>'); ?></td>`)),s!==n&&await e.writeFile(i,s)}async function Z(e,t){const i=o.joinPaths(t,"wp-admin/includes/screen.php");if(!e.fileExists(i))return;const n=e.readFileAsText(i);if(!n.includes("self::$this->_help_sidebar"))return;const s=n.replace(/self::\$this->_help_sidebar/g,"$this->_help_sidebar");s!==n&&await e.writeFile(i,s)}async function J(e,t){const i=o.joinPaths(t,"wp-admin/plugins.php");if(!e.fileExists(i))return;const n=e.readFileAsText(i);if(n.includes("/* pg_wp21_active_plugins_array */"))return;const s="$current = get_option('active_plugins');";if(!n.includes(s))return;const r=n.replace(s,s+`
686
+ if (!is_array($current)) $current = array(); /* pg_wp21_active_plugins_array */`);r!==n&&await e.writeFile(i,r)}async function ee(e,t){const i=o.joinPaths(t,"wp-login.php");if(!e.fileExists(i))return;const n=e.readFileAsText(i),s="AND user_pass = '$password'";if(!n.includes(s)||n.includes("pg_wp10_plain_or_md5"))return;let r=n.replace(s,"AND (user_pass = '$password' OR user_pass = MD5('$password')) /* pg_wp10_plain_or_md5 */");r=r.replace("$login->user_pass == $password","($login->user_pass == $password || $login->user_pass == md5($password))"),r!==n&&await e.writeFile(i,r)}async function te(e,t){const i=o.joinPaths(t,"wp-includes");if(!e.isDir(i))return;const n=o.joinPaths(i,"version.php");e.fileExists(n)||await e.writeFile(n,"<?php $wp_version = '1.0';")}async function ne(e,t){const i=o.joinPaths(t,"wp-blog-header.php");if(e.fileExists(i)){const s=e.readFileAsText(i),r=`$where .= ' AND (post_status = "publish"';`;s.includes(r)&&await e.writeFile(i,s.replace(r,`$where .= " AND (post_status = 'publish'";`))}const n=o.joinPaths(t,"wp-includes/vars.php");if(e.fileExists(n)){const s=e.readFileAsText(n),r="add_filter('all', 'wptexturize');";s.includes(r)&&await e.writeFile(n,s.replace(r,`// ${r} // Disabled by Playground: mangles SQL literals.`))}}async function ie(e,t){const i=o.joinPaths(t,"wp-load.php");e.fileExists(i)||await e.writeFile(i,`<?php
687
+ if ( !defined('ABSPATH') ) {
688
+ define('ABSPATH', dirname(__FILE__) . '/');
689
+ }
690
+ require_once(ABSPATH . 'wp-config.php');
691
+ `)}async function se(e,t){const i=o.joinPaths(t,"wp-settings.php");if(!e.fileExists(i))return;const n=e.readFileAsText(i);let s=n;s=s.replace(/if\s*\(\s*!extension_loaded\('mysql'\)\s*\)\s*\n\s*die/,`if ( false ) // Patched for SQLite
692
+ die`),s=s.replace(/error_reporting\(([^)]+)\)/g,(r,a)=>a.includes("~8192")&&a.includes("~2048")?r:`error_reporting((${a}) & ~8192 & ~2048)`),s=s.replace(/set_magic_quotes_runtime\(\s*0\s*\)\s*;/g,"// set_magic_quotes_runtime(0); // Removed"),s.includes("function_exists('get_magic_quotes_gpc')")||(s=s.replace(/get_magic_quotes_gpc\(\)/g,"(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc())")),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(/define\('WPINC',\s*'wp-includes'\);/,`define('WPINC', 'wp-includes');
693
+ if (!defined('WP_CONTENT_DIR')) define('WP_CONTENT_DIR', ABSPATH . 'wp-content');`)),s=s.replace(/unset\(\s*\$wp_filter\s*,/,"unset("),s=re(s),s=ae(s),s!==n&&await e.writeFile(i,s)}function re(e){const t=e.indexOf("installed WP");if(t===-1)return e;const i=e.lastIndexOf("die(",t);if(i===-1)return e;let n=0;for(let s=i+3;s<e.length;s++)if(e[s]==="(")n++;else if(e[s]===")"&&(n--,n===0)){let r=s+1;return e[r]===";"&&r++,e.substring(0,i)+"true; /* die removed by Playground */"+e.substring(r)}return e}function ae(e){return e.replace("do_action('init');",`// Remove hooks that make outbound HTTP requests (crash WASM).
694
+ if (function_exists('remove_action')) {
695
+ @remove_action('init', 'wp_cron');
696
+ @remove_action('init', 'wp_version_check');
697
+ @remove_action('init', 'wp_update_plugins');
698
+ @remove_action('init', 'wp_update_themes');
699
+ @remove_action('admin_init', '_maybe_update_plugins');
700
+ @remove_action('admin_init', '_maybe_update_themes');
701
+ @remove_action('admin_init', 'wp_version_check');
702
+ @remove_action('admin_init', 'wp_update_plugins');
703
+ @remove_action('admin_init', 'wp_update_themes');
704
+ @remove_action('load-plugins.php', 'wp_update_plugins');
705
+ @remove_action('load-update.php', 'wp_update_plugins');
706
+ @remove_action('load-update.php', 'wp_update_themes');
707
+ @remove_action('load-themes.php', 'wp_update_themes');
708
+ @remove_action('wp_update_plugins', 'wp_update_plugins');
709
+ @remove_action('wp_version_check', 'wp_version_check');
710
+ }
711
+ if (function_exists('add_filter')) {
712
+ function _pg_disable_curl() { return false; }
713
+ function _pg_disable_streams() { return false; }
714
+ @add_filter('use_curl_transport', '_pg_disable_curl');
715
+ @add_filter('use_streams_transport', '_pg_disable_streams');
716
+ @add_filter('use_ftp_transport', '_pg_disable_curl');
717
+ @add_filter('use_fsockopen_transport', '_pg_disable_streams');
718
+ }
719
+ do_action('init');`)}async function oe(e,t){const i=o.joinPaths(t,"wp-includes/functions.php");if(!e.fileExists(i))return;let n=e.readFileAsText(i),s=!1;n.includes("$all_options->{$option->option_name}")&&!n.includes("$all_options = new stdClass")&&(n=n.replace("foreach ($options as $option) {",`$all_options = new stdClass;
720
+ foreach ($options as $option) {`),s=!0),s&&await e.writeFile(i,n)}async function le(e,t){const i=o.joinPaths(t,"wp-admin/install.php");if(!e.fileExists(i))return;const n=e.readFileAsText(i);let s=n;const r=o.joinPaths(t,"wp-admin");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)}async function _e(e,t){const i=o.joinPaths(t,"wp-includes/wp-db.php");if(!e.fileExists(i))return;const n=e.readFileAsText(i);let s=n;s.includes("isset($wpdb)")||(s=s.replace("$wpdb = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);","if ( !isset($wpdb) ) { $wpdb = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST); }")),s.includes("db_connect")||(s=s.replace(/\$this->dbh\s*=\s*@mysql_connect\(\$dbhost\s*,\s*\$dbuser\s*,\s*\$dbpassword(?:\s*,\s*true)?\);/,'if (method_exists($this, "db_connect")) { $this->dbname = $dbname; $this->db_connect(); } else { $this->dbh = @mysql_connect($dbhost, $dbuser, $dbpassword); }')),s=ce(s),s!==n&&await e.writeFile(i,s)}function ce(e){const t=[];if(e.includes("function set_prefix")||t.push(`
721
+ function set_prefix($prefix) {
722
+ $this->prefix = $prefix;
723
+ $tables = array('posts', 'users', 'categories', 'post2cat', 'comments', 'link2cat', 'links', 'options', 'postmeta', 'usermeta', 'terms', 'term_taxonomy', 'term_relationships');
724
+ foreach ($tables as $t) {
725
+ $this->$t = $prefix . $t;
726
+ }
727
+ return $prefix;
728
+ }`),e.includes("function timer_start")||t.push(`
729
+ function timer_start() {
730
+ $this->time_start = microtime(true);
731
+ return true;
732
+ }`),e.includes("function timer_stop")||t.push(`
733
+ function timer_stop() {
734
+ return microtime(true) - $this->time_start;
735
+ }`),e.includes("function init_charset")||t.push(`
736
+ function init_charset() {
737
+ if (defined('DB_CHARSET')) $this->charset = DB_CHARSET;
738
+ if (defined('DB_COLLATE')) $this->collate = DB_COLLATE;
739
+ }`),e.includes("function bail")||t.push(`
740
+ function bail($message, $error_code = '500') {
741
+ die($message);
742
+ }`),e.includes("function check_connection")||t.push(`
743
+ function check_connection($allow_bail = true) {
744
+ return true;
745
+ }`),t.length===0)return e;const i=e.match(/^(\s*})\s*\n+(\$wpdb|\?>\s*$|if\s*\(\s*!\s*isset\(\s*\$wpdb\s*\))/m);if(!i||i.index===void 0)return e;const n=`
746
+ // Polyfills added by WordPress Playground.
747
+ `+t.join(`
748
+ `)+`
749
+
750
+ `;return e.substring(0,i.index)+n+e.substring(i.index)}async function ue(e,t){const i=a=>{let l=a,_=0;for(;l.startsWith("../");)_++,l=l.slice(3);for(;l.startsWith("./");)l=l.slice(2);let c="dirname(__FILE__)";for(let u=0;u<_;u++)c=`dirname(${c})`;return`${c} . '/${l}'`},n=o.joinPaths(t,"wp-admin");if(e.isDir(n))for(const a of e.listFiles(n)){if(!a.endsWith(".php"))continue;const l=o.joinPaths(n,a),_=e.readFileAsText(l),c=_.replace(/((?:require|include)(?:_once)?)\s*\(\s*(['"])(\.\.\/[^'"]+)\2\s*\)/g,(u,d,$,p)=>`${d}(${i(p)})`).replace(/((?:require|include)(?:_once)?)\s*\(\s*(['"])(\.\/[^'"]+)\2\s*\)/g,(u,d,$,p)=>`${d}(${i(p)})`).replace(/((?:require|include)(?:_once)?)\s*\(\s*(['"])([a-z][\w-]*\.php)\2\s*\)/g,(u,d,$,p)=>`${d}(${i(p)})`).replace(/((?:require|include)(?:_once)?)\s+(['"])(\.\.\/[^'"]+)\2/g,(u,d,$,p)=>`${d}(${i(p)})`).replace(/((?:require|include)(?:_once)?)\s+(['"])(\.\/[^'"]+)\2/g,(u,d,$,p)=>`${d}(${i(p)})`).replace(/((?:require|include)(?:_once)?)\s+(['"])([a-z][\w-]*\.php)\2/g,(u,d,$,p)=>`${d}(${i(p)})`).replace(/ABSPATH\s*\.\s*'\/wp-/g,"ABSPATH . 'wp-");c!==_&&await e.writeFile(l,c)}const s=o.joinPaths(t,"wp-admin/index.php");if(e.fileExists(s)){let a=e.readFileAsText(s);a.includes("get_settings('siteurl')")&&(a=a.replace(/get_settings\('siteurl'\)\s*\.\s*'\/wp-admin\//g,"'"),await e.writeFile(s,a))}const r=o.joinPaths(t,"wp-admin/menu.php");if(e.fileExists(r)){const a=e.readFileAsText(r),l="file('./menu.txt')";a.includes(l)&&await e.writeFile(r,a.replace(l,"file(dirname(__FILE__) . '/menu.txt')"))}}async function de(e,t){const i=o.joinPaths(t,"wp-admin/admin-functions.php");if(!e.fileExists(i))return;const n=e.readFileAsText(i);if(!n.includes("function check_admin_referer()")||!n.includes("$_SERVER['HTTP_REFERER']"))return;const s=pe(n,"check_admin_referer",`
751
+ do_action('check_admin_referer', '');
752
+ `);s!==n&&await e.writeFile(i,s)}function pe(e,t,i){const n=`function ${t}()`,s=e.indexOf(n);if(s===-1)return e;const r=e.indexOf("{",s+n.length);if(r===-1)return e;let a=1;for(let l=r+1;l<e.length;l++){const _=e[l];if(_==="{")a++;else if(_==="}"&&(a--,a===0))return e.substring(0,r+1)+i+e.substring(l)}return e}async function fe(e,t){const i=o.joinPaths(t,"wp-admin/index.php");if(e.fileExists(i)){const n=e.readFileAsText(i),s=n.replace(/AND post_date_gmt < '\$today'/,"");s!==n&&await e.writeFile(i,s)}await $e(e,t)}async function $e(e,t){const i=o.joinPaths(t,"wp-includes/rss-functions.php");if(!e.fileExists(i))return;let n=e.readFileAsText(i);!/^\s*error\s*\(/m.test(n)||/^function\s+error\s*\(/m.test(n)||(n=n.replace(/^(<\?php\s*)/,`$1
753
+ if (!function_exists('error')) {
754
+ function error($msg = '', $lvl = E_USER_WARNING) {
755
+ if (defined('MAGPIE_DEBUG') && MAGPIE_DEBUG) {
756
+ trigger_error($msg, $lvl);
757
+ }
758
+ }
759
+ }
760
+ `),await e.writeFile(i,n))}async function he(e,t){const i=o.joinPaths(t,"wp-login.php");if(!e.fileExists(i))return;let n=e.readFileAsText(i),s=!1;for(const r of["log","pwd"]){const a=new RegExp(`(\\bname=(['"])${r}\\2)(?![^>]*data-1p-ignore)`);a.test(n)&&(n=n.replace(a,"$1 data-1p-ignore"),s=!0)}s&&await e.writeFile(i,n)}async function ge(e,t){const i=o.joinPaths(t,"wp-admin/admin.php");if(e.fileExists(i)){const s=e.readFileAsText(i);if(s.includes("auth_redirect()")){const r=`
761
+ // Playground: populate auth cookies and force admin user before auth_redirect.
762
+ if (defined('PLAYGROUND_AUTO_LOGIN_AS_USER')) {
763
+ if (function_exists('is_user_logged_in') && is_user_logged_in()) {
764
+ // On WP < 4.0, wp_set_auth_cookie() does not update $_COOKIE
765
+ // in-process — auth_redirect() reads $_COOKIE, so re-emit.
766
+ if (function_exists('wp_generate_auth_cookie') && defined('LOGGED_IN_COOKIE') && empty($_COOKIE[LOGGED_IN_COOKIE])) {
767
+ $_pg_uid = wp_get_current_user()->ID;
768
+ $_pg_exp = time() + 172800;
769
+ $_COOKIE[AUTH_COOKIE] = wp_generate_auth_cookie($_pg_uid, $_pg_exp, 'auth');
770
+ if (defined('SECURE_AUTH_COOKIE'))
771
+ $_COOKIE[SECURE_AUTH_COOKIE] = wp_generate_auth_cookie($_pg_uid, $_pg_exp, 'secure_auth');
772
+ $_COOKIE[LOGGED_IN_COOKIE] = wp_generate_auth_cookie($_pg_uid, $_pg_exp, 'logged_in');
773
+ }
774
+ } else {
775
+ ${A("PLAYGROUND_AUTO_LOGIN_AS_USER")}
776
+ // WP 2.0-2.4: kses_init() runs during do_action('init') inside
777
+ // wp-settings.php and caches $current_user as WP_User(0) when
778
+ // no cookies were set yet. Reset and re-evaluate so capability
779
+ // checks see the user we just authenticated.
780
+ if (!function_exists('wp_generate_auth_cookie')) {
781
+ $GLOBALS['current_user'] = null;
782
+ if (function_exists('get_currentuserinfo')) {
783
+ get_currentuserinfo();
784
+ }
785
+ }
786
+ }
787
+ // Force admin caps in-memory: if populate_roles() never ran
788
+ // (e.g. WP 2.0, or WP 2.5 installs that crashed before writing
789
+ // roles), the user has no caps and every current_user_can() fails.
790
+ $_pg_cu = isset($GLOBALS['current_user']) ? $GLOBALS['current_user'] : null;
791
+ if ($_pg_cu && isset($_pg_cu->ID) && $_pg_cu->ID > 0 && empty($_pg_cu->allcaps['read'])) {
792
+ // Respect a DB-stored user_level so a blueprint that auto-logs
793
+ // in as a lower-privilege user doesn't silently get level 10.
794
+ $_pg_db_level = isset($_pg_cu->user_level)
795
+ ? (int) $_pg_cu->user_level
796
+ : null;
797
+ if ($_pg_db_level === null && isset($_pg_user) && $_pg_user) {
798
+ $_pg_db_level = isset($_pg_user->user_level)
799
+ ? (int) $_pg_user->user_level
800
+ : null;
801
+ }
802
+ $_pg_cu->user_level = $_pg_db_level !== null ? $_pg_db_level : 10;
803
+ $_pg_effective_level = $_pg_cu->user_level;
804
+ $_pg_caps = array('read');
805
+ for ($_pg_i = 0; $_pg_i <= $_pg_effective_level; $_pg_i++) {
806
+ $_pg_caps[] = 'level_' . $_pg_i;
807
+ }
808
+ if ($_pg_effective_level >= 10) {
809
+ $_pg_caps = array_merge($_pg_caps, array(
810
+ 'switch_themes','edit_themes','activate_plugins',
811
+ 'edit_plugins','edit_users','edit_files','manage_options',
812
+ 'moderate_comments','manage_categories','manage_links',
813
+ 'upload_files','import','unfiltered_html','edit_posts',
814
+ 'edit_others_posts','edit_published_posts','publish_posts',
815
+ 'edit_pages'));
816
+ }
817
+ foreach ($_pg_caps as $_pg_c) {
818
+ $_pg_cu->allcaps[$_pg_c] = true;
819
+ }
820
+ if ($_pg_effective_level >= 10) {
821
+ $_pg_cu->caps = array('administrator' => true);
822
+ }
823
+ }
824
+ }
825
+ `,a=s.replace("auth_redirect();",r+"auth_redirect();");a!==s&&await e.writeFile(i,a)}}const n=o.joinPaths(t,"wp-admin/auth.php");if(e.fileExists(n)){const s=e.readFileAsText(n);if(s.includes("$cookiehash")&&!s.includes("Playground: bypass auth")){const r=`<?php
826
+ require_once(ABSPATH . 'wp-config.php');
827
+ // Playground: bypass auth and manually populate user globals.
828
+ global $user_login, $userdata, $user_level, $user_ID,
829
+ $user_nickname, $user_email, $user_url, $user_pass_md5, $cookiehash;
830
+ $__pg_user_login = defined('PLAYGROUND_AUTO_LOGIN_AS_USER')
831
+ ? PLAYGROUND_AUTO_LOGIN_AS_USER
832
+ : 'admin';
833
+ $__pg_cookiehash = defined('COOKIEHASH')
834
+ ? COOKIEHASH
835
+ : (isset($cookiehash) && $cookiehash
836
+ ? $cookiehash
837
+ : md5(function_exists('get_settings') ? get_settings('siteurl') : ''));
838
+ if ($__pg_cookiehash) {
839
+ $_COOKIE['wordpressuser_' . $__pg_cookiehash] = $__pg_user_login;
840
+ }
841
+ if (function_exists('get_userdatabylogin')) {
842
+ $__pg_userdata = get_userdatabylogin($__pg_user_login);
843
+ if ($__pg_userdata) {
844
+ $user_login = $__pg_user_login;
845
+ $userdata = $__pg_userdata;
846
+ $user_level = isset($__pg_userdata->user_level)
847
+ ? (int) $__pg_userdata->user_level
848
+ : 10;
849
+ $user_ID = $__pg_userdata->ID;
850
+ $user_nickname = isset($__pg_userdata->user_nickname)
851
+ ? $__pg_userdata->user_nickname
852
+ : $__pg_user_login;
853
+ $user_email = isset($__pg_userdata->user_email)
854
+ ? $__pg_userdata->user_email
855
+ : '';
856
+ $user_url = isset($__pg_userdata->user_url)
857
+ ? $__pg_userdata->user_url
858
+ : '';
859
+ $user_pass_md5 = md5(
860
+ isset($__pg_userdata->user_pass) ? $__pg_userdata->user_pass : ''
861
+ );
862
+ }
863
+ }
864
+ ?>`;r!==s&&await e.writeFile(n,r)}}}async function me(e,t){const i=o.joinPaths(t,"wp-admin/admin-ajax.php");if(!e.fileExists(i))return;let n=e.readFileAsText(i);if(!n.includes("is_user_logged_in"))return;const s=`
865
+ // Playground: authenticate admin user for AJAX requests on WP < 2.8.
866
+ if (defined('PLAYGROUND_AUTO_LOGIN_AS_USER')) {
867
+ ${A("PLAYGROUND_AUTO_LOGIN_AS_USER")}
868
+ }
869
+ `;n=n.replace(/if\s*\(\s*!\s*is_user_logged_in\(\)\s*\)/,s+"if ( !is_user_logged_in() )"),await e.writeFile(i,n)}function A(e){return`
870
+ $_pg_user = null;
871
+ if (function_exists('wp_generate_auth_cookie')) {
872
+ $_pg_user = function_exists('get_user_by')
873
+ ? get_user_by('login', ${e})
874
+ : (function_exists('get_userdatabylogin')
875
+ ? get_userdatabylogin(${e}) : null);
876
+ if ($_pg_user) {
877
+ wp_set_current_user($_pg_user->ID, $_pg_user->user_login);
878
+ $_pg_exp = time() + 172800;
879
+ if (defined('AUTH_COOKIE'))
880
+ $_COOKIE[AUTH_COOKIE] = wp_generate_auth_cookie($_pg_user->ID, $_pg_exp, 'auth');
881
+ if (defined('SECURE_AUTH_COOKIE'))
882
+ $_COOKIE[SECURE_AUTH_COOKIE] = wp_generate_auth_cookie($_pg_user->ID, $_pg_exp, 'secure_auth');
883
+ if (defined('LOGGED_IN_COOKIE'))
884
+ $_COOKIE[LOGGED_IN_COOKIE] = wp_generate_auth_cookie($_pg_user->ID, $_pg_exp, 'logged_in');
885
+ }
886
+ }
887
+ `}async function we(e,t){const i=E(e,t);if(i===null)return;const n=parseFloat(i);if(!Number.isFinite(n)||n>=3.3)return;const s=o.joinPaths(t,"wp-admin/includes/schema.php");if(!e.fileExists(s))return;const r=e.readFileAsText(s);/\$wp_queries\s*=\s*"CREATE TABLE/.test(r)&&!r.includes("function wp_get_db_schema")&&await Ee(e,t,s,r)}async function Ee(e,t,i,n){const s=n.match(/\$wp_queries\s*=\s*"CREATE TABLE/);if(!s||s.index===void 0)return;const r=s.index,a='";',l=n.indexOf(a,r);if(l===-1)return;const _=l+a.length,u=`function wp_get_db_schema( $scope = 'all', $blog_id = null ) {
888
+ global $wpdb, $wp_queries, $charset_collate;
889
+ $charset_collate = '';
890
+ if ( ! empty($wpdb->charset) )
891
+ $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
892
+ if ( ! empty($wpdb->collate) )
893
+ $charset_collate .= " COLLATE $wpdb->collate";
894
+ ${n.substring(r,_)}
895
+ return $wp_queries;
896
+ }`,d=n.substring(0,r)+u+n.substring(_);await e.writeFile(i,d);const $=o.joinPaths(t,"wp-admin/includes/upgrade.php");if(e.fileExists($)){const p=e.readFileAsText($),P=p.replace(/(\$alterations\s*=\s*dbDelta\(\s*\$wp_queries\s*\))/g,"if ( function_exists('wp_get_db_schema') ) { $wp_queries = wp_get_db_schema(); } $1");P!==p&&await e.writeFile($,P)}}function Te(){return`<?php
897
+ // @playground-managed — Playground-generated db.php.
898
+ // WP < 3.0 loads only db.php and skips wp-db.php, so we pull
899
+ // in the wpdb class definition explicitly.
900
+ if (defined('ABSPATH') && defined('WPINC') && !class_exists('wpdb', false)) {
901
+ require_once(ABSPATH . WPINC . '/wp-db.php');
902
+ }
903
+ // Old wpdb (WP < 3.0) has no db_connect() and calls mysql_connect()
904
+ // inline, so the SQLite driver never gets a chance to attach. Load
905
+ // the integration here and reinitialise to swap the dbh in place.
906
+ if (
907
+ class_exists('wpdb', false) &&
908
+ isset($GLOBALS['wpdb']) &&
909
+ !($GLOBALS['wpdb'] instanceof wpdb) &&
910
+ !method_exists('wpdb', 'db_connect') &&
911
+ file_exists('/internal/shared/mu-plugins/sqlite-database-integration.php')
912
+ ) {
913
+ require_once '/internal/shared/mu-plugins/sqlite-database-integration.php';
914
+ if (
915
+ isset($GLOBALS['wpdb']) &&
916
+ $GLOBALS['wpdb'] instanceof wpdb &&
917
+ method_exists($GLOBALS['wpdb'], 'reinitialize_sqlite')
918
+ ) {
919
+ $GLOBALS['wpdb']->reinitialize_sqlite();
920
+ }
921
+ }
922
+ // Remaining mysqli_* stubs not covered by the 0-sqlite.php preload.
923
+ // WP 4.x's extension_loaded('mysqli') check expects these to exist.
924
+ if (!function_exists('mysqli_real_connect')) {
925
+ function mysqli_real_connect() { return true; }
926
+ }
927
+ if (!function_exists('mysqli_error')) {
928
+ function mysqli_error() { return ''; }
929
+ }
930
+ if (!function_exists('mysqli_errno')) {
931
+ function mysqli_errno() { return 0; }
932
+ }
933
+ if (!function_exists('mysqli_query')) {
934
+ function mysqli_query() { return false; }
935
+ }
936
+ if (!function_exists('mysqli_set_charset')) {
937
+ function mysqli_set_charset() { return true; }
938
+ }
939
+ if (!function_exists('mysqli_select_db')) {
940
+ function mysqli_select_db() { return true; }
941
+ }
942
+ if (!function_exists('mysqli_close')) {
943
+ function mysqli_close() { return true; }
944
+ }
945
+ `}async function Le(e,t){let i=null;const n=o.joinPaths(e.documentRoot,"wp-includes/version.php");if(e.fileExists(n)){const r=e.readFileAsText(n).match(/\$wp_version\s*=\s*['"]([^'"]+)['"]/);r&&(i=r[1])}const s=i!==null&&parseFloat(i)<3.5;try{await e.run({code:`<?php
946
+ // WP_INSTALLING bypasses WP 1.x's "not installed" die() in wp-settings.php.
947
+ define('WP_INSTALLING', true);
948
+ error_reporting(${T});
949
+ ini_set('display_errors', '0');
950
+ ob_start();
951
+ $_pg_db_path = getenv('DOCUMENT_ROOT') . '/wp-content/database/.ht.sqlite';
952
+ if (!file_exists($_pg_db_path)) { exit; }
953
+ $_pg_pdo = new PDO('sqlite:' . $_pg_db_path);
954
+ $_pg_check = $_pg_pdo->query("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='wp_users'")->fetchColumn();
955
+ $_pg_pdo = null;
956
+ if (!$_pg_check) { exit; }
957
+ $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
958
+ if (!file_exists($wp_load)) { exit; }
959
+ require $wp_load;
960
+ ob_clean();
961
+ global $wpdb;
962
+ if (!isset($wpdb) || !method_exists($wpdb, 'query')) { exit; }
963
+
964
+ // Persist the scoped siteurl/home to the DB so parse_request()
965
+ // strips the scope prefix from REQUEST_URI. Filters alone
966
+ // (env.php) aren't enough on WP < 2.2.
967
+ $_pg_opts = !empty($wpdb->options) ? $wpdb->options : $GLOBALS['table_prefix'] . 'options';
968
+ try {
969
+ $_pg_url = getenv('PLAYGROUND_SITE_URL');
970
+ if ($_pg_url) {
971
+ $_pg_current = $wpdb->get_var("SELECT option_value FROM {$_pg_opts} WHERE option_name = 'siteurl'");
972
+ if ($_pg_current !== $_pg_url) {
973
+ $wpdb->query("UPDATE {$_pg_opts} SET option_value = '{$_pg_url}' WHERE option_name = 'siteurl'");
974
+ $wpdb->query("UPDATE {$_pg_opts} SET option_value = '{$_pg_url}' WHERE option_name = 'home'");
975
+ }
976
+ }
977
+ } catch (Exception $e) {}
978
+
979
+ // $wpdb->users exists on WP 1.5+; older WP needs the prefix.
980
+ $users_table = !empty($wpdb->users) ? $wpdb->users : $GLOBALS['table_prefix'] . 'users';
981
+
982
+ // WP 1.0/1.2 installers often leave the users table or admin row missing.
983
+ $wpdb->query("CREATE TABLE IF NOT EXISTS {$users_table} (
984
+ ID int(10) unsigned NOT NULL auto_increment,
985
+ user_login varchar(20) NOT NULL default '',
986
+ user_pass varchar(64) NOT NULL default '',
987
+ user_firstname varchar(50) NOT NULL default '',
988
+ user_lastname varchar(50) NOT NULL default '',
989
+ user_nickname varchar(50) NOT NULL default '',
990
+ user_icq int(10) unsigned NOT NULL default '0',
991
+ user_email varchar(100) NOT NULL default '',
992
+ user_url varchar(100) NOT NULL default '',
993
+ user_ip varchar(15) NOT NULL default '',
994
+ user_domain varchar(200) NOT NULL default '',
995
+ user_browser varchar(200) NOT NULL default '',
996
+ dateYMDhour datetime NOT NULL default '0000-00-00 00:00:00',
997
+ user_level int(2) unsigned NOT NULL default '0',
998
+ user_aim varchar(50) NOT NULL default '',
999
+ user_msn varchar(100) NOT NULL default '',
1000
+ user_yim varchar(50) NOT NULL default '',
1001
+ user_idmode varchar(20) NOT NULL default '',
1002
+ PRIMARY KEY (ID),
1003
+ UNIQUE KEY user_login (user_login)
1004
+ )");
1005
+ if (!$wpdb->get_var("SELECT COUNT(*) FROM {$users_table}")) {
1006
+ $now = date('Y-m-d H:i:s');
1007
+ $wpdb->query(
1008
+ "INSERT INTO {$users_table} (ID, user_login, user_pass, user_email, user_level, dateYMDhour, user_nickname) " .
1009
+ "VALUES (1, 'admin', MD5('password'), 'admin@localhost.com', 10, '{$now}', 'admin')"
1010
+ );
1011
+ }
1012
+ $wpdb->query(
1013
+ "UPDATE {$users_table} SET user_pass = MD5('password') WHERE user_login = 'admin'"
1014
+ );
1015
+
1016
+ // populate_roles() can fail on SQLite; seed the admin role and caps directly.
1017
+ $p = $GLOBALS['table_prefix'];
1018
+ $roles_key = $p . 'user_roles';
1019
+ try {
1020
+ $has_roles = $wpdb->get_var(
1021
+ "SELECT COUNT(*) FROM {$p}options WHERE option_name = '{$roles_key}'"
1022
+ );
1023
+ } catch (Exception $e) {
1024
+ $has_roles = 0;
1025
+ }
1026
+ if (!$has_roles) {
1027
+ $roles = array('administrator' => array(
1028
+ 'name' => 'Administrator',
1029
+ 'capabilities' => array(
1030
+ 'switch_themes'=>true, 'edit_themes'=>true,
1031
+ 'activate_plugins'=>true, 'edit_plugins'=>true,
1032
+ 'edit_users'=>true, 'edit_files'=>true,
1033
+ 'manage_options'=>true, 'moderate_comments'=>true,
1034
+ 'manage_categories'=>true, 'manage_links'=>true,
1035
+ 'upload_files'=>true, 'import'=>true,
1036
+ 'unfiltered_html'=>true, 'edit_posts'=>true,
1037
+ 'edit_others_posts'=>true, 'edit_published_posts'=>true,
1038
+ 'publish_posts'=>true, 'edit_pages'=>true,
1039
+ 'read'=>true, 'level_10'=>true, 'level_9'=>true,
1040
+ 'level_8'=>true, 'level_7'=>true, 'level_6'=>true,
1041
+ 'level_5'=>true, 'level_4'=>true, 'level_3'=>true,
1042
+ 'level_2'=>true, 'level_1'=>true, 'level_0'=>true,
1043
+ 'edit_others_pages'=>true, 'edit_published_pages'=>true,
1044
+ 'publish_pages'=>true, 'delete_pages'=>true,
1045
+ 'delete_others_pages'=>true, 'delete_published_pages'=>true,
1046
+ 'delete_posts'=>true, 'delete_others_posts'=>true,
1047
+ 'delete_published_posts'=>true, 'delete_private_posts'=>true,
1048
+ 'edit_private_posts'=>true, 'read_private_posts'=>true,
1049
+ 'delete_private_pages'=>true, 'edit_private_pages'=>true,
1050
+ 'read_private_pages'=>true,
1051
+ )
1052
+ ));
1053
+ $wpdb->query("INSERT INTO {$p}options (option_name, option_value, autoload) VALUES ('{$roles_key}', '" . addslashes(serialize($roles)) . "', 'yes')");
1054
+ }
1055
+ $um = isset($wpdb->usermeta) ? $wpdb->usermeta : $p . 'usermeta';
1056
+ try {
1057
+ $has_cap = $wpdb->get_var("SELECT COUNT(*) FROM {$um} WHERE user_id=1 AND meta_key='{$p}capabilities'");
1058
+ if (!$has_cap) {
1059
+ $cap_val = addslashes(serialize(array('administrator' => true)));
1060
+ $wpdb->query("INSERT INTO {$um} (user_id, meta_key, meta_value) VALUES (1, '{$p}capabilities', '{$cap_val}')");
1061
+ }
1062
+ $has_level = $wpdb->get_var("SELECT COUNT(*) FROM {$um} WHERE user_id=1 AND meta_key='{$p}user_level'");
1063
+ if (!$has_level) {
1064
+ $wpdb->query("INSERT INTO {$um} (user_id, meta_key, meta_value) VALUES (1, '{$p}user_level', '10')");
1065
+ }
1066
+ } catch (Exception $e) {}
1067
+
1068
+ // Seed default content when the install left the posts table empty.
1069
+ $posts_table = !empty($wpdb->posts) ? $wpdb->posts : $GLOBALS['table_prefix'] . 'posts';
1070
+ $has_posts = false;
1071
+ try { $has_posts = (bool)$wpdb->get_var("SELECT COUNT(*) FROM {$posts_table}"); } catch (Exception $e) {}
1072
+ if (!$has_posts) {
1073
+ $now = date('Y-m-d H:i:s');
1074
+ $now_gmt = gmdate('Y-m-d H:i:s');
1075
+ if (isset($wpdb->categories)) {
1076
+ $wpdb->query("INSERT INTO {$wpdb->categories} (cat_ID, cat_name, category_nicename, category_description, category_parent) VALUES (1, 'Uncategorized', 'uncategorized', '', 0)");
1077
+ }
1078
+ // Columns common to WP 1.0+.
1079
+ $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}', '')");
1080
+ if (isset($wpdb->comments)) {
1081
+ $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)");
1082
+ }
1083
+ if (isset($wpdb->post2cat)) {
1084
+ $wpdb->query("INSERT INTO {$wpdb->post2cat} (rel_id, post_id, category_id) VALUES (1, 1, 1)");
1085
+ }
1086
+ }
1087
+ `,env:{DOCUMENT_ROOT:e.documentRoot,PLAYGROUND_SITE_URL:t||""}})}catch(r){h.logger.warn("Legacy WP post-install fixups failed (non-fatal):",r)}if(s)try{await e.run({code:`<?php
1088
+ $db_dir = getenv('DOCUMENT_ROOT') . '/wp-content/database/';
1089
+ if (!is_dir($db_dir)) { @mkdir($db_dir, 0777, true); }
1090
+ $db_path = $db_dir . '.ht.sqlite';
1091
+ $pdo = new PDO('sqlite:' . $db_path);
1092
+ $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
1093
+
1094
+ $prefix = 'wp_';
1095
+ $table = $prefix . 'users';
1096
+ try {
1097
+ $count = $pdo->query("SELECT COUNT(*) FROM {$table}")->fetchColumn();
1098
+ } catch (Exception $e) {
1099
+ $pdo->exec("CREATE TABLE IF NOT EXISTS {$table} (
1100
+ ID INTEGER PRIMARY KEY AUTOINCREMENT,
1101
+ user_login TEXT NOT NULL DEFAULT '',
1102
+ user_pass TEXT NOT NULL DEFAULT '',
1103
+ user_nickname TEXT NOT NULL DEFAULT '',
1104
+ user_email TEXT NOT NULL DEFAULT '',
1105
+ user_url TEXT NOT NULL DEFAULT '',
1106
+ user_ip TEXT NOT NULL DEFAULT '',
1107
+ user_domain TEXT NOT NULL DEFAULT '',
1108
+ user_browser TEXT NOT NULL DEFAULT '',
1109
+ dateYMDhour TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1110
+ user_level INTEGER NOT NULL DEFAULT 0,
1111
+ user_idmode TEXT NOT NULL DEFAULT '',
1112
+ user_firstname TEXT NOT NULL DEFAULT '',
1113
+ user_lastname TEXT NOT NULL DEFAULT '',
1114
+ user_icq INTEGER NOT NULL DEFAULT 0,
1115
+ user_aim TEXT NOT NULL DEFAULT '',
1116
+ user_msn TEXT NOT NULL DEFAULT '',
1117
+ user_yim TEXT NOT NULL DEFAULT ''
1118
+ )");
1119
+ $count = 0;
1120
+ }
1121
+ if ($count == 0) {
1122
+ $now = date('Y-m-d H:i:s');
1123
+ // SECURITY: md5('password') matches WP 1.0-1.2's single-md5
1124
+ // scheme so auto-login works without a blueprint password.
1125
+ // Safe only inside the Playground WASM sandbox.
1126
+ $pass = md5('password');
1127
+ try {
1128
+ $col_info = $pdo->query("PRAGMA table_info({$table})")->fetchAll(PDO::FETCH_ASSOC);
1129
+ $known = array(
1130
+ 'ID' => '1', 'user_login' => "'admin'",
1131
+ 'user_pass' => "'{$pass}'", 'user_email' => "'admin@localhost.com'",
1132
+ 'user_level' => '10', 'dateYMDhour' => "'{$now}'",
1133
+ 'user_nickname' => "'admin'", 'user_nicename' => "'admin'",
1134
+ 'user_registered' => "'{$now}'", 'user_status' => '0',
1135
+ );
1136
+ $ins_cols = array(); $ins_vals = array();
1137
+ foreach ($col_info as $ci) {
1138
+ $cn = $ci['name'];
1139
+ $ins_cols[] = $cn;
1140
+ if (isset($known[$cn])) {
1141
+ $ins_vals[] = $known[$cn];
1142
+ } elseif ($ci['dflt_value'] !== null) {
1143
+ $ins_vals[] = $ci['dflt_value'];
1144
+ } elseif (stripos($ci['type'], 'int') !== false) {
1145
+ $ins_vals[] = '0';
1146
+ } else {
1147
+ $ins_vals[] = "''";
1148
+ }
1149
+ }
1150
+ $pdo->exec("INSERT INTO {$table} (" . implode(',', $ins_cols) . ") VALUES (" . implode(',', $ins_vals) . ")");
1151
+ } catch (Exception $e) {}
1152
+ } else {
1153
+ // See SECURITY note above.
1154
+ $pass = md5('password');
1155
+ try { $pdo->exec("UPDATE {$table} SET user_pass = '{$pass}' WHERE user_login = 'admin'"); } catch (Exception $e) {}
1156
+ }
1157
+
1158
+ // WP 1.0-1.2 install often leaves these tables missing because
1159
+ // the SQLite driver can't translate the old-style CREATE TABLEs.
1160
+ $now = date('Y-m-d H:i:s');
1161
+ $now_gmt = gmdate('Y-m-d H:i:s');
1162
+ $tables_sql = array(
1163
+ 'posts' => "CREATE TABLE IF NOT EXISTS {$prefix}posts (
1164
+ ID INTEGER PRIMARY KEY AUTOINCREMENT,
1165
+ post_author INTEGER NOT NULL DEFAULT 0,
1166
+ post_date TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1167
+ post_date_gmt TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1168
+ post_content TEXT NOT NULL DEFAULT '',
1169
+ post_title TEXT NOT NULL DEFAULT '',
1170
+ post_category INTEGER NOT NULL DEFAULT 0,
1171
+ post_excerpt TEXT NOT NULL DEFAULT '',
1172
+ post_status TEXT NOT NULL DEFAULT 'publish',
1173
+ comment_status TEXT NOT NULL DEFAULT 'open',
1174
+ ping_status TEXT NOT NULL DEFAULT 'open',
1175
+ post_password TEXT NOT NULL DEFAULT '',
1176
+ post_name TEXT NOT NULL DEFAULT '',
1177
+ to_ping TEXT NOT NULL DEFAULT '',
1178
+ pinged TEXT NOT NULL DEFAULT '',
1179
+ post_modified TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1180
+ post_modified_gmt TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1181
+ post_content_filtered TEXT NOT NULL DEFAULT '',
1182
+ post_parent INTEGER NOT NULL DEFAULT 0,
1183
+ menu_order INTEGER NOT NULL DEFAULT 0,
1184
+ post_mime_type TEXT NOT NULL DEFAULT ''
1185
+ )",
1186
+ 'categories' => "CREATE TABLE IF NOT EXISTS {$prefix}categories (
1187
+ cat_ID INTEGER PRIMARY KEY AUTOINCREMENT,
1188
+ cat_name TEXT NOT NULL DEFAULT '',
1189
+ category_nicename TEXT NOT NULL DEFAULT '',
1190
+ category_description TEXT NOT NULL DEFAULT '',
1191
+ category_parent INTEGER NOT NULL DEFAULT 0
1192
+ )",
1193
+ 'post2cat' => "CREATE TABLE IF NOT EXISTS {$prefix}post2cat (
1194
+ rel_id INTEGER PRIMARY KEY AUTOINCREMENT,
1195
+ post_id INTEGER NOT NULL DEFAULT 0,
1196
+ category_id INTEGER NOT NULL DEFAULT 0
1197
+ )",
1198
+ 'comments' => "CREATE TABLE IF NOT EXISTS {$prefix}comments (
1199
+ comment_ID INTEGER PRIMARY KEY AUTOINCREMENT,
1200
+ comment_post_ID INTEGER NOT NULL DEFAULT 0,
1201
+ comment_author TEXT NOT NULL DEFAULT '',
1202
+ comment_author_email TEXT NOT NULL DEFAULT '',
1203
+ comment_author_url TEXT NOT NULL DEFAULT '',
1204
+ comment_author_IP TEXT NOT NULL DEFAULT '',
1205
+ comment_date TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1206
+ comment_date_gmt TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1207
+ comment_content TEXT NOT NULL DEFAULT '',
1208
+ comment_karma INTEGER NOT NULL DEFAULT 0,
1209
+ comment_approved TEXT NOT NULL DEFAULT '1',
1210
+ comment_agent TEXT NOT NULL DEFAULT '',
1211
+ comment_type TEXT NOT NULL DEFAULT '',
1212
+ comment_parent INTEGER NOT NULL DEFAULT 0,
1213
+ user_id INTEGER NOT NULL DEFAULT 0
1214
+ )",
1215
+ 'options' => "CREATE TABLE IF NOT EXISTS {$prefix}options (
1216
+ option_id INTEGER PRIMARY KEY AUTOINCREMENT,
1217
+ blog_id INTEGER NOT NULL DEFAULT 0,
1218
+ option_name TEXT NOT NULL DEFAULT '',
1219
+ option_can_override TEXT NOT NULL DEFAULT 'Y',
1220
+ option_type INTEGER NOT NULL DEFAULT 1,
1221
+ option_value TEXT NOT NULL DEFAULT '',
1222
+ option_width INTEGER NOT NULL DEFAULT 20,
1223
+ option_height INTEGER NOT NULL DEFAULT 8,
1224
+ option_description TEXT NOT NULL DEFAULT '',
1225
+ option_admin_level INTEGER NOT NULL DEFAULT 1,
1226
+ autoload TEXT NOT NULL DEFAULT 'yes'
1227
+ )",
1228
+ 'postmeta' => "CREATE TABLE IF NOT EXISTS {$prefix}postmeta (
1229
+ meta_id INTEGER PRIMARY KEY AUTOINCREMENT,
1230
+ post_id INTEGER NOT NULL DEFAULT 0,
1231
+ meta_key TEXT NOT NULL DEFAULT '',
1232
+ meta_value TEXT NOT NULL DEFAULT ''
1233
+ )",
1234
+ 'links' => "CREATE TABLE IF NOT EXISTS {$prefix}links (
1235
+ link_id INTEGER PRIMARY KEY AUTOINCREMENT,
1236
+ link_url TEXT NOT NULL DEFAULT '',
1237
+ link_name TEXT NOT NULL DEFAULT '',
1238
+ link_image TEXT NOT NULL DEFAULT '',
1239
+ link_target TEXT NOT NULL DEFAULT '',
1240
+ link_category INTEGER NOT NULL DEFAULT 0,
1241
+ link_description TEXT NOT NULL DEFAULT '',
1242
+ link_visible TEXT NOT NULL DEFAULT 'Y',
1243
+ link_owner INTEGER NOT NULL DEFAULT 1,
1244
+ link_rating INTEGER NOT NULL DEFAULT 0,
1245
+ link_updated TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
1246
+ link_rel TEXT NOT NULL DEFAULT '',
1247
+ link_notes TEXT NOT NULL DEFAULT '',
1248
+ link_rss TEXT NOT NULL DEFAULT ''
1249
+ )",
1250
+ 'linkcategories' => "CREATE TABLE IF NOT EXISTS {$prefix}linkcategories (
1251
+ cat_id INTEGER PRIMARY KEY AUTOINCREMENT,
1252
+ cat_name TEXT NOT NULL DEFAULT '',
1253
+ auto_toggle TEXT NOT NULL DEFAULT 'N',
1254
+ show_images TEXT NOT NULL DEFAULT 'Y',
1255
+ show_description TEXT NOT NULL DEFAULT 'N',
1256
+ show_rating TEXT NOT NULL DEFAULT 'Y',
1257
+ show_updated TEXT NOT NULL DEFAULT 'Y',
1258
+ sort_order TEXT NOT NULL DEFAULT 'name',
1259
+ sort_desc TEXT NOT NULL DEFAULT 'ASC',
1260
+ text_before_link TEXT NOT NULL DEFAULT '<li>',
1261
+ text_after_link TEXT NOT NULL DEFAULT '<br />',
1262
+ text_after_all TEXT NOT NULL DEFAULT '</li>',
1263
+ list_limit INTEGER NOT NULL DEFAULT -1
1264
+ )",
1265
+ 'optiongroups' => "CREATE TABLE IF NOT EXISTS {$prefix}optiongroups (
1266
+ group_id INTEGER PRIMARY KEY AUTOINCREMENT,
1267
+ group_name TEXT NOT NULL DEFAULT '',
1268
+ group_desc TEXT DEFAULT '',
1269
+ group_longdesc TEXT DEFAULT ''
1270
+ )",
1271
+ 'optiongroup_options' => "CREATE TABLE IF NOT EXISTS {$prefix}optiongroup_options (
1272
+ group_id INTEGER NOT NULL DEFAULT 0,
1273
+ option_id INTEGER NOT NULL DEFAULT 0,
1274
+ seq INTEGER NOT NULL DEFAULT 0,
1275
+ PRIMARY KEY (group_id, option_id)
1276
+ )"
1277
+ );
1278
+ foreach ($tables_sql as $t => $sql) {
1279
+ try { $pdo->exec($sql); } catch (Exception $e) {}
1280
+ }
1281
+ // Backfill columns that WP 1.0-1.2 installs leave off but later code paths read.
1282
+ $alter_cols = array(
1283
+ 'categories' => array(
1284
+ 'category_nicename' => "TEXT NOT NULL DEFAULT ''",
1285
+ 'category_description' => "TEXT NOT NULL DEFAULT ''",
1286
+ 'category_parent' => "INTEGER NOT NULL DEFAULT 0",
1287
+ 'category_count' => "INTEGER NOT NULL DEFAULT 0",
1288
+ ),
1289
+ // WP 1.5+ get_comments_number() reads comment_count off wp_posts.
1290
+ 'posts' => array(
1291
+ 'comment_count' => "INTEGER NOT NULL DEFAULT 0",
1292
+ ),
1293
+ );
1294
+ foreach ($alter_cols as $t => $cols_to_add) {
1295
+ try {
1296
+ $existing = $pdo->query("PRAGMA table_info({$prefix}{$t})")->fetchAll(PDO::FETCH_COLUMN, 1);
1297
+ foreach ($cols_to_add as $col => $type) {
1298
+ if (!in_array($col, $existing)) {
1299
+ $pdo->exec("ALTER TABLE {$prefix}{$t} ADD COLUMN {$col} {$type}");
1300
+ }
1301
+ }
1302
+ } catch (Exception $e) {}
1303
+ }
1304
+ // Dynamic column detection because the schema differs across WP 1.x.
1305
+ try {
1306
+ if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}posts")->fetchColumn()) {
1307
+ $post_cols = $pdo->query("PRAGMA table_info({$prefix}posts)")->fetchAll(PDO::FETCH_COLUMN, 1);
1308
+ $post_vals = array(
1309
+ 'ID' => '1', 'post_author' => '1',
1310
+ 'post_date' => "'{$now}'", 'post_date_gmt' => "'{$now_gmt}'",
1311
+ 'post_content' => "'Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!'",
1312
+ 'post_title' => "'Hello world!'", 'post_excerpt' => "''",
1313
+ 'post_status' => "'publish'", 'comment_status' => "'open'",
1314
+ 'ping_status' => "'open'", 'post_password' => "''",
1315
+ 'post_name' => "'hello-world'", 'to_ping' => "''", 'pinged' => "''",
1316
+ 'post_modified' => "'{$now}'", 'post_modified_gmt' => "'{$now_gmt}'",
1317
+ 'post_content_filtered' => "''",
1318
+ );
1319
+ $ins_c = array(); $ins_v = array();
1320
+ foreach ($post_vals as $c => $v) {
1321
+ if (in_array($c, $post_cols)) { $ins_c[] = $c; $ins_v[] = $v; }
1322
+ }
1323
+ if ($ins_c) $pdo->exec("INSERT INTO {$prefix}posts (" . implode(',', $ins_c) . ") VALUES (" . implode(',', $ins_v) . ")");
1324
+ }
1325
+ } catch (Exception $e) {}
1326
+ try {
1327
+ if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}categories")->fetchColumn()) {
1328
+ $pdo->exec("INSERT INTO {$prefix}categories (cat_ID, cat_name, category_nicename, category_description, category_parent) VALUES (1, 'Uncategorized', 'uncategorized', '', 0)");
1329
+ }
1330
+ } catch (Exception $e) {}
1331
+ try {
1332
+ $env_site = getenv('PLAYGROUND_SITE_URL');
1333
+ $site = $env_site ? $env_site : 'http://localhost';
1334
+ if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}options WHERE option_name='siteurl'")->fetchColumn()) {
1335
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('siteurl', '{$site}')");
1336
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('blogname', 'My WordPress Website')");
1337
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('blogdescription', 'Just another WordPress weblog')");
1338
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('home', '{$site}')");
1339
+ }
1340
+ // Overwrite the placeholder 'http://localhost' with the scoped URL.
1341
+ if ($env_site) {
1342
+ $pdo->exec("UPDATE {$prefix}options SET option_value = '{$env_site}' WHERE option_name = 'siteurl'");
1343
+ $pdo->exec("UPDATE {$prefix}options SET option_value = '{$env_site}' WHERE option_name = 'home'");
1344
+ }
1345
+ // populate_options() sets template/stylesheet; backfill if it crashed.
1346
+ if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}options WHERE option_name='template'")->fetchColumn()) {
1347
+ $themes_dir = getenv('DOCUMENT_ROOT') . '/wp-content/themes/';
1348
+ $tpl = 'default';
1349
+ if (is_dir($themes_dir)) {
1350
+ $entries = glob($themes_dir . '*', GLOB_ONLYDIR);
1351
+ if ($entries) {
1352
+ foreach ($entries as $e) {
1353
+ $name = basename($e);
1354
+ if ($name === '.' || $name === '..') continue;
1355
+ if (file_exists($e . '/style.css')) {
1356
+ $tpl = $name;
1357
+ break;
1358
+ }
1359
+ }
1360
+ }
1361
+ }
1362
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value, autoload) VALUES ('template', '{$tpl}', 'yes')");
1363
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value, autoload) VALUES ('stylesheet', '{$tpl}', 'yes')");
1364
+ }
1365
+ // Without a correct db_version, WP 2.0-2.5 admin redirects to upgrade.php.
1366
+ $version_path = getenv('DOCUMENT_ROOT') . '/wp-includes/version.php';
1367
+ if (file_exists($version_path)) {
1368
+ $wp_db_version = 0;
1369
+ include $version_path;
1370
+ if ($wp_db_version > 0) {
1371
+ $has_dbv = $pdo->query("SELECT COUNT(*) FROM {$prefix}options WHERE option_name='db_version'")->fetchColumn();
1372
+ if (!$has_dbv) {
1373
+ $pdo->exec("INSERT INTO {$prefix}options (option_name, option_value, autoload) VALUES ('db_version', '{$wp_db_version}', 'yes')");
1374
+ } else {
1375
+ $pdo->exec("UPDATE {$prefix}options SET option_value = '{$wp_db_version}' WHERE option_name = 'db_version'");
1376
+ }
1377
+ }
1378
+ }
1379
+ } catch (Exception $e) {}
1380
+ `,env:{DOCUMENT_ROOT:e.documentRoot,PLAYGROUND_SITE_URL:t||""}})}catch(r){h.logger.warn("Legacy WP PDO fallback failed (non-fatal):",r)}}const ye=`
1381
+ // Connection stubs — wpdb::__construct bails on a falsy return.
1382
+ if (!function_exists('mysqli_connect')) {
1383
+ function mysqli_connect() { return true; }
1384
+ }
1385
+ if (!function_exists('mysqli_init')) {
1386
+ function mysqli_init() { return true; }
1387
+ }
1388
+ if (!function_exists('mysql_connect')) {
1389
+ function mysql_connect() { return true; }
1390
+ }
1391
+ if (!function_exists('mysql_select_db')) {
1392
+ function mysql_select_db() { return true; }
1393
+ }
1394
+ // WordPress < 3.0 wpdb::__construct calls mysql_set_charset directly.
1395
+ if (!function_exists('mysql_set_charset')) {
1396
+ function mysql_set_charset() { return true; }
1397
+ }
1398
+ // Functional mysql_* stubs that delegate to $wpdb (SQLite driver).
1399
+ $GLOBALS['_mysql_results'] = array();
1400
+ $GLOBALS['_mysql_result_id'] = 0;
1401
+ if (!function_exists('mysql_query')) {
1402
+ function mysql_query($query, $link = null) {
1403
+ global $wpdb;
1404
+ if (isset($wpdb) && method_exists($wpdb, 'query')) {
1405
+ $wpdb->query($query);
1406
+ if (preg_match('/^\\s*(SELECT|SHOW|DESCRIBE|EXPLAIN)/i', $query)) {
1407
+ $rows = isset($wpdb->last_result) ? $wpdb->last_result : array();
1408
+ $id = ++$GLOBALS['_mysql_result_id'];
1409
+ $GLOBALS['_mysql_results'][$id] = array(
1410
+ 'rows' => $rows,
1411
+ 'index' => 0,
1412
+ );
1413
+ return $id;
1414
+ }
1415
+ return true;
1416
+ }
1417
+ return false;
1418
+ }
1419
+ }
1420
+ if (!function_exists('mysql_error')) {
1421
+ function mysql_error($link = null) {
1422
+ global $wpdb;
1423
+ if (isset($wpdb) && isset($wpdb->last_error)) {
1424
+ return $wpdb->last_error;
1425
+ }
1426
+ return '';
1427
+ }
1428
+ }
1429
+ if (!function_exists('mysql_list_tables')) {
1430
+ function mysql_list_tables($db = '', $link = null) {
1431
+ global $wpdb;
1432
+ if (isset($wpdb) && method_exists($wpdb, 'get_results')) {
1433
+ $tables = $wpdb->get_results(
1434
+ "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
1435
+ );
1436
+ $rows = array();
1437
+ if ($tables) {
1438
+ foreach ($tables as $t) {
1439
+ $obj = new stdClass();
1440
+ $obj->name = is_object($t) ? $t->name : $t['name'];
1441
+ $rows[] = $obj;
1442
+ }
1443
+ }
1444
+ $id = ++$GLOBALS['_mysql_result_id'];
1445
+ $GLOBALS['_mysql_results'][$id] = array(
1446
+ 'rows' => $rows,
1447
+ 'index' => 0,
1448
+ );
1449
+ return $id;
1450
+ }
1451
+ return false;
1452
+ }
1453
+ }
1454
+ if (!function_exists('mysql_fetch_row')) {
1455
+ function mysql_fetch_row($result) {
1456
+ if (!isset($GLOBALS['_mysql_results'][$result])) return null;
1457
+ $r = &$GLOBALS['_mysql_results'][$result];
1458
+ if ($r['index'] >= count($r['rows'])) return null;
1459
+ $row = $r['rows'][$r['index']++];
1460
+ return array_values((array)$row);
1461
+ }
1462
+ }
1463
+ if (!function_exists('mysql_fetch_object')) {
1464
+ function mysql_fetch_object($result) {
1465
+ if (!isset($GLOBALS['_mysql_results'][$result])) return null;
1466
+ $r = &$GLOBALS['_mysql_results'][$result];
1467
+ if ($r['index'] >= count($r['rows'])) return null;
1468
+ return (object)(array)$r['rows'][$r['index']++];
1469
+ }
1470
+ }
1471
+ if (!function_exists('mysql_num_rows')) {
1472
+ function mysql_num_rows($result) {
1473
+ if (isset($GLOBALS['_mysql_results'][$result])) {
1474
+ return count($GLOBALS['_mysql_results'][$result]['rows']);
1475
+ }
1476
+ return 0;
1477
+ }
1478
+ }
1479
+ if (!function_exists('mysql_get_server_info')) {
1480
+ function mysql_get_server_info() { return '8.0.0'; }
1481
+ }
1482
+ if (!function_exists('mysql_affected_rows')) {
1483
+ function mysql_affected_rows() {
1484
+ global $wpdb;
1485
+ if (isset($wpdb) && isset($wpdb->rows_affected)) {
1486
+ return $wpdb->rows_affected;
1487
+ }
1488
+ return 0;
1489
+ }
1490
+ }
1491
+ if (!function_exists('mysql_insert_id')) {
1492
+ function mysql_insert_id() {
1493
+ global $wpdb;
1494
+ if (isset($wpdb) && isset($wpdb->insert_id)) {
1495
+ return $wpdb->insert_id;
1496
+ }
1497
+ return 0;
1498
+ }
1499
+ }
1500
+ if (!function_exists('mysql_free_result')) {
1501
+ function mysql_free_result($result) {
1502
+ unset($GLOBALS['_mysql_results'][$result]);
1503
+ return true;
1504
+ }
1505
+ }
1506
+ if (!function_exists('mysql_num_fields')) {
1507
+ function mysql_num_fields($result) {
1508
+ if (isset($GLOBALS['_mysql_results'][$result])
1509
+ && !empty($GLOBALS['_mysql_results'][$result]['rows'])) {
1510
+ return count((array)$GLOBALS['_mysql_results'][$result]['rows'][0]);
1511
+ }
1512
+ return 0;
1513
+ }
1514
+ }
1515
+ if (!function_exists('mysql_real_escape_string')) {
1516
+ function mysql_real_escape_string($s) { return addslashes($s); }
1517
+ }
1518
+ if (!function_exists('mysql_escape_string')) {
1519
+ function mysql_escape_string($s) { return addslashes($s); }
1520
+ }`;async function Pe(e,t,i={}){await e.isDir("/tmp/sqlite-database-integration")&&await e.rmdir("/tmp/sqlite-database-integration",{recursive:!0}),await e.mkdir("/tmp/sqlite-database-integration"),await g.unzipFile(e,t,"/tmp/sqlite-database-integration");const n="/internal/shared/sqlite-database-integration",s=`/tmp/sqlite-database-integration/${(await e.listFiles("/tmp/sqlite-database-integration"))[0]}`;await e.mv(s,n),await be(e,n),await e.defineConstant("SQLITE_MAIN_FILE","1");let a=(await e.readFileAsText(o.joinPaths(n,"db.copy"))).replace("'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",o.phpVar(n)).replace("'{SQLITE_PLUGIN}'",o.phpVar(o.joinPaths(n,"load.php")));a=a.replace(/^add_action\(/gm,'function_exists("add_action") && add_action(');const l=o.joinPaths(await e.documentRoot,"wp-content/db.php"),_="/internal/shared/mu-plugins/sqlite-database-integration.php",c=`
1521
+ if(file_exists(${o.phpVar(l)})) {
1522
+ $_pg_db_php = @file_get_contents(${o.phpVar(l)});
1523
+ if (strpos($_pg_db_php, '@playground-managed') === false) {
1524
+ return;
1525
+ }
1526
+ unset($_pg_db_php);
1527
+ }
1528
+ `;await e.writeFile(_,`<?php
1529
+ ${c}?>`+a),await e.writeFile("/internal/shared/preload/0-sqlite.php",Oe(c,_)),await e.writeFile("/internal/shared/mu-plugins/sqlite-test.php",`<?php
1530
+ global $wpdb;
1531
+ if(!($wpdb instanceof WP_SQLite_DB)) {
1532
+ var_dump(isset($wpdb));
1533
+ die("SQLite integration not loaded " . get_class($wpdb));
1534
+ }
1535
+ `)}async function be(e,t){const i=o.joinPaths(t,"wp-includes/database/sqlite/class-wp-pdo-mysql-on-sqlite.php");if(!await e.fileExists(i))return;const n=await e.readFileAsText(i),s=n.replace(/\$active_sql_modes\s*=\s*array\s*\([^)]*\)\s*;/,"$active_sql_modes = array();");s!==n&&await e.writeFile(i,s)}function Oe(e,t){return`<?php
1536
+ ${e}?>
1537
+ <?php
1538
+ // Shim __() etc. only for WP < 1.2 (no l10n layer; the SQLite
1539
+ // plugin calls __() from print_error()). WP 1.2–1.4 ship
1540
+ // wp-l10n.php and WP 1.5+ ships l10n.php — defining the shims
1541
+ // then would fatal on redeclare.
1542
+ $_pg_doc_root = isset($_SERVER['DOCUMENT_ROOT'])
1543
+ ? $_SERVER['DOCUMENT_ROOT'] : '/wordpress';
1544
+ if (
1545
+ !file_exists($_pg_doc_root . '/wp-includes/l10n.php')
1546
+ && !file_exists($_pg_doc_root . '/wp-includes/wp-l10n.php')
1547
+ ) {
1548
+ if (!function_exists('__')) {
1549
+ function __($text, $domain = null) { return $text; }
1550
+ }
1551
+ if (!function_exists('_e')) {
1552
+ function _e($text, $domain = null) { echo $text; }
1553
+ }
1554
+ if (!function_exists('esc_html__')) {
1555
+ function esc_html__($text, $domain = null) {
1556
+ return htmlspecialchars($text, ENT_QUOTES);
1557
+ }
1558
+ }
1559
+ if (!function_exists('esc_html_e')) {
1560
+ function esc_html_e($text, $domain = null) {
1561
+ echo htmlspecialchars($text, ENT_QUOTES);
1562
+ }
1563
+ }
1564
+ }
1565
+ ?>
1566
+ <?php
1567
+ ${N(`require_once ${o.phpVar(t)};
1568
+ if (
1569
+ isset($GLOBALS['wpdb']) &&
1570
+ method_exists($GLOBALS['wpdb'], 'reinitialize_sqlite')
1571
+ ) {
1572
+ $GLOBALS['wpdb']->reinitialize_sqlite();
1573
+ }`)}
1574
+ ${ye}
1575
+ if (PHP_MAJOR_VERSION < 7) {
1576
+ // E_DEPRECATED (8192) / E_STRICT (2048) are PHP 5.3+ symbols;
1577
+ // LEGACY_WP_ERROR_REPORTING_PHP_EXPR uses numeric literals.
1578
+ $level = ${T};
1579
+ error_reporting($level);
1580
+ ini_set('error_reporting', $level);
1581
+ }
1582
+
1583
+ `}const S=`<?php
2
1584
 
3
1585
  /**
4
1586
  * Transforms the "wp-config.php" file.
@@ -469,21 +2051,63 @@ class WP_Config_Transformer {
469
2051
  && ( T_WHITESPACE === $token[0] || T_COMMENT === $token[0] || T_DOC_COMMENT === $token[0] );
470
2052
  }
471
2053
  }
472
- `;async function g(t,e){const n=r.joinPaths(e,"wp-config.php");!t.fileExists(n)&&t.fileExists(r.joinPaths(e,"wp-config-sample.php"))&&await t.writeFile(n,await t.readFileAsBuffer(r.joinPaths(e,"wp-config-sample.php"))),t.fileExists(n)&&await x(t,n,{DB_NAME:"wordpress"})}async function I(t,e,n){const i=r.phpVars({wpConfigPath:e,constants:n});if((await t.run({code:`${$}
473
- $wp_config_path = ${i.wpConfigPath};
2054
+ `;async function v(e,t){const i=o.joinPaths(t,"wp-config.php");!e.fileExists(i)&&e.fileExists(o.joinPaths(t,"wp-config-sample.php"))&&await e.writeFile(i,await e.readFileAsBuffer(o.joinPaths(t,"wp-config-sample.php"))),e.fileExists(i)&&await Ae(e,i,{DB_NAME:"wordpress"})}async function Ne(e,t,i){const n=o.phpVars({wpConfigPath:t,constants:i});if((await e.run({code:`${S}
2055
+ $wp_config_path = ${n.wpConfigPath};
474
2056
  $transformer = WP_Config_Transformer::from_file($wp_config_path);
475
- $transformer->define_constants(${i.constants});
2057
+ $transformer->define_constants(${n.constants});
476
2058
  $transformer->to_file($wp_config_path);
477
- `})).errors.length>0)throw new Error("Failed to rewrite constants in wp-config.php.")}async function x(t,e,n){const i=Object.keys(n),a=r.phpVars({wpConfigPath:e,constantNames:i}),s=await t.run({code:`${$}
478
- $transformer = WP_Config_Transformer::from_file(${a.wpConfigPath});
2059
+ `})).errors.length>0)throw new Error("Failed to rewrite constants in wp-config.php.")}async function Ae(e,t,i){const n=Object.keys(i),s=o.phpVars({wpConfigPath:t,constantNames:n}),r=await e.run({code:`${S}
2060
+ $transformer = WP_Config_Transformer::from_file(${s.wpConfigPath});
479
2061
  $missing = [];
480
- foreach (${a.constantNames} as $name) {
2062
+ foreach (${s.constantNames} as $name) {
481
2063
  if (!$transformer->constant_exists($name)) {
482
2064
  $missing[] = $name;
483
2065
  }
484
2066
  }
485
2067
  echo json_encode($missing);
486
- `});if(s.errors.length>0)throw new Error("Failed to check wp-config.php for constants.");let l;try{l=JSON.parse(s.text)}catch{throw new Error(`Failed to parse wp-config.php constant check output: ${s.text}`)}for(const o of l)await t.defineConstant(o,n[o])}async function L(t){const e=await w(t);return await m(e,t),e}async function m(t,e){var l,o;const n=await t.getPrimaryPhp();if((l=e.hooks)!=null&&l.beforeWordPressFiles&&await e.hooks.beforeWordPressFiles(n),e.wordPressZip&&await R(n,await e.wordPressZip),e.constants)for(const c in e.constants)n.defineConstant(c,e.constants[c]);e.dataSqlPath&&(n.defineConstant("DB_DIR",r.dirname(e.dataSqlPath)),n.defineConstant("DB_FILE",r.basename(e.dataSqlPath))),n.defineConstant("WP_HOME",e.siteUrl),n.defineConstant("WP_SITEURL",e.siteUrl),await g(n,t.documentRoot),(o=e.hooks)!=null&&o.beforeDatabaseSetup&&await e.hooks.beforeDatabaseSetup(n);let i=!1;e.sqliteIntegrationPluginZip&&(i=!0,await v(n,await e.sqliteIntegrationPluginZip));const a=e.wordpressInstallMode??"download-and-install",s=!!e.dataSqlPath;if(["download-and-install","install-from-existing-files"].includes(a)){await h(t,{usesSqlite:i,hasCustomDatabasePath:s});try{await f(n)}catch(c){throw s||await u(t),c}s||await u(t)}else if(a==="install-from-existing-files-if-needed"){if(await h(t,{usesSqlite:i,hasCustomDatabasePath:s}),!await P(n))try{await f(n)}catch(c){throw s||await u(t),c}s||await u(t)}return t}async function h(t,{usesSqlite:e,hasCustomDatabasePath:n}){const i=await t.getPrimaryPhp();if(i.isFile("/internal/shared/preload/0-sqlite.php"))return;const a=r.joinPaths(t.documentRoot,"wp-content/mu-plugins/sqlite-database-integration");if(!i.isDir(a)&&!e&&!n&&!C(i))throw new Error("Error connecting to the MySQL database.")}async function u(t){const e=await t.getPrimaryPhp();if(await W(e))return;if(e.isFile("/internal/shared/preload/0-sqlite.php"))throw new Error("Error connecting to the SQLite database.");const i=r.joinPaths(t.documentRoot,"wp-content/mu-plugins/sqlite-database-integration");throw e.isDir(i)?new Error("Error connecting to the SQLite database."):new Error("Error connecting to the MySQL database.")}async function w(t){const e=t.spawnHandler??d.sandboxedSpawnHandlerFactory;async function n(a,s=!1){const l=await t.createPhpRuntime(s),o=new d.PHP(l);if(t.sapiName&&o.setSapiName(t.sapiName),a&&(o.requestHandler=a),t.phpIniEntries&&d.setPhpIniEntries(o,t.phpIniEntries),o.defineConstant("WP_SQLITE_AST_DRIVER",!0),t.constants)for(const c in t.constants)o.defineConstant(c,t.constants[c]);return s&&!o.isFile("/internal/.boot-files-written")&&(await T(o),await d.writeFiles(o,"/",t.createFiles||{}),await E(o,r.joinPaths(new URL(t.siteUrl).pathname,"phpinfo.php")),await d.writeFiles(o,"/internal",{".boot-files-written":""})),e&&await o.setSpawnHandler(e(a?()=>a.instanceManager.acquirePHPInstance():void 0)),o.enableRuntimeRotation({recreateRuntime:t.createPhpRuntime,maxRequests:400}),t.onPHPInstanceCreated&&await t.onPHPInstanceCreated(o,{isPrimary:s}),o}const i=new d.PHPRequestHandler({documentRoot:t.documentRoot||"/wordpress",absoluteUrl:t.siteUrl,rewriteRules:b,pathAliases:t.pathAliases,getFileNotFoundAction:t.getFileNotFoundAction??k,cookieStore:t.cookieStore,php:t.maxPhpInstances===1?await n(void 0,!0):void 0,phpFactory:t.maxPhpInstances!==1?async({isPrimary:a})=>n(i,a):void 0,maxPhpInstances:t.maxPhpInstances});return i}async function P(t){return(await t.run({code:`<?php
2068
+ `});if(r.errors.length>0)throw new Error("Failed to check wp-config.php for constants.");let a;try{a=JSON.parse(r.text)}catch{throw new Error(`Failed to parse wp-config.php constant check output: ${r.text}`)}for(const l of a)await e.defineConstant(l,i[l])}async function w(e,{usesSqlite:t,hasCustomDatabasePath:i}){const n=await e.getPrimaryPhp();if(n.isFile("/internal/shared/preload/0-sqlite.php"))return;const s=o.joinPaths(e.documentRoot,"wp-content/mu-plugins/sqlite-database-integration");if(!n.isDir(s)&&!t&&!i&&!Se(n))throw new Error("Error connecting to the MySQL database.")}function Se(e){const t=o.joinPaths(e.documentRoot,"wp-config.php");if(!e.isFile(t))return!1;const i=e.readFileAsText(t),n=i.match(/define\s*\(\s*['"]DB_NAME['"]\s*,\s*['"]([^'"]*)['"]/),s=i.match(/define\s*\(\s*['"]DB_USER['"]\s*,\s*['"]([^'"]*)['"]/);return!n||!s?!1:n[1]!=="database_name_here"&&s[1]!=="username_here"}const x=["fsockopen","pfsockopen","curl_init","curl_exec","curl_multi_exec","mail"];function ve(e,t){var r,a;if(!f.isLegacyPHPVersion(t.phpVersion))return;const i=(((r=t.phpIniEntries)==null?void 0:r.disable_functions)??"").split(",").map(l=>l.trim()).filter(l=>l),s={disable_functions:Array.from(new Set([...i,...x])).join(","),allow_url_fopen:"0"};(a=t.phpIniEntries)!=null&&a["date.timezone"]||(s["date.timezone"]="UTC"),f.setPhpIniEntries(e,s)}async function xe(e,t){var a,l;const i=await e.getPrimaryPhp();if((a=t.hooks)!=null&&a.beforeWordPressFiles&&await t.hooks.beforeWordPressFiles(i),t.wordPressZip&&await y(i,await t.wordPressZip),t.constants)for(const _ in t.constants)i.defineConstant(_,t.constants[_]);i.defineConstant("WP_HOME",t.siteUrl),i.defineConstant("WP_SITEURL",t.siteUrl),await Re(i,e.documentRoot),await j(i,e.documentRoot),(l=t.hooks)!=null&&l.beforeDatabaseSetup&&await t.hooks.beforeDatabaseSetup(i);let n=!1;t.sqliteIntegrationPluginZip&&(n=!0,await L(i,await t.sqliteIntegrationPluginZip,{phpVersion:t.phpVersion}),await Ue(i,e.documentRoot));const s=t.wordpressInstallMode??"download-and-install",r=!!t.dataSqlPath;return(s==="download-and-install"||s==="install-from-existing-files"||s==="install-from-existing-files-if-needed")&&(await w(e,{usesSqlite:n,hasCustomDatabasePath:r}),await ke(i,e)),e}async function Re(e,t){const i=o.joinPaths(t,"wp-config.php"),n=o.joinPaths(t,"wp-config-sample.php");!e.fileExists(i)&&e.fileExists(n)&&await e.writeFile(i,await e.readFileAsBuffer(n))}async function Ue(e,t){const i=o.joinPaths(t,"wp-content"),n=o.joinPaths(i,"db.php");e.isDir(i)&&!e.fileExists(n)&&await e.writeFile(n,Te())}async function ke(e,t){try{await Ie(e)}catch(i){h.logger.warn("Legacy PHP WordPress installation error:",i)}await Le(e,t.absoluteUrl)}async function Ie(e){var r,a,l,_,c,u;const t=Ce(e,e.documentRoot);if(t!==null){const d=parseFloat(t);if(d<2.1)return;if(d<=3){await Fe(e);return}}const i={disable_functions:x.join(","),allow_url_fopen:"0",error_reporting:String(B)},n=await f.withPHPIniValues(e,i,async()=>await e.request({url:"/wp-admin/install.php?step=2",method:"POST",body:{language:"en",prefix:"wp_",weblog_title:"My WordPress Website",user_name:"admin",admin_password:"password",admin_password2:"password",Submit:"Install WordPress",pw_weak:"1",admin_email:"admin@localhost.com"}}));if(!(((r=n.text)==null?void 0:r.includes("Success"))||((a=n.text)==null?void 0:a.includes("successful"))||((l=n.text)==null?void 0:l.includes("Finished"))||((_=n.text)==null?void 0:_.includes("Already Installed"))||((c=n.text)==null?void 0:c.includes("already have WordPress installed"))||!1))throw new Error(`Failed to install WordPress – installer responded with "${(u=n.text)==null?void 0:u.substring(0,100)}"`);await De(e)}async function De(e){try{(await e.run({code:`<?php
2069
+ $db_dir = getenv('DOCUMENT_ROOT') . '/wp-content/database/';
2070
+ $db_path = $db_dir . '.ht.sqlite';
2071
+ if (!file_exists($db_path)) { echo '0'; exit; }
2072
+ $pdo = new PDO('sqlite:' . $db_path);
2073
+ $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
2074
+ $nice_permalinks = '/%year%/%monthnum%/%day%/%postname%/';
2075
+ $stmt = $pdo->prepare(
2076
+ "UPDATE wp_options SET option_value = :val WHERE option_name = 'permalink_structure'"
2077
+ );
2078
+ $stmt->execute(array(':val' => $nice_permalinks));
2079
+ if ($stmt->rowCount() === 0) {
2080
+ $stmt = $pdo->prepare(
2081
+ "INSERT INTO wp_options (option_name, option_value, autoload) VALUES ('permalink_structure', :val, 'yes')"
2082
+ );
2083
+ $stmt->execute(array(':val' => $nice_permalinks));
2084
+ }
2085
+ $check = $pdo->query(
2086
+ "SELECT option_value FROM wp_options WHERE option_name = 'permalink_structure'"
2087
+ )->fetchColumn();
2088
+ echo $check === $nice_permalinks ? '1' : '0';
2089
+ `,env:{DOCUMENT_ROOT:e.documentRoot}})).text!=="1"&&h.logger.warn("Failed to default to pretty permalinks after WP install.")}catch{h.logger.warn("Failed to set pretty permalinks after WP install (non-fatal).")}}async function Fe(e){try{await e.run({code:`<?php
2090
+ define('WP_INSTALLING', true);
2091
+ error_reporting(${T});
2092
+ ini_set('display_errors', '0');
2093
+ ob_start();
2094
+ require getenv('DOCUMENT_ROOT') . '/wp-load.php';
2095
+ ob_clean();
2096
+ if (file_exists(ABSPATH . 'wp-admin/includes/upgrade.php')) {
2097
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
2098
+ } elseif (file_exists(ABSPATH . 'wp-admin/upgrade-functions.php')) {
2099
+ require_once ABSPATH . 'wp-admin/upgrade-functions.php';
2100
+ }
2101
+ if (function_exists('make_db_current_silent')) {
2102
+ make_db_current_silent();
2103
+ }
2104
+ // Seed essential options/roles when the loader exposes
2105
+ // them. The PDO fallback in runPostInstallLegacyFixups
2106
+ // backfills anything missing if either call dies.
2107
+ if (function_exists('populate_options')) populate_options();
2108
+ if (function_exists('populate_roles')) populate_roles();
2109
+ echo 'OK';
2110
+ `,env:{DOCUMENT_ROOT:e.documentRoot}})}catch(t){h.logger.warn("runDbDeltaOnly failed (non-fatal):",t)}}function Ce(e,t){const i=o.joinPaths(t,"wp-includes/version.php");if(!e.fileExists(i))return null;const s=e.readFileAsText(i).match(/\$wp_version\s*=\s*['"]([^'"]+)['"]/);return s?s[1]:null}async function qe(e){const t=await U(e);return await R(t,e),t}async function R(e,t){var a,l;if(f.isLegacyPHPVersion(t.phpVersion))return xe(e,t);const i=await e.getPrimaryPhp();if((a=t.hooks)!=null&&a.beforeWordPressFiles&&await t.hooks.beforeWordPressFiles(i),t.wordPressZip&&await y(i,await t.wordPressZip),t.constants)for(const _ in t.constants)i.defineConstant(_,t.constants[_]);t.dataSqlPath&&(i.defineConstant("DB_DIR",o.dirname(t.dataSqlPath)),i.defineConstant("DB_FILE",o.basename(t.dataSqlPath))),i.defineConstant("WP_HOME",t.siteUrl),i.defineConstant("WP_SITEURL",t.siteUrl),await v(i,e.documentRoot),(l=t.hooks)!=null&&l.beforeDatabaseSetup&&await t.hooks.beforeDatabaseSetup(i);let n=!1;t.sqliteIntegrationPluginZip&&(n=!0,await L(i,await t.sqliteIntegrationPluginZip,{phpVersion:t.phpVersion}),await H(i,e.documentRoot));const s=t.wordpressInstallMode??"download-and-install",r=!!t.dataSqlPath;if(["download-and-install","install-from-existing-files"].includes(s)){await w(e,{usesSqlite:n,hasCustomDatabasePath:r});try{await b(i)}catch(_){throw r||await m(e),_}r||await m(e)}else if(s==="install-from-existing-files-if-needed"){if(await w(e,{usesSqlite:n,hasCustomDatabasePath:r}),!await k(i))try{await b(i)}catch(_){throw r||await m(e),_}r||await m(e)}return e}async function m(e){const t=await e.getPrimaryPhp();if(await We(t))return;if(t.isFile("/internal/shared/preload/0-sqlite.php"))throw new Error("Error connecting to the SQLite database.");const n=o.joinPaths(e.documentRoot,"wp-content/mu-plugins/sqlite-database-integration");throw t.isDir(n)?new Error("Error connecting to the SQLite database."):new Error("Error connecting to the MySQL database.")}async function U(e){const t=e.spawnHandler??f.sandboxedSpawnHandlerFactory;async function i(s,r=!1){const a=await e.createPhpRuntime(r),l=new f.PHP(a);if(e.sapiName&&l.setSapiName(e.sapiName),s&&(l.requestHandler=s),e.phpIniEntries&&f.setPhpIniEntries(l,e.phpIniEntries),ve(l,{phpVersion:e.phpVersion,phpIniEntries:e.phpIniEntries}),l.defineConstant("WP_SQLITE_AST_DRIVER",!0),e.constants)for(const _ in e.constants)l.defineConstant(_,e.constants[_]);return r&&!l.isFile("/internal/.boot-files-written")&&(await C(l,{phpVersion:e.phpVersion}),await f.writeFiles(l,"/",e.createFiles||{}),await q(l,o.joinPaths(new URL(e.siteUrl).pathname,"phpinfo.php")),await f.writeFiles(l,"/internal",{".boot-files-written":""})),t&&await l.setSpawnHandler(t(s?()=>s.instanceManager.acquirePHPInstance():void 0)),l.enableRuntimeRotation({recreateRuntime:e.createPhpRuntime,maxRequests:400}),e.onPHPInstanceCreated&&await e.onPHPInstanceCreated(l,{isPrimary:r}),l}const n=new f.PHPRequestHandler({documentRoot:e.documentRoot||"/wordpress",absoluteUrl:e.siteUrl,rewriteRules:F,pathAliases:e.pathAliases,getFileNotFoundAction:e.getFileNotFoundAction??I,cookieStore:e.cookieStore,php:e.maxPhpInstances===1?await i(void 0,!0):void 0,phpFactory:e.maxPhpInstances!==1?async({isPrimary:s})=>i(n,s):void 0,maxPhpInstances:e.maxPhpInstances});return n}async function k(e){return(await e.run({code:`<?php
487
2111
  ob_start();
488
2112
  $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
489
2113
  if (!file_exists($wp_load)) {
@@ -494,7 +2118,7 @@ class WP_Config_Transformer {
494
2118
  ob_clean();
495
2119
  echo is_blog_installed() ? '1' : '0';
496
2120
  ob_end_flush();
497
- `,env:{DOCUMENT_ROOT:t.documentRoot}})).text==="1"}async function f(t){var i;const e=await d.withPHPIniValues(t,{disable_functions:"fsockopen",allow_url_fopen:"0"},async()=>await t.request({url:"/wp-admin/install.php?step=2",method:"POST",body:{language:"en",prefix:"wp_",weblog_title:"My WordPress Website",user_name:"admin",admin_password:"password",admin_password2:"password",Submit:"Install WordPress",pw_weak:"1",admin_email:"admin@localhost.com"}}));if(!await P(t))throw new Error(`Failed to install WordPress – installer responded with "${(i=e.text)==null?void 0:i.substring(0,100)}"`);(await t.run({code:`<?php
2121
+ `,env:{DOCUMENT_ROOT:e.documentRoot}})).text==="1"}async function b(e){var n;const t=await f.withPHPIniValues(e,{disable_functions:"fsockopen",allow_url_fopen:"0"},async()=>await e.request({url:"/wp-admin/install.php?step=2",method:"POST",body:{language:"en",prefix:"wp_",weblog_title:"My WordPress Website",user_name:"admin",admin_password:"password",admin_password2:"password",Submit:"Install WordPress",pw_weak:"1",admin_email:"admin@localhost.com"}}));if(!await k(e))throw new Error(`Failed to install WordPress – installer responded with "${(n=t.text)==null?void 0:n.substring(0,100)}"`);(await e.run({code:`<?php
498
2122
  ob_start();
499
2123
  $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
500
2124
  if (!file_exists($wp_load)) {
@@ -514,7 +2138,7 @@ class WP_Config_Transformer {
514
2138
  echo '0';
515
2139
  }
516
2140
  ob_end_flush();
517
- `,env:{DOCUMENT_ROOT:t.documentRoot}})).text!=="1"&&_.logger.warn("Failed to default to pretty permalinks after WP install.")}function k(t){return{type:"internal-redirect",uri:"/index.php"}}function C(t){const e=r.joinPaths(t.documentRoot,"wp-config.php");if(!t.isFile(e))return!1;const n=t.readFileAsText(e),i=n.match(/define\s*\(\s*['"]DB_NAME['"]\s*,\s*['"]([^'"]*)['"]/),a=n.match(/define\s*\(\s*['"]DB_USER['"]\s*,\s*['"]([^'"]*)['"]/);return!i||!a?!1:i[1]!=="database_name_here"&&a[1]!=="username_here"}async function W(t){return(await t.run({code:`<?php
2141
+ `,env:{DOCUMENT_ROOT:e.documentRoot}})).text!=="1"&&h.logger.warn("Failed to default to pretty permalinks after WP install.")}function I(e){return{type:"internal-redirect",uri:"/index.php"}}async function We(e){return(await e.run({code:`<?php
518
2142
  ob_start();
519
2143
  $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
520
2144
  if (!file_exists($wp_load)) {
@@ -525,10 +2149,10 @@ class WP_Config_Transformer {
525
2149
  ob_clean();
526
2150
  echo $wpdb->check_connection( false ) ? '1' : '0';
527
2151
  ob_end_flush();
528
- `,env:{DOCUMENT_ROOT:t.documentRoot}})).text==="1"}async function O(t){const{php:e,reap:n}=await t.instanceManager.acquirePHPInstance();try{const a=(await e.run({code:`<?php
529
- require '${t.documentRoot}/wp-includes/version.php';
2152
+ `,env:{DOCUMENT_ROOT:e.documentRoot}})).text==="1"}async function Ge(e){const{php:t,reap:i}=await e.instanceManager.acquirePHPInstance();try{const s=(await t.run({code:`<?php
2153
+ require '${e.documentRoot}/wp-includes/version.php';
530
2154
  echo $wp_version;
531
- `})).text;if(!a)throw new Error("Unable to read loaded WordPress version.");return y(a)}finally{n()}}function y(t){if(/-(alpha|beta|RC)\d*-\d+$/.test(t))return"trunk";if(/-(beta|RC)\d*$/.test(t))return"beta";const i=t.match(/^(\d+\.\d+)(?:\.\d+)?$/);return i!==null?i[1]:t}const b=[{match:new RegExp("^(/[_0-9a-zA-Z-]+)?(/wp-(content|admin|includes)/.*)"),replacement:"$2"}];async function T(t){await t.mkdir("/internal/shared/mu-plugins"),await t.writeFile("/internal/shared/preload/env.php",`<?php
2155
+ `})).text;if(!s)throw new Error("Unable to read loaded WordPress version.");return D(s)}finally{i()}}function D(e){if(/-(alpha|beta|RC)\d*-\d+$/.test(e))return"trunk";if(/-(beta|RC)\d*$/.test(e))return"beta";const n=e.match(/^(\d+\.\d+)(?:\.\d+)?$/);return n!==null?n[1]:e}const F=[{match:new RegExp("^(/[_0-9a-zA-Z-]+)?(/wp-(content|admin|includes)/.*)"),replacement:"$2"}];async function C(e,t={}){if(f.isLegacyPHPVersion(t.phpVersion))return G(e);await e.mkdir("/internal/shared/mu-plugins"),await e.writeFile("/internal/shared/preload/env.php",`<?php
532
2156
 
533
2157
  // Allow adding filters/actions prior to loading WordPress.
534
2158
  // $function_to_add MUST be a string.
@@ -555,7 +2179,7 @@ class WP_Config_Transformer {
555
2179
  require_once $mu_plugin;
556
2180
  }
557
2181
  }
558
- `),await t.writeFile("/internal/shared/mu-plugins/1-auto-login.php",`<?php
2182
+ `),await e.writeFile("/internal/shared/mu-plugins/1-auto-login.php",`<?php
559
2183
  /**
560
2184
  * Returns the username to auto-login as, if any.
561
2185
  * @return string|false
@@ -709,105 +2333,7 @@ class WP_Config_Transformer {
709
2333
  }
710
2334
  return $interval;
711
2335
  });
712
- `),await t.writeFile("/internal/shared/mu-plugins/0-playground.php",`<?php
713
-
714
- // Save WordPress environment information to a file.
715
- add_action('wp_loaded', function() {
716
- if (defined('DB_ENGINE') && DB_ENGINE === 'sqlite') {
717
- $db_info = array(
718
- 'type' => 'sqlite',
719
- 'path' => FQDB,
720
- 'driver_path' => defined('WP_MYSQL_ON_SQLITE_LOADER_PATH')
721
- ? WP_MYSQL_ON_SQLITE_LOADER_PATH
722
- : dirname(SQLITE_MAIN_FILE) . '/wp-pdo-mysql-on-sqlite.php',
723
- );
724
- } else {
725
- $db_info = array(
726
- 'type' => 'mysql',
727
- // TODO: Save MySQL connection config.
728
- );
729
- }
730
- $wp_env = array('db' => $db_info);
731
- $wp_env_php = sprintf('<?php return %s;', var_export($wp_env, true));
732
- $wp_env_file = '/internal/shared/wp-env.php';
733
- if (!file_exists($wp_env_file) || file_get_contents($wp_env_file) !== $wp_env_php ) {
734
- file_put_contents($wp_env_file, $wp_env_php);
735
- }
736
- });
737
-
738
- // Needed because gethostbyname( 'wordpress.org' ) returns
739
- // a private network IP address for some reason.
740
- add_filter( 'allowed_redirect_hosts', function( $deprecated = '' ) {
741
- return array(
742
- 'wordpress.org',
743
- 'api.wordpress.org',
744
- 'downloads.wordpress.org',
745
- );
746
- } );
747
-
748
- /**
749
- * Prevents wp_http_validate_url() from universally failing.
750
- *
751
- * wp_http_validate_url() calls gethostbyname() to verify whether the host
752
- * is external. If it is internal, the URL validation fails and WordPress
753
- * refuses to make a request.
754
- *
755
- * However, in EMscripten, gethostbyname() returns a private network IP address.
756
- * This causes wp_http_validate_url() to return false for all URLs.
757
- *
758
- * This filter ensures that all URLs are considered external. In production
759
- * environments, this would be considered a security risk. However, Playground
760
- * already provides multiple code execution vectors as features (e.g. Blueprints).
761
- *
762
- * If someone wants to poke around local IP addresses, they already have multiple
763
- * tools at their disposal. Therefore, this is not a real security risk in context
764
- * of WordPress Playground or Playground CLI.
765
- */
766
- add_filter('http_request_host_is_external', '__return_true');
767
-
768
- // Support pretty permalinks
769
- add_filter( 'got_url_rewrite', '__return_true' );
770
-
771
- // Create the fonts directory if missing
772
- if(!file_exists(WP_CONTENT_DIR . '/fonts')) {
773
- mkdir(WP_CONTENT_DIR . '/fonts');
774
- }
775
-
776
- $log_file = WP_CONTENT_DIR . '/debug.log';
777
- if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
778
- if ( is_string( WP_DEBUG_LOG ) ) {
779
- $log_file = WP_DEBUG_LOG;
780
- }
781
- ini_set('error_log', $log_file);
782
- } else {
783
- ini_set('log_errors', '0');
784
- }
785
- define('ERROR_LOG_FILE', $log_file);
786
- ?>`),await t.writeFile("/internal/shared/mu-plugins/sitemap-redirect.php",`<?php
787
- /**
788
- * Redirect sitemap.xml to wp-sitemap.xml for non-root installations.
789
- *
790
- * WordPress seems to only generate the sitemap.xml → wp-sitemap.xml rewrite
791
- * rule when installed at the domain root. This mu-plugin handles the
792
- * redirect for non-root installations.
793
- */
794
- if (isset($_SERVER['REQUEST_URI'])) {
795
- $site_url = site_url();
796
- $parsed = parse_url($site_url);
797
- $base_path = isset($parsed['path']) ? rtrim($parsed['path'], '/') : '';
798
-
799
- $request_uri = $_SERVER['REQUEST_URI'];
800
- if (
801
- $request_uri === $base_path . '/sitemap.xml' ||
802
- strpos($request_uri, $base_path . '/sitemap.xml?') === 0 ||
803
- strpos($request_uri, $base_path . '/sitemap.xml/') === 0
804
- ) {
805
- $query_string = strpos($request_uri, '?') !== false ? substr($request_uri, strpos($request_uri, '?')) : '';
806
- header('Location: ' . $base_path . '/wp-sitemap.xml' . $query_string, true, 301);
807
- exit;
808
- }
809
- }
810
- `),await t.writeFile("/internal/shared/preload/error-handler.php",`<?php
2336
+ `),await O(e),await e.writeFile("/internal/shared/preload/error-handler.php",`<?php
811
2337
  (function() {
812
2338
  $playground_consts = [];
813
2339
  if(file_exists('/internal/shared/consts.json')) {
@@ -855,97 +2381,29 @@ class WP_Config_Transformer {
855
2381
  }
856
2382
  return false;
857
2383
  });
858
- })();`)}async function E(t,e="/phpinfo.php"){await t.writeFile("/internal/shared/preload/phpinfo.php",`<?php
2384
+ })();`)}async function q(e,t="/phpinfo.php"){await e.writeFile("/internal/shared/preload/phpinfo.php",`<?php
859
2385
  // Render PHPInfo if the requested page is /phpinfo.php
860
- if ( isset($_SERVER['REQUEST_URI']) && ${r.phpVar(e)} === $_SERVER['REQUEST_URI'] ) {
2386
+ if ( isset($_SERVER['REQUEST_URI']) && ${o.phpVar(t)} === $_SERVER['REQUEST_URI'] ) {
861
2387
  phpinfo();
862
2388
  exit;
863
2389
  }
864
- `)}async function v(t,e){await t.isDir("/tmp/sqlite-database-integration")&&await t.rmdir("/tmp/sqlite-database-integration",{recursive:!0}),await t.mkdir("/tmp/sqlite-database-integration"),await p.unzipFile(t,e,"/tmp/sqlite-database-integration");const n="/internal/shared/sqlite-database-integration",i=`/tmp/sqlite-database-integration/${(await t.listFiles("/tmp/sqlite-database-integration"))[0]}`;await t.mv(i,n),await t.defineConstant("SQLITE_MAIN_FILE","1");const s=(await t.readFileAsText(r.joinPaths(n,"db.copy"))).replace("'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",r.phpVar(n)).replace("'{SQLITE_PLUGIN}'",r.phpVar(r.joinPaths(n,"load.php"))),l=r.joinPaths(await t.documentRoot,"wp-content/db.php"),o=`<?php
2390
+ `)}async function L(e,t,i={}){if(f.isLegacyPHPVersion(i.phpVersion))return Pe(e,t,i);await e.isDir("/tmp/sqlite-database-integration")&&await e.rmdir("/tmp/sqlite-database-integration",{recursive:!0}),await e.mkdir("/tmp/sqlite-database-integration"),await g.unzipFile(e,t,"/tmp/sqlite-database-integration");const n="/internal/shared/sqlite-database-integration",s=`/tmp/sqlite-database-integration/${(await e.listFiles("/tmp/sqlite-database-integration"))[0]}`;await e.mv(s,n);const r=o.joinPaths(n,"wp-includes/sqlite/class-wp-sqlite-db.php");if(await e.fileExists(r)){const d=await e.readFileAsText(r),$=d.replace("private $allow_unsafe_unquoted_parameters","protected $allow_unsafe_unquoted_parameters");$!==d&&await e.writeFile(r,$)}await e.defineConstant("SQLITE_MAIN_FILE","1");const l=(await e.readFileAsText(o.joinPaths(n,"db.copy"))).replace("'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",o.phpVar(n)).replace("'{SQLITE_PLUGIN}'",o.phpVar(o.joinPaths(n,"load.php"))),_=o.joinPaths(await e.documentRoot,"wp-content/db.php"),c=`<?php
865
2391
  // Do not preload this if WordPress comes with a custom db.php file.
866
- if(file_exists(${r.phpVar(l)})) {
2392
+ if(file_exists(${o.phpVar(_)})) {
867
2393
  return;
868
2394
  }
869
- ?>`,c="/internal/shared/mu-plugins/sqlite-database-integration.php";await t.writeFile(c,o+s),await t.writeFile("/internal/shared/preload/0-sqlite.php",o+`<?php
870
-
871
- /**
872
- * Loads the SQLite integration plugin before WordPress is loaded
873
- * and without creating a drop-in "db.php" file.
874
- *
875
- * Technically, it creates a global $wpdb object whose only two
876
- * purposes are to:
877
- *
878
- * * Exist – because the require_wp_db() WordPress function won't
879
- * connect to MySQL if $wpdb is already set.
880
- * * Load the SQLite integration plugin the first time it's used
881
- * and replace the global $wpdb reference with the SQLite one.
882
- *
883
- * This lets Playground keep the WordPress installation clean and
884
- * solves dillemas like:
885
- *
886
- * * Should we include db.php in Playground exports?
887
- * * Should we remove db.php from Playground imports?
888
- * * How should we treat stale db.php from long-lived OPFS sites?
889
- *
890
- * @see https://github.com/WordPress/wordpress-playground/discussions/1379 for
891
- * more context.
892
- */
893
- class Playground_SQLite_Integration_Loader {
894
- public function __call($name, $arguments) {
895
- $this->load_sqlite_integration();
896
- if($GLOBALS['wpdb'] === $this) {
897
- throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
898
- }
899
- return call_user_func_array(
900
- array($GLOBALS['wpdb'], $name),
901
- $arguments
902
- );
903
- }
904
- public function __get($name) {
905
- $this->load_sqlite_integration();
906
- if($GLOBALS['wpdb'] === $this) {
907
- throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
908
- }
909
- return $GLOBALS['wpdb']->$name;
910
- }
911
- public function __set($name, $value) {
912
- $this->load_sqlite_integration();
913
- if($GLOBALS['wpdb'] === $this) {
914
- throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
2395
+ ?>`,u="/internal/shared/mu-plugins/sqlite-database-integration.php";await e.writeFile(u,c+l),await e.writeFile("/internal/shared/preload/0-sqlite.php",Me(c,u)),await e.writeFile("/internal/shared/mu-plugins/sqlite-test.php",`<?php
2396
+ global $wpdb;
2397
+ if(!($wpdb instanceof WP_SQLite_DB)) {
2398
+ var_dump(isset($wpdb));
2399
+ die("SQLite integration not loaded " . get_class($wpdb));
915
2400
  }
916
- $GLOBALS['wpdb']->$name = $value;
917
- }
918
- protected function load_sqlite_integration() {
919
- require_once ${r.phpVar(c)};
920
- }
921
- }
922
- /**
923
- * The Query Monitor plugin short-circuits in the CLI SAPI. However, in Playground,
924
- * the SAPI is always "cli" at the moment. Let's set a constant to disable the CLI
925
- * detection.
926
- *
927
- * @see https://github.com/WordPress/sqlite-database-integration/pull/212
928
- * @see https://github.com/WordPress/sqlite-database-integration/pull/215
929
- */
930
- define('QM_TESTS', true);
931
- $wpdb = $GLOBALS['wpdb'] = new Playground_SQLite_Integration_Loader();
2401
+ `)}function Me(e,t){return e+`<?php
932
2402
 
933
- /**
934
- * WordPress is capable of using a preloaded global $wpdb. However, if
935
- * it cannot find the drop-in db.php plugin it still checks whether
936
- * the mysqli_connect() function exists even though it's not used.
937
- *
938
- * What WordPress demands, Playground shall provide.
939
- */
2403
+ ${N(`require_once ${o.phpVar(t)};`)}
940
2404
  if(!function_exists('mysqli_connect')) {
941
2405
  function mysqli_connect() {}
942
2406
  }
943
2407
 
944
- `),await t.writeFile("/internal/shared/mu-plugins/sqlite-test.php",`<?php
945
- global $wpdb;
946
- if(!($wpdb instanceof WP_SQLite_DB)) {
947
- var_dump(isset($wpdb));
948
- die("SQLite integration not loaded " . get_class($wpdb));
949
- }
950
- `)}async function R(t,e){t.mkdir("/tmp/unzipped-wordpress"),await p.unzipFile(t,e,"/tmp/unzipped-wordpress"),t.fileExists("/tmp/unzipped-wordpress/wordpress.zip")&&await p.unzipFile(t,"/tmp/unzipped-wordpress/wordpress.zip","/tmp/unzipped-wordpress");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";if(!t.fileExists(r.joinPaths(n,"wp-config-sample.php"))){const a=t.listFiles(n);if(a.length){const s=a[0];t.fileExists(r.joinPaths(n,s,"wp-config-sample.php"))&&(n=r.joinPaths(n,s))}}const i=(a,s,l)=>{if(l.isDir(a)&&l.isDir(s))for(const o of l.listFiles(a)){const c=r.joinPaths(a,o),S=r.joinPaths(s,o);i(c,S,l)}else{if(l.fileExists(s)){const o=a.replace(/^\/tmp\/unzipped-wordpress\//,"/");_.logger.warn(`Cannot unzip WordPress files at ${s}: ${o} already exists.`);return}l.mv(a,s)}};i(n,t.documentRoot,t),t.fileExists(n)&&t.rmdir(n,{recursive:!0}),!t.fileExists(r.joinPaths(t.documentRoot,"wp-config.php"))&&t.fileExists(r.joinPaths(t.documentRoot,"wp-config-sample.php"))&&t.writeFile(r.joinPaths(t.documentRoot,"wp-config.php"),t.readFileAsText(r.joinPaths(t.documentRoot,"/wp-config-sample.php")))}const q=p.createMemoizedFetch(fetch),A="https://github.com/WordPress/WordPress/archive/refs/heads/master.zip";async function U(t="latest"){if(t===null)t="latest";else if(t.startsWith("https://")||t.startsWith("http://")){const i=await crypto.subtle.digest("SHA-1",new TextEncoder().encode(t)),a=Array.from(new Uint8Array(i)).map(s=>s.toString(16).padStart(2,"0")).join("");return{releaseUrl:t,version:"custom-"+a.substring(0,8),source:"inferred"}}else if(t==="trunk"||t==="nightly"){const i=new Date().toISOString().split("T")[0];return{releaseUrl:`${A}?ts=${i}`,version:"trunk",source:"inferred"}}let n=await(await q("https://api.wordpress.org/core/version-check/1.7/?channel=beta")).json();n=n.offers.filter(i=>i.response==="autoupdate");for(const i of n){if(t==="beta"&&(i.version.includes("beta")||i.version.includes("RC")))return{releaseUrl:i.download,version:i.version,source:"api"};if(t==="latest"&&!i.version.includes("beta")&&!i.version.includes("RC"))return{releaseUrl:i.download,version:i.version,source:"api"};if(i.version.substring(0,t.length)===t)return{releaseUrl:i.download,version:i.version,source:"api"}}return t.match(/^\d+\.\d+\.0$/)&&(t=t.split(".").slice(0,2).join(".")),{releaseUrl:`https://wordpress.org/wordpress-${t}.zip`,version:t,source:"inferred"}}exports.bootRequestHandler=w;exports.bootWordPress=m;exports.bootWordPressAndRequestHandler=L;exports.defineWpConfigConstants=I;exports.ensureWpConfig=g;exports.getFileNotFoundActionForWordPress=k;exports.getLoadedWordPressVersion=O;exports.preloadPhpInfoRoute=E;exports.preloadSqliteIntegration=v;exports.resolveWordPressRelease=U;exports.setupPlatformLevelMuPlugins=T;exports.unzipWordPress=R;exports.versionStringToLoadedWordPressVersion=y;exports.wordPressRewriteRules=b;
2408
+ `}async function y(e,t){e.mkdir("/tmp/unzipped-wordpress"),await g.unzipFile(e,t,"/tmp/unzipped-wordpress"),e.fileExists("/tmp/unzipped-wordpress/wordpress.zip")&&await g.unzipFile(e,"/tmp/unzipped-wordpress/wordpress.zip","/tmp/unzipped-wordpress");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";if(!e.fileExists(o.joinPaths(i,"wp-config-sample.php"))){const s=e.listFiles(i);if(s.length){const r=s[0];e.fileExists(o.joinPaths(i,r,"wp-config-sample.php"))&&(i=o.joinPaths(i,r))}}const n=(s,r,a)=>{if(a.isDir(s)&&a.isDir(r))for(const l of a.listFiles(s)){const _=o.joinPaths(s,l),c=o.joinPaths(r,l);n(_,c,a)}else{if(a.fileExists(r)){const l=s.replace(/^\/tmp\/unzipped-wordpress\//,"/");h.logger.warn(`Cannot unzip WordPress files at ${r}: ${l} already exists.`);return}a.mv(s,r)}};n(i,e.documentRoot,e),e.fileExists(i)&&e.rmdir(i,{recursive:!0}),!e.fileExists(o.joinPaths(e.documentRoot,"wp-config.php"))&&e.fileExists(o.joinPaths(e.documentRoot,"wp-config-sample.php"))&&e.writeFile(o.joinPaths(e.documentRoot,"wp-config.php"),e.readFileAsText(o.joinPaths(e.documentRoot,"/wp-config-sample.php")))}const He=g.createMemoizedFetch(fetch),Be="https://github.com/WordPress/WordPress/archive/refs/heads/master.zip";async function je(e="latest"){if(e===null)e="latest";else if(e.startsWith("https://")||e.startsWith("http://")){const n=await crypto.subtle.digest("SHA-1",new TextEncoder().encode(e)),s=Array.from(new Uint8Array(n)).map(r=>r.toString(16).padStart(2,"0")).join("");return{releaseUrl:e,version:"custom-"+s.substring(0,8),source:"inferred"}}else if(e==="trunk"||e==="nightly"){const n=new Date().toISOString().split("T")[0];return{releaseUrl:`${Be}?ts=${n}`,version:"trunk",source:"inferred"}}let i=await(await He("https://api.wordpress.org/core/version-check/1.7/?channel=beta")).json();i=i.offers.filter(n=>n.response==="autoupdate");for(const n of i){if(e==="beta"&&(n.version.includes("beta")||n.version.includes("RC")))return{releaseUrl:n.download,version:n.version,source:"api"};if(e==="latest"&&!n.version.includes("beta")&&!n.version.includes("RC"))return{releaseUrl:n.download,version:n.version,source:"api"};if(n.version.substring(0,e.length)===e)return{releaseUrl:n.download,version:n.version,source:"api"}}return e.match(/^\d+\.\d+\.0$/)&&(e=e.split(".").slice(0,2).join(".")),{releaseUrl:`https://wordpress.org/wordpress-${e}.zip`,version:e,source:"inferred"}}exports.bootRequestHandler=U;exports.bootWordPress=R;exports.bootWordPressAndRequestHandler=qe;exports.defineWpConfigConstants=Ne;exports.ensureWpConfig=v;exports.getFileNotFoundActionForWordPress=I;exports.getLoadedWordPressVersion=Ge;exports.preloadPhpInfoRoute=q;exports.preloadSqliteIntegration=L;exports.resolveWordPressRelease=je;exports.setupPlatformLevelMuPlugins=C;exports.unzipWordPress=y;exports.versionStringToLoadedWordPressVersion=D;exports.wordPressRewriteRules=F;
951
2409
  //# sourceMappingURL=index.cjs.map