diff --git a/IStreamProcessor.php b/IStreamProcessor.php new file mode 100644 index 0000000..895edfe --- /dev/null +++ b/IStreamProcessor.php @@ -0,0 +1,8 @@ +' )`. + * style of including JavaScript inside of HTML comments to avoid accidentally + * closing the SCRIPT from inside a JavaScript string. E.g. `console.log( '' )`. * - `TITLE` and `TEXTAREA` whose contents are treated as plaintext and then any * character references are decoded. E.g. `1 < 2 < 3` becomes `1 < 2 < 3`. * - `IFRAME`, `NOSCRIPT`, `NOEMBED`, `NOFRAME`, `STYLE` whose contents are treated as @@ -1524,21 +1524,10 @@ private function parse_next_tag() { $was_at = $this->bytes_already_parsed; $at = $was_at; - while ( false !== $at && $at < $doc_length ) { + while ( $at < $doc_length ) { $at = strpos( $html, '<', $at ); - - /* - * This does not imply an incomplete parse; it indicates that there - * can be nothing left in the document other than a #text node. - */ if ( false === $at ) { - $this->parser_state = self::STATE_TEXT_NODE; - $this->token_starts_at = $was_at; - $this->token_length = strlen( $html ) - $was_at; - $this->text_starts_at = $was_at; - $this->text_length = $this->token_length; - $this->bytes_already_parsed = strlen( $html ); - return true; + break; } if ( $at > $was_at ) { @@ -1554,19 +1543,9 @@ private function parse_next_tag() { * * @see https://html.spec.whatwg.org/#tag-open-state */ - if ( strlen( $html ) > $at + 1 ) { - $next_character = $html[ $at + 1 ]; - $at_another_node = ( - '!' === $next_character || - '/' === $next_character || - '?' === $next_character || - ( 'A' <= $next_character && $next_character <= 'Z' ) || - ( 'a' <= $next_character && $next_character <= 'z' ) - ); - if ( ! $at_another_node ) { - ++$at; - continue; - } + if ( 1 !== strspn( $html, '!/?abcdefghijklmnopqrstuvwxyzABCEFGHIJKLMNOPQRSTUVWXYZ', $at + 1, 1 ) ) { + ++$at; + continue; } $this->parser_state = self::STATE_TEXT_NODE; @@ -1630,11 +1609,7 @@ private function parse_next_tag() { * `') !== false || + strpos($new_value, '--!>') !== false + ) + ) { + _doing_it_wrong( + __METHOD__, + __( 'Cannot set a comment closer as a text of an HTML comment.' ), + 'WP_VERSION' + ); + return false; + } + if( + $p->get_token_type() === '#cdata-section' && + strpos($new_value, '>') !== false + ) { + _doing_it_wrong( + __METHOD__, + __( 'Cannot set a CDATA closer as text of an HTML CDATA-lookalike section.' ), + 'WP_VERSION' + ); + return false; + } + $lexical_updates_now = $lexical_updates->getValue($p); + $lexical_updates_now[] = new WP_HTML_Text_Replacement( + $accessible_text_starts_at->getValue($p), + $accessible_text_length->getValue($p), + $new_value + ); + $lexical_updates->setValue($p, $lexical_updates_now); + return true; + default: + _doing_it_wrong( + __METHOD__, + __( 'Cannot set text content on a non-text node.' ), + 'WP_VERSION' + ); + return false; + } + } +} diff --git a/class-wp-xml-processor.php b/class-wp-xml-processor.php index a18e35f..b3a73ed 100644 --- a/class-wp-xml-processor.php +++ b/class-wp-xml-processor.php @@ -10,7 +10,7 @@ /** * @since WP_VERSION */ -class WP_XML_Processor extends WP_XML_Tag_Processor { +class WP_XML_Processor extends WP_XML_Tag_Processor implements IStreamProcessor { /** * Indicates the current parsing stage. @@ -60,7 +60,7 @@ public static function stream_tokens( $input_stream, $output_stream, $buffer_siz $token_found = $processor->next_token(); $processor->get_updated_xml(); - if ( $processor->paused_at_incomplete_token() ) { + if ( $processor->is_paused_at_incomplete_input() ) { fwrite( $output_stream, $processor->get_processed_xml() ); $next_chunk = fread( $input_stream, $buffer_size ); @@ -88,6 +88,47 @@ public static function stream_tokens( $input_stream, $output_stream, $buffer_siz } } + public function pause() { + return array( + 'xml' => $this->xml, + // @TODO: Include all the information below in the bookmark: + 'bytes_already_parsed' => $this->token_starts_at, + 'breadcrumbs' => $this->get_breadcrumbs(), + 'parser_context' => $this->get_parser_context(), + 'stack_of_open_elements' => $this->stack_of_open_elements, + ); + } + + public function resume($paused) { + $this->xml = $paused['xml']; + $this->stack_of_open_elements = $paused['stack_of_open_elements']; + $this->parser_context = $paused['parser_context']; + $this->bytes_already_parsed = $paused['bytes_already_parsed']; + $this->base_class_next_token(); + } + + /** + * Wipes out the processed XML and appends the next chunk of XML to + * any remaining unprocessed XML. + * + * @param string $next_chunk XML to append. + */ + public function append_bytes( string $next_chunk ) + { + $this->get_updated_xml(); + + $new_xml = $this->get_unprocessed_xml() . $next_chunk; + $breadcrumbs = $this->get_breadcrumbs(); + $parser_context = $this->get_parser_context(); + + $this->reset_state(); + + $this->xml = $new_xml; + $this->stack_of_open_elements = $breadcrumbs; + $this->parser_context = $parser_context; + $this->had_previous_chunks = true; + } + /** * Constructor. * diff --git a/class-wp-xml-tag-processor.php b/class-wp-xml-tag-processor.php index db06e54..1a29ff7 100644 --- a/class-wp-xml-tag-processor.php +++ b/class-wp-xml-tag-processor.php @@ -337,7 +337,7 @@ class WP_XML_Tag_Processor { * @since WP_VERSION * @var string */ - protected $xml; + public $xml; /** * The last query passed to next_tag(). @@ -428,7 +428,7 @@ class WP_XML_Tag_Processor { * @since WP_VERSION * @var int */ - private $bytes_already_parsed = 0; + public $bytes_already_parsed = 0; /** * Byte offset in input document where current token starts. @@ -443,7 +443,7 @@ class WP_XML_Tag_Processor { * * @var int|null */ - private $token_starts_at; + protected $token_starts_at; /** * Byte length of current token. @@ -870,16 +870,27 @@ protected function base_class_next_token() { * * $processor = new WP_XML_Tag_Processor( ' + + + + +My WordPress Website +http://127.0.0.1:9400 + +Wed, 12 Jun 2024 11:34:29 +0000 +en-US +1.2 +http://127.0.0.1:9400 +http://127.0.0.1:9400 + + 1 + admin + admin@localhost.com + + + + +https://wordpress.org/?v=6.6-beta2 + + <![CDATA[15-resources.blockhtml]]> + http://127.0.0.1:9400/?page_id=1 + + admin + + + +

Links and Resources

+ + + +

Frequently sought links

+ + + + + + + +

Apps built with WordPress Playground

+ + + + + + + +

Reading materials

+ + + + + + + +

Videos

+ + + + +]]>
+ + 1 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[17-changelog.blockhtml]]> + http://127.0.0.1:9400/?page_id=2 + + admin + + + +

Changelog

+ + + +

All notable changes to this project are documented in this file by a CI job
that runs on every NPM release. The file follows the Keep a Changelog
format.

+ + + +

[v0.7.20] (2024-05-21)

+ + + +

Breaking Changes

+ + + +
    +
  • [Breaking] Refactor PHP.ini management, remove php.setPhpIniPath() and php.setPhpIniEntry(). (#1423)
  • +
+ + + +

Enhancements

+ + + +
    +
  • CLI: Distinguish between mount and mountBeforeInstall options. (#1410)
  • + + + +
  • CLI: Support fetching WordPress zips from custom URLs. (#1415)
  • + + + +
  • Introduce a new @wp-playground/common package to avoid circular depencies. (#1387)
  • + + + +
  • Website: Ship the SQLite database integration plugin. (#1418)
  • +
+ + + +

Boot Flow

+ + + +
    +
  • Playground CLI: Don't create /wordpress/wp-config.php on boot. (#1407)
  • +
+ + + +

Blueprints

+ + + +
    +
  • Define constants in auto_prepend_file, silence warnings related to redefining those constants. (#1400)
  • + + + +
  • Detect silent failures when activating plugins and theme. (#1436)
  • + + + +
  • Re-activate single-file plugins when enabling a multisite. (#1435)
  • + + + +
  • Throw an error when activating a theme or plugin that doesn't exist. (#1391)
  • + + + +
  • Write sunrise.php to /internal in enableMultisite step. (#1401)
  • +
+ + + +

Tools

+ + + +
    +
  • Add VSCode branch protection. (#1408)
  • + + + +
  • Show error log if Playground fails to start. (#1336)
  • +
+ + + +

Blueprints

+ + + +
    +
  • Unzip: Only delete a temporary zip file after unzipping, do not delete the original zip. (#1412)
  • +
+ + + +

GitHub integration

+ + + +
    +
  • GitHub export: Create new commits in your fork when writing to the upstream repo isn't allowed. (#1392)
  • +
+ + + +

Import/Export

+ + + +
    +
  • Support wp_crop_image in import wxr. (#1357)
  • +
+ + + +

Devrel

+ + + +
    +
  • Add puzzle API. (#1372)
  • +
+ + + +

Documentation

+ + + +
    +
  • Docs: Use step function names instead of TypeScript type names. (#1373)
  • + + + +
  • Updated the GitHub issue link to open in a new tab. (#1353)
  • + + + +
  • Use step id name. (#1377)
  • +
+ + + +

Experiments

+ + + +
    +
  • Explore: Setup SQLite database integration without creating wp-content/db.php. (#1382)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Add shareable extension-to-MIME-type mapping. (#1355)
  • + + + +
  • Document php ini functions. (#1430)
  • + + + +
  • JSPI: Enable the origin trial on Chrome. (#1346)
  • + + + +
  • PHP: Add libjpeg and libwebp support. (#1393)
  • + + + +
  • PHP: Always set the auto_prepend_file php.ini entry, even when the auto_prepend_file.php file exists. (#1388)
  • + + + +
  • PHP: Move internal shared directories to /internal/shared. (#1386)
  • + + + +
  • PHP: Remove mentions of a custom PHP extension. (#1422)
  • + + + +
  • PHP: Remove the MODE_EVAL_CODE execution mode. (#1433)
  • + + + +
  • PHP: Support php.mv() between devices via recursive copy. (#1411)
  • + + + +
  • PHP: Use /internal/shared/php.ini by default. (#1419)
  • + + + +
  • PHP: Use auto_prepend_file to preload mu-plugins (instead of creating them in wp-content/mu-plugins). (#1366)
  • +
+ + + +

Website

+ + + +
    +
  • Improve log modal styles, a11y, error message wording. (#1369)
  • + + + +
  • Move puzzle app to a Playground package. (#1385)
  • + + + +
  • Add secrets on-demand for more endpoints. (#1362)
  • + + + +
  • Boot: Move WordPress zip extraction logic to a common unzipWordPress() utility. (#1427)
  • + + + +
  • Derive MIME types for PHP served files from shared JSON. (#1360)
  • + + + +
  • Fix constant names for GH export oauth. (#1378)
  • + + + +
  • Playground Boot: Align the boot process between remote.html and CLI. (#1389)
  • + + + +
  • Remote.html: Install WordPress if it isn't installed yet. (#1425)
  • + + + +
  • Remote.html: Preload the SQLite database plugin, but only execute it if there's no custom db.php inside wp-content. (#1424)
  • + + + +
  • Simplify website deployment workflows. (#1404)
  • + + + +
  • Update rsync command to clean up more completely. (#1361)
  • +
+ + + +

Blueprints

+ + + +
    +
  • Provide non-gzipped wp-cli.phar file with website build. (#1406)
  • + + + +
  • Simplify runPhpWithZipFunctions() setup. (#1434)
  • +
+ + + +

Internal

+ + + +
    +
  • Fix changelog automation. (#1413)
  • +
+ + + +

Bug Fixes

+ + + +
    +
  • Add name to Puzzle package. (#1443)
  • + + + +
  • Fixed images not loading on the page. (#1352)
  • + + + +
  • Restore nightly wordpress build. (#1437)
  • +
+ + + +

Reliability

+ + + +
    +
  • Disable console logging when running tests. (#1368)
  • +
+ + + +

+ + + +
    +
  • Lint: Disable console warnings for paths where they're not useful. (#1421)
  • +
+ + + +

Various

+ + + +
    +
  • Add links to kitchen sink (PHP extensions), networking. (#1363)
  • + + + +
  • Reorganize and update documentation. (#1354)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @bgrgicak @brandonpayton @flexseth @ironnysh @josevarghese

+ + + +

[v0.7.15] (2024-04-30)

+ + + +

Website

+ + + +
    +
  • Avoid edge-caching conditionally redirected resources. (#1351)
  • + + + +
  • Fix deploy-time check for file with PHP-handled redirect. (#1350)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@brandonpayton

+ + + +

[v0.7.10] (2024-04-30)

+ + + +

PHP WebAssembly

+ + + +
    +
  • PHP.wasm Node: Revert a part of #1289, do not import a .wasm file. (#1348)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel

+ + + +

[v0.7.5] (2024-04-30)

+ + + +

Internal

+ + + +
    +
  • Meta: Move the minified WordPress to the new @wp-playground/wordpress-builds package. (#1343)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel

+ + + +

[v0.7.3] (2024-04-29)

+ + + +

PHP WebAssembly

+ + + +
    +
  • Playground CLI. (#1289)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel

+ + + +

[v0.7.2] (2024-04-29)

+ + + +

Breaking Changes

+ + + +
    +
  • PHP: Remove setSapiName, setPhpIniEntry, setPhpIniPath methods from the remote PHP API client. (#1321)
  • + + + +
  • Remove the wp-playground/node package. (#1323)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Breaking: Loopback Request Support. (#1287)
  • +
+ + + +

Tools

+ + + +
    +
  • Centralize log storage. (#1315)
  • +
+ + + +

Documentation

+ + + +
    +
  • Link to Installing Nx Globally in the README. (#1325)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Add PHPResponse.forHttpCode() shorthand. (#1322)
  • + + + +
  • Asyncify: List ZEND_FETCH_OBJ_R_SPEC_CV_CV_HANDLER. (#1342)
  • + + + +
  • Curl extension for the Node.js build of PHP.wasm. (#1273)
  • + + + +
  • Explore curl support. (#1133)
  • + + + +
  • PHP Process Manager. (#1301)
  • + + + +
  • PHPProcessManager: Clear nextInstance when the concurrency limit is exhausted. (#1324)
  • + + + +
  • Spawn handler: Wrap the program call with try/catch, exit gracefully on error. (#1320)
  • +
+ + + +

Website

+ + + +
    +
  • Add initial workflow for deploying the website to WP Cloud. (#1293)
  • + + + +
  • Eliminate 404s due to nested files-to-serve-via-php dir. (#1333)
  • + + + +
  • Stop WP rewrite rules from matching files like wp-admin.css. (#1317)
  • + + + +
  • Stop using PHP to serve most static files on WP Cloud. (#1331)
  • + + + +
  • WP Cloud: Relay secrets for error logger. (#1337)
  • +
+ + + +

Documentation

+ + + +
    +
  • Document WP Cloud website setup. (#1338)
  • +
+ + + +

Reliability

+ + + +
    +
  • Add log methods, log handlers, and separate log collection. (#1264)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @bgrgicak @brandonpayton @juanmaguitar @mho22

+ + + +

[v0.7.1] (2024-04-24)

+ + + +

[v0.7.0] (2024-04-24)

+ + + +

Breaking Changes

+ + + +

PHP WebAssembly

+ + + +
    +
  • Breaking: Remove PHPBrowser. (#1302)
  • +
+ + + +

Enhancements

+ + + +
    +
  • Bump TypeScript to 5.4.5. (#1299)
  • + + + +
  • Semaphore: Add timeout option. (#1300)
  • +
+ + + +

Blueprints

+ + + +
    +
  • Builder: Fix stuck loader bar. (#1284)
  • + + + +
  • Remove setPhpIniEntry step. (#1288)
  • +
+ + + +

Tools

+ + + +

GitHub integration

+ + + +
    +
  • GitHub: Don't delete all the files when exporting a theme. (#1308)
  • + + + +
  • Urlencode branch name. (#1275)
  • +
+ + + +

Blueprints

+ + + +
    +
  • Blueprints builder: Support ?blueprint-url. (#1309)
  • +
+ + + +

Documentation

+ + + +
    +
  • Use new learning resources in Playground documentation. (#1276)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Browser: Remove setSpawnHandler function from the public API. (#1303)
  • + + + +
  • PHP: Add a cwd argument to hotSwapPHPRuntime(). (#1304)
  • + + + +
  • PHP: Remove addServerGlobalEntry() method, accept $_SERVER as php.run() property. (#1286)
  • + + + +
  • PHPRequestHandler: Add a generic PHP argument. (#1310)
  • + + + +
  • nit: Clean up after node PHP popen() test. (#1280)
  • +
+ + + +

Website

+ + + +
    +
  • Add more info to crash reports. (#1253)
  • + + + +
  • Memoize fetch() responses when requesting php.wasm. (#1306)
  • + + + +
  • Progress monitoring: Use a custom instantiateWasm handler to avoid monkey-patching WebAssembly.instantiateStreaming. (#1305)
  • + + + +
  • Remove sandbox attribute from iframe. (#1313)
  • + + + +
  • Service Worker: Fetch credentialless to play more nicely with server caches (#1311). (#1311)
  • +
+ + + +

Internal

+ + + +
    +
  • Automate Changelog generation after each npm release. (#1312)
  • + + + +
  • CI: Fix intermittent documentation build failures. (#1307)
  • +
+ + + +

Bug Fixes

+ + + +
    +
  • Add styles to ensure iframes are responsive. (#1267)
  • + + + +
  • Docs: Fix the Blueprint example of the Gutenberg PR preview. (#1268)
  • + + + +
  • Docs: Move Steps Shorthands to a separate page to fix Steps TOC. (#1265)
  • +
+ + + +

Reliability

+ + + +
    +
  • Add network error message. (#1281)
  • + + + +
  • Explore logging to a file. (#1292)
  • +
+ + + +

Various

+ + + +
    +
  • Add PDF to infer mime type list. (#1298)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @bgrgicak @brandonpayton @ironnysh @peeranat-dan

+ + + +

[v0.6.16] (2024-04-17)

+ + + +

Blueprints

+ + + +
    +
  • Replace set_current_user call with wp_set_current_user to fix a PHP notice. (#1262)
  • +
+ + + +

Tools

+ + + +
    +
  • Install themes and plugins using the ReadableStream API. (#919)
  • +
+ + + +

Documentation

+ + + +
    +
  • Docs: Update WordPress versions used in the documentation, document using older releases. (#1235)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Filter Requests library to use the Fetch handler. (#1048)
  • + + + +
  • PHP: Handle request errors in PHPRequestHandler, return response code 500. (#1249)
  • + + + +
  • PHP: Reset exit code before dispatching a request. (#1251)
  • +
+ + + +

Various

+ + + +
    +
  • Add documentation for shorthand alternatives of Blueprint steps. (#1261)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @dd32 @ironnysh @kozer

+ + + +

[v0.6.15] (2024-04-16)

+ + + +

Blueprints

+ + + +
    +
  • Add ifAlreadyInstalled to installPlugin and installTheme steps. (#1244)
  • + + + +
  • Support a landingPage value without the initial slash. (#1227)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Investigate OOB: Run unit tests with instrumented PHP 8.0 code. (#1220)
  • + + + +
  • Unit tests: Restore site-data.spec.ts. (#1194)
  • + + + +
  • Web PHP: Increase memory limit to 256 M. (#1232)
  • +
+ + + +

Website

+ + + +
    +
  • Browser: Display PHP output when Fatal Error is trigerred. (#1234)
  • + + + +
  • Fix accessibility issues found by Axe. (#1246)
  • + + + +
  • Request Handler: Urldecode the requested path. (#1228)
  • +
+ + + +

Bug Fixes

+ + + +
    +
  • fix: Set required engine version to 18.18.0. (#1214)
  • +
+ + + +

Various

+ + + +
    +
  • Blueprints/json example. (#1188)
  • + + + +
  • Doc: Update 01-index.md. (#1216)
  • + + + +
  • Move DefineSiteUrlStep doc warning so it displays in documentation. (#1245)
  • + + + +
  • Updated link to native WordPress importer. (#1243)
  • + + + +
  • documentation update proposal: Provide more info on features, extensions?. (#1208)
  • + + + +
  • php-wasm/node: Update express to newest version, and move it to devDependencies. (#1218)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @artpi @bph @brandonpayton @eliot-akira @flexseth @ironnysh @kirjavascript

+ + + +

[v0.6.14] (2024-04-11)

+ + + +

Bug Fixes

+ + + +
    +
  • Revert changes to the documentation build. (#1226)
  • +
+ + + +

Reliability

+ + + +
    +
  • Update error modal description label. (#1224)
  • +
+ + + +

Various

+ + + +
    +
  • Try memory leak workaround with zeroed mem. (#1229)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @bgrgicak @brandonpayton

+ + + +

[v0.6.13] (2024-04-10)

+ + + +

PHP WebAssembly

+ + + +
    +
  • Try to repro memory out of bounds errors in CI. (#1199)
  • +
+ + + +

Bug Fixes

+ + + +
    +
  • Fix docs-site build. (#1222)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@bgrgicak @brandonpayton

+ + + +

[v0.6.11] (2024-04-09)

+ + + +

Tools

+ + + +
    +
  • Avoid Service Worker update issues on localhost. (#1209)
  • +
+ + + +

Import/Export

+ + + +
    +
  • importWxr: Preserve backslashes in the imported content. (#1213)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Catch DNS errors to avoid unhandled exceptions. (#1215)
  • + + + +
  • Revert "Avoid partial munmap memory leak". (#1195)
  • + + + +
  • Try to repro memory out of bounds errors in CI. (#1198)
  • +
+ + + +

Various

+ + + +
    +
  • Adjust link to LICENSE file. (#1210)
  • + + + +
  • Try to reproduce the memory access error with files from 096a017. (#1212)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @brandonpayton @emmanuel-ferdman @fluiddot

+ + + +

[v0.6.10] (2024-04-04)

+ + + +

Blueprints

+ + + +
    +
  • Rename importFile to importWxr, switch to humanmade/WordPress importer. (#1192)
  • +
+ + + +

Tools

+ + + +

Blueprints

+ + + +
    +
  • Explorations: Stream API. (#851)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Avoid partial munmap memory leak. (#1189)
  • +
+ + + +

Website

+ + + +
    +
  • Make kitchen sink extension bundle the default. (#1191)
  • +
+ + + +

Bug Fixes

+ + + +
    +
  • Fix cross-device mv by switching to copy. (#846)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @brandonpayton @seanmorris

+ + + +

[v0.6.9] (2024-04-03)

+ + + +

Tools

+ + + +
    +
  • Devex: Expose window.playground for quick testing and debugging. (#1125)
  • +
+ + + +

GitHub integration

+ + + +
    +
  • Website: Query API options to preconfigure the GitHub export form. (#1174)
  • +
+ + + +

Documentation

+ + + +
    +
  • Update the wp-cli step code example. (#1140)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Add PHP iterator and yield support. (#1181)
  • + + + +
  • Fix fileinfo support. (#1179)
  • + + + +
  • Fix mbregex support. (#1155)
  • + + + +
  • PHP.run(): Throw JS exception on runtime error, remove throwOnError flag. (#1137)
  • +
+ + + +

Website

+ + + +
    +
  • Add error report modal. (#1102)
  • + + + +
  • Ensure PromiseRejectionEvent has reason before logging it. (#1150)
  • + + + +
  • Request handler: Remove everything after # from the URL. (#1126)
  • + + + +
  • Web: Make the "Apply changes" button work in Playground settings form. (#1122)
  • +
+ + + +

Plugin proxy

+ + + +
    +
  • Allow requests to WordPress.org. (#1154)
  • +
+ + + +

Internal

+ + + +
    +
  • Refresh WordPress with the latest SQLite integration plugin. (#1151)
  • +
+ + + +

Bug Fixes

+ + + +
    +
  • Fix typo in blueprints/public/schema-readme.md. (#1134)
  • + + + +
  • Priority: Fix broken link to VS Code extension. (#1141)
  • +
+ + + +

Various

+ + + +
    +
  • Docs/update - Add implied step. (#1144)
  • + + + +
  • Give brandonpayton permission to run Playground GH workflows. (#1139)
  • + + + +
  • Logger API: Add rate limiting. (#1142)
  • + + + +
  • Remove --disable-all configuration option in PHP compile process. (#1132)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @bgrgicak @brandonpayton @flexseth @jblz @mho22

+ + + +

[v0.6.8] (2024-03-21)

+ + + +

Blueprints

+ + + +
    +
  • Allow optional metadata. (#1103)
  • +
+ + + +

Tools

+ + + +
    +
  • Add VSCode Chrome debugging support. (#1088)
  • + + + +
  • Website: Support Base64-encoding Blueprints passed in the URL. (#1091)
  • +
+ + + +

Documentation

+ + + +
    +
  • Docs: Expand Details section. (#1109)
  • + + + +
  • Update activate-theme.ts to use themeFolderName. (#1119)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Blueprints: Explore switching to the PHP implementation. (#1051)
  • + + + +
  • Explore weird register_shutdown_function behavior. (#1099)
  • + + + +
  • Fix post_message_to_js memory out of bounds. (#1114)
  • + + + +
  • Fix shutdown errors. (#1104)
  • + + + +
  • Fixing build regression [BISON COMPILE]. (#871)
  • + + + +
  • PHP : Set appropriate SCRIPT variables in $_SERVER superglobal. (#1092)
  • +
+ + + +

Website

+ + + +
    +
  • Add logger API. (#1113)
  • + + + +
  • Add multisite rewrite rules. (#1083)
  • + + + +
  • Service worker: Improve error reporting in non-secure contexts. (#1098)
  • +
+ + + +

Bug Fixes

+ + + +
    +
  • Fix experimental notice in FF ESR. (#1117)
  • + + + +
  • Fix php bison dep for building on non-arm64 architectures. (#1115)
  • +
+ + + +

Reliability

+ + + +
    +
  • Add fatal errror listener. (#1095)
  • +
+ + + +

Various

+ + + +
    +
  • Update examples and demos in the documentation. (#1107)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@0aveRyan @adamziel @bgrgicak @brandonpayton @ironnysh @mho22 @seanmorris @StevenDufresne

+ + + +

[v0.6.7] (2024-03-06)

+ + + +

Website

+ + + +
    +
  • Node polyfills: Only apply them in Node.js, not in web browsers. (#1089)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel

+ + + +

[v0.6.6] (2024-03-06)

+ + + +

Website

+ + + +
    +
  • Comlink API: Pass the context argument to windowEndpoint, not wrap. (#1087)
  • + + + +
  • Fix: Playground not starting due to a race condition. (#1084)
  • + + + +
  • Hide the "This is experimental WordPress" notice on click. (#1082)
  • + + + +
  • Set the API context when using Comlink.wrap(). (#1085)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel

+ + + +

[v0.6.5] (2024-03-05)

+ + + +

Tools

+ + + +

Plugin proxy

+ + + +
    +
  • Add Sensei to the allowed repositories for plugin proxy. (#1079)
  • +
+ + + +

Blueprints

+ + + +
    +
  • Snapshot Import Protocol v1. (#1007)
  • +
+ + + +

Internal

+ + + +
    +
  • Build the php-wasm/util package as both ESM and CJS. (#1081)
  • +
+ + + +

Reliability

+ + + +

Blueprints

+ + + +
    +
  • Add unit tests to the mkdir step. (#1029)
  • +
+ + + +

Various

+ + + +
    +
  • Website query API: Continue plugin installs on error. (#605)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @eliot-akira @reimic @renatho

+ + + +

[v0.6.4] (2024-03-04)

+ + + +

Enhancements

+ + + +
    +
  • Add logging support to Playground. (#1035)
  • +
+ + + +

Blueprints

+ + + +
    +
  • PHP Blueprints: Display progress. (#1077)
  • + + + +
  • Set progress caption and communicate failures in the import file step. (#1034)
  • +
+ + + +

Tools

+ + + +

Blueprints

+ + + +
    +
  • PHP Blueprints demo page. (#1070)
  • + + + +
  • PHP: Do not prepend a whitespace when encoding body as multipart form data. (#1033)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Fix response header escaping. (#1050)
  • + + + +
  • Fix: Networking broken when extra PHP extensions are enabled. (#1045)
  • + + + +
  • PHP.wasm: Yield 0 bytes read on fd_read failure to improve PHP's fread() and feof() behavior. (#1053)
  • + + + +
  • PHP: Support $env and $cwd proc_open arguments. (#1064)
  • + + + +
  • Parse shell commands in createSpawnHandler. (#1065)
  • + + + +
  • Prototype: Spawning PHP sub-processes in Web Workers. (#1031)
  • + + + +
  • Spawning PHP sub-processes in Web Workers. (#1069)
  • +
+ + + +

Website

+ + + +
    +
  • Add Google Analytics events to Playground. (#1040)
  • + + + +
  • Fix error on reload site click. (#1041)
  • +
+ + + +

Internal

+ + + +
    +
  • Rebuild WordPress every 20 minutes, short-circuit if no new version is found. (#1061)
  • + + + +
  • Rebuild WordPress within an hour of a beta release. (#1059)
  • +
+ + + +

Bug Fixes

+ + + +
    +
  • Fix the login message so it doesn't override another. (#1044)
  • +
+ + + +

Various

+ + + +
    +
  • Add arguments to default node spawn method. (#1037)
  • + + + +
  • Add bgrgicak to deployment allowlists. (#1057)
  • + + + +
  • Allow for CORS requests to api.wordpress.org to pass. (#1009)
  • + + + +
  • Default URL rewrites to /index.php. (#1072)
  • + + + +
  • Remove repository specific Code of Conduct. (#1038)
  • + + + +
  • Ship WordPress 6.5 beta 1. (#1036)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @bgrgicak @dd32 @desrosj @johnbillion @mho22

+ + + +

[v0.6.3] (2024-02-12)

+ + + +

Blueprints

+ + + + + + + +

PHP WebAssembly

+ + + +
    +
  • Calls proc_open two times in a row. (#1012)
  • + + + +
  • Experiment: Build PHP with OPFS support. (#1030)
  • + + + +
  • PHP: Pass request body as UInt8Array. (#1018)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @mho22

+ + + +

[v0.6.2] (2024-02-08)

+ + + +

PHP WebAssembly

+ + + +
    +
  • Networking: Swap Requests transports using the http_api_transports instead of patching the Requests library. (#1004)
  • + + + +
  • Remove crypto.randomUUID dependency in favor of a custom function. (#1016)
  • + + + +
  • Remove x-request-issuer header on cross-origin requests. (#1010)
  • + + + +
  • Update wp_http_fetch.php. (#1002)
  • +
+ + + +

Website

+ + + +
    +
  • Remote.html: Always install the playground mu-plugin. (#1005)
  • +
+ + + +

Various

+ + + +
    +
  • 32bit integer workaround. (#1014)
  • + + + +
  • Test/hello world blueprint. (#908)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @bgrgicak @jdevalk @sejas @stoph

+ + + +

[v0.6.1] (2024-02-05)

+ + + +

Website

+ + + +

Blueprints

+ + + +
    +
  • Remove the applyWordPressPatches step, enable the Site Health Plugin. (#1001)
  • +
+ + + +

Various

+ + + +
    +
  • Add crypto to Polyfills improving Blueprint compatibility for Node. (#1000)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @sejas

+ + + +

[v0.6.0] (2024-02-05)

+ + + +

Enhancements

+ + + +
    +
  • Add wp-cli and code editor examples to the demos page. (#965)
  • + + + +
  • WordPress: Preserve PHP attributes and wp-config.php whitespace. (#964)
  • +
+ + + +

Blueprints

+ + + +
    +
  • Add enableMultisite step. (#888)
  • + + + +
  • Set_current_user to admin before activating plugins and themes. (#984)
  • +
+ + + +

Tools

+ + + +
    +
  • Use .zip files instead of .data files for loading WordPress. (#978)
  • +
+ + + +

Blueprints

+ + + +
    +
  • Throw on failure. (#982)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Support wp-cli in the browser. (#957)
  • +
+ + + +

PHP WebAssembly

+ + + +
    +
  • Correcting OOB & Prevent Crash on Saving Large Post. (#870)
  • + + + +
  • Memory leak: Add rotatedPHP to kill and recreate PHP instances after a certain number of requests. (#990)
  • + + + +
  • PHP : Add args and descriptors dynamic arrays in proc open function. (#969)
  • + + + +
  • PHP.wasm: Fix stack overflow in wasm_set_request_body. (#993)
  • +
+ + + +

Website

+ + + +
    +
  • Add .htaccess file to prevent caching of index.html and enable importing the client.js library. (#989)
  • + + + +
  • Add og meta tags and meta description. (#980)
  • + + + +
  • CORS headers for client/index.js. (#893)
  • + + + +
  • wp-cli: Respect quotes when parsing shell commands. (#966)
  • +
+ + + +

Internal

+ + + +
    +
  • Remove the interactive block playground. (#988)
  • +
+ + + +

Bug Fixes

+ + + +
    +
  • Fix "WP-CLI" typos. (#971)
  • + + + +
  • Fix footer styling issue in the "Code is Poetry" in wordpress.github.io/wordpress-playground. (#959)
  • + + + +
  • WordPress build: Add newlines after PHP annotations. (#986)
  • +
+ + + +

Various

+ + + +
    +
  • Add a blueprint example. (#946)
  • + + + +
  • Add terminal to playground site. (#161)
  • + + + +
  • Match the .nvmrc node version to the changes made in commit ec2605b. (#972)
  • + + + +
  • PHP : Dispatch available descriptor specs in js_open_process function. (#963)
  • + + + +
  • PHP : Give access to command arguments if array type is given in php ^7.4 proc_open function. (#944)
  • + + + +
  • Rebuild WordPress. (#987)
  • + + + +
  • Update the networking disabled error messages in wp-admin for plugins and themes. (#936)
  • +
+ + + +

Contributors

+ + + +

The following contributors merged PRs in this release:

+ + + +

@adamziel @bph @ironnysh @marcarmengou @mho22 @rowasc @seanmorris @swissspidy @tyrann0us

+ + + +

[v0.5.9] - 2021-09-29

+ + + +

Changed

+ + + +

Breaking: Remoddsaved the PHPBrowser class (##1302)

+ + + +

Added

+ + + +

– Added CHANGELOG.md to keep track of notable changes (##1302)

+]]>
+ + 2 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[08-query-api]]> + http://127.0.0.1:9400/?page_id=3 + + admin + + + +

Query API

+ + + +

WordPress Playground exposes a simple API that you can use to configure the Playground in the browser.

+ + + +

It works by passing configuration options as query parameters to the Playground URL. For example, to install the pendant theme, you would use the following URL:

+ + + +
https://playground.wordpress.net/?theme=pendant
+
+ + + +

You can go ahead and try it out. The Playground will automatically install the theme and log you in as an admin. You may even embed this URL in your website using an <iframe> tag:

+ + + +

+
+ + + +

:::info CORS policy

+ + + +

To import files from a URL, such as a site zip package, they must be served with Access-Control-Allow-Origin header set. For reference, see: Cross-Origin Resource Sharing (CORS).

+ + + +

:::

+ + + +

GitHub Export Options

+ + + +

The following additional query parameters may be used to pre-configure the GitHub export form:

+ + + +
    +
  • gh-ensure-auth: If set to yes, Playground will display a modal to ensure the
    user is authenticated with GitHub before proceeding.
  • + + + +
  • ghexport-repo-url: The URL of the GitHub repository to export to.
  • + + + +
  • ghexport-pr-action: The action to take when exporting (create or update).
  • + + + +
  • ghexport-playground-root: The root directory in the Playground to export from.
  • + + + +
  • ghexport-repo-root: The root directory in the repository to export to.
  • + + + +
  • ghexport-content-type: The content type of the export (plugin, theme, wp-content, custom-paths).
  • + + + +
  • ghexport-plugin: Plugin path. When the content type is plugin, pre-select the plugin to export.
  • + + + +
  • ghexport-theme: Theme directory name. When the content type is theme, pre-select the theme to export.
  • + + + +
  • ghexport-path: A path relative to ghexport-playground-root. Can be provided multiple times. When the
    content type is custom-paths, it pre-populates the list of paths to export.
  • + + + +
  • ghexport-commit-message: The commit message to use when exporting.
  • + + + +
  • ghexport-allow-include-zip: Whether to offer an option to include a zip file in the GitHub
    export (yes, no). Optional. Defaults to yes.
  • +
+]]>
+ + 3 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[01-start-here]]> + http://127.0.0.1:9400/?page_id=4 + + admin + + + +

WordPress Playground

+ + + +

:::info Looking for the official Playground website?

+ + + +

WordPress Playground website moved to wordpress.org/playground/. The site you're at now hosts the documentation.

+ + + +

:::

+ + + +

👋 Hi! Welcome to WordPress Playground documentation. Playground is an online tool to experiment and learn about WordPress – learn more in the overview section.

+ + + +

The documentation consists of two major sections:

+ + + +
    +
  • Documentation (you're here) – Introduction, concepts, and guides
  • + + + +
  • API reference – All the APIs exposed by WordPress Playground
  • +
+ + + +

This site (Documentation) is where you will find all the information you need to start using Playground. To learn more about what this fantastic tool, read Introduction to Playground: running WordPress in the browser

+ + + +

Quick start

+ + + + + + + +

Take a deep dive

+ + + +

import APIList from '@site/docs/_fragments/_api_list.mdx';

+ + + + + + + +

Get Involved

+ + + +

WordPress Playground is an open-source project and welcomes all contributors from code to design, and from documentation to triage. Don't worry, you don't need to know WebAssembly to contribute!

+ + + + + + + +

As with all WordPress projects, we want to ensure a welcoming environment for everyone. With that in mind, all contributors are expected to follow our Code of Conduct.

+ + + +

License

+ + + +

WordPress Playground is free software, and is released under the terms of the GNU General Public License version 2 or (at your option) any later version. See LICENSE.md. for complete license.

+ + + +

<br/><br/><p align="center"><img src="https://s.w.org/style/images/codeispoetry.png?1" alt="Code is Poetry." /></p>

+]]>
+ + 4 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[02-start-using]]> + http://127.0.0.1:9400/?page_id=5 + + admin + + + +

import ThisIsQueryApi from '@site/docs/_fragments/_this_is_query_api.md';

+ + + +

Start using WordPress Playground in 5 minutes

+ + + +

WordPress Playground can help you with any of the following:

+ + + +

import TOCInline from '@theme/TOCInline';

+ + + + + + + +

This page will guide you through each of these. Oh, and if you're a visual learner – here's a video:

+ + + + + + + +

Start a new WordPress site

+ + + +

Every time you visit the official demo on playground.wordpress.net, you get a fresh WordPress site.

+ + + +

You can then create pages, upload plugins, themes, import your own site, and do most things you would do on a regular WordPress.

+ + + +

It's that easy to start!

+ + + +

The entire site lives in your browser and is scraped when you close the tab. Want to start over? Just refresh the page!

+ + + +

:::info WordPress Playground is private

+ + + +

Everything you build stays in your browser and is not sent anywhere. Once you're finished, you can export your site as a zip file. Or just refresh the page and start over!

+ + + +

:::

+ + + +

Try a block, a theme, or a plugin

+ + + +

You can upload any plugin or theme you want in /wp-admin/.

+ + + +

To save a few clicks, you can preinstall plugins or themes from the WordPress plugin directory by adding a plugin or theme parameter to the URL. For example, to install the coblocks plugin, you can use this URL:

+ + + +

https://playground.wordpress.net/?plugin=coblocks

+ + + +

Or this URL to preinstall the pendant theme:

+ + + +

https://playground.wordpress.net/?theme=pendant

+ + + +

You can also mix and match these parameters and even add multiple plugins:

+ + + +

https://playground.wordpress.net/?plugin=coblocks&plugin=friends&theme=pendant

+ + + + + + + +

:::info Plugin directory doesn't work in WordPress Playground

+ + + +

Plugins must be installed manually because your WordPress site doesn't send any data to the internet. You won't be able to navigate the WordPress plugin directory inside /wp-admin/. The Query API method may seem to contradict that, but behind the scenes it uses the same plugin upload form as you would.

+ + + +

:::

+ + + +

Save your site

+ + + +

To keep your WordPress Playground site for longer than a single browser session, you can export it as a zip file.

+ + + +

Use the "Export" button in the top bar:

+ + + +
Export button
+ + + +

The exported file contains the complete site you've built. You could host it on any server that supports PHP and SQLite. All WordPress core files, plugins, themes, and everything else you've added to your site are in there.

+ + + +

The SQLite database file is also included in the export, you'll find it wp-content/database/.ht.sqlite. Keep in mind that files starting with a dot are hidden by default on most operating systems so you might need to enable the "Show hidden files" option in your file manager.

+ + + +

Restore a saved site

+ + + +

You can restore the site you saved by using the import button in WordPress Playground:

+ + + +
Import button
+ + + +

Use a specific WordPress or PHP version

+ + + +

The easiest way is to use the version switcher on the official demo site:

+ + + +
WordPress Version switcher
+ + + +

:::info Test your plugin or theme

+ + + +

Compatibility testing with so many WordPres and PHP versions was always a pain. WordPress Playground makes this process effortless – use it to your advantage!

+ + + +

:::

+ + + +

You can also use the wp and php query parameters to open Playground with the right versions already loaded:

+ + + +
    +
  • https://playground.wordpress.net/?wp=6.5
  • + + + +
  • https://playground.wordpress.net/?php=7.4
  • + + + +
  • https://playground.wordpress.net/?php=8.2&wp=6.2
  • +
+ + + + + + + +

:::info Major versions only

+ + + +

You can specify major versions like wp=6.2 or php=8.1 and expect the most recent release in that line. You cannot, however, request older minor versions so neither wp=6.1.2 nor php=7.4.9 will work.

+ + + +

:::

+ + + +

Import a WXR file

+ + + +

You can import a WordPress export file by uploading a WXR file in /wp-admin/.

+ + + +

You can also use JSON Blueprints. See getting started with Blueprints to learn more.

+ + + +

This is different from the import feature described above. The import feature exports the entire site, including the database. This import feature imports a WXR file into an existing site.

+ + + +

Build apps with WordPress Playground

+ + + +

WordPress Playground is programmable which means you can build WordPress apps, setup plugin demos, and even use it as a zero-setup local development environment.

+ + + +

To learn more about developing with WordPress Playground, check out the development quick start section.

+]]>
+ + 5 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[12-limitations]]> + http://127.0.0.1:9400/?page_id=6 + + admin + + + +

Limitations

+ + + +

WordPress Playground is under active development and has some limitations you should keep in mind when running it and developing with it.

+ + + +

You can track the status of these issues on the Playground Project board.

+ + + +

In the browser

+ + + +

Access the Plugins, Themes, Blocks, or Patterns directories

+ + + +

Playground disables network connections by default, blocking access to wp.org assets (themes, plugins, blocks, or patterns) in wp-admin. You can still upload zipped plugin and theme files from your device or enable the option via the Query API or Blueprints API.

+ + + +

Temporary by design

+ + + +

As Playground streams rather than serves WordPress, all database changes and uploads will be gone when you refresh the page. To avoid losing your work, either export your work before or enable storage in the browser/device via the Query API or the UI.

+ + + +

When developing with Playground

+ + + +

Iframe quirks

+ + + +

Playground renders WordPress in an iframe so clicking links with target="_top" will reload the page you’re working on.
Also, JavaScript popups originating in the iframe may not always display.

+ + + +

Run WordPress PHP functions

+ + + +

Playground supports running PHP code in Blueprints using the runPHP step. To run WordPress-specific PHP functions, you’d need to first require wp-load.php:

+ + + +
{
+	"step": "runPHP",
+	"code": ""
+}
+
+ + + +

Using WP-CLI

+ + + +

You can execute wp-cli commands via the Blueprints wp-cli step. However, since Playground runs in the browser, it doesn't support the full array of available commands. While there is no definite list of supported commands, experimenting in the online demo will help you assess what's possible.

+]]>
+ + 6 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[02-code.blockhtml]]> + http://127.0.0.1:9400/?page_id=7 + + admin + + + +

Code contributions

+ + + +

Like all WordPress projects, Playground uses GitHub to manage code and track issues. The main repository is at https://github.com/WordPress/wordpress-playground and the Playground Tools repository is at https://github.com/WordPress/playground-tools/.

+ + + +

:::info Contribute to Playground Tools

+ + + +

This guide includes links to the main repository, but all the steps and options apply for both. If you're interested in the plugins or local development tools—start there.

+ + + +

:::

+ + + +

Browse the list of open issues to find what to work on. The Good First Issue label is a recommended starting point for first-time contributors.

+ + + +

Be sure to review the following resources before you begin:

+ + + + + + + +

Contribute Pull Requests

+ + + +

Fork the Playground repository and clone it to your local machine. To do that, copy and paste these commands into your terminal:

+ + + +
git clone -b trunk --single-branch --depth 1
+
+# replace `YOUR-GITHUB-USERNAME` with your GitHub username:
+git@github.com:YOUR-GITHUB-USERNAME/wordpress-playground.git
+cd wordpress-playground
+npm install
+
+ + + +

Create a branch, make changes, and test it locally by running the following command:

+ + + +
npm run dev
+
+ + + +

Playground will open in a new browser tab and refresh automatically with each change.

+ + + +

When your'e ready, commit the changes and submit a Pull Request.

+ + + +

:::info Formatting

+ + + +

We handle code formatting and linting automatically. Relax, type away, and let the machines do the work.

+ + + +

:::

+ + + +

Running a local Multisite

+ + + +

WordPress Multisite has a few restrictions when run locally. If you plan to test a Multisite network using Playground's enableMultisite step, make sure you either change wp-now's default port or set a local test domain running via HTTPS.

+ + + +

To change wp-now's default port to the one supported by WordPress Multisite, run it using the --port=80 flag:

+ + + +
npx @wp-now/wp-now start --port=80
+
+ + + +

There are a few ways to set up a local test domain, including editing your hosts file. If you're unsure how to do that, we suggest installing Laravel Valet and then running the following command:

+ + + +
valet proxy playground.test http://localhost:5400 --secure
+
+ + + +

Your dev server is now available on https://playground.test.

+ + + +

Debugging

+ + + +

Use VS Code and Chrome

+ + + +

If you're using VS Code and have Chrome installed, you can debug Playground in the code editor:

+ + + +
    +
  • Open the project folder in VS Code.
  • + + + +
  • Select Run > Start Debugging from the main menu or press F5/fn+F5.
  • +
+ + + +

Debugging PHP

+ + + +

Playground logs PHP errors in the browser console after every PHP request.

+]]>
+ + 7 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[03-build-an-app]]> + http://127.0.0.1:9400/?page_id=8 + + admin + + + +

Build an app with WordPress Playground in 5 minutes

+ + + +

WordPress Playground was created as a programmable tool. Below you'll find a few examples of what you can do with it. Each discussed API is described in detail in the APIs section:

+ + + +

import TOCInline from '@theme/TOCInline';

+ + + + + + + +

Embed WordPress on your website

+ + + +

Playground can be embedded on your website using the HTML <iframe> tag as follows:

+ + + +

+
+
+
+

VS Code Playground extension

+ + + +

The Visual Studio Code Playground extension is a friendly zero-setup development environment.

+ + + +
    +
  1. Open VS Code and navigate to the Extensions tab (View > Extensions).
  2. + + + +
  3. In the search bar, type WordPress Playground and click Install.
  4. + + + +
  5. To interact with Playground, click the new icon in the Activity Bar and hit the Start WordPress Server button.
  6. + + + +
  7. A new tab will open in your browser within seconds.
  8. +
+ + + +

wp-now NPM package

+ + + +

@wp-now/wp-now is a CLI tool that allows you to spin up a WordPress site with a single command. No Docker, MySQL, or Apache are required.

+ + + +

Prerequisites

+ + + +

wp-now requires Node.js and NPM. If you haven’t yet, download and install both before you begin.

+ + + +

Depending on the Make WordPress team you contribute to, you may need a different Node.js version than the one you have installed. You can use Node Version Manager (NVM) to switch between versions. Find the installation guide here.

+ + + +

Run wp-now

+ + + +

You don’t have to install wp-now on your device to use it. Navigate to your plugin or theme directory and start wp-now with the following commands:

+ + + +
cd my-plugin-or-theme-directory
+npx @wp-now/wp-now start
+
+ + + +

Ideas for contributors

+ + + +

Create a Gutenberg Pull Request (PR)

+ + + +
    +
  1. Fork the Gutenberg repository in your GitHub account.
  2. + + + +
  3. Then, clone the forked repository to download the files.
  4. + + + +
  5. Install the necessary dependencies and build the code in development mode.
  6. +
+ + + +
git clone git@github.com:WordPress/gutenberg.git
+cd gutenberg
+npm install
+npm run dev
+
+ + + +

:::info

+ + + +

If you’re unsure about the steps listed above, visit the official Gutenberg Project Contributor Guide. Note that in this case, wp-now replaces wp-env.

+ + + +

:::

+ + + +

Open a new terminal terminal tab, navigate to the Gutenberg directory, and start WordPress using wp-now:

+ + + +
cd gutenberg
+npx @wp-now/wp-now start
+
+ + + +

When you’re ready, commit and push your changes to your forked repository on GitHub and open a Pull Request on the Gutenberg repository.

+ + + +

Test a Gutenberg PR

+ + + +
    +
  1. To test other Gutenberg PRs, checkout the branch associated with it.
  2. + + + +
  3. Pull the latest changes to ensure your local copy is up to date.
  4. + + + +
  5. Next, install the necessary dependencies, ensuring your testing environment matches the latest changes.
  6. + + + +
  7. Finally, build the code in development mode.
  8. +
+ + + +
# copy the branch-name from GitHub #
+git checkout branch-name
+git pull
+npm install
+npm run dev
+
+# In a different terminal inside the Gutenberg directory *
+npx @wp-now/wp-now start
+
+ + + +

Test a Gutenberg PR with Playground in the browser

+ + + +

You don’t need a local development environment to test Gutenberg PRs—use Playground to do it directly in the browser.

+ + + +
    +
  1. Copy the ID of the PR you’d like to test (pick one from the list of open Pull Requests).
  2. + + + +
  3. Open Playground’s Gutenberg PR Previewer and paste the ID you copied.
  4. + + + +
  5. Once you click Go, Playground will verify the PR is valid and open a new tab with the relevant PR, allowing you to review the proposed changes.
  6. +
+ + + +

Translate WordPress Plugins with Playground in the browser

+ + + +

You can translate supported WordPress Plugins by loading the plugin you want to translate and use Inline Translation. If the plugin developers have added the option, you'll find the Translate Live link on the top right toolbar of the translation view. You can read more about this exciting new option on this Polyglots blog post.

+ + + +

Get help and contribute to WordPress Playground

+ + + +

Have a question or an idea for a new feature? Found a bug? Something’s not working as expected? We’re here to help:

+ + + + +]]> + + 28 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 + + + <![CDATA[08-browser-concepts.blockhtml]]> + http://127.0.0.1:9400/?page_id=29 + + admin + + + +

Running PHP apps in the browser with ServiceWorkers and Worker Threads

+ + + +

On a high level, WordPress Playground works in web browsers as follows:

+ + + +
    +
  • The index.html file on playground.wordpress.net loads the remote.html file via an <iframe src="/remote.html">.
  • + + + +
  • remote.html starts a Worker Thread and a ServiceWorker and sends back the download progress information.
  • + + + +
  • The Worker Thread starts PHP and populates the filesystem with a WordPress patched to run on SQLite.
  • + + + +
  • The ServiceWorker starts intercepting all HTTP requests and forwarding them to the Worker Thread.
  • + + + +
  • remote.html creates an <iframe src="/index.php">, and the Service Worker forwards the index.php request to the Worker Thread where the WordPress homepage is rendered.
  • +
+ + + +

Visually, it looks like this:

+ + + +
Architecture overview
+ + + +

High-level ideas

+ + + +

The @php-wasm/web is built on top of the following ideas:

+ + + +
    +
  • Browser tab orchestrates everything – The browser tab is the main program. Closing or reloading it means destroying the entire execution environment.
  • + + + +
  • Iframe-based rendering – Every response produced by the PHP server must be rendered in an iframe to avoid reloading the browser tab when the user clicks on a link.
  • + + + +
  • PHP Worker Thread – The PHP server is slow and must run in a web worker, otherwise handling requests freezes the website UI.
  • + + + +
  • Service Worker routing – All HTTP requests originating in that iframe must be intercepted by a Service worker and passed on to the PHP worker thread for rendering.
  • +
+]]>
+ + 29 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[03-coding-standards.blockhtml]]> + http://127.0.0.1:9400/?page_id=30 + + admin + + + +

Coding principles

+ + + +

Error messages

+ + + +

A good error message tells the user what to do next. Any ambiguity in errors thrown by Playground public APIs will prompt the developers to open issues.

+ + + +

Consider a network error, for example—can we infer the type of error and display a relevant message summarizing the next steps?

+ + + +
    +
  • Network error: "Your internet connection twitched. Try to reload the page.
  • + + + +
  • 404: "Could not find the file".
  • + + + +
  • 403: "The server blocked access to the file".
  • + + + +
  • CORS: clarify it's a browser security feature and add a link to a detailed explanation (on MDN or another reliable source). Suggest the user move their file somewhere else, like raw.githubusercontent.com, and link to a resource explaining how to set up CORS headers on their servers.
  • +
+ + + +

We handle code formatting and linting automatically. Relax, type away, and let the machines do the work.

+ + + +

Public API

+ + + +

Playground aims to keep the narrowest possible API scope.

+ + + +

Public APIs are easy to add and hard to remove. It only takes one PR to introduce a new API, but it may take a thousand to remove it, especially if other projects have already consumed it.

+ + + +
    +
  • Don't expose unnecessary function, class, constant, or other components.
  • +
+ + + +

Blueprints

+ + + +

Blueprints are the primary way to interact with Playground. These JSON files describe a set of steps that Playground executes in order.

+ + + +

Guidelines

+ + + +

Blueprint steps should be concise and focused. They should do one thing and do it well.

+ + + +
    +
  • If you need to create a new step, try refactoring an existing one first.
  • + + + +
  • If that's not enough, ensure the new step delivers a new capability. Don't replicate the functionality of existing steps.
  • + + + +
  • Assume the step would be called more than once.
  • + + + +
  • Assume it would run in a specific order.
  • + + + +
  • Add unit tests to verify that.
  • +
+ + + +

Blueprints should be intuitive and straightforward.

+ + + +
    +
  • Don't require arguments that can be optional.
  • + + + +
  • Use plain argument. For example, slug instead of path.
  • + + + +
  • Define constants in virtual JSON files—don't modify PHP files.
  • + + + +
  • Define a TypeScript type for the Blueprint. That's how Playground generates its JSON schema.
  • + + + +
  • Write a function to handle a Blueprint step. Accept the argument of the type you defined.
  • + + + +
  • Provide a usage example in the doc string. It's automatically reflected in the docs.
  • +
+]]>
+ + 30 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[02-wasm-php-overview.blockhtml]]> + http://127.0.0.1:9400/?page_id=31 + + admin + + + +

WebAssembly PHP

+ + + +

WordPress Playground build the PHP interpreter to WebAssembly using Emscripten and a dedicated pipeline.

+ + + +
Building C programs to WebAssembly
+ + + +

Building PHP to WebAssembly is very similar to building vanilla PHP. The wasm build required adjusting a function signature here, forcing a config variable there, and applying a few small patches, but there's relatively few adjustments involved.

+ + + +
Building PHP to WebAssembly
+ + + +

However, vanilla PHP builds aren't very useful in the browser. As a server software, PHP doesn't have a JavaScript API to pass the request body, upload files, or populate the php://stdin stream. WordPress Playground had to build one from scratch. The WebAssembly binary comes with a dedicated PHP API module written in C and a JavaScript PHP class that exposes methods like writeFile() or run().

+ + + +

Because every PHP version is just a static .wasm file, the PHP version switcher is actually pretty boring. It simply tells the browser to download, for example, php_7_3.wasm instead of, say, php_8_2.wasm.

+ + + +
Building different versions of PHP to WebAssembly
+ + + +

Networking support varies between platforms

+ + + +

When it comes to networking, WebAssembly programs are limited to calling JavaScript APIs. It is a safety feature, but also presents a challenge. How do you support low-level, synchronous networking code used by PHP with the high-level asynchronous APIs available in JavaScript?

+ + + +

In Node.js, the answer involves a WebSocket to TCP socket proxy, Asyncify, and patching deep PHP internals like php_select. It's complex, but there's a reward. The Node.js-targeted PHP build can request web APIs, install composer packages, and even connect to a MySQL server.

+ + + +

In the browser, networking is supported to a limited extent. Network calls initiated using wp_safe_remote_get, like the ones in the plugin directory or the font library, are translated into fetch() calls and succeed if the remote server sends the correct CORS headers. However, a full support for arbitrary HTTPS connection involves opening a raw TCP socket which is not possible in the browser. There is an open GitHub issue that explores possible ways of addressing this problem.

+]]>
+ + 31 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[17-browser-wordpress.blockhtml]]> + http://127.0.0.1:9400/?page_id=32 + + admin + + + +

Bundling WordPress for the browser

+ + + +

The web bundler Dockerfile turns a vanilla WordPress into a browser-optimized one:

+ + + +
    +
  • Makes WordPress run on SQLite using the official drop-in plugin as MySQL is unsupported in the browser.
  • + + + +
  • Reduces the WordPress website size from about 70MB to about 10MB, or 5MB compressed.
  • + + + +
  • Runs the WordPress installation wizard.
  • + + + +
  • Bundles WordPress as a data dependency
  • +
+ + + +

Build a new bundle with nx bundle-wordpress playground-wordpress-builds --wp-version=<version>, e.g.:

+ + + +
nx bundle-wordpress playground-wordpress-builds --wp-version=6.1
+
+ + + +

The bundler outputs:

+ + + +
    +
  • packages/playground/wordpress-builds/public/wp-6.1.zip – zipped WordPress files
  • + + + +
  • packages/playground/wordpress-builds/public/wp-6.1/ – a directory with static assets for the specified WordPress versions
  • +
+ + + +

Consult the web bundler Dockerfile for more details (like the list of supported WordPress versions) and modify it to customize the default WordPress installation.

+]]>
+ + 32 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[03-php-wasm-node.blockhtml]]> + http://127.0.0.1:9400/?page_id=33 + + admin + + + +

Using WordPress Playground in Node.js

+ + + +

As a WebAssembly project, you can also use WordPress Playground in Node.js.

+ + + +

If you need low-level control over the underlying WebAssembly PHP build, take a look at the @php-wasm/node package which ships the PHP WebAssembly runtime. This package is at the core of all WordPress Playground tools for Node.js.

+ + + +

:::info API reference

+ + + +

Consult the complete list of Classes, Functions, Interfaces, and Type Aliases.

+ + + +

:::

+ + + +

import PHPWASMNode from '@php-wasm/node/\README.md';

+ + + + +]]>
+ + 33 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + 0000-00-00 00:00:00 + open + open + + publish + 0 + 0 + page + + 0 +
+ + <![CDATA[02-using-blueprints.blockhtml]]> + http://127.0.0.1:9400/?page_id=34 + + admin + + + +

Using Blueprints

+ + + +

You can use Blueprints in one of two ways:

+ + + +
    +
  • By passing them as a URL fragment to the Playground.
  • + + + +
  • By using the JavaScript API.
  • +
+ + + +

URL Fragment

+ + + +

The easiest way to start using Blueprints is to paste one into the URL "fragment" on WordPress Playground website, e.g. https://playground.wordpress.net/#{"preferredVersions....

+ + + +

For example, to create a Playground with specific versions of WordPress and PHP you would use the following Blueprint:

+ + + +
{
+	"$schema": "https://playground.wordpress.net/blueprint-schema.json",
+	"preferredVersions": {
+		"php": "7.4",
+		"wp": "6.5"
+	}
+}
+
+ + + +

And then you would go to
https://playground.wordpress.net/#{"preferredVersions": {"php":"7.4", "wp":"6.5"}}.

+ + + +

You won't have to paste links to follow along. We'll use code examples with a "Try it out" button that will automatically run the examples for you:

+ + + +

import BlueprintExample from '@site/src/components/Blueprints/BlueprintExample.mdx';

+ + + +

"preferredVersions": {
"php": "7.4",
"wp": "6.5"
}
}} />

+ + + +

Base64 encoded Blueprints

+ + + +

Some tools, including GitHub, might not format the Blueprint correctly when pasted into the URL. In such cases, encode your Blueprint in Base64 and append it to the URL. For example, that's the above Blueprint in Base64 format: eyIkc2NoZW1hIjogImh0dHBzOi8vcGxheWdyb3VuZC53b3JkcHJlc3MubmV0L2JsdWVwcmludC1zY2hlbWEuanNvbiIsInByZWZlcnJlZFZlcnNpb25zIjogeyJwaHAiOiAiNy40Iiwid3AiOiAiNi41In19.

+ + + +

To run it, go to https://playground.wordpress.net/#eyIkc2NoZW1hIjogImh0dHBzOi8vcGxheWdyb3VuZC53b3JkcHJlc3MubmV0L2JsdWVwcmludC1zY2hlbWEuanNvbiIsInByZWZlcnJlZFZlcnNpb25zIjogeyJwaHAiOiAiNy40Iiwid3AiOiAiNi41In19

+ + + +

Load Blueprint from a URL

+ + + +

When your Blueprint gets too wieldy, you can load it via the ?blueprint-url query parameter in the URL, like this:

+ + + +

https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/adamziel/blueprints/trunk/blueprints/latest-gutenberg/blueprint.json

+ + + +

Note that the Blueprint must be publicly accessible and served with the correct Access-Control-Allow-Origin header:

+ + + +
Access-Control-Allow-Origin: *
+
+ + + +

JavaScript API

+ + + +

You can also use Blueprints with the JavaScript API using the startPlaygroundWeb() function from the @wp-playground/client package. Here's a small, self-contained example you can run on JSFiddle or CodePen:

+ + + +