chore(dev): one-command local WordPress, and stop the unbuilt-block notice #3

Merged
laoc merged 1 commit from chore/local-dev-env into main 2026-07-30 21:52:11 +00:00
Owner

Takes a fresh clone to a working local WordPress with the plugin active and demo pages rendering live relay data, in one command. laoc_buzz asked for something he can click around in.

make dev     # vendor -> up -> install-wp -> seed -> status

Verified clean-room: run from a git worktree with no docker-data/ at all, not against an already-working environment.

Four things were in the way

1. The composer targets pointed at a path that never existed. composer:, composer-shared: and install: all used wp-content/plugins/wp-nostr/amb-nostr, but docker-compose.yml mounts each module directly at wp-content/plugins/<module>. There is no wp-nostr parent. Replaced with a host-side vendor: target: the wordpress:6.8-php8.4-apache image has neither composer nor ext-gmp, and swentel/nostr-php requires gmp. nix supplies both.

2. Nothing waited for MariaDB. docker compose up -d returns while the database is still initialising, so the first wp call fails with "Error establishing a database connection" — which reads like a misconfiguration rather than a race, and sends you debugging the wrong thing. up: now polls until the DB answers a query.

3. A fresh install has plain permalinks, so /amb-demo 404s. Now sets /%postname%/ and flushes. The plugin's planned archive routes need rewrite rules regardless.

4. Blocks registered from an unbuilt directory — a real plugin bug. build/ is a compiled artifact and gitignored, so a fresh checkout has no block.json there. register_block_type() then falls back to treating the path string as a block name, and WordPress emits

Block type names must contain a namespace prefix. Example: my-plugin/my-custom-block-type

on every page load. Both blocks now check for the built block.json and return quietly if it is absent. The shortcodes never needed the build; only the editor blocks do, via make build.

Safety

install-wp deliberately does not activate nostr-publish — it can sign and publish events to a live relay, and this environment is for reading. Everything here only issues REQ/COUNT.

Evidence

After make dev on an empty tree:

http://localhost:8080/amb-demo     200, 10 live kind-30142 resources rendered
http://localhost:8080/amb-search   200, search form renders
"namespace prefix" notices          0   (previously on every page load)
make seed run twice                 idempotent

Filter honoured through the full WordPress stack, with the bogus-value control that makes the number mean something:

[amb_nostr t="Erwachsenenbildung"]          -> resources
[amb_nostr t="zzz-kein-solches-schlagwort"] -> 0

ExtendedFilter exercised inside the container on the real runtime (PHP 8.4, nostr-php 1.9.4), not just on the host:

#ext:ekw:gradeLevel:id = <real>    ->   3
#ext:ekw:gradeLevel:id = <bogus>   ->   0   (twice)
kinds only, no tag filter          -> 100

Suites, unchanged by the block guard:

shared 15/15   longform-nostr 5/5   nostr-calendar 17/17   nostr-publish 14/14

Known and out of scope here

The ext: facet filters are not reachable from the shortcode UI[amb_nostr] accepts only t, authors, limit, and SearchEndpoint still has the hardcoded four-facet FILTER_FIELD_MAP. That is the §3.1 gap in the architecture doc and the next build task (ExtTagParserFacetDiscoveryArchiveRoute), not a regression.

Takes a fresh clone to a working local WordPress with the plugin active and demo pages rendering live relay data, in one command. laoc_buzz asked for something he can click around in. ```sh make dev # vendor -> up -> install-wp -> seed -> status ``` **Verified clean-room**: run from a git worktree with no `docker-data/` at all, not against an already-working environment. ## Four things were in the way **1. The composer targets pointed at a path that never existed.** `composer:`, `composer-shared:` and `install:` all used `wp-content/plugins/wp-nostr/amb-nostr`, but `docker-compose.yml` mounts each module directly at `wp-content/plugins/<module>`. There is no `wp-nostr` parent. Replaced with a host-side `vendor:` target: the `wordpress:6.8-php8.4-apache` image has neither composer nor `ext-gmp`, and `swentel/nostr-php` requires gmp. nix supplies both. **2. Nothing waited for MariaDB.** `docker compose up -d` returns while the database is still initialising, so the first `wp` call fails with *"Error establishing a database connection"* — which reads like a misconfiguration rather than a race, and sends you debugging the wrong thing. `up:` now polls until the DB answers a query. **3. A fresh install has plain permalinks**, so `/amb-demo` 404s. Now sets `/%postname%/` and flushes. The plugin's planned archive routes need rewrite rules regardless. **4. Blocks registered from an unbuilt directory — a real plugin bug.** `build/` is a compiled artifact and gitignored, so a fresh checkout has no `block.json` there. `register_block_type()` then falls back to treating the path *string* as a block name, and WordPress emits ``` Block type names must contain a namespace prefix. Example: my-plugin/my-custom-block-type ``` on **every page load**. Both blocks now check for the built `block.json` and return quietly if it is absent. The shortcodes never needed the build; only the editor blocks do, via `make build`. ## Safety `install-wp` deliberately does **not** activate `nostr-publish` — it can sign and publish events to a live relay, and this environment is for reading. Everything here only issues `REQ`/`COUNT`. ## Evidence After `make dev` on an empty tree: ``` http://localhost:8080/amb-demo 200, 10 live kind-30142 resources rendered http://localhost:8080/amb-search 200, search form renders "namespace prefix" notices 0 (previously on every page load) make seed run twice idempotent ``` Filter honoured through the full WordPress stack, with the bogus-value control that makes the number mean something: ``` [amb_nostr t="Erwachsenenbildung"] -> resources [amb_nostr t="zzz-kein-solches-schlagwort"] -> 0 ``` `ExtendedFilter` exercised inside the container on the real runtime (PHP 8.4, nostr-php 1.9.4), not just on the host: ``` #ext:ekw:gradeLevel:id = <real> -> 3 #ext:ekw:gradeLevel:id = <bogus> -> 0 (twice) kinds only, no tag filter -> 100 ``` Suites, unchanged by the block guard: ``` shared 15/15 longform-nostr 5/5 nostr-calendar 17/17 nostr-publish 14/14 ``` ## Known and out of scope here The `ext:` facet filters are **not reachable from the shortcode UI** — `[amb_nostr]` accepts only `t`, `authors`, `limit`, and `SearchEndpoint` still has the hardcoded four-facet `FILTER_FIELD_MAP`. That is the §3.1 gap in the architecture doc and the next build task (`ExtTagParser` → `FacetDiscovery` → `ArchiveRoute`), not a regression.
`make dev` now takes a fresh clone to a working WordPress with the plugin
active and demo pages rendering live relay data. Verified clean-room: from a
worktree with no docker-data/ at all.

Four things were in the way.

**The composer targets pointed at a path the compose file never creates.**
`composer:`, `composer-shared:` and `install:` all used
`wp-content/plugins/wp-nostr/amb-nostr`, but docker-compose.yml mounts each
module directly at `wp-content/plugins/<module>`. They could not have worked.
Replaced with a host-side `vendor:` target — the wordpress image has neither
composer nor ext-gmp, which swentel/nostr-php requires, and nix supplies both.

**Nothing waited for the database.** `docker compose up -d` returns while
mariadb is still initialising, so the first `wp` call failed with "Error
establishing a database connection" — which reads like a misconfiguration
rather than a race. `up:` now polls until the DB accepts a query.

**A fresh install has plain permalinks**, so /amb-demo 404'd. Set
`/%postname%/` and flush; the plugin's future archive routes need rewrite
rules regardless.

**Blocks registered from an unbuilt directory.** `build/` is a compiled
artifact and gitignored, so a fresh checkout has no block.json there.
`register_block_type()` then falls back to treating the path string as a block
name, and WordPress emits "Block type names must contain a namespace prefix"
on *every page load*. Both blocks now check for the built block.json first and
return quietly if it is absent. The shortcodes never needed the build; only the
editor block does, via `make build`.

nostr-publish is deliberately left deactivated by `install-wp`: it can sign and
publish events to a live relay, and the local environment is for reading.

Verified end to end after `make dev` on an empty tree:

    http://localhost:8080/amb-demo    200, 10 live kind-30142 resources
    http://localhost:8080/amb-search  200, search form renders
    "namespace prefix" notices        0  (was on every page load)
    make seed, run twice              idempotent

    shared 15/15   longform 5/5   calendar 17/17   publish 14/14

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
laoc merged commit ade9fbad03 into main 2026-07-30 21:52:11 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
edufeed/wp-plugin-amb-nostr!3
No description provided.