Skip to content

feat: add headless WordPress + Next.js frontend scaffold#74

Merged
PAMulligan merged 2 commits into
mainfrom
22-add-headless-wordpress-and-decoupled-frontend-support
May 20, 2026
Merged

feat: add headless WordPress + Next.js frontend scaffold#74
PAMulligan merged 2 commits into
mainfrom
22-add-headless-wordpress-and-decoupled-frontend-support

Conversation

@PAMulligan
Copy link
Copy Markdown
Collaborator

Closes #22.

Summary

  • Adds an opt-in headless compose profile that installs WPGraphQL (+ optional JWT auth and Content Blocks), generates a preview secret, and verifies the REST + GraphQL endpoints respond
  • Adds mu-plugins/flavian-headless.php for CORS, preview-link rewriting, and REST hardening — gated on the flavian_headless_mode option so the default stack is unchanged
  • Ships scripts/scaffold-frontend.sh which generates a Next.js 14 (App Router) app under frontend/<slug>/ with a fetch-based WPGraphQL client and working /api/preview + /api/exit-preview routes
  • Adds a headless-developer agent and docs/headless-wordpress/README.md covering setup and the canonical preview-mode troubleshooting checklist

Nuxt and Astro scaffolds are deliberately deferred and tracked as follow-ups in the docs.

Acceptance criteria

  • Headless WordPress Docker configuration available (docker compose --profile headless up headless-installer)
  • At least one frontend framework scaffold included (Next.js)
  • WPGraphQL pre-configured in headless mode
  • Preview mode working for draft content (validated via the mu-plugin's preview_post_link rewrite + the Next.js /api/preview route)

Test plan

  • docker compose up -d then docker compose --profile headless up headless-installer succeeds end-to-end and prints non-empty env values
  • bash scripts/scaffold-frontend.sh demo --name "Demo" produces 14 files under frontend/demo/ with no {{TOKEN}} placeholders remaining
  • cd frontend/demo && pnpm install && pnpm dev boots without errors; http://localhost:3000 renders the posts list from /graphql
  • In /wp-admin, create a draft post and click Preview — lands on /posts/<slug> with the draft-mode banner visible; clicking Exit preview clears it
  • Toggle wp option update flavian_headless_mode 0 and confirm /api/preview?secret=... returns 401 (mu-plugin's stored secret check still works) and that CORS headers are no longer sent
  • docker run --rm -v "$(pwd)/mu-plugins:/code:ro" php:8.3-cli php -l /code/flavian-headless.php reports no syntax errors (already verified locally)

🤖 Generated with Claude Code

Closes #22. Ships headless WP as an opt-in compose profile alongside the
existing stack — `docker compose --profile headless up headless-installer`
installs WPGraphQL (+ optional JWT and Content Blocks), generates a preview
secret, and prints the env values the frontend needs.

The CORS, preview-link rewriting, and REST hardening live in a single
mu-plugin (`mu-plugins/flavian-headless.php`) that short-circuits when
`flavian_headless_mode` is off, so the default stack is unchanged.

`scripts/scaffold-frontend.sh` generates a self-contained Next.js 14 app
under `frontend/<slug>/` with a fetch-based WPGraphQL client and working
`/api/preview` + `/api/exit-preview` routes. Nuxt and Astro are tracked
as follow-ups in `docs/headless-wordpress/README.md`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@PAMulligan PAMulligan linked an issue May 20, 2026 that may be closed by this pull request
4 tasks
CI flagged the mu-plugin against WordPress-Extra/Docs. Changes are
mechanical — same behaviour:

- Add @Package tag to the file docblock.
- Add @return/@param docblocks to every function (closure aside).
- Yoda all comparisons (null === $x, '' === $secret, etc).
- Reformat multi-line array_filter / http_build_query / register_rest_field
  so opening parens close the line and each argument sits on its own line.
- Drop the `?:` short ternary in rewrite_permalink in favour of an explicit
  empty() check.
- Rename the register_rest_field callback's reserved `$object` parameter to
  `$post_arr`; ignore the unused `$field` arg.
- Align `=>` columns in the schema array.
- Sanitize $_SERVER['REQUEST_METHOD'] via wp_unslash + sanitize_text_field
  before comparing it.

Verified with the exact CI command (`phpcs --standard=WordPress-Extra,
WordPress-Docs --extensions=php --ignore=*/index.php mu-plugins/`): 1 file
scanned, 0 errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@PAMulligan PAMulligan merged commit 74e57b9 into main May 20, 2026
8 checks passed
@PAMulligan PAMulligan deleted the 22-add-headless-wordpress-and-decoupled-frontend-support branch May 20, 2026 23:44
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.

Add headless WordPress and decoupled frontend support

1 participant