@wp-playground/wordpress
Advanced tools
Comparing version 0.7.19 to 0.7.20
@@ -0,2 +1,31 @@ | ||
import { BasePHP, UniversalPHP } from '../../../php-wasm/universal/src/index.ts'; | ||
export * from './rewrite-rules'; | ||
export declare const RecommendedPHPVersion = "8.0"; | ||
/** | ||
* Preloads the platform mu-plugins from /internal/shared/mu-plugins. | ||
* This avoids polluting the WordPress installation with mu-plugins | ||
* that are only needed in the Playground environment. | ||
* | ||
* @param php | ||
*/ | ||
export declare function enablePlatformMuPlugins(php: UniversalPHP): Promise<void>; | ||
export declare function preloadRequiredMuPlugin(php: UniversalPHP): Promise<void>; | ||
/** | ||
* Runs phpinfo() when the requested path is /phpinfo.php. | ||
*/ | ||
export declare function preloadPhpInfoRoute(php: UniversalPHP, requestPath?: string): Promise<void>; | ||
export declare function preloadSqliteIntegration(php: UniversalPHP, sqliteZip: File): Promise<void>; | ||
/** | ||
* Prepare the WordPress document root given a WordPress zip file and | ||
* the sqlite-database-integration zip file. | ||
* | ||
* This is a TypeScript function for now, just to get something off the | ||
* ground, but it may be superseded by the PHP Blueprints library developed | ||
* at https://github.com/WordPress/blueprints-library/ | ||
* | ||
* That PHP library will come with a set of functions and a CLI tool to | ||
* turn a Blueprint into a WordPress directory structure or a zip Snapshot. | ||
* Let's **not** invest in the TypeScript implementation of this function, | ||
* accept the limitation, and switch to the PHP implementation as soon | ||
* as that's viable. | ||
*/ | ||
export declare function unzipWordPress(php: BasePHP, wpZip: File): Promise<void>; |
206
index.js
@@ -1,1 +0,205 @@ | ||
const e=[{match:/^\/(.*?)(\/wp-(content|admin|includes)\/.*)/g,replacement:"$2"}],n="8.0";export{n as RecommendedPHPVersion,e as wordPressRewriteRules}; | ||
function o(...e){let t=e.join("/");const i=t[0]==="/",n=t.substring(t.length-1)==="/";return t=c(t),!t&&!i&&(t="."),t&&n&&(t+="/"),t}function c(e){const t=e[0]==="/";return e=f(e.split("/").filter(i=>!!i),!t).join("/"),(t?"/":"")+e.replace(/\/$/,"")}function f(e,t){let i=0;for(let n=e.length-1;n>=0;n--){const r=e[n];r==="."?e.splice(n,1):r===".."?(e.splice(n,1),i++):i&&(e.splice(n,1),i--)}if(t)for(;i;i--)e.unshift("..");return e}function s(e){return`json_decode(base64_decode('${_(JSON.stringify(e))}'), true)`}function g(e){const t={};for(const i in e)t[i]=s(e[i]);return t}function _(e){return w(new TextEncoder().encode(e))}function w(e){const t=String.fromCodePoint(...e);return btoa(t)}const a="/tmp/file.zip",d=async(e,t,i)=>{if(t instanceof File){const r=t;t=a,await e.writeFile(t,new Uint8Array(await r.arrayBuffer()))}const n=g({zipPath:t,extractToPath:i});await e.run({code:`<?php | ||
function unzip($zipPath, $extractTo, $overwrite = true) | ||
{ | ||
if (!is_dir($extractTo)) { | ||
mkdir($extractTo, 0777, true); | ||
} | ||
$zip = new ZipArchive; | ||
$res = $zip->open($zipPath); | ||
if ($res === TRUE) { | ||
$zip->extractTo($extractTo); | ||
$zip->close(); | ||
chmod($extractTo, 0777); | ||
} else { | ||
throw new Exception("Could not unzip file"); | ||
} | ||
} | ||
unzip(${n.zipPath}, ${n.extractToPath}); | ||
`}),await e.fileExists(a)&&await e.unlink(a)},m=[{match:/^\/(.*?)(\/wp-(content|admin|includes)\/.*)/g,replacement:"$2"}];async function $(e){await e.mkdir("/internal/shared/mu-plugins"),await e.writeFile("/internal/shared/preload/env.php",`<?php | ||
// Allow adding filters/actions prior to loading WordPress. | ||
// $function_to_add MUST be a string. | ||
function playground_add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { | ||
global $wp_filter; | ||
$wp_filter[$tag][$priority][$function_to_add] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); | ||
} | ||
function playground_add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { | ||
playground_add_filter( $tag, $function_to_add, $priority, $accepted_args ); | ||
} | ||
// Load our mu-plugins after customer mu-plugins | ||
// NOTE: this means our mu-plugins can't use the muplugins_loaded action! | ||
playground_add_action( 'muplugins_loaded', 'playground_load_mu_plugins', 0 ); | ||
function playground_load_mu_plugins() { | ||
// Load all PHP files from /internal/shared/mu-plugins, sorted by filename | ||
$mu_plugins_dir = '/internal/shared/mu-plugins'; | ||
if(!is_dir($mu_plugins_dir)){ | ||
return; | ||
} | ||
$mu_plugins = glob( $mu_plugins_dir . '/*.php' ); | ||
sort( $mu_plugins ); | ||
foreach ( $mu_plugins as $mu_plugin ) { | ||
require_once $mu_plugin; | ||
} | ||
} | ||
`)}async function h(e){const i=Object.values({addTrailingSlashToWpAdmin:`<?php | ||
// Redirect /wp-admin to /wp-admin/ | ||
add_filter( 'redirect_canonical', function( $redirect_url ) { | ||
if ( '/wp-admin' === $redirect_url ) { | ||
return $redirect_url . '/'; | ||
} | ||
return $redirect_url; | ||
} ); | ||
?>`,allowRedirectHosts:`<?php | ||
// Needed because gethostbyname( 'wordpress.org' ) returns | ||
// a private network IP address for some reason. | ||
add_filter( 'allowed_redirect_hosts', function( $deprecated = '' ) { | ||
return array( | ||
'wordpress.org', | ||
'api.wordpress.org', | ||
'downloads.wordpress.org', | ||
); | ||
} ); | ||
?>`,supportPermalinksWithoutIndexPhp:`<?php | ||
add_filter( 'got_url_rewrite', '__return_true' ); | ||
?>`,createFontsDirectory:`<?php | ||
// Create the fonts directory if missing | ||
if(!file_exists(WP_CONTENT_DIR . '/fonts')) { | ||
mkdir(WP_CONTENT_DIR . '/fonts'); | ||
} | ||
?>`,configureErrorLogging:`<?php | ||
$log_file = WP_CONTENT_DIR . '/debug.log'; | ||
define('ERROR_LOG_FILE', $log_file); | ||
ini_set('error_log', $log_file); | ||
?>`}).map(n=>n.trim()).join(` | ||
`);await e.writeFile("/internal/shared/mu-plugins/0-playground.php",i),await e.writeFile("/internal/shared/preload/error-handler.php",`<?php | ||
(function() { | ||
$playground_consts = []; | ||
if(file_exists('/internal/shared/consts.json')) { | ||
$playground_consts = @json_decode(file_get_contents('/internal/shared/consts.json'), true) ?: []; | ||
$playground_consts = array_keys($playground_consts); | ||
} | ||
set_error_handler(function($severity, $message, $file, $line) use($playground_consts) { | ||
/** | ||
* This is a temporary workaround to hide the 32bit integer warnings that | ||
* appear when using various time related function, such as strtotime and mktime. | ||
* Examples of the warnings that are displayed: | ||
* | ||
* Warning: mktime(): Epoch doesn't fit in a PHP integer in <file> | ||
* Warning: strtotime(): Epoch doesn't fit in a PHP integer in <file> | ||
*/ | ||
if (strpos($message, "fit in a PHP integer") !== false) { | ||
return; | ||
} | ||
/** | ||
* Playground defines some constants upfront, and some of them may be redefined | ||
* in wp-config.php. For example, SITE_URL or WP_DEBUG. This is expected and | ||
* we want Playground constants to take priority without showing warnings like: | ||
* | ||
* Warning: Constant SITE_URL already defined in | ||
*/ | ||
if (strpos($message, "already defined") !== false) { | ||
foreach($playground_consts as $const) { | ||
if(strpos($message, "Constant $const already defined") !== false) { | ||
return; | ||
} | ||
} | ||
} | ||
/** | ||
* Don't complain about network errors when not connected to the network. | ||
*/ | ||
if ( | ||
( | ||
! defined('USE_FETCH_FOR_REQUESTS') || | ||
! USE_FETCH_FOR_REQUESTS | ||
) && | ||
strpos($message, "WordPress could not establish a secure connection to WordPress.org") !== false) | ||
{ | ||
return; | ||
} | ||
return false; | ||
}); | ||
})();`)}async function b(e,t="/phpinfo.php"){await e.writeFile("/internal/shared/preload/phpinfo.php",`<?php | ||
// Render PHPInfo if the requested page is /phpinfo.php | ||
if ( ${s(t)} === $_SERVER['REQUEST_URI'] ) { | ||
phpinfo(); | ||
exit; | ||
} | ||
`)}async function y(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 d(e,t,"/tmp/sqlite-database-integration");const i="/internal/shared/sqlite-database-integration";await e.mv("/tmp/sqlite-database-integration/sqlite-database-integration-main",i);const r=(await e.readFileAsText(o(i,"db.copy"))).replace("'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",s(i)).replace("'{SQLITE_PLUGIN}'",s(o(i,"load.php"))),u=o(await e.documentRoot,"wp-content/db.php"),l=`<?php | ||
// Do not preload this if WordPress comes with a custom db.php file. | ||
if(file_exists(${s(u)})) { | ||
return; | ||
} | ||
?>`,p="/internal/shared/mu-plugins/sqlite-database-integration.php";await e.writeFile(p,l+r),await e.writeFile("/internal/shared/preload/0-sqlite.php",l+`<?php | ||
/** | ||
* Loads the SQLite integration plugin before WordPress is loaded | ||
* and without creating a drop-in "db.php" file. | ||
* | ||
* Technically, it creates a global $wpdb object whose only two | ||
* purposes are to: | ||
* | ||
* * Exist – because the require_wp_db() WordPress function won't | ||
* connect to MySQL if $wpdb is already set. | ||
* * Load the SQLite integration plugin the first time it's used | ||
* and replace the global $wpdb reference with the SQLite one. | ||
* | ||
* This lets Playground keep the WordPress installation clean and | ||
* solves dillemas like: | ||
* | ||
* * Should we include db.php in Playground exports? | ||
* * Should we remove db.php from Playground imports? | ||
* * How should we treat stale db.php from long-lived OPFS sites? | ||
* | ||
* @see https://github.com/WordPress/wordpress-playground/discussions/1379 for | ||
* more context. | ||
*/ | ||
class Playground_SQLite_Integration_Loader { | ||
public function __call($name, $arguments) { | ||
$this->load_sqlite_integration(); | ||
if($GLOBALS['wpdb'] === $this) { | ||
throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded'); | ||
} | ||
return call_user_func_array( | ||
array($GLOBALS['wpdb'], $name), | ||
$arguments | ||
); | ||
} | ||
public function __get($name) { | ||
$this->load_sqlite_integration(); | ||
if($GLOBALS['wpdb'] === $this) { | ||
throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded'); | ||
} | ||
return $GLOBALS['wpdb']->$name; | ||
} | ||
public function __set($name, $value) { | ||
$this->load_sqlite_integration(); | ||
if($GLOBALS['wpdb'] === $this) { | ||
throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded'); | ||
} | ||
$GLOBALS['wpdb']->$name = $value; | ||
} | ||
protected function load_sqlite_integration() { | ||
require_once ${s(p)}; | ||
} | ||
} | ||
$wpdb = $GLOBALS['wpdb'] = new Playground_SQLite_Integration_Loader(); | ||
/** | ||
* WordPress is capable of using a preloaded global $wpdb. However, if | ||
* it cannot find the drop-in db.php plugin it still checks whether | ||
* the mysqli_connect() function exists even though it's not used. | ||
* | ||
* What WordPress demands, Playground shall provide. | ||
*/ | ||
if(!function_exists('mysqli_connect')) { | ||
function mysqli_connect() {} | ||
} | ||
`),await e.writeFile("/internal/shared/mu-plugins/sqlite-test.php",`<?php | ||
global $wpdb; | ||
if(!($wpdb instanceof WP_SQLite_DB)) { | ||
var_dump(isset($wpdb)); | ||
die("SQLite integration not loaded " . get_class($wpdb)); | ||
} | ||
`)}async function P(e,t){e.mkdir("/tmp/unzipped-wordpress"),await d(e,t,"/tmp/unzipped-wordpress"),e.fileExists("/tmp/unzipped-wordpress/wordpress.zip")&&await d(e,"/tmp/unzipped-wordpress/wordpress.zip","/tmp/unzipped-wordpress");const i=e.fileExists("/tmp/unzipped-wordpress/wordpress")?"/tmp/unzipped-wordpress/wordpress":e.fileExists("/tmp/unzipped-wordpress/build")?"/tmp/unzipped-wordpress/build":"/tmp/unzipped-wordpress";e.mv(i,e.documentRoot),!e.fileExists(o(e.documentRoot,"wp-config.php"))&&e.fileExists(o(e.documentRoot,"wp-config-sample.php"))&&e.writeFile(o(e.documentRoot,"wp-config.php"),e.readFileAsText(o(e.documentRoot,"/wp-config-sample.php")))}export{$ as enablePlatformMuPlugins,b as preloadPhpInfoRoute,h as preloadRequiredMuPlugin,y as preloadSqliteIntegration,P as unzipWordPress,m as wordPressRewriteRules}; |
{ | ||
"name": "@wp-playground/wordpress", | ||
"version": "0.7.19", | ||
"version": "0.7.20", | ||
"description": "WordPress-related plumbing for WordPress Playground", | ||
@@ -30,6 +30,3 @@ "repository": { | ||
}, | ||
"dependencies": { | ||
"@php-wasm/universal": "^0.6.6" | ||
}, | ||
"gitHead": "687ec237085853ff5c808814c28be349146a5d1a" | ||
"gitHead": "5915ef756c88da8dcb665f9f0e49ddc0c0b10d50" | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Trivial Package
Supply chain riskPackages less than 10 lines of code are easily copied into your own project and may not warrant the additional supply chain risk of an external dependency.
Found 1 instance in 1 package
13033
0
244
- Removed@php-wasm/universal@^0.6.6
- Removed@php-wasm/universal@0.6.16(transitive)