Skip to content

chore: parallel local dev — isolated WP instances per worktree - #128

Closed
dmytrobez wants to merge 177 commits into
mainfrom
chore/parallel-local-dev
Closed

chore: parallel local dev — isolated WP instances per worktree#128
dmytrobez wants to merge 177 commits into
mainfrom
chore/parallel-local-dev

Conversation

@dmytrobez

Copy link
Copy Markdown

What

Infrastructure to run several isolated local WordPress instances in parallel — one per git worktree — so multiple people (or agents) can work side by side without port / database / container-name conflicts.

  • wordpress/docker-compose.yml — parameterized via env (PROJECT_CODE, WP_PORT, DB_PORT, WORDPRESS_URL, NEXT_URL, DEV_AUTOLOGIN_SECRET). Each instance gets its own compose project name, ports, DB and containers; WP_HOME/WP_SITEURL follow the instance URL so a seeded DB works on any port. Every var is defaulted — with no .env, behavior is identical to today (:80, :3306, project spck).
  • scripts/create-worktree.sh <n> [ref] — creates a detached worktree ../<repo>-wt<n>, copy-on-write clones the heavy gitignored dirs (plugins, theme/static, theme/vendors, node_modules), then runs setup.
  • scripts/setup-instance.sh <n> — generates per-instance wordpress/.env, wp-cli.local.yml, next/.env with free-port detection.
  • wordpress/scripts/db-snapshot.sh / db-seed.sh — export the main DB and seed an instance from it (URL search-replace + uploads rsync).
  • wordpress/server/mu-plugins/dev-autologin.php — local-only auto-login helper.

Guide: docs/parallel-local-dev.md.

Usage

sh scripts/create-worktree.sh 1                 # create instance 1
(cd ../<repo>-wt1/wordpress && npm start)        # boot it
sh wordpress/scripts/db-snapshot.sh              # (from the main checkout)
(cd ../<repo>-wt1 && sh wordpress/scripts/db-seed.sh /path/to/main-checkout)

Why it's safe on staging/production

  • The only file that runs inside WordPress is the auto-login mu-plugin, and it is inert unless DEV_AUTOLOGIN_SECRET is set — which only the local docker-compose.yml does. It can't activate on a real server.
  • The mu-plugin is mounted into the container purely by the local compose file; nothing in the deploy path ships wordpress/server/mu-plugins/.
  • All docker-compose.yml / start-wp.sh changes are local-dev only and fully backward-compatible (defaulted env), so the standard single-instance workflow is untouched.

Provenance & adaptations

This was first built and used on a client project (tipee.ch#33 — ran 3 simultaneous instances / 13 concurrent editor sessions). Ported here to the starter and adapted to superstack conventions, rather than copied verbatim:

  • Kept superstack's THEME_NAME / WORDPRESS_PATH / WORDPRESS_ENV compose env vars, the ./uploads path, and the ${THEME_NAME:-superstack} default (the client fork had diverged on these).
  • start-wp.sh only adds the per-instance .env loader — no -e passthrough, since superstack already passes those vars via the compose environment: block.
  • db-seed.sh uploads rsync targets superstack's ./uploads (not the fork's .data/uploads).

Status

Draft — not for merge yet. Opening for team review of the approach before it lands in the starter. Two spots worth a reviewer's eye: the ./uploads seeding path and whether the auto-login mu-plugin belongs in the starter as-is.

snugglejuice and others added 30 commits April 13, 2026 16:10
Went from 26 vulnerabilities (5 moderate, 19 high, 2 critical) to 6 vulnerabilities (1 moderate, 5 high)
snugglejuice and others added 25 commits June 11, 2026 17:36
get_site_url()/get_next_url() hosts are interpolated straight into the
preg_match pattern that gates URL rewriting. On sub-path installs the
host contains a slash (e.g. "localhost/us"), which is read as the regex
delimiter, so PHP parses the remainder as modifiers and emits
"preg_match(): Unknown modifier '|'" on every resolved URI field.

Wrap both hosts in preg_quote(..., '/') so slashes and other
regex-special characters are treated literally.
Infrastructure to run several isolated local WordPress instances in
parallel (one per git worktree), so multiple people/agents can work
side by side without port, database or container-name conflicts.

- docker-compose.yml parameterized via env (PROJECT_CODE, WP_PORT,
  DB_PORT, WORDPRESS_URL, NEXT_URL); WP_HOME/WP_SITEURL follow the
  instance URL so a seeded DB works on any port. All vars are defaulted,
  so the default single-instance workflow is unchanged (:80, :3306, spck).
- scripts/create-worktree.sh — detached worktree at ../<repo>-wtN plus a
  copy-on-write clone of the heavy gitignored dirs, then per-instance setup.
- scripts/setup-instance.sh — generates per-instance wordpress/.env,
  wp-cli.local.yml and next/.env with free-port detection.
- wordpress/scripts/db-snapshot.sh / db-seed.sh — copy DB + uploads from
  another checkout, with URL search-replace. Both refuse to touch a
  container owned by a different checkout, since PROJECT_CODE falls back
  to "spck" and every superstack-derived project shares that default.
- wordpress/server/mu-plugins/dev-autologin.php — local-only auto-login,
  gated on DEV_AUTOLOGIN_SECRET (only set by local compose, so it is inert
  on staging/production).

wordpress/.env is no longer tracked: setup-instance.sh writes it per
instance, so keeping it in git meant every worktree carried a modified
file holding a random auto-login secret. It is replaced by
wordpress/.env.example, matching how next/.env is already handled, and
docker-compose.yml now defaults THEME_NAME so compose still resolves
without an .env file.

start-wp.sh loads wordpress/.env when present; the existing compose
environment already carries the vars provision.sh reads, so provisioning
is unchanged for the default workflow.
@dmytrobez

Copy link
Copy Markdown
Author

Superseded by #129, which targets future — the scripts rely on the next/ subdirectory layout that only exists there. GitHub auto-closed this PR on the force-push and would not let it be reopened or retargeted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants