Skip to content

[Website] Embeddable PHP code snippets via <php-snippet> - #3528

Merged
adamziel merged 5 commits into
trunkfrom
adamziel/php-snippet-embed
Apr 27, 2026
Merged

[Website] Embeddable PHP code snippets via <php-snippet>#3528
adamziel merged 5 commits into
trunkfrom
adamziel/php-snippet-embed

Conversation

@adamziel

@adamziel adamziel commented Apr 25, 2026

Copy link
Copy Markdown
Collaborator

Adds a runnable PHP code snippet web component:

CleanShot.2026-04-25.at.17.45.39.mp4

Here's how to use it:

<script type="module" src="https://playground.wordpress.net/php-code-snippet.js"></script>

<php-snippet name="lazy-load-images.php">
  <script type="application/x-php">
<?php
require '/wordpress/wp-load.php';
$tags = new WP_HTML_Tag_Processor( '<img src="hero.jpg">' );
while ( $tags->next_tag( 'img' ) ) {
    $tags->set_attribute( 'loading', 'lazy' );
}
echo $tags->get_updated_html();
  </script>
</php-snippet>

The script is around 5 KB gzipped and contains no PHP or WordPress — those are downloaded only on the first Run click. Multiple snippets on the same page share a single hidden Playground iframe, so a docs page with five examples pays the runtime cost once instead of five times.

There is no code editor shipped with this PR, just a tiny tokenizer/syntax highlighter.

The progress bar that shows up during boot is the real staged progress drawn from the live events Playground emits internally, so visitors see the same captions ("Preparing WordPress", download progress, blueprint steps) they'd see in the standalone PHP Playground at /php-playground.html.

Try it

Run npm run dev and open http://127.0.0.1:5400/website-server/php-code-snippet-demo.html. Three snippets, one shared runtime — open the Network tab and watch the second and third Run clicks reuse what the first one downloaded.

What's in here

  • The <php-snippet> web component (packages/playground/website/public/php-code-snippet.js) and a demo page next to it.
  • Playwright coverage for boot, progress, output, and runtime sharing — picked up automatically by the existing test-e2e-playwright CI job.
  • A new guide page (/guides/php-code-snippets) that documents both the embed and the standalone PHP Playground at /php-playground.html — the latter previously had no docs at all. Linked prominently from the Guides index.

Notes for reviewers

The component duck-types a ProgressTracker so it can subscribe to staged progress events. The published /client/index.js doesn't export the real ProgressTracker class today; once it does, the inline copy can be replaced with an import. Worth a small follow-up.

Test plan

  • CI test-e2e-playwright (Chromium / Firefox / WebKit) passes the three new tests.
  • Open the demo page locally, click Run on the first snippet, watch the staged progress + output, then click Run on the other two and confirm they reuse the runtime (no extra network requests for WP/PHP).
  • Browse to /guides/php-code-snippets in the docs site, verify the page renders and the sidebar entry sits at the top of Guides.
Drop one script tag on any page and you can embed runnable PHP — and
the full WordPress runtime — as inline, syntax-highlighted snippets.
Multiple snippets share a single hidden Playground iframe, so a docs
page with five examples downloads the runtime once instead of five
times. The runtime only boots on the first Run click; until then the
page costs nothing more than a few KB of JS.

The bar that appears during boot is the real staged progress drawn
from the live events Playground emits internally, so visitors see the
same captions ("Preparing WordPress", download progress, blueprint
steps) they would in the standalone PHP Playground.

Includes Playwright coverage that exercises the boot-then-reuse path
across three snippets, and a guide page that documents both the new
embed and the standalone PHP Playground at /php-playground.html.
@adamziel
adamziel requested review from a team, Copilot and zaerl April 25, 2026 00:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds an embeddable <php-snippet> web component that lazy-loads a shared WordPress Playground runtime to run and syntax-highlight PHP snippets, plus demo/docs and Playwright E2E coverage.

Changes:

  • Introduces php-code-snippet.js custom element with shared runtime boot + progress tracking and a small PHP syntax highlighter.
  • Adds a demo HTML page and Playwright E2E tests validating progress, output, and runtime reuse.
  • Documents the embed + standalone PHP Playground and links the guide prominently in the docs sidebar/index.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
packages/playground/website/public/php-code-snippet.js Implements <php-snippet> component, shared runtime boot/progress, and syntax highlighting.
packages/playground/website/public/php-code-snippet-demo.html Adds a local demo page with three example snippets.
packages/playground/website/playwright/e2e/php-code-snippet.spec.ts Adds E2E tests for rendering, progress/output, and runtime sharing.
packages/docs/site/sidebars.js Adds the new guide to the Guides sidebar.
packages/docs/site/docs/main/guides/php-code-snippets.md Documents embedding via <php-snippet> and the standalone PHP Playground.
packages/docs/site/docs/main/guides/index.md Links to the new guide at the top of the Guides index.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/playground/website/public/php-code-snippet.js Outdated
Comment thread packages/playground/website/public/php-code-snippet.js Outdated
Comment thread packages/playground/website/public/php-code-snippet.js Outdated
Comment thread packages/playground/website/public/php-code-snippet.js Outdated
Comment thread packages/playground/website/public/php-code-snippet.js Outdated
Comment thread packages/playground/website/public/php-code-snippet.js Outdated
Comment thread packages/playground/website/public/php-code-snippet.js Outdated
Comment thread packages/playground/website/public/php-code-snippet.js
Comment thread packages/playground/website/public/php-code-snippet.js
Comment thread packages/playground/website/public/php-code-snippet.js Outdated
@adamziel
adamziel marked this pull request as draft April 25, 2026 00:14
Three things came back from the review and they were all fair:

The shared-runtime cache used a single global slot. If two snippets on
the same page asked for different {origin, php, wp} combinations, the
key bookkeeping could get crossed and a snippet might receive the wrong
runtime — or its progress events would leak across boots. Replaced the
single slot with a Map keyed by the runtime triple, with each entry
carrying its own tracker, subscribers, and client. One runtime per
unique combination, no cross-talk.

When a snippet loads its code via the src attribute, a 4xx/5xx response
was treated as snippet code (usually an HTML error page). Now it throws
with status, statusText, and the URL so the failure shows up clearly in
the output panel.

Render used innerHTML += on the shadow root, which serializes and
reparses the previous content. Switched to building the markup in a
template and appending the document fragment, so the style node and any
existing handlers stay intact. Added aria-live="polite" and
aria-atomic="true" on the progress region so screen readers announce
caption and percent updates.
The progress-event dispatch was using a `const self = this` alias that
tripped no-this-alias. The lazy getters were carry-over habit from the
upstream ProgressTracker — for a one-shot CustomEvent the values at
dispatch time are what subscribers see anyway, so the detail object
reads them directly off `this` instead.

While in there, fixed a related leak Copilot hinted at: if the runtime
boot threw, the entry sat in the cache with a rejected promise and
every subsequent Run would re-await the same rejection forever. The
entry now drops itself on failure, so the next Run gets a fresh attempt.
@adamziel

Copy link
Copy Markdown
Collaborator Author

@fellyph this adds a docusaurus doc page – is there a https://wordpress.org/ URL where I should also add it?

Clarified the comparison between Standalone PHP Playground and <php-snippet> in the documentation.
@adamziel
adamziel marked this pull request as ready for review April 27, 2026 14:25
@adamziel adamziel changed the title Embeddable PHP code snippets via <php-snippet> Apr 27, 2026
@adamziel
adamziel merged commit 3f4fd14 into trunk Apr 27, 2026
47 checks passed
@adamziel
adamziel deleted the adamziel/php-snippet-embed branch April 27, 2026 14:28
adamziel added a commit that referenced this pull request Apr 27, 2026
Stacked on #3528.

Two changes for the `<php-snippet>` web component:

## 1. Editable snippets

Add `editable` to make a snippet a tiny inline playground. Visitors type
into a transparent textarea overlaid on the highlighted code; syntax
colors update as they go; Run executes whatever's currently in the
textarea.

```html
<php-snippet name="scratch.php" editable>
  <script type="application/x-php">
<?php
$nums = range(1, 10);
echo "Sum: " . array_sum($nums);
  </script>
</php-snippet>
```

No CodeMirror, no Monaco, no extra dependency — ~50 lines added to the
component, opt-in. Tab inserts a tab character so it actually feels like
an editor. Edits live only in the page; refresh resets to the initial
code.

## 2. Better PHP tokenizer

The regex highlighter previously bailed on heredoc/nowdoc and didn't
know about backticks or PHP 8 attributes. Now it handles:

- **Backtick** shell-exec strings (``` `…` ```) — same escape rules as
`"…"`.
- **Heredoc** (`<<<EOT … EOT;`) and **nowdoc** (`<<<'EOT' … EOT;`),
including PHP 7.3+ indented closers.
- **`#[Attribute]`** (PHP 8) — no longer eaten as a `#` line comment.
- Single, double, and backtick quotes share one `scanQuoted` helper that
correctly skips `\\`, `\"`, `\'`, etc., and tolerates unterminated
strings without overshooting.

## Try it

Run `npm run dev` and open
http://127.0.0.1:5400/website-server/php-code-snippet-demo.html — the
demo includes an editable snippet and a snippet exercising
heredoc/backticks/attributes.

## Test plan

- [ ] CI passes including the new editable-runs-typed-code Playwright
test.
- [ ] In the demo page, type into the editable snippet, see colors
update, click Run, see your output.
- [ ] Confirm the three non-editable snippets render unchanged.
- [ ] Snippets containing heredoc, backticks, or `#[Attribute]`
highlight correctly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2 participants