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
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,25 @@ Both demo Blueprints explicitly request PHP `intl` support because editor-time C

Developer-facing CI/runtime coverage details are listed in the development section below.

## Footprint & Performance

Borges is a static-output block: formatted bibliography HTML, JSON-LD, and COinS are baked into post content at save time, so **published pages add zero database queries and zero server-side formatting** — the citeproc engine and metadata lookups run only while you edit. All figures below are hand-verified; re-derivation commands live in [`docs/current-metrics.md`](docs/current-metrics.md).

| Metric | Value |
|---|---|
| First-party PHP (main plugin file) | ~1,880 LOC (single file) |
| JS source (`src/`) | ~8,850 LOC |
| Frontend runtime shipped to visitors | `view.js` ~1.4 KB + `style-index.css` ~2.9 KB, enqueued only when the block is present |
| Installed footprint | ~2.1 MB (`vendor/` ~1.0 MB incl. citeproc-php and curated CSL styles, translations 724 KB, assets 328 KB) |
Comment thread
dknauss marked this conversation as resolved.
| Distributed ZIP (compressed) | ~0.9–1 MB |
| **Added DB queries per page** | **0** — regardless of block or citation count |
| Autoloaded options / registered settings / cron / custom tables / custom post types | none |
| `render_callback` on the frontend | none (static `save()` only) |

The only per-visitor cost is the small `view.js`/`style-index.css` pair, loaded solely on pages that contain a bibliography. Deactivating the plugin leaves the rendered bibliographies intact as static HTML.

Editor-time PMID and formatting results are cached in the object cache and in short-lived, non-autoloaded `_transient_bbb_*` transients — written only while editing, never on a visitor request. (DOI imports are deduped in a browser-session cache, not stored server-side.)

## Recent Release Highlights

- **1.3.4** — Refreshes the translation template plus 19 seed PO/MO locale pairs, adds CI validation for i18n artifacts, clarifies the bundled seed versus official language-pack policy, and archives historical planning notes out of active docs.
Expand Down
93 changes: 93 additions & 0 deletions docs/current-metrics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Current metrics

Hand-verified size, footprint, and runtime-overhead metrics for Borges Bibliography Builder.
Each number carries the exact command used to re-derive it, so the figures can be re-checked
on demand rather than trusted on faith. Re-run the relevant command and update the number **in
the same commit** whenever the underlying quantity changes.

Last verified: **2026-07-05** against `main` (commit `49f623b`).

## Lines of code

| Metric | Value | Re-derivation command |
|---|---|---|
| Main plugin file (`bibliography-builder.php`) | **1,881** | `wc -l bibliography-builder.php` |
| All first-party PHP (excl. vendor, tests, scripts, packages, output, node_modules, generated `build/`) | **1,979** | `find . -name '*.php' -not -path './vendor/*' -not -path './node_modules/*' -not -path './tests/*' -not -path './packages/*' -not -path './scripts/*' -not -path './output/*' -not -path './build/*' -print0 \| xargs -0 wc -l \| tail -1` |
| JS source (`src/`, excl. `*.test.js`) | **8,851** | `find ./src -name '*.js' -not -name '*.test.js' -print0 \| xargs -0 wc -l \| tail -1` |
| Shipped frontend runtime (`build/view.js`, minified) | **1,449 bytes** | `npm run build` then `wc -c < build/view.js` |

The only PHP that executes at runtime on a visitor request path is `bibliography-builder.php`
(REST registration + block registration); the CSL formatting engine under `vendor/` runs
**only** for editor-time REST calls. `scripts/*.php` are dev tooling and are not packaged.

## Storage footprint (installed)

Measured from a full release build (`npm run package:release`), which copies the shipped
Comment thread
dknauss marked this conversation as resolved.
files and installs runtime Composer dependencies with `--no-dev`, then prunes tests/docs/images
from `vendor/`.

**Prerequisite:** `build/` is gitignored (produced by `npm run build`), and
`scripts/package-release.sh` copies it, so run **`npm run build`** first on a clean checkout —
otherwise `package:release` (and the `du -sh build` row below) fails with `cannot stat build`.

| Component | Size | Re-derivation command |
|---|---|---|
| `vendor/` — citeproc-php engine + `seboettg/collection` + `myclabs/php-enum` + curated `citation-style-language/styles` & `/locales`, pruned | **~1.0 MB** | `du -sh output/release/borges-bibliography-builder/vendor` (after `npm run package:release`) |
| `languages/` — seed PO/MO/JSON translations | **724 KB** | `du -sh languages` |
| `build/` — editor + frontend assets | **328 KB** | `du -sh build` |
| PHP + `block.json` + `readme.txt` + `LICENSE` + `THIRD-PARTY-NOTICES.txt` | **~100 KB** | — |
| **Total installed** | **~2.1 MB** | `du -sh output/release/borges-bibliography-builder` (after `npm run package:release`) |
| Distributed ZIP (compressed) | **~0.9–1 MB** | `du -h output/release/borges-bibliography-builder.zip` |

The source tree's `packages/` directory (60 KB) is **not** a separate shipped component: the
release script (`scripts/package-release.sh`) Composer-installs those path packages into
`vendor/citation-style-language/*` and then deletes the staged `packages/` (`rm -rf`). The
curated CSL styles are therefore counted inside the `vendor/` figure above.

Notes:
- `vendor/seboettg/citeproc-php` is **3.2 MB** unpruned and **~536 KB** after the release
script strips tests/docs. The pruning is what keeps the installed footprint near 2 MB.
- The bundled `citation-style-language/styles` is a **curated subset** (the nine styles the
plugin ships), not the full upstream repository (~40 MB). This is a deliberate footprint
control, not an accident of packaging.

## Runtime / query overhead

The block uses **static `save()` output with no `render_callback`** — formatted bibliography
HTML, JSON-LD, and COinS are serialized into `post_content` at edit time. The visitor request
path therefore adds **zero** database queries and **zero** citeproc/PHP formatting work.

| Overhead on the frontend (per published page) | Value | Re-derivation |
|---|---|---|
| Additional database queries | **0** | Static save; nothing on the block runs on the frontend — see audit below |
| REST calls | **0** | `POST /format` and `GET /pmid/{pmid}` fire only in the editor |
| `render_callback` invocations | **0** | Block registers no server render |
| Autoloaded options / registered settings | **0** | No `add_option`/`update_option`/`register_setting` |
| Cron events | **0** | No `wp_schedule_event` |
| Custom post types / custom tables | **0** | No `register_post_type` / `dbDelta` |
| Enqueued frontend assets (only when block present) | `view.js` ~1.4 KB + `style-index.css` ~2.9 KB | `wc -c build/view.js build/style-index.css` |

Persistence/hook audit — no persistent settings, options, cron, CPTs, or custom tables
(expected output: **NONE**):

```
grep -rEl "add_option|update_option|register_setting|register_post_type|dbDelta|wp_schedule_event" \
Comment thread
dknauss marked this conversation as resolved.
--include='*.php' . | grep -vE 'vendor|tests|node_modules'
```

**One caveat on `wp_options`.** On every store, the plugin's editor-time cache
(`bibliography_builder_cache_set()`) calls **both** `wp_cache_set()` and `set_transient()` —
they are two independent `if ( function_exists() )` guards, not an object-cache-else-transient
fallback. With a persistent object cache drop-in active, `set_transient()` also routes to the
object cache and **no** option row is written; without one, it materializes
**non-autoloaded, expiring** `_transient_bbb_*` rows in `wp_options`. Either way the write
happens **only during editor REST calls** (`/format`, `/pmid`) as short-lived caches of
upstream lookups — never on a visitor request, and never added to the autoload set. So there
are no long-lived settings and nothing on the autoload path, but "zero rows ever touch
`wp_options`" would be inaccurate on a site without an external object cache. (DOI imports are
deduped separately in a browser-session JS `Map` in `src/lib/parser.js` and never reach this
PHP cache.)

The "average queries per page" figure is a flat **0 additional queries**, independent of the
number of bibliography blocks or citations on the page — all expensive resolution (Crossref
DOI, NCBI/PMC PMID) and CSL formatting happens at edit time and never touches a visitor.
15 changes: 15 additions & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,21 @@ PHP 7.4+ and WordPress 6.4+. Borges Bibliography Builder is tested up to WordPre
8. Export the whole bibliography from the sidebar: copy as plain text, or download CSL-JSON, BibTeX, BibLaTeX, or RIS.
9. Readers can expand the per-entry Cite / Export panel on the published page to copy a citation or download it as RIS, CSL-JSON, BibTeX, or BibLaTeX.

== Performance & Footprint ==

Borges is a static-output block. Formatted bibliography HTML, JSON-LD, and COinS are baked into your post content when you save, so the citeproc formatting engine and the DOI/PubMed lookups run **only in the editor** — never on the front end.

What this means for a published page:

* **Zero added database queries** — no matter how many bibliographies or citations the page contains. Query load does not grow with your content.
* **No `render_callback`, no REST calls, no shortcodes** on the front end. Output is static HTML from the block's `save()`.
* **No long-lived settings** — the plugin registers no settings or autoloaded options, no custom tables, no custom post types, and no cron events. Editor-time PMID and formatting results are cached in the object cache and in short-lived, non-autoloaded transients, written only while editing. DOI imports are deduped in a browser-session cache, not stored server-side.
* **Tiny front-end payload** — only a small view script (~1.4 KB) and stylesheet (~2.9 KB) load, and only on pages that actually contain a bibliography.

Installed footprint is roughly **2.1 MB** (the bundled citeproc-php formatting engine accounts for about half; the rest is translations, editor/front-end assets, and a curated set of citation styles). The downloadable ZIP is about 0.9–1 MB compressed.

Because output is static, your bibliographies remain intact as plain HTML even if the plugin is deactivated.

== Known Limitations ==

**OSCOLA grouped bibliography** — OSCOLA convention requires the bibliography to be divided into source-type groups (cases, legislation, books, articles, online sources). Borges currently renders a single alphabetized list regardless of style. A dismissible notice in the editor explains this when OSCOLA is selected. Grouped-bibliography support is planned for a future release.
Expand Down
Loading