@wp-playground/wordpress 3.0.19 → 3.0.21

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/boot.d.ts CHANGED
@@ -74,6 +74,7 @@ export interface BootRequestHandlerOptions {
74
74
  */
75
75
  cookieStore?: CookieStore | false;
76
76
  }
77
+ export type WordPressInstallMode = 'download-and-install' | 'install-from-existing-files' | 'install-from-existing-files-if-needed' | 'do-not-attempt-installing';
77
78
  export interface BootWordPressOptions {
78
79
  /**
79
80
  * Mounting and Copying is handled via hooks for starters.
@@ -85,6 +86,8 @@ export interface BootWordPressOptions {
85
86
  hooks?: Hooks;
86
87
  /** SQL file to load instead of installing WordPress. */
87
88
  dataSqlPath?: string;
89
+ /** How to handle WordPress installation. */
90
+ wordpressInstallMode?: WordPressInstallMode;
88
91
  /** Zip with the WordPress installation to extract in /wordpress. */
89
92
  wordPressZip?: File | Promise<File> | undefined;
90
93
  /** Preloaded SQLite integration plugin. */
package/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("@php-wasm/util"),p=require("@wp-playground/common"),c=require("@php-wasm/logger"),d=require("@php-wasm/universal"),R=`<?php
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("@php-wasm/util"),f=require("@wp-playground/common"),h=require("@php-wasm/logger"),u=require("@php-wasm/universal"),x=`<?php
2
2
 
3
3
  /**
4
4
  * Rewrites the wp-config.php file to ensure specific constants are defined
@@ -343,8 +343,8 @@ function skip_whitespace($tokens) {
343
343
  }
344
344
  return $output;
345
345
  }
346
- `;async function _(e,t,n,i="rewrite"){const r=o.phpVars({wpConfigPath:t,constants:n,whenAlreadyDefined:i});if((await e.run({code:`<?php ob_start(); ?>
347
- ${R}
346
+ `;async function g(e,n,t,i="rewrite"){const r=a.phpVars({wpConfigPath:n,constants:t,whenAlreadyDefined:i});if((await e.run({code:`<?php ob_start(); ?>
347
+ ${x}
348
348
  $wp_config_path = ${r.wpConfigPath};
349
349
  $wp_config = file_get_contents($wp_config_path);
350
350
  $new_wp_config = rewrite_wp_config_to_define_constants($wp_config, ${r.constants}, ${r.whenAlreadyDefined});
@@ -352,7 +352,7 @@ function skip_whitespace($tokens) {
352
352
  ob_clean();
353
353
  echo false === $return_value ? '0' : '1';
354
354
  ob_end_flush();
355
- `})).text!=="1")throw new Error("Failed to rewrite constants in wp-config.php.")}async function h(e,t){const n=o.joinPaths(t,"wp-config.php"),i={DB_NAME:"wordpress"};!e.fileExists(n)&&e.fileExists(o.joinPaths(t,"wp-config-sample.php"))&&await e.writeFile(n,await e.readFileAsBuffer(o.joinPaths(t,"wp-config-sample.php"))),await _(e,n,i,"skip")}async function v(e){const t=await w(e);return await g(t,e),t}async function g(e,t){var i,r;const n=await e.getPrimaryPhp();if((i=t.hooks)!=null&&i.beforeWordPressFiles&&await t.hooks.beforeWordPressFiles(n),t.wordPressZip&&await E(n,await t.wordPressZip),t.constants)for(const a in t.constants)n.defineConstant(a,t.constants[a]);if(t.dataSqlPath&&(n.defineConstant("DB_DIR",o.dirname(t.dataSqlPath)),n.defineConstant("DB_FILE",o.basename(t.dataSqlPath))),n.defineConstant("WP_HOME",t.siteUrl),n.defineConstant("WP_SITEURL",t.siteUrl),await h(n,e.documentRoot),(r=t.hooks)!=null&&r.beforeDatabaseSetup&&await t.hooks.beforeDatabaseSetup(n),t.sqliteIntegrationPluginZip&&await k(n,await t.sqliteIntegrationPluginZip),t.wordPressZip&&!t.dataSqlPath&&(await f(n)||await S(n),!await f(n))){if(await L(n))throw new Error("WordPress installation has failed.");if(n.isFile("/internal/shared/preload/0-sqlite.php"))throw new Error("Error connecting to the SQLite database.");if(!t.sqliteIntegrationPluginZip){const l=o.joinPaths(e.documentRoot,"wp-content/mu-plugins/sqlite-database-integration");if(n.isDir(l))throw new Error("Error connecting to the SQLite database.")}throw new Error("Error connecting to the MySQL database.")}return e}async function w(e){const t=e.spawnHandler??d.sandboxedSpawnHandlerFactory;async function n(r,a){const l=await e.createPhpRuntime(a),s=new d.PHP(l);return e.sapiName&&s.setSapiName(e.sapiName),r&&(s.requestHandler=r),e.phpIniEntries&&d.setPhpIniEntries(s,e.phpIniEntries),s.defineConstant("WP_SQLITE_AST_DRIVER",!0),a&&!s.isFile("/internal/.boot-files-written")&&(await y(s),await d.writeFiles(s,"/",e.createFiles||{}),await P(s,o.joinPaths(new URL(e.siteUrl).pathname,"phpinfo.php")),await d.writeFiles(s,"/internal",{".boot-files-written":""})),t&&await s.setSpawnHandler(t(r.processManager)),s.enableRuntimeRotation({recreateRuntime:e.createPhpRuntime,maxRequests:400}),e.onPHPInstanceCreated&&await e.onPHPInstanceCreated(s,{isPrimary:a}),s}const i=new d.PHPRequestHandler({phpFactory:async({isPrimary:r})=>n(i,r),documentRoot:e.documentRoot||"/wordpress",absoluteUrl:e.siteUrl,rewriteRules:b,getFileNotFoundAction:e.getFileNotFoundAction??$,cookieStore:e.cookieStore});return i}async function f(e){return(await e.run({code:`<?php
355
+ `})).text!=="1")throw new Error("Failed to rewrite constants in wp-config.php.")}async function w(e,n){const t=a.joinPaths(n,"wp-config.php"),i={DB_NAME:"wordpress"};!e.fileExists(t)&&e.fileExists(a.joinPaths(n,"wp-config-sample.php"))&&await e.writeFile(t,await e.readFileAsBuffer(a.joinPaths(n,"wp-config-sample.php"))),await g(e,t,i,"skip")}async function L(e){const n=await m(e);return await $(n,e),n}async function $(e,n){var l,s;const t=await e.getPrimaryPhp();if((l=n.hooks)!=null&&l.beforeWordPressFiles&&await n.hooks.beforeWordPressFiles(t),n.wordPressZip&&await S(t,await n.wordPressZip),n.constants)for(const d in n.constants)t.defineConstant(d,n.constants[d]);n.dataSqlPath&&(t.defineConstant("DB_DIR",a.dirname(n.dataSqlPath)),t.defineConstant("DB_FILE",a.basename(n.dataSqlPath))),t.defineConstant("WP_HOME",n.siteUrl),t.defineConstant("WP_SITEURL",n.siteUrl),await w(t,e.documentRoot),(s=n.hooks)!=null&&s.beforeDatabaseSetup&&await n.hooks.beforeDatabaseSetup(t);let i=!1;n.sqliteIntegrationPluginZip&&(i=!0,await R(t,await n.sqliteIntegrationPluginZip));const r=n.wordpressInstallMode??"download-and-install",o=!!n.dataSqlPath;if(["download-and-install","install-from-existing-files"].includes(r)){await c(e,{usesSqlite:i,hasCustomDatabasePath:o});try{await _(t)}catch(d){throw o||await p(e),d}o||await p(e)}else if(r==="install-from-existing-files-if-needed"){if(await c(e,{usesSqlite:i,hasCustomDatabasePath:o}),!await b(t))try{await _(t)}catch(d){throw o||await p(e),d}o||await p(e)}return e}async function c(e,{usesSqlite:n,hasCustomDatabasePath:t}){const i=await e.getPrimaryPhp();if(i.isFile("/internal/shared/preload/0-sqlite.php"))return;const r=a.joinPaths(e.documentRoot,"wp-content/mu-plugins/sqlite-database-integration");if(!i.isDir(r)&&!n&&!t)throw new Error("Error connecting to the MySQL database.")}async function p(e){const n=await e.getPrimaryPhp();if(await I(n))return;if(n.isFile("/internal/shared/preload/0-sqlite.php"))throw new Error("Error connecting to the SQLite database.");const i=a.joinPaths(e.documentRoot,"wp-content/mu-plugins/sqlite-database-integration");throw n.isDir(i)?new Error("Error connecting to the SQLite database."):new Error("Error connecting to the MySQL database.")}async function m(e){const n=e.spawnHandler??u.sandboxedSpawnHandlerFactory;async function t(r,o){const l=await e.createPhpRuntime(o),s=new u.PHP(l);return e.sapiName&&s.setSapiName(e.sapiName),r&&(s.requestHandler=r),e.phpIniEntries&&u.setPhpIniEntries(s,e.phpIniEntries),s.defineConstant("WP_SQLITE_AST_DRIVER",!0),o&&!s.isFile("/internal/.boot-files-written")&&(await E(s),await u.writeFiles(s,"/",e.createFiles||{}),await T(s,a.joinPaths(new URL(e.siteUrl).pathname,"phpinfo.php")),await u.writeFiles(s,"/internal",{".boot-files-written":""})),n&&await s.setSpawnHandler(n(r.processManager)),s.enableRuntimeRotation({recreateRuntime:e.createPhpRuntime,maxRequests:400}),e.onPHPInstanceCreated&&await e.onPHPInstanceCreated(s,{isPrimary:o}),s}const i=new u.PHPRequestHandler({phpFactory:async({isPrimary:r})=>t(i,r),documentRoot:e.documentRoot||"/wordpress",absoluteUrl:e.siteUrl,rewriteRules:k,getFileNotFoundAction:e.getFileNotFoundAction??y,cookieStore:e.cookieStore});return i}async function b(e){return(await e.run({code:`<?php
356
356
  ob_start();
357
357
  $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
358
358
  if (!file_exists($wp_load)) {
@@ -363,7 +363,7 @@ function skip_whitespace($tokens) {
363
363
  ob_clean();
364
364
  echo is_blog_installed() ? '1' : '0';
365
365
  ob_end_flush();
366
- `,env:{DOCUMENT_ROOT:e.documentRoot}})).text==="1"}async function S(e){await d.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"}})),(await e.run({code:`<?php
366
+ `,env:{DOCUMENT_ROOT:e.documentRoot}})).text==="1"}async function _(e){var i;const n=await u.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 b(e))throw new Error(`Failed to install WordPress – installer responded with "${(i=n.text)==null?void 0:i.substring(0,100)}"`);(await e.run({code:`<?php
367
367
  ob_start();
368
368
  $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
369
369
  if (!file_exists($wp_load)) {
@@ -378,7 +378,7 @@ function skip_whitespace($tokens) {
378
378
  ob_clean();
379
379
  echo $option_result ? '1' : '0';
380
380
  ob_end_flush();
381
- `,env:{DOCUMENT_ROOT:e.documentRoot}})).text!=="1"&&c.logger.warn("Failed to default to pretty permalinks after WP install.")}function $(e){return{type:"internal-redirect",uri:"/index.php"}}async function L(e){return(await e.run({code:`<?php
381
+ `,env:{DOCUMENT_ROOT:e.documentRoot}})).text!=="1"&&h.logger.warn("Failed to default to pretty permalinks after WP install.")}function y(e){return{type:"internal-redirect",uri:"/index.php"}}async function I(e){return(await e.run({code:`<?php
382
382
  ob_start();
383
383
  $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
384
384
  if (!file_exists($wp_load)) {
@@ -387,12 +387,12 @@ function skip_whitespace($tokens) {
387
387
  }
388
388
  require $wp_load;
389
389
  ob_clean();
390
- echo $wpdb->check_connection( false) ? '1' : '0';
390
+ echo $wpdb->check_connection( false ) ? '1' : '0';
391
391
  ob_end_flush();
392
- `,env:{DOCUMENT_ROOT:e.documentRoot}})).text==="1"}async function x(e){const{php:t,reap:n}=await e.processManager.acquirePHPInstance({considerPrimary:!0});try{const r=(await t.run({code:`<?php
392
+ `,env:{DOCUMENT_ROOT:e.documentRoot}})).text==="1"}async function W(e){const{php:n,reap:t}=await e.processManager.acquirePHPInstance({considerPrimary:!0});try{const r=(await n.run({code:`<?php
393
393
  require '${e.documentRoot}/wp-includes/version.php';
394
394
  echo $wp_version;
395
- `})).text;if(!r)throw new Error("Unable to read loaded WordPress version.");return m(r)}finally{n()}}function m(e){if(/-(alpha|beta|RC)\d*-\d+$/.test(e))return"nightly";if(/-(beta|RC)\d*$/.test(e))return"beta";const i=e.match(/^(\d+\.\d+)(?:\.\d+)?$/);return i!==null?i[1]:e}const b=[{match:/^\/(.*?)(\/wp-(content|admin|includes)\/.*)/g,replacement:"$2"}];async function y(e){await e.mkdir("/internal/shared/mu-plugins"),await e.writeFile("/internal/shared/preload/env.php",`<?php
395
+ `})).text;if(!r)throw new Error("Unable to read loaded WordPress version.");return P(r)}finally{t()}}function P(e){if(/-(alpha|beta|RC)\d*-\d+$/.test(e))return"nightly";if(/-(beta|RC)\d*$/.test(e))return"beta";const i=e.match(/^(\d+\.\d+)(?:\.\d+)?$/);return i!==null?i[1]:e}const k=[{match:new RegExp("^(/[_0-9a-zA-Z-]+)?(/wp-(content|admin|includes)/.*)"),replacement:"$2"}];async function E(e){await e.mkdir("/internal/shared/mu-plugins"),await e.writeFile("/internal/shared/preload/env.php",`<?php
396
396
 
397
397
  // Allow adding filters/actions prior to loading WordPress.
398
398
  // $function_to_add MUST be a string.
@@ -663,18 +663,18 @@ function skip_whitespace($tokens) {
663
663
  }
664
664
  return false;
665
665
  });
666
- })();`)}async function P(e,t="/phpinfo.php"){await e.writeFile("/internal/shared/preload/phpinfo.php",`<?php
666
+ })();`)}async function T(e,n="/phpinfo.php"){await e.writeFile("/internal/shared/preload/phpinfo.php",`<?php
667
667
  // Render PHPInfo if the requested page is /phpinfo.php
668
- if ( isset($_SERVER['REQUEST_URI']) && ${o.phpVar(t)} === $_SERVER['REQUEST_URI'] ) {
668
+ if ( isset($_SERVER['REQUEST_URI']) && ${a.phpVar(n)} === $_SERVER['REQUEST_URI'] ) {
669
669
  phpinfo();
670
670
  exit;
671
671
  }
672
- `)}async function k(e,t){await e.isDir("/tmp/sqlite-database-integration")&&await e.rmdir("/tmp/sqlite-database-integration",{recursive:!0}),await e.mkdir("/tmp/sqlite-database-integration"),await p.unzipFile(e,t,"/tmp/sqlite-database-integration");const n="/internal/shared/sqlite-database-integration",i=`/tmp/sqlite-database-integration/${(await e.listFiles("/tmp/sqlite-database-integration"))[0]}`;await e.mv(i,n),await e.defineConstant("SQLITE_MAIN_FILE","1");const 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"))),l=o.joinPaths(await e.documentRoot,"wp-content/db.php"),s=`<?php
672
+ `)}async function R(e,n){await e.isDir("/tmp/sqlite-database-integration")&&await e.rmdir("/tmp/sqlite-database-integration",{recursive:!0}),await e.mkdir("/tmp/sqlite-database-integration"),await f.unzipFile(e,n,"/tmp/sqlite-database-integration");const t="/internal/shared/sqlite-database-integration",i=`/tmp/sqlite-database-integration/${(await e.listFiles("/tmp/sqlite-database-integration"))[0]}`;await e.mv(i,t),await e.defineConstant("SQLITE_MAIN_FILE","1");const o=(await e.readFileAsText(a.joinPaths(t,"db.copy"))).replace("'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",a.phpVar(t)).replace("'{SQLITE_PLUGIN}'",a.phpVar(a.joinPaths(t,"load.php"))),l=a.joinPaths(await e.documentRoot,"wp-content/db.php"),s=`<?php
673
673
  // Do not preload this if WordPress comes with a custom db.php file.
674
- if(file_exists(${o.phpVar(l)})) {
674
+ if(file_exists(${a.phpVar(l)})) {
675
675
  return;
676
676
  }
677
- ?>`,u="/internal/shared/mu-plugins/sqlite-database-integration.php";await e.writeFile(u,s+a),await e.writeFile("/internal/shared/preload/0-sqlite.php",s+`<?php
677
+ ?>`,d="/internal/shared/mu-plugins/sqlite-database-integration.php";await e.writeFile(d,s+o),await e.writeFile("/internal/shared/preload/0-sqlite.php",s+`<?php
678
678
 
679
679
  /**
680
680
  * Loads the SQLite integration plugin before WordPress is loaded
@@ -724,7 +724,7 @@ class Playground_SQLite_Integration_Loader {
724
724
  $GLOBALS['wpdb']->$name = $value;
725
725
  }
726
726
  protected function load_sqlite_integration() {
727
- require_once ${o.phpVar(u)};
727
+ require_once ${a.phpVar(d)};
728
728
  }
729
729
  }
730
730
  /**
@@ -755,5 +755,5 @@ if(!function_exists('mysqli_connect')) {
755
755
  var_dump(isset($wpdb));
756
756
  die("SQLite integration not loaded " . get_class($wpdb));
757
757
  }
758
- `)}async function E(e,t){e.mkdir("/tmp/unzipped-wordpress"),await p.unzipFile(e,t,"/tmp/unzipped-wordpress"),e.fileExists("/tmp/unzipped-wordpress/wordpress.zip")&&await p.unzipFile(e,"/tmp/unzipped-wordpress/wordpress.zip","/tmp/unzipped-wordpress");let n=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(n,"wp-config-sample.php"))){const r=e.listFiles(n);if(r.length){const a=r[0];e.fileExists(o.joinPaths(n,a,"wp-config-sample.php"))&&(n=o.joinPaths(n,a))}}const i=(r,a,l)=>{if(l.isDir(r)&&l.isDir(a))for(const s of l.listFiles(r)){const u=o.joinPaths(r,s),T=o.joinPaths(a,s);i(u,T,l)}else{if(l.fileExists(a)){const s=r.replace(/^\/tmp\/unzipped-wordpress\//,"/");c.logger.warn(`Cannot unzip WordPress files at ${a}: ${s} already exists.`);return}l.mv(r,a)}};i(n,e.documentRoot,e),e.fileExists(n)&&e.rmdir(n,{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 I=p.createMemoizedFetch(fetch);async function W(e="latest"){if(e.startsWith("https://")||e.startsWith("http://")){const i=await crypto.subtle.digest("SHA-1",new TextEncoder().encode(e)),r=Array.from(new Uint8Array(i)).map(a=>a.toString(16).padStart(2,"0")).join("");return{releaseUrl:e,version:"custom-"+r.substring(0,8),source:"inferred"}}else if(e==="trunk"||e==="nightly")return{releaseUrl:"https://wordpress.org/nightly-builds/wordpress-latest.zip",version:"nightly-"+new Date().toISOString().split("T")[0],source:"inferred"};let n=await(await I("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(e==="beta"&&i.version.includes("beta"))return{releaseUrl:i.download,version:i.version,source:"api"};if(e==="latest"&&!i.version.includes("beta"))return{releaseUrl:i.download,version:i.version,source:"api"};if(i.version.substring(0,e.length)===e)return{releaseUrl:i.download,version:i.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=w;exports.bootWordPress=g;exports.bootWordPressAndRequestHandler=v;exports.defineWpConfigConstants=_;exports.ensureWpConfig=h;exports.getFileNotFoundActionForWordPress=$;exports.getLoadedWordPressVersion=x;exports.preloadPhpInfoRoute=P;exports.preloadSqliteIntegration=k;exports.resolveWordPressRelease=W;exports.setupPlatformLevelMuPlugins=y;exports.unzipWordPress=E;exports.versionStringToLoadedWordPressVersion=m;exports.wordPressRewriteRules=b;
758
+ `)}async function S(e,n){e.mkdir("/tmp/unzipped-wordpress"),await f.unzipFile(e,n,"/tmp/unzipped-wordpress"),e.fileExists("/tmp/unzipped-wordpress/wordpress.zip")&&await f.unzipFile(e,"/tmp/unzipped-wordpress/wordpress.zip","/tmp/unzipped-wordpress");let t=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(a.joinPaths(t,"wp-config-sample.php"))){const r=e.listFiles(t);if(r.length){const o=r[0];e.fileExists(a.joinPaths(t,o,"wp-config-sample.php"))&&(t=a.joinPaths(t,o))}}const i=(r,o,l)=>{if(l.isDir(r)&&l.isDir(o))for(const s of l.listFiles(r)){const d=a.joinPaths(r,s),v=a.joinPaths(o,s);i(d,v,l)}else{if(l.fileExists(o)){const s=r.replace(/^\/tmp\/unzipped-wordpress\//,"/");h.logger.warn(`Cannot unzip WordPress files at ${o}: ${s} already exists.`);return}l.mv(r,o)}};i(t,e.documentRoot,e),e.fileExists(t)&&e.rmdir(t,{recursive:!0}),!e.fileExists(a.joinPaths(e.documentRoot,"wp-config.php"))&&e.fileExists(a.joinPaths(e.documentRoot,"wp-config-sample.php"))&&e.writeFile(a.joinPaths(e.documentRoot,"wp-config.php"),e.readFileAsText(a.joinPaths(e.documentRoot,"/wp-config-sample.php")))}const U=f.createMemoizedFetch(fetch);async function C(e="latest"){if(e.startsWith("https://")||e.startsWith("http://")){const i=await crypto.subtle.digest("SHA-1",new TextEncoder().encode(e)),r=Array.from(new Uint8Array(i)).map(o=>o.toString(16).padStart(2,"0")).join("");return{releaseUrl:e,version:"custom-"+r.substring(0,8),source:"inferred"}}else if(e==="trunk"||e==="nightly")return{releaseUrl:"https://wordpress.org/nightly-builds/wordpress-latest.zip",version:"nightly-"+new Date().toISOString().split("T")[0],source:"inferred"};let t=await(await U("https://api.wordpress.org/core/version-check/1.7/?channel=beta")).json();t=t.offers.filter(i=>i.response==="autoupdate");for(const i of t){if(e==="beta"&&i.version.includes("beta"))return{releaseUrl:i.download,version:i.version,source:"api"};if(e==="latest"&&!i.version.includes("beta"))return{releaseUrl:i.download,version:i.version,source:"api"};if(i.version.substring(0,e.length)===e)return{releaseUrl:i.download,version:i.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=m;exports.bootWordPress=$;exports.bootWordPressAndRequestHandler=L;exports.defineWpConfigConstants=g;exports.ensureWpConfig=w;exports.getFileNotFoundActionForWordPress=y;exports.getLoadedWordPressVersion=W;exports.preloadPhpInfoRoute=T;exports.preloadSqliteIntegration=R;exports.resolveWordPressRelease=C;exports.setupPlatformLevelMuPlugins=E;exports.unzipWordPress=S;exports.versionStringToLoadedWordPressVersion=P;exports.wordPressRewriteRules=k;
759
759
  //# sourceMappingURL=index.cjs.map
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { PHP, UniversalPHP } from '@php-wasm/universal';
2
2
  export { bootWordPress, bootWordPressAndRequestHandler, bootRequestHandler, getFileNotFoundActionForWordPress, } from './boot';
3
- export type { PhpIniOptions, PHPInstanceCreatedHook } from './boot';
3
+ export type { PhpIniOptions, PHPInstanceCreatedHook, WordPressInstallMode, } from './boot';
4
4
  export { defineWpConfigConstants, ensureWpConfig } from './rewrite-wp-config';
5
5
  export { getLoadedWordPressVersion } from './version-detect';
6
6
  export * from './version-detect';
package/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { phpVars as g, joinPaths as s, dirname as $, basename as w, phpVar as l } from "@php-wasm/util";
2
- import { createMemoizedFetch as m, unzipFile as p } from "@wp-playground/common";
3
- import { logger as _ } from "@php-wasm/logger";
4
- import { sandboxedSpawnHandlerFactory as b, PHPRequestHandler as y, withPHPIniValues as k, PHP as P, setPhpIniEntries as E, writeFiles as f } from "@php-wasm/universal";
5
- const T = `<?php
1
+ import { phpVars as m, joinPaths as s, dirname as b, basename as y, phpVar as u } from "@php-wasm/util";
2
+ import { createMemoizedFetch as k, unzipFile as f } from "@wp-playground/common";
3
+ import { logger as g } from "@php-wasm/logger";
4
+ import { sandboxedSpawnHandlerFactory as P, PHPRequestHandler as E, withPHPIniValues as T, PHP as R, setPhpIniEntries as S, writeFiles as c } from "@php-wasm/universal";
5
+ const v = `<?php
6
6
 
7
7
  /**
8
8
  * Rewrites the wp-config.php file to ensure specific constants are defined
@@ -348,11 +348,11 @@ function skip_whitespace($tokens) {
348
348
  return $output;
349
349
  }
350
350
  `;
351
- async function R(e, t, n, i = "rewrite") {
352
- const r = g({ wpConfigPath: t, constants: n, whenAlreadyDefined: i });
351
+ async function x(e, n, t, i = "rewrite") {
352
+ const r = m({ wpConfigPath: n, constants: t, whenAlreadyDefined: i });
353
353
  if ((await e.run({
354
354
  code: `<?php ob_start(); ?>
355
- ${T}
355
+ ${v}
356
356
  $wp_config_path = ${r.wpConfigPath};
357
357
  $wp_config = file_get_contents($wp_config_path);
358
358
  $new_wp_config = rewrite_wp_config_to_define_constants($wp_config, ${r.constants}, ${r.whenAlreadyDefined});
@@ -364,54 +364,92 @@ async function R(e, t, n, i = "rewrite") {
364
364
  })).text !== "1")
365
365
  throw new Error("Failed to rewrite constants in wp-config.php.");
366
366
  }
367
- async function v(e, t) {
368
- const n = s(t, "wp-config.php"), i = {
367
+ async function L(e, n) {
368
+ const t = s(n, "wp-config.php"), i = {
369
369
  DB_NAME: "wordpress"
370
370
  };
371
- !e.fileExists(n) && e.fileExists(s(t, "wp-config-sample.php")) && await e.writeFile(
372
- n,
371
+ !e.fileExists(t) && e.fileExists(s(n, "wp-config-sample.php")) && await e.writeFile(
372
+ t,
373
373
  await e.readFileAsBuffer(
374
- s(t, "wp-config-sample.php")
374
+ s(n, "wp-config-sample.php")
375
375
  )
376
- ), await R(e, n, i, "skip");
376
+ ), await x(e, t, i, "skip");
377
377
  }
378
- async function H(e) {
379
- const t = await x(e);
380
- return await S(t, e), t;
378
+ async function Q(e) {
379
+ const n = await U(e);
380
+ return await I(n, e), n;
381
381
  }
382
- async function S(e, t) {
383
- var i, r;
384
- const n = await e.getPrimaryPhp();
385
- if ((i = t.hooks) != null && i.beforeWordPressFiles && await t.hooks.beforeWordPressFiles(n), t.wordPressZip && await q(n, await t.wordPressZip), t.constants)
386
- for (const a in t.constants)
387
- n.defineConstant(a, t.constants[a]);
388
- if (t.dataSqlPath && (n.defineConstant("DB_DIR", $(t.dataSqlPath)), n.defineConstant("DB_FILE", w(t.dataSqlPath))), n.defineConstant("WP_HOME", t.siteUrl), n.defineConstant("WP_SITEURL", t.siteUrl), await v(n, e.documentRoot), (r = t.hooks) != null && r.beforeDatabaseSetup && await t.hooks.beforeDatabaseSetup(n), t.sqliteIntegrationPluginZip && await A(
389
- n,
390
- await t.sqliteIntegrationPluginZip
391
- ), t.wordPressZip && !t.dataSqlPath && (await c(n) || await L(n), !await c(n))) {
392
- if (await U(n))
393
- throw new Error("WordPress installation has failed.");
394
- if (n.isFile("/internal/shared/preload/0-sqlite.php"))
395
- throw new Error("Error connecting to the SQLite database.");
396
- if (!t.sqliteIntegrationPluginZip) {
397
- const d = s(
398
- e.documentRoot,
399
- "wp-content/mu-plugins/sqlite-database-integration"
400
- );
401
- if (n.isDir(d))
402
- throw new Error(
403
- "Error connecting to the SQLite database."
404
- );
382
+ async function I(e, n) {
383
+ var l, o;
384
+ const t = await e.getPrimaryPhp();
385
+ if ((l = n.hooks) != null && l.beforeWordPressFiles && await n.hooks.beforeWordPressFiles(t), n.wordPressZip && await q(t, await n.wordPressZip), n.constants)
386
+ for (const d in n.constants)
387
+ t.defineConstant(d, n.constants[d]);
388
+ n.dataSqlPath && (t.defineConstant("DB_DIR", b(n.dataSqlPath)), t.defineConstant("DB_FILE", y(n.dataSqlPath))), t.defineConstant("WP_HOME", n.siteUrl), t.defineConstant("WP_SITEURL", n.siteUrl), await L(t, e.documentRoot), (o = n.hooks) != null && o.beforeDatabaseSetup && await n.hooks.beforeDatabaseSetup(t);
389
+ let i = !1;
390
+ n.sqliteIntegrationPluginZip && (i = !0, await N(
391
+ t,
392
+ await n.sqliteIntegrationPluginZip
393
+ ));
394
+ const r = n.wordpressInstallMode ?? "download-and-install", a = !!n.dataSqlPath;
395
+ if (["download-and-install", "install-from-existing-files"].includes(
396
+ r
397
+ )) {
398
+ await _(e, {
399
+ usesSqlite: i,
400
+ hasCustomDatabasePath: a
401
+ });
402
+ try {
403
+ await h(t);
404
+ } catch (d) {
405
+ throw a || await p(e), d;
405
406
  }
406
- throw new Error("Error connecting to the MySQL database.");
407
+ a || await p(e);
408
+ } else if (r === "install-from-existing-files-if-needed") {
409
+ if (await _(e, {
410
+ usesSqlite: i,
411
+ hasCustomDatabasePath: a
412
+ }), !await w(t))
413
+ try {
414
+ await h(t);
415
+ } catch (d) {
416
+ throw a || await p(e), d;
417
+ }
418
+ a || await p(e);
407
419
  }
408
420
  return e;
409
421
  }
410
- async function x(e) {
411
- const t = e.spawnHandler ?? b;
412
- async function n(r, a) {
413
- const d = await e.createPhpRuntime(a), o = new P(d);
414
- return e.sapiName && o.setSapiName(e.sapiName), r && (o.requestHandler = r), e.phpIniEntries && E(o, e.phpIniEntries), o.defineConstant("WP_SQLITE_AST_DRIVER", !0), a && /**
422
+ async function _(e, {
423
+ usesSqlite: n,
424
+ hasCustomDatabasePath: t
425
+ }) {
426
+ const i = await e.getPrimaryPhp();
427
+ if (i.isFile("/internal/shared/preload/0-sqlite.php"))
428
+ return;
429
+ const r = s(
430
+ e.documentRoot,
431
+ "wp-content/mu-plugins/sqlite-database-integration"
432
+ );
433
+ if (!i.isDir(r) && !n && !t)
434
+ throw new Error("Error connecting to the MySQL database.");
435
+ }
436
+ async function p(e) {
437
+ const n = await e.getPrimaryPhp();
438
+ if (await C(n))
439
+ return;
440
+ if (n.isFile("/internal/shared/preload/0-sqlite.php"))
441
+ throw new Error("Error connecting to the SQLite database.");
442
+ const i = s(
443
+ e.documentRoot,
444
+ "wp-content/mu-plugins/sqlite-database-integration"
445
+ );
446
+ throw n.isDir(i) ? new Error("Error connecting to the SQLite database.") : new Error("Error connecting to the MySQL database.");
447
+ }
448
+ async function U(e) {
449
+ const n = e.spawnHandler ?? P;
450
+ async function t(r, a) {
451
+ const l = await e.createPhpRuntime(a), o = new R(l);
452
+ return e.sapiName && o.setSapiName(e.sapiName), r && (o.requestHandler = r), e.phpIniEntries && S(o, e.phpIniEntries), o.defineConstant("WP_SQLITE_AST_DRIVER", !0), a && /**
415
453
  * Only the first PHP instance of the first worker created
416
454
  * during WordPress boot writes these files – otherwise we'll keep
417
455
  * overwriting them with concurrent writers living in other worker
@@ -421,29 +459,29 @@ async function x(e) {
421
459
  * mechanism. It works, because secondary workers are only booted
422
460
  * once the primary worker has fully booted.
423
461
  */
424
- !o.isFile("/internal/.boot-files-written") && (await C(o), await f(o, "/", e.createFiles || {}), await D(
462
+ !o.isFile("/internal/.boot-files-written") && (await A(o), await c(o, "/", e.createFiles || {}), await F(
425
463
  o,
426
464
  s(new URL(e.siteUrl).pathname, "phpinfo.php")
427
- ), await f(o, "/internal", {
465
+ ), await c(o, "/internal", {
428
466
  ".boot-files-written": ""
429
- })), t && await o.setSpawnHandler(
430
- t(r.processManager)
467
+ })), n && await o.setSpawnHandler(
468
+ n(r.processManager)
431
469
  ), o.enableRuntimeRotation({
432
470
  recreateRuntime: e.createPhpRuntime,
433
471
  maxRequests: 400
434
472
  }), e.onPHPInstanceCreated && await e.onPHPInstanceCreated(o, { isPrimary: a }), o;
435
473
  }
436
- const i = new y({
437
- phpFactory: async ({ isPrimary: r }) => n(i, r),
474
+ const i = new E({
475
+ phpFactory: async ({ isPrimary: r }) => t(i, r),
438
476
  documentRoot: e.documentRoot || "/wordpress",
439
477
  absoluteUrl: e.siteUrl,
440
- rewriteRules: O,
441
- getFileNotFoundAction: e.getFileNotFoundAction ?? I,
478
+ rewriteRules: D,
479
+ getFileNotFoundAction: e.getFileNotFoundAction ?? W,
442
480
  cookieStore: e.cookieStore
443
481
  });
444
482
  return i;
445
483
  }
446
- async function c(e) {
484
+ async function w(e) {
447
485
  return (await e.run({
448
486
  code: `<?php
449
487
  ob_start();
@@ -462,8 +500,9 @@ async function c(e) {
462
500
  }
463
501
  })).text === "1";
464
502
  }
465
- async function L(e) {
466
- await k(
503
+ async function h(e) {
504
+ var i;
505
+ const n = await T(
467
506
  e,
468
507
  {
469
508
  disable_functions: "fsockopen",
@@ -485,7 +524,15 @@ async function L(e) {
485
524
  admin_email: "admin@localhost.com"
486
525
  }
487
526
  })
488
- ), (await e.run({
527
+ );
528
+ if (!await w(e))
529
+ throw new Error(
530
+ `Failed to install WordPress – installer responded with "${(i = n.text) == null ? void 0 : i.substring(
531
+ 0,
532
+ 100
533
+ )}"`
534
+ );
535
+ (await e.run({
489
536
  code: `<?php
490
537
  ob_start();
491
538
  $wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
@@ -505,15 +552,15 @@ async function L(e) {
505
552
  env: {
506
553
  DOCUMENT_ROOT: e.documentRoot
507
554
  }
508
- })).text !== "1" && _.warn("Failed to default to pretty permalinks after WP install.");
555
+ })).text !== "1" && g.warn("Failed to default to pretty permalinks after WP install.");
509
556
  }
510
- function I(e) {
557
+ function W(e) {
511
558
  return {
512
559
  type: "internal-redirect",
513
560
  uri: "/index.php"
514
561
  };
515
562
  }
516
- async function U(e) {
563
+ async function C(e) {
517
564
  return (await e.run({
518
565
  code: `<?php
519
566
  ob_start();
@@ -524,7 +571,7 @@ async function U(e) {
524
571
  }
525
572
  require $wp_load;
526
573
  ob_clean();
527
- echo $wpdb->check_connection( false) ? '1' : '0';
574
+ echo $wpdb->check_connection( false ) ? '1' : '0';
528
575
  ob_end_flush();
529
576
  `,
530
577
  env: {
@@ -532,12 +579,12 @@ async function U(e) {
532
579
  }
533
580
  })).text === "1";
534
581
  }
535
- async function z(e) {
536
- const { php: t, reap: n } = await e.processManager.acquirePHPInstance({
582
+ async function V(e) {
583
+ const { php: n, reap: t } = await e.processManager.acquirePHPInstance({
537
584
  considerPrimary: !0
538
585
  });
539
586
  try {
540
- const r = (await t.run({
587
+ const r = (await n.run({
541
588
  code: `<?php
542
589
  require '${e.documentRoot}/wp-includes/version.php';
543
590
  echo $wp_version;
@@ -545,12 +592,12 @@ async function z(e) {
545
592
  })).text;
546
593
  if (!r)
547
594
  throw new Error("Unable to read loaded WordPress version.");
548
- return W(r);
595
+ return O(r);
549
596
  } finally {
550
- n();
597
+ t();
551
598
  }
552
599
  }
553
- function W(e) {
600
+ function O(e) {
554
601
  if (/-(alpha|beta|RC)\d*-\d+$/.test(e))
555
602
  return "nightly";
556
603
  if (/-(beta|RC)\d*$/.test(e))
@@ -558,13 +605,23 @@ function W(e) {
558
605
  const i = e.match(/^(\d+\.\d+)(?:\.\d+)?$/);
559
606
  return i !== null ? i[1] : e;
560
607
  }
561
- const O = [
608
+ const D = [
609
+ /**
610
+ * Substitutes the multisite WordPress rewrite rule:
611
+ *
612
+ * RewriteBase /
613
+ * RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
614
+ */
562
615
  {
563
- match: /^\/(.*?)(\/wp-(content|admin|includes)\/.*)/g,
616
+ match: new RegExp(
617
+ /* The .htaccess rule does not have an explicit initial slash,
618
+ but it's still implied by `RewriteBase /` */
619
+ "^(/[_0-9a-zA-Z-]+)?(/wp-(content|admin|includes)/.*)"
620
+ ),
564
621
  replacement: "$2"
565
622
  }
566
623
  ];
567
- async function C(e) {
624
+ async function A(e) {
568
625
  await e.mkdir("/internal/shared/mu-plugins"), await e.writeFile(
569
626
  "/internal/shared/preload/env.php",
570
627
  `<?php
@@ -850,13 +907,13 @@ async function C(e) {
850
907
  })();`
851
908
  );
852
909
  }
853
- async function D(e, t = "/phpinfo.php") {
910
+ async function F(e, n = "/phpinfo.php") {
854
911
  await e.writeFile(
855
912
  "/internal/shared/preload/phpinfo.php",
856
913
  `<?php
857
914
  // Render PHPInfo if the requested page is /phpinfo.php
858
- if ( isset($_SERVER['REQUEST_URI']) && ${l(
859
- t
915
+ if ( isset($_SERVER['REQUEST_URI']) && ${u(
916
+ n
860
917
  )} === $_SERVER['REQUEST_URI'] ) {
861
918
  phpinfo();
862
919
  exit;
@@ -864,27 +921,27 @@ async function D(e, t = "/phpinfo.php") {
864
921
  `
865
922
  );
866
923
  }
867
- async function A(e, t) {
924
+ async function N(e, n) {
868
925
  await e.isDir("/tmp/sqlite-database-integration") && await e.rmdir("/tmp/sqlite-database-integration", {
869
926
  recursive: !0
870
- }), await e.mkdir("/tmp/sqlite-database-integration"), await p(e, t, "/tmp/sqlite-database-integration");
871
- const n = "/internal/shared/sqlite-database-integration", i = `/tmp/sqlite-database-integration/${(await e.listFiles("/tmp/sqlite-database-integration"))[0]}`;
872
- await e.mv(i, n), await e.defineConstant("SQLITE_MAIN_FILE", "1");
927
+ }), await e.mkdir("/tmp/sqlite-database-integration"), await f(e, n, "/tmp/sqlite-database-integration");
928
+ const t = "/internal/shared/sqlite-database-integration", i = `/tmp/sqlite-database-integration/${(await e.listFiles("/tmp/sqlite-database-integration"))[0]}`;
929
+ await e.mv(i, t), await e.defineConstant("SQLITE_MAIN_FILE", "1");
873
930
  const a = (await e.readFileAsText(
874
- s(n, "db.copy")
931
+ s(t, "db.copy")
875
932
  )).replace(
876
933
  "'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",
877
- l(n)
934
+ u(t)
878
935
  ).replace(
879
936
  "'{SQLITE_PLUGIN}'",
880
- l(s(n, "load.php"))
881
- ), d = s(await e.documentRoot, "wp-content/db.php"), o = `<?php
937
+ u(s(t, "load.php"))
938
+ ), l = s(await e.documentRoot, "wp-content/db.php"), o = `<?php
882
939
  // Do not preload this if WordPress comes with a custom db.php file.
883
- if(file_exists(${l(d)})) {
940
+ if(file_exists(${u(l)})) {
884
941
  return;
885
942
  }
886
- ?>`, u = "/internal/shared/mu-plugins/sqlite-database-integration.php";
887
- await e.writeFile(u, o + a), await e.writeFile(
943
+ ?>`, d = "/internal/shared/mu-plugins/sqlite-database-integration.php";
944
+ await e.writeFile(d, o + a), await e.writeFile(
888
945
  "/internal/shared/preload/0-sqlite.php",
889
946
  o + `<?php
890
947
 
@@ -936,7 +993,7 @@ class Playground_SQLite_Integration_Loader {
936
993
  $GLOBALS['wpdb']->$name = $value;
937
994
  }
938
995
  protected function load_sqlite_integration() {
939
- require_once ${l(u)};
996
+ require_once ${u(d)};
940
997
  }
941
998
  }
942
999
  /**
@@ -973,51 +1030,51 @@ if(!function_exists('mysqli_connect')) {
973
1030
  `
974
1031
  );
975
1032
  }
976
- async function q(e, t) {
977
- e.mkdir("/tmp/unzipped-wordpress"), await p(e, t, "/tmp/unzipped-wordpress"), e.fileExists("/tmp/unzipped-wordpress/wordpress.zip") && await p(
1033
+ async function q(e, n) {
1034
+ e.mkdir("/tmp/unzipped-wordpress"), await f(e, n, "/tmp/unzipped-wordpress"), e.fileExists("/tmp/unzipped-wordpress/wordpress.zip") && await f(
978
1035
  e,
979
1036
  "/tmp/unzipped-wordpress/wordpress.zip",
980
1037
  "/tmp/unzipped-wordpress"
981
1038
  );
982
- let n = e.fileExists("/tmp/unzipped-wordpress/wordpress") ? "/tmp/unzipped-wordpress/wordpress" : e.fileExists("/tmp/unzipped-wordpress/build") ? "/tmp/unzipped-wordpress/build" : "/tmp/unzipped-wordpress";
983
- if (!e.fileExists(s(n, "wp-config-sample.php"))) {
984
- const r = e.listFiles(n);
1039
+ let t = e.fileExists("/tmp/unzipped-wordpress/wordpress") ? "/tmp/unzipped-wordpress/wordpress" : e.fileExists("/tmp/unzipped-wordpress/build") ? "/tmp/unzipped-wordpress/build" : "/tmp/unzipped-wordpress";
1040
+ if (!e.fileExists(s(t, "wp-config-sample.php"))) {
1041
+ const r = e.listFiles(t);
985
1042
  if (r.length) {
986
1043
  const a = r[0];
987
1044
  e.fileExists(
988
- s(n, a, "wp-config-sample.php")
989
- ) && (n = s(n, a));
1045
+ s(t, a, "wp-config-sample.php")
1046
+ ) && (t = s(t, a));
990
1047
  }
991
1048
  }
992
- const i = (r, a, d) => {
993
- if (d.isDir(r) && d.isDir(a))
994
- for (const o of d.listFiles(r)) {
995
- const u = s(r, o), h = s(a, o);
996
- i(u, h, d);
1049
+ const i = (r, a, l) => {
1050
+ if (l.isDir(r) && l.isDir(a))
1051
+ for (const o of l.listFiles(r)) {
1052
+ const d = s(r, o), $ = s(a, o);
1053
+ i(d, $, l);
997
1054
  }
998
1055
  else {
999
- if (d.fileExists(a)) {
1056
+ if (l.fileExists(a)) {
1000
1057
  const o = r.replace(
1001
1058
  /^\/tmp\/unzipped-wordpress\//,
1002
1059
  "/"
1003
1060
  );
1004
- _.warn(
1061
+ g.warn(
1005
1062
  `Cannot unzip WordPress files at ${a}: ${o} already exists.`
1006
1063
  );
1007
1064
  return;
1008
1065
  }
1009
- d.mv(r, a);
1066
+ l.mv(r, a);
1010
1067
  }
1011
1068
  };
1012
- i(n, e.documentRoot, e), e.fileExists(n) && e.rmdir(n, { recursive: !0 }), !e.fileExists(s(e.documentRoot, "wp-config.php")) && e.fileExists(s(e.documentRoot, "wp-config-sample.php")) && e.writeFile(
1069
+ i(t, e.documentRoot, e), e.fileExists(t) && e.rmdir(t, { recursive: !0 }), !e.fileExists(s(e.documentRoot, "wp-config.php")) && e.fileExists(s(e.documentRoot, "wp-config-sample.php")) && e.writeFile(
1013
1070
  s(e.documentRoot, "wp-config.php"),
1014
1071
  e.readFileAsText(
1015
1072
  s(e.documentRoot, "/wp-config-sample.php")
1016
1073
  )
1017
1074
  );
1018
1075
  }
1019
- const F = m(fetch);
1020
- async function Q(e = "latest") {
1076
+ const G = k(fetch);
1077
+ async function j(e = "latest") {
1021
1078
  if (e.startsWith("https://") || e.startsWith("http://")) {
1022
1079
  const i = await crypto.subtle.digest(
1023
1080
  "SHA-1",
@@ -1034,13 +1091,13 @@ async function Q(e = "latest") {
1034
1091
  version: "nightly-" + (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
1035
1092
  source: "inferred"
1036
1093
  };
1037
- let n = await (await F(
1094
+ let t = await (await G(
1038
1095
  "https://api.wordpress.org/core/version-check/1.7/?channel=beta"
1039
1096
  )).json();
1040
- n = n.offers.filter(
1097
+ t = t.offers.filter(
1041
1098
  (i) => i.response === "autoupdate"
1042
1099
  );
1043
- for (const i of n) {
1100
+ for (const i of t) {
1044
1101
  if (e === "beta" && i.version.includes("beta"))
1045
1102
  return {
1046
1103
  releaseUrl: i.download,
@@ -1067,19 +1124,19 @@ async function Q(e = "latest") {
1067
1124
  };
1068
1125
  }
1069
1126
  export {
1070
- x as bootRequestHandler,
1071
- S as bootWordPress,
1072
- H as bootWordPressAndRequestHandler,
1073
- R as defineWpConfigConstants,
1074
- v as ensureWpConfig,
1075
- I as getFileNotFoundActionForWordPress,
1076
- z as getLoadedWordPressVersion,
1077
- D as preloadPhpInfoRoute,
1078
- A as preloadSqliteIntegration,
1079
- Q as resolveWordPressRelease,
1080
- C as setupPlatformLevelMuPlugins,
1127
+ U as bootRequestHandler,
1128
+ I as bootWordPress,
1129
+ Q as bootWordPressAndRequestHandler,
1130
+ x as defineWpConfigConstants,
1131
+ L as ensureWpConfig,
1132
+ W as getFileNotFoundActionForWordPress,
1133
+ V as getLoadedWordPressVersion,
1134
+ F as preloadPhpInfoRoute,
1135
+ N as preloadSqliteIntegration,
1136
+ j as resolveWordPressRelease,
1137
+ A as setupPlatformLevelMuPlugins,
1081
1138
  q as unzipWordPress,
1082
- W as versionStringToLoadedWordPressVersion,
1083
- O as wordPressRewriteRules
1139
+ O as versionStringToLoadedWordPressVersion,
1140
+ D as wordPressRewriteRules
1084
1141
  };
1085
1142
  //# sourceMappingURL=index.js.map
package/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wp-playground/wordpress",
3
- "version": "3.0.19",
3
+ "version": "3.0.21",
4
4
  "description": "WordPress-related plumbing for WordPress Playground",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,18 +35,18 @@
35
35
  "access": "public",
36
36
  "directory": "../../../dist/packages/playground/wordpress"
37
37
  },
38
- "gitHead": "5d6cbf03fb33b4c58c587c43a4a7793d4b050885",
38
+ "gitHead": "8d3a2da8f91ca792ba8f6fe7e92fdb658f4075ee",
39
39
  "dependencies": {
40
40
  "express": "4.21.2",
41
41
  "ini": "4.1.2",
42
42
  "wasm-feature-detect": "1.8.0",
43
43
  "ws": "8.18.3",
44
44
  "yargs": "17.7.2",
45
- "@php-wasm/universal": "3.0.19",
46
- "@php-wasm/util": "3.0.19",
47
- "@php-wasm/logger": "3.0.19",
48
- "@wp-playground/common": "3.0.19",
49
- "@php-wasm/node": "3.0.19"
45
+ "@php-wasm/universal": "3.0.21",
46
+ "@php-wasm/util": "3.0.21",
47
+ "@php-wasm/logger": "3.0.21",
48
+ "@wp-playground/common": "3.0.21",
49
+ "@php-wasm/node": "3.0.21"
50
50
  },
51
51
  "packageManager": "npm@10.9.2",
52
52
  "overrides": {
@@ -1,5 +1,141 @@
1
1
  import type { RewriteRule } from '@php-wasm/universal';
2
2
  /**
3
- * The default rewrite rules for WordPress.
3
+ * WordPress rewrite rules adapted for Playground.
4
+ *
5
+ * These rules are matched against the requested path without the site path prefix.
6
+ *
7
+ * For example:
8
+ *
9
+ * * The site URL is `https://playground.wordpress.net/scope:ambitious-chic-country/`.
10
+ * * The site path prefix is `/scope:ambitious-chic-country/`.
11
+ * * The requested URL is `https://playground.wordpress.net/scope:ambitious-chic-country/wp-admin/index.php`,
12
+ * * The requested path without the site path prefix is `/wp-admin/index.php`.
13
+ *
14
+ * And so, the rewrite rules are matched against `/wp-admin/index.php`.
15
+ * This is similar to setting the `RewriteBase` to `/scope:ambitious-chic-country`.
16
+ *
17
+ * ## Rationale
18
+ *
19
+ * WordPress does not use a single, static set of rewrite rules. Rather, it generates
20
+ * its own .htaccess file based on the current configuration using the save_mod_rewrite_rules()
21
+ * function:
22
+ *
23
+ * https://developer.wordpress.org/reference/functions/save_mod_rewrite_rules/
24
+ *
25
+ * Here's a few examples of what that .htaccess might look like for different
26
+ * WordPress configurations:
27
+ *
28
+ * ### Vanilla WordPress single-site installation
29
+ *
30
+ * ```apache
31
+ * RewriteBase /
32
+ * RewriteRule ^index\.php$ - [L]
33
+ * RewriteCond %{REQUEST_FILENAME} !-f
34
+ * RewriteCond %{REQUEST_FILENAME} !-d
35
+ * RewriteRule . /index.php [L]
36
+ * ```
37
+ *
38
+ * ### Single-site installation living at a /subdirectory/
39
+ *
40
+ * ```apache
41
+ * # https://developer.wordpress.org/advanced-administration/server/wordpress-in-directory/:
42
+ * RewriteCond %{REQUEST_URI} !^/subdirectory/
43
+ * RewriteCond %{REQUEST_FILENAME} !-f
44
+ * RewriteCond %{REQUEST_FILENAME} !-d
45
+ * RewriteRule ^(.*)$ /subdirectory/$1
46
+ * RewriteRule ^(/)?$ subdirectory/index.php [L]
47
+ * ```
48
+ *
49
+ * Some sources also set the RewriteBase to `/subdirectory/`.
50
+ *
51
+ * ### Multisite installation using subfolder network type
52
+ *
53
+ * ```apache
54
+ * # https://wordpress.org/documentation/article/htaccess/#multisite
55
+ *
56
+ * RewriteBase /
57
+ * RewriteRule ^index\.php$ - [L]
58
+ *
59
+ * // add a trailing slash to /wp-admin
60
+ * RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
61
+ *
62
+ * RewriteCond %{REQUEST_FILENAME} -f [OR]
63
+ * RewriteCond %{REQUEST_FILENAME} -d
64
+ * RewriteRule ^ - [L]
65
+ * RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) $2 [L]
66
+ * RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ $2 [L]
67
+ * RewriteRule . index.php [L]
68
+ * ```
69
+ *
70
+ * # Multisite living at /scope:ambitious-chic-country/
71
+ *
72
+ * ```apache
73
+ * RewriteBase /scope:ambitious-chic-country/
74
+ * RewriteRule ^index\.php$ - [L]
75
+ *
76
+ * // Add a trailing slash to /wp-admin
77
+ * RewriteRule ^([_0-9a-zA-Z-]+/)?wp-admin$ $1wp-admin/ [R=301,L]
78
+ *
79
+ * RewriteCond %{REQUEST_FILENAME} -f [OR]
80
+ * RewriteCond %{REQUEST_FILENAME} -d
81
+ * RewriteRule ^ - [L]
82
+ *
83
+ * // The `wordpress/` prefix matches the document root, but seeing
84
+ * // it here is unexpected. @TODO: Why is it being added by WordPress?
85
+ * RewriteRule ^([_0-9a-zA-Z-]+/)?(wp-(content|admin|includes).*) wordpress/$2 [L]
86
+ * RewriteRule ^([_0-9a-zA-Z-]+/)?(.*\.php)$ wordpress/$2 [L]
87
+ * RewriteRule . index.php [L]
88
+ * ```
89
+ *
90
+ * ## .htaccess syntax
91
+ *
92
+ * Here's an excerpt/summary from the .htaccess documentation [^1][^2] for
93
+ * convenience:
94
+ *
95
+ * The mod_rewrite module uses a rule-based rewriting engine, based
96
+ * on a PCRE regular-expression parser, to rewrite requested URLs on
97
+ * the fly. By default, mod_rewrite maps a URL to a filesystem path.
98
+ * However, it can also be used to redirect one URL to another URL,
99
+ * or to invoke an internal proxy fetch.
100
+ *
101
+ * ## RewriteBase Directive
102
+ *
103
+ * The RewriteBase directive specifies the URL prefix to be used for
104
+ * per-directory (htaccess) RewriteRule directives that substitute a
105
+ * relative path.
106
+ *
107
+ * Syntax:
108
+ * RewriteBase URL-path
109
+ *
110
+ * (Setting RewriteBase to "/" makes it possible to use RewriteRule
111
+ * patterns that **do not** start with a slash.)
112
+ *
113
+ * ## RewriteRule Directive
114
+ *
115
+ * Defines rules for the rewriting engine.
116
+ *
117
+ * Syntax:
118
+ * RewriteRule Pattern Substitution [flags]
119
+ *
120
+ * ## Flags
121
+ *
122
+ * - L|Last
123
+ * Stop processing the rule set. In most contexts, this means
124
+ * that if the rule matches, no further rules will be processed
125
+ *
126
+ * - NC|No Case
127
+ * Ignore case when matching.
128
+ *
129
+ * - R|Redirect
130
+ * Causes a HTTP redirect to be issued to the browser.
131
+ *
132
+ * (Note that Playground does not implement analogs of these flags as
133
+ * there was no need for them yet. They're only described here for
134
+ * convenience to help you read the original .htaccess rules.)
135
+ *
136
+ * ## Differences with .htaccess
137
+ *
138
+ * [1] https://httpd.apache.org/docs/current/rewrite/intro.html
139
+ * [2] https://httpd.apache.org/docs/current/rewrite/flags.html
4
140
  */
5
141
  export declare const wordPressRewriteRules: RewriteRule[];