Phase 05 M3: block settings and reformat write routes - #106
Merged
Merged
Conversation
Tier 3 of the writable REST design, behind the M2 opt-in filter and with
the same dry-run, edit_post, and If-Match rules:
- PATCH /posts/{id}/bibliographies/{ref} changes block settings: the
visible heading and the JSON-LD, COinS, CSL-JSON, and Cite / Export
toggles. citationStyle is refused with a pointer to reformat, and a
setting sent with its block.json default leaves the block comment, as
the editor's serializer drops it.
- POST /posts/{id}/bibliographies/{ref}/reformat switches the citation
style like the editor's handleCitationStyleChange: every entry is
formatted in the new style (50 at a time, up to 200), manual text and
export strings are kept, entries are re-sorted, and a heading still set
to the old style's default becomes the new style's. Entries the
formatter cannot use fail the request with 409 and are listed.
The runtime smoke now changes settings and reformats over HTTP in every
cell, the dev Playground helper gains settings() and reformat(), and the
docs, memo, and roadmap mark M3 done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #106 +/- ##
==========================================
+ Coverage 87.20% 87.39% +0.18%
==========================================
Files 54 54
Lines 5847 6021 +174
Branches 597 597
==========================================
+ Hits 5099 5262 +163
- Misses 267 278 +11
Partials 481 481 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
dknauss
marked this pull request as ready for review
September 26, 2026 20:50
dknauss
pushed a commit
that referenced
this pull request
Sep 26, 2026
Full GPL CSL styles and locales (#103), Phase 05 M0-M3 (stable IDs, review routes and abilities, opt-in citation and block write routes: #104, #106), the save-markup language fix, reference-manager .bib fixes, the Playground demo page (#102), and the runtime matrix on the release package with formatter-parity and write-route checks (#105). Version bumped in the plugin header, block.json, readme.txt Stable tag, the POT header, and the package manifests. CHANGELOG [Unreleased] is dated as 1.7.0; readme.txt gains a user-facing changelog entry, an Upgrade Notice, and an FAQ note on the opt-in write routes. README highlights and STATE/ROADMAP move to the 1.7.0 baseline. Tested up to stays 7.1: WordPress latest is 7.1.2, which CI's runtime matrix exercises, including formatter parity across all nine styles. package-release.sh now also prunes .git directories from vendor/. When Composer falls back from dist to a git clone (as it did in this sandbox), the ZIP otherwise carried 4 MB of git metadata. Release checklist gates run locally: lint:js, lint:css, lint:i18n, npm audit (0), composer audit (none), Jest 873 passed / 2 skipped, PHPUnit 318 OK (the 4 vendor deprecations already on main), build, package:release (552,718-byte ZIP). citeproc-php v2.7.1 is current. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2
dknauss
added a commit
that referenced
this pull request
Sep 26, 2026
* chore(release): 1.7.0 Full GPL CSL styles and locales (#103), Phase 05 M0-M3 (stable IDs, review routes and abilities, opt-in citation and block write routes: #104, #106), the save-markup language fix, reference-manager .bib fixes, the Playground demo page (#102), and the runtime matrix on the release package with formatter-parity and write-route checks (#105). Version bumped in the plugin header, block.json, readme.txt Stable tag, the POT header, and the package manifests. CHANGELOG [Unreleased] is dated as 1.7.0; readme.txt gains a user-facing changelog entry, an Upgrade Notice, and an FAQ note on the opt-in write routes. README highlights and STATE/ROADMAP move to the 1.7.0 baseline. Tested up to stays 7.1: WordPress latest is 7.1.2, which CI's runtime matrix exercises, including formatter parity across all nine styles. package-release.sh now also prunes .git directories from vendor/. When Composer falls back from dist to a git clone (as it did in this sandbox), the ZIP otherwise carried 4 MB of git metadata. Release checklist gates run locally: lint:js, lint:css, lint:i18n, npm audit (0), composer audit (none), Jest 873 passed / 2 skipped, PHPUnit 318 OK (the 4 vendor deprecations already on main), build, package:release (552,718-byte ZIP). citeproc-php v2.7.1 is current. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2 * Parse each CSL style once per format request CiteProc::render() calls init() every time, which builds a new Context, reads and parses the locale file, and rebuilds the style's object tree: about 3 ms, against well under 1 ms to render an entry. With one render per entry (the fix that stopped an "et al." entry from dropping the next entry's "and"), 50 entries took about 90 ms, against about 8 ms in 1.6.0 with its short stand-in styles. Bibliography_Builder_Reusable_CiteProc parses once, records every property of every object in the parsed style tree, and before each later render restores them, resets the Context's per-render lists, and zeroes Layout's static cited-item counter. Each entry renders against the state a fresh parse would give it: 50 entries now take about 25 ms. The nine style goldens still match byte for byte. A new test formats the corpus in reverse order, putting the "et al." and APA 21+ entries ahead of the short author lists, and requires every entry to match its golden line; with the restore disabled, both the goldens and the new test fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2 * Drop the #[\Override] attribute from the reusable formatter PHP 7.4 reads an attribute on its own line as a comment (php -l on 7.4 passes, and so does the PHP 7.4 runtime smoke), but Copilot flagged it as a 7.4 parse error, and compatibility scanners can do the same. It does nothing at runtime, so drop it, and turn off Psalm's MissingOverrideAttribute, which cannot apply to a plugin that supports PHP 7.4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2 --------- Co-authored-by: Claude <noreply@anthropic.com>
dknauss
pushed a commit
that referenced
this pull request
Sep 26, 2026
Since #106, all three nginx cells of the full matrix fail at the settings PATCH with nginx's own "405 Not Allowed": the smoke test sent REST requests to /?rest_route=, and for a directory request nginx's index module only hands GET, HEAD, and POST to index.php, so PATCH, PUT, and DELETE fall through to the static handler. #105's write steps used only GET and POST, so they passed. Sites are not affected: WordPress builds plain-permalink REST URLs as index.php?rest_route=, and pretty permalinks reach index.php through try_files. Send every smoke REST request to index.php?rest_route= (REST_URL), and add nginx-php83-wplatest to the pull-request matrix, which had only Apache cells and so could not catch this before merge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2
4 of 10 tasks
dknauss
added a commit
that referenced
this pull request
Sep 27, 2026
Since #106, all three nginx cells of the full matrix fail at the settings PATCH with nginx's own "405 Not Allowed": the smoke test sent REST requests to /?rest_route=, and for a directory request nginx's index module only hands GET, HEAD, and POST to index.php, so PATCH, PUT, and DELETE fall through to the static handler. #105's write steps used only GET and POST, so they passed. Sites are not affected: WordPress builds plain-permalink REST URLs as index.php?rest_route=, and pretty permalinks reach index.php through try_files. Send every smoke REST request to index.php?rest_route= (REST_URL), and add nginx-php83-wplatest to the pull-request matrix, which had only Apache cells and so could not catch this before merge. Claude-Session: https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2 Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
What changed?
This adds Tier 3 of the writable REST design. M2 already shipped reorder and ETag, so M3 is these two routes. Both sit behind the same
bibliography_builder_enable_write_routesfilter and follow M2's rules:edit_post, dry run by default, andIf-Matchrequired. They use M2's write path too: the PHP port ofsave()rebuilds the markup, the change is spliced into only that block, and a check confirms nothing else in the post changed.PATCH /posts/{id}/bibliographies/{ref}changes block settings:headingText,outputJsonLd,outputCoins,outputCslJson, andoutputCiteExport.400.block.jsondefault is left out of the block comment, the same way the editor's serializer drops it.citationStyleis refused (400,bibliography_builder_style_needs_reformat), because a style change without reformatting would leave every entry in the old style.POST /posts/{id}/bibliographies/{ref}/reformatwith{ "style": "<key>" }mirrors the editor'shandleCitationStyleChange:/formatlimit), up to the editor's 200-citation cap;headingPlaceholdersupplies those defaults, and a drift test pins it to the JS registry.409, listed indata.entries.Runtime smoke: every matrix cell now sends a real settings
PATCHand a real reformat to APA over HTTP. It then checks:save().The
PATCHshares its path with the publicGETread route, so this also proves WordPress falls through to it (match_request_to_handlerskips a route with no handler for the method).Dev Playground:
borgesWrite.settings()andborgesWrite.reformat().Docs:
docs/rest-write-routes.md(now "Bibliography write routes"), the README,CLAUDE.md, the CHANGELOG, the design memo (M3 status and how it differs from the sketch), the roadmap, and the metrics (PHP line count).Why? It was requested ("start m3"), and it's the next milestone in the Phase 05 sequencing table. It also clears the M0–M3 blocker on write abilities (M5).
Validation
npm run lint:jspassesnpm run lint:css: no CSS changesnpm run lint:i18npasses (new PHP strings)npm run testpasses (873)npm run build: no JS source changescomposer test:php(318 tests),composer lint:php, Psalm, andverify-metrics.shpass.save());409for entries it can't format;mainafter merge.Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_01KbVuMPN7YTcV27vwsG3LZ2
Generated by Claude Code