feat: add headless WordPress + Next.js frontend scaffold#74
Merged
PAMulligan merged 2 commits intoMay 20, 2026
Merged
Conversation
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>
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>
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.
Closes #22.
Summary
headlesscompose profile that installs WPGraphQL (+ optional JWT auth and Content Blocks), generates a preview secret, and verifies the REST + GraphQL endpoints respondmu-plugins/flavian-headless.phpfor CORS, preview-link rewriting, and REST hardening — gated on theflavian_headless_modeoption so the default stack is unchangedscripts/scaffold-frontend.shwhich generates a Next.js 14 (App Router) app underfrontend/<slug>/with a fetch-based WPGraphQL client and working/api/preview+/api/exit-previewroutesheadless-developeragent anddocs/headless-wordpress/README.mdcovering setup and the canonical preview-mode troubleshooting checklistNuxt and Astro scaffolds are deliberately deferred and tracked as follow-ups in the docs.
Acceptance criteria
docker compose --profile headless up headless-installer)preview_post_linkrewrite + the Next.js/api/previewroute)Test plan
docker compose up -dthendocker compose --profile headless up headless-installersucceeds end-to-end and prints non-empty env valuesbash scripts/scaffold-frontend.sh demo --name "Demo"produces 14 files underfrontend/demo/with no{{TOKEN}}placeholders remainingcd frontend/demo && pnpm install && pnpm devboots without errors; http://localhost:3000 renders the posts list from/graphql/wp-admin, create a draft post and click Preview — lands on/posts/<slug>with the draft-mode banner visible; clicking Exit preview clears itwp option update flavian_headless_mode 0and confirm/api/preview?secret=...returns 401 (mu-plugin's stored secret check still works) and that CORS headers are no longer sentdocker run --rm -v "$(pwd)/mu-plugins:/code:ro" php:8.3-cli php -l /code/flavian-headless.phpreports no syntax errors (already verified locally)🤖 Generated with Claude Code