Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,56 @@ jobs:
name: bibliography-release
path: output/release/borges-bibliography-builder.zip
if-no-files-found: error

# Publish the packaged main build to a rolling `main-preview` pre-release so
# WordPress Playground has a stable, CORS-reachable URL for the current main
# HEAD (git:directory is unavailable in live Playground). Isolated in its own
# job so the write-scoped token is never present during checkout/build/package
# (and never on pull_request or codex/** runs), gated behind the full required
# CI suite so the Main-build badge can't install a build from a run that later
# failed, and reuses the exact artifact those gates validated.
publish-main-preview:
name: Publish rolling main preview
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs:
- quality
- phpunit
- playwright-playground
- psalm
- package-release
permissions:
contents: write

steps:
- name: Download packaged plugin artifact
uses: actions/download-artifact@v6
with:
name: bibliography-release
path: output/release

# Guard against a slower older run overwriting `main-preview` with a
# stale ZIP. The tip re-check and the asset write live in ONE step so
# the check happens immediately before the upload (minimal TOCTOU
# window): if `main` has advanced past this commit, skip — the newer
# run publishes. Correct regardless of job-scheduling order, unlike
# job-level concurrency (which can cancel the newer run instead).
- name: Publish rolling main preview
# This job has no checkout, so gh cannot infer the repo from a local
# git remote; GH_REPO gives `gh release`/`gh api` their repo context.
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
tip="$(gh api "repos/${{ github.repository }}/commits/main" --jq .sha)"
if [ "$tip" != "${{ github.sha }}" ]; then
echo "::notice::main advanced to ${tip}; skipping stale main-preview publish for ${{ github.sha }}"
exit 0
fi
if ! gh release view main-preview >/dev/null 2>&1; then
Comment thread
dknauss marked this conversation as resolved.
gh release create main-preview \
--prerelease \
--title "Main branch preview (rolling)" \
--notes "Automated rolling build of the \`main\` branch, refreshed on every push. This is **not** a stable release — for production use install the latest tagged release or the WordPress.org listing."
fi
gh release upload main-preview output/release/borges-bibliography-builder.zip --clobber
22 changes: 22 additions & 0 deletions .github/workflows/demo-links.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Demo Link Monitor

# Verifies the Playground demo blueprints' install URLs stay reachable and never
# regress to the browser-broken `git:directory` resource. Scheduled (external
# release assets can rot over time) plus manual dispatch. Not run on PRs — the
# structural blueprint contract is already covered by src/blueprint.test.js.

on:
schedule:
- cron: '17 9 * * 1' # Mondays 09:17 UTC
workflow_dispatch:

permissions:
contents: read

jobs:
check-demo-links:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- name: Check demo install URLs resolve
run: sh ./scripts/check-demo-links.sh
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add a second WordPress Playground demo that boots the current `main` branch build, alongside the existing released-version demo. CI publishes the freshly built plugin to a rolling `main-preview` pre-release so live Playground has a stable, CORS-reachable URL for main HEAD; the README exposes both as separate Playground badges.
- Add a scheduled Demo Link Monitor (`demo-links.yml` / `npm run test:demo-links`) that verifies each Playground blueprint's install URL stays reachable and guards against reintroducing the hosted-browser-broken `git:directory` resource.

## [1.4.2] - 2026-06-21

### Added
Expand Down
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ A Gutenberg block plugin that accepts DOI identifiers, PubMed/PMID records, BibT

### Playground

The Playground blueprint at `playground/blueprint.json` configures the GitHub/readme demo. It installs the latest GitHub Release ZIP through the WordPress Playground CORS proxy, installs Block Accessibility Checks from WordPress.org, and requires both `"phpExtensionBundles": ["kitchen-sink"]` and `features.intl` for the CSL formatter. The WordPress.org Preview blueprint at `.wordpress-org/blueprints/blueprint.json` is separate; WordPress.org installs Borges automatically there. The E2E tests (`npm run test:e2e:playground`) run against the GitHub/readme blueprint.
The Playground blueprint at `playground/blueprint.json` configures the GitHub/readme demo (released version). It installs the latest GitHub Release ZIP through the WordPress Playground CORS proxy, installs Block Accessibility Checks from WordPress.org, and requires both `"phpExtensionBundles": ["kitchen-sink"]` and `features.intl` for the CSL formatter. A second blueprint at `playground/blueprint-main.json` powers the README "Main build" badge: it installs the `main-preview` rolling pre-release ZIP that CI's `publish-main-preview` job refreshes on every push to `main` — after the full CI suite passes and only when the commit is still `main`'s tip (live Playground can't use `git:directory`, so a stable release asset is how main HEAD boots). The WordPress.org Preview blueprint at `.wordpress-org/blueprints/blueprint.json` is separate; WordPress.org installs Borges automatically there. The E2E tests (`npm run test:e2e:playground`) run against the GitHub/readme blueprint.

### Release

Expand All @@ -108,3 +108,4 @@ The Playground blueprint at `playground/blueprint.json` configures the GitHub/re
- **release.yml** — tag-triggered GitHub Release and ZIP publication
- **wp-deploy.yml** — deploys to WordPress.org SVN on published GitHub release, release dispatch, or manual run
- **codeql.yml** — security analysis
- **demo-links.yml** — scheduled/manual check that Playground demo blueprint install URLs stay reachable and never regress to the browser-broken `git:directory` resource
22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
[![Runtime matrix](https://github.com/dknauss/Borges/actions/workflows/runtime-matrix.yml/badge.svg)](https://github.com/dknauss/Borges/actions/workflows/runtime-matrix.yml)
[![CodeQL](https://github.com/dknauss/Borges/actions/workflows/codeql.yml/badge.svg)](https://github.com/dknauss/Borges/actions/workflows/codeql.yml)
[![codecov](https://codecov.io/gh/dknauss/Borges/branch/main/graph/badge.svg?token=2MSXL46VTF)](https://codecov.io/gh/dknauss/Borges)
[![WordPress Playground](https://img.shields.io/badge/WordPress%20Playground-Try%20it-3858e9.svg?logo=wordpress&logoColor=white)](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/dknauss/Borges/main/playground/blueprint.json)
[![Playground: Release](https://img.shields.io/badge/Playground-Release-3858e9.svg?logo=wordpress&logoColor=white)](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/dknauss/Borges/main/playground/blueprint.json)
[![Playground: Main build](https://img.shields.io/badge/Playground-Main%20build-8858e9.svg?logo=wordpress&logoColor=white)](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/dknauss/Borges/main/playground/blueprint-main.json)
[![WordPress.org](https://img.shields.io/badge/WordPress.org-Install-21759b.svg?logo=wordpress&logoColor=white)](https://wordpress.org/plugins/borges-bibliography-builder/)

Borges Bibliography Builder is named after Jorge Luis Borges (1899–1986), the Argentine writer, essayist, poet, and librarian whose work imagined infinite libraries, invented books, and self-referential labyrinths.
Expand All @@ -22,9 +23,12 @@ Just write out your citations or paste DOIs, PubMed/PMID identifiers, and BibTeX

## Try it in WordPress Playground

Install the public release from [WordPress.org](https://wordpress.org/plugins/borges-bibliography-builder/) or launch a disposable WordPress instance with the plugin preinstalled: [Try the Borges Bibliography Builder in WordPress Playground](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/dknauss/Borges/main/playground/blueprint.json).
Install the public release from [WordPress.org](https://wordpress.org/plugins/borges-bibliography-builder/), or launch a disposable WordPress instance with the plugin preinstalled — no setup, no database, and gone when you close the tab. Two Playground demos are available:

The GitHub-hosted demo Blueprint installs the latest GitHub Release ZIP through the WordPress Playground CORS proxy and explicitly requests PHP `intl` support because editor-time CSL formatting runs through the plugin's local PHP formatter. The WordPress.org Preview blueprint is separate; WordPress.org installs Borges automatically there, and the blueprint only seeds demo content and auxiliary plugin setup.
- **[Try the released version](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/dknauss/Borges/main/playground/blueprint.json)** — installs the latest GitHub Release ZIP (the same build published to WordPress.org) through the WordPress Playground CORS proxy. Use this to try the current stable plugin.
- **[Try the current main build](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/dknauss/Borges/main/playground/blueprint-main.json)** — installs the development build of the `main` branch from the rolling `main-preview` pre-release, which CI refreshes on every push to `main`. Use this to preview unreleased changes ahead of the next release; it is not a stable build.

Both demo Blueprints explicitly request PHP `intl` support because editor-time CSL formatting runs through the plugin's local PHP formatter. The WordPress.org Preview blueprint is separate; WordPress.org installs Borges automatically there, and the blueprint only seeds demo content and auxiliary plugin setup.

## Screenshots

Expand Down Expand Up @@ -259,21 +263,23 @@ Multisite runtime smoke coverage is included in CI. SQLite is not currently part
- [GitHub releases](https://github.com/dknauss/Borges/releases)
- [Release readiness checklist](./docs/release-readiness-checklist.md)
- [WordPress.org SVN deploy checklist](./docs/wporg-svn-checklist.md) — maintainer-facing notes
- [Playground blueprint](./playground/blueprint.json) — GitHub demo Blueprint; keep its `features.intl` and `phpExtensionBundles` settings aligned with `.wordpress-org/blueprints/blueprint.json` for WordPress.org previews.
- [Playground blueprint](./playground/blueprint.json) — GitHub demo Blueprint (released version); keep its `features.intl` and `phpExtensionBundles` settings aligned with `.wordpress-org/blueprints/blueprint.json` for WordPress.org previews.
- [Playground main-build blueprint](./playground/blueprint-main.json) — GitHub demo Blueprint that runs the current `main` branch from the rolling `main-preview` pre-release.
- [Runtime matrix smoke script](./scripts/runtime-matrix/smoke.sh)
- [Brand assets](./.wordpress-org/)

WordPress.org branding assets live in [.wordpress-org](./.wordpress-org/), editable source files live in [.wordpress-org/source](./.wordpress-org/source/), and maintainer-facing deploy notes live in [docs/wporg-svn-checklist.md](./docs/wporg-svn-checklist.md).

### Playground Blueprint maintenance

The Playground demo and WordPress.org Preview both rely on the PHP formatter used by the editor REST endpoint. That formatter uses `citeproc-php`, which requires PHP `intl`. Keep both Blueprint files in sync:
The Playground demos and WordPress.org Preview all rely on the PHP formatter used by the editor REST endpoint. That formatter uses `citeproc-php`, which requires PHP `intl`. Keep the Blueprint files in sync:

- `playground/blueprint.json` powers the GitHub README and WordPress.org readme demo link; it installs the latest GitHub Release ZIP through the WordPress Playground CORS proxy so the demo exercises the packaged release artifact without direct GitHub asset CORS failures.
- `playground/blueprint.json` powers the GitHub README (Release badge) and WordPress.org readme demo link; it installs the latest GitHub Release ZIP through the WordPress Playground CORS proxy so the demo exercises the packaged release artifact without direct GitHub asset CORS failures.
- `playground/blueprint-main.json` powers the GitHub README Main-build badge; it installs the `borges-bibliography-builder.zip` asset from the rolling `main-preview` pre-release through the same CORS proxy. CI's `publish-main-preview` job refreshes that pre-release on every push to `main` — after the full CI suite passes, and only when the commit is still `main`'s tip — while the `package-release` job just builds and uploads the artifact it consumes (`git:directory` is unavailable in live Playground, so a stable release asset is the reliable way to boot main HEAD).
- `.wordpress-org/blueprints/blueprint.json` deploys to WordPress.org SVN as `assets/blueprints/blueprint.json` for the plugin-directory Preview button. WordPress.org installs the plugin automatically in that preview, so this blueprint does not install Borges itself.
- Both files intentionally declare `phpExtensionBundles: ["kitchen-sink"]` and `features: { "networking": true, "intl": true }`. The bundle form follows WordPress.org Preview documentation; the `features.intl` flag is required by the live browser Playground runtime so formatter requests do not fall back with `bibliography_builder_formatter_extension_missing`.
- All three files intentionally declare `phpExtensionBundles: ["kitchen-sink"]` and `features: { "networking": true, "intl": true }`. The bundle form follows WordPress.org Preview documentation; the `features.intl` flag is required by the live browser Playground runtime so formatter requests do not fall back with `bibliography_builder_formatter_extension_missing`.
Comment thread
dknauss marked this conversation as resolved.

Run `npm run test -- --runTestsByPath src/blueprint.test.js` after editing either Blueprint.
Run `npm run test -- --runTestsByPath src/blueprint.test.js` after editing any Blueprint.

### Plugin File Structure

Expand Down
2 changes: 1 addition & 1 deletion SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -985,7 +985,7 @@ SQLite is not currently part of the GitHub runtime matrix. Future runtime work s

`citation-js` remains the best fit for BibTeX parsing and fallback DOI support in the editor. Primary browser DOI resolution uses CrossRef's CSL transform endpoint directly because that path works in WordPress Playground without `doi.org` content-negotiation redirects. Formatting is handled by `citeproc-php` on a local WordPress REST endpoint so the editor bundle does not include citeproc-js and the WordPress.org package can avoid non-GPL-compatible CSL/citeproc-js licensing concerns. The block still saves static plain-text output in post content; PHP formatting is an editor-time service, not a frontend render callback.

Because formatter requests depend on `citeproc-php`, any WordPress Playground demo that exercises editor formatting must load PHP `intl`. Keep both `playground/blueprint.json` and `.wordpress-org/blueprints/blueprint.json` configured with both `phpExtensionBundles: ["kitchen-sink"]` and `features: { "networking": true, "intl": true }`. The bundle form matches WordPress.org Preview guidance, while the explicit `features.intl` flag is required by the live browser Playground runtime to avoid `bibliography_builder_formatter_extension_missing` fallback notices.
Because formatter requests depend on `citeproc-php`, any WordPress Playground demo that exercises editor formatting must load PHP `intl`. There are three Blueprints: `playground/blueprint.json` (README "Release" badge — latest GitHub Release ZIP via the CORS proxy), `playground/blueprint-main.json` (README "Main build" badge — the rolling `main-preview` pre-release ZIP that CI's `publish-main-preview` job refreshes on every push to `main`, after the full CI suite passes and only when the commit is still `main`'s tip), and `.wordpress-org/blueprints/blueprint.json` (WordPress.org Preview button). Keep all three configured with both `phpExtensionBundles: ["kitchen-sink"]` and `features: { "networking": true, "intl": true }`. The bundle form matches WordPress.org Preview guidance, while the explicit `features.intl` flag is required by the live browser Playground runtime to avoid `bibliography_builder_formatter_extension_missing` fallback notices. Live browser Playground cannot use `git:directory` (WordPress/wordpress-playground#3875), which is why the main build ships as a rolling release asset.

### Why the editor uses wrapped `@wordpress/icons` imports

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"test:e2e": "sh ./scripts/test-smoke-e2e.sh",
"test:e2e:playground": "sh ./scripts/test-playground-e2e.sh",
"test:e2e:lifecycle": "sh ./scripts/test-lifecycle-e2e.sh",
"test:demo-links": "sh ./scripts/check-demo-links.sh",
"test:runtime:local": "sh ./scripts/runtime-matrix/smoke.sh",
"test:interop:zotero": "sh ./scripts/test-zotero-interop.sh",
"test:a11y": "sh ./scripts/test-a11y.sh",
Expand Down
48 changes: 48 additions & 0 deletions playground/blueprint-main.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"$schema": "https://playground.wordpress.net/blueprint-schema.json",
"meta": {
"title": "Borges Bibliography Builder (main build)",
"description": "Launch WordPress Playground with the current development build of the Borges Bibliography Builder plugin from the main branch.",
"author": "danknauss",
"categories": ["plugin", "bibliography", "block-editor"]
},
"landingPage": "/wp-admin/post.php?post=1&action=edit",
"preferredVersions": {
"php": "8.3",
"wp": "latest"
},
"phpExtensionBundles": ["kitchen-sink"],
"features": {
"networking": true,
"intl": true
},
"login": true,
"steps": [
{
"step": "installPlugin",
"pluginData": {
"resource": "url",
"url": "https://wordpress-playground-cors-proxy.net/?https://github.com/dknauss/Borges/releases/download/main-preview/borges-bibliography-builder.zip"
},
"options": {
"activate": true,
"targetFolderName": "borges-bibliography-builder"
},
"ifAlreadyInstalled": "overwrite"
},
{
"step": "installPlugin",
"pluginData": {
"resource": "wordpress.org/plugins",
"slug": "block-accessibility-checks"
},
"options": {
"activate": true
}
},
{
"step": "runPHP",
"code": "<?php\nrequire_once '/wordpress/wp-load.php';\n\n$post_content = <<<'EOT'\n<!-- wp:paragraph -->\n<p><strong>Welcome to the Borges Bibliography Builder development build.</strong> This Playground runs the current <code>main</code> branch, not a stable release. Use the Bibliography block below, then paste one or more sample entries into the <em>Paste / Import</em> field (separate entries with a blank line).</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code>10.1145/3368089.3409742\n\n10.1038/s41586-020-2649-2\n\nPMID:26673779\n\n@article{knuth1984literate,\n author = {Knuth, Donald E.},\n title = {Literate Programming},\n journal = {The Computer Journal},\n year = {1984},\n volume = {27},\n number = {2},\n pages = {97--111},\n doi = {10.1093/comjnl/27.2.97}\n}</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>Tip: In the block sidebar, try changing citation style and export actions (CSL-JSON, BibTeX, RIS).</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:bibliography-builder/bibliography {\"citationStyle\":\"chicago-notes-bibliography\",\"showHeading\":true,\"headingText\":\"References\",\"outputJsonLd\":true,\"outputCoins\":false,\"outputCslJson\":false,\"citations\":[]} /-->\nEOT;\n\nwp_update_post(\n\tarray(\n\t\t'ID' => 1,\n\t\t'post_title' => 'Borges Bibliography Playground Starter (main build)',\n\t\t'post_content' => $post_content,\n\t)\n);\n"
}
]
}
Loading
Loading