diff --git a/.github/workflows/audit-dependencies.yml b/.github/workflows/audit-dependencies.yml
new file mode 100644
index 000000000..4c1abea8b
--- /dev/null
+++ b/.github/workflows/audit-dependencies.yml
@@ -0,0 +1,12 @@
+name: Audit Dependencies
+
+on: pull_request
+
+jobs:
+ audit_depedencies:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Audit for vulnerabilities
+ run: npx audit-ci@^6 --config ./audit-ci.jsonc
diff --git a/audit-ci.jsonc b/audit-ci.jsonc
new file mode 100644
index 000000000..861713ff4
--- /dev/null
+++ b/audit-ci.jsonc
@@ -0,0 +1,5 @@
+{
+ "$schema": "https://github.com/IBM/audit-ci/raw/main/docs/schema.json",
+ "moderate": true,
+ "allowlist": []
+}
diff --git a/examples/next/faustwp-getting-started/package.json b/examples/next/faustwp-getting-started/package.json
index c8e43b0dc..fc447f4f9 100644
--- a/examples/next/faustwp-getting-started/package.json
+++ b/examples/next/faustwp-getting-started/package.json
@@ -10,7 +10,7 @@
},
"dependencies": {
"@apollo/client": "^3.6.6",
- "@faustwp/cli": "0.1.3",
+ "@faustwp/cli": "0.1.4",
"@faustwp/core": "0.1.3",
"@wordpress/base-styles": "^4.7.0",
"@wordpress/block-library": "^7.13.0",
diff --git a/internal/faustjs.org/blog/2021-12-03-upgrading-to-faustwp.md b/internal/faustjs.org/blog/2021-12-03-upgrading-to-faustwp.md
new file mode 100644
index 000000000..aef8d05f6
--- /dev/null
+++ b/internal/faustjs.org/blog/2021-12-03-upgrading-to-faustwp.md
@@ -0,0 +1,36 @@
+---
+title: Upgrading to FaustWP
+description: All you need to know about upgrading to FaustWP.
+slug: upgrading-to-faustwp
+hide_table_of_contents: true
+---
+
+The WP Engine Headless (or WPE Headless) plugin has been renamed to FaustWP starting with version 0.7.0. Along with the rename, distribution of the plugin has moved off of WP Engine servers and into the official wordpress.org plugin repository. In order to continue receiving plugin updates and remain compatible with future versions of Faust.js NPM packages, site owners will need to do the following:
+
+1. Log in to your WordPress admin dashboard.
+2. Go to “Plugins -> Add New” in the admin sidebar.
+3. In the top right corner, enter "FaustWP" in the search box.
+4. Click the “Install Now” button.
+5. Once the installation is complete, click “Activate”.
+
+Activating FaustWP will automatically deactivate WP Engine Headless if it is installed and active on your site. **All plugin settings will be preserved, including your secret key.** You can now remove the old, deactivated WP Engine Headless plugin:
+
+1. Go to "Plugins -> Installed Plugins" in the admin sidebar.
+2. Verify that FaustWP is installed and active.
+3. Verify that WP Engine Headless is inactive.
+4. Delete WP Engine Headless.
+
+We have done our best to ensure a seamless upgrade experience, but we encourage users to review the [plugin changelog](https://faustjs.org/docs/changelog/faustwp) to evaluate any impacts these changes might have in their own applications.
+
+## Package Updates
+
+Version 0.7.0 of FaustWP is best suited for use with `@faustjs/core` version 0.14.0 or greater. As noted in the [changelog](https://faustjs.org/docs/changelog/core) for version 0.14.0:
+
+> The FaustWP plugin has deprecated the REST endpoint that `@faustjs/core` uses for authorization. Both the plugin and the `@faustjs/core` package will continue to work with the deprecated endpoint until it is removed in a future version. Make sure to always update your FaustWP plugin and `@faustjs` packages together to avoid any issues that may arise from incompatible versions.
+
+We recommend updating all of your Faust.js packages after installing the FaustWP plugin.
+
+### Changelogs
+- [@faustjs/core](https://faustjs.org/docs/changelog/core)
+- [@faustjs/next](https://faustjs.org/docs/changelog/next)
+- [@faustjs/react](https://faustjs.org/docs/changelog/react)
diff --git a/internal/faustjs.org/blog/2022-07-06-the-future-of-faust.md b/internal/faustjs.org/blog/2022-07-06-the-future-of-faust.md
new file mode 100644
index 000000000..7cc274da4
--- /dev/null
+++ b/internal/faustjs.org/blog/2022-07-06-the-future-of-faust.md
@@ -0,0 +1,38 @@
+---
+title: The Future of Faust.js
+description: An update on Faust.js, where it is and where it is going
+slug: the-future-of-faust
+hide_table_of_contents: true
+---
+
+We launched this blog 7 months ago with a goal of keeping you informed of what is going on in the development of Faust.js as well as to help you get started using the framework in your own projects. To date, we simply have not prioritized keeping up here on the blog and it is time for that to change.
+
+
+
+Today we want to talk about where Faust.js is and where we're working on taking it in the future. It will be the first of many regular posts designed to tell the story of Faust.js and how it affects developers of all backgrounds.
+
+## Where Faust.js is Today
+
+First and foremost, the development of Faust.js is alive and well. When the last post was written in December we were a rather unorthodox team of two engineers working on understanding what Faust.js should be.
+
+Today the Faust.js team, known internally as Team Merlin, is made of of five engineers and an engineering manager and [we're still looking for one more staff/lead engineer to join our team](https://wpengine.wd1.myworkdayjobs.com/en-US/WP_Engine/job/Software-Engineer-IV--ATLAS---Themes-_JR100226).
+
+While we've expanded, we've moved much of our development process out of GitHub projects and into company tools that allow us to be more in tune with the needs of the organization and [Atlas](https://wpengine.com/atlas/) as well as allows us to more easily communicate the story of Faust.js to stakeholders throughout the company.
+
+Today we're revisiting this blog primarily as a way to update you on what we're doing now that we're currently not working in public. From this point forward we'll be updating the blog at least once every two weeks with the current accomplishments and next steps on our journey to ensure Faust.js is the leading framework for folks looking to develop headless sites with WordPress.
+
+## Where Faust.js is Going
+
+As [WP Engine](https://wpengine.com) has made a significant investment in the future of Faust.js by increasing the team working on it, it's time to talk to where we're currently spending our time.
+
+When Faust.js was first conceived a decision was made to go with [GQty](https://gqty.dev) as our data library as we thought it would be the simplest way for users to pull data from WordPress using [WPGraphQL](https://www.wpgraphql.com). While we largely were able to prove it was indeed simple, that simplicity came with complications. GQty proved a difficult choice for users to scale with as it over-abstracted enough of the data layer that modifying how a user was getting data from WordPress quickly became a difficult process.
+
+Today we're working on removing the limits imposed by choosing GQty by replacing it with the popular [Apollo library](https://www.apollographql.com). This will allow users to get what they need from WordPress in whatever way they need it. Users won't be constrained on the queries they run and will be able to more easily modify a default query to fit any use case imaginable. You can expect to see our work on this feature available in the 3rd quarter of 2022.
+
+As part of replacing GQty with Apollo, another shift in Faust.js since our last writing is that we've realized our target audience is not so much JavaScript developers forced to use WordPress but is, in fact, WordPress developers pivoting to headless sites. While the difference might sound trivial, the shift comes with a change of expectations that lead to numerous features in development. For instance, in the 3rd quarter of 2022 we also hope to release a template hierarchy feature that utilizes WordPress' core routing system, popularly known as [permalinks](https://wordpress.org/support/article/using-permalinks/), to power a developer experience that better utilizes the existing development skills of WordPress developers and agencies.
+
+While our audience might not be what we originally thought it was, that isn't to say we're not working on cutting edge features for JavaScript developers as well. From the ability to share components between your front end and WordPress' Block Editor to authentication and even advanced ways to handle use cases such as A/B testing and more there is a lot planned in our backlog and we can't wait to start rolling it out to you over the coming months.
+
+## Check Back Often For Updates From Our Latest Sprint
+
+Faust.js has a bright future and we look forward to sharing it with you. Check back here roughly every two weeks for news on where we're at and what we're working on and, as always, you can ask the team questions in our [GitHub issues](https://github.com/wpengine/faustjs) or on [our Discord server](https://developers.wpengine.com). We're looking forward to powering your project.
diff --git a/internal/faustjs.org/blog/2022-07-20-sprint-14-update.md b/internal/faustjs.org/blog/2022-07-20-sprint-14-update.md
new file mode 100644
index 000000000..f3642aaa7
--- /dev/null
+++ b/internal/faustjs.org/blog/2022-07-20-sprint-14-update.md
@@ -0,0 +1,30 @@
+---
+title: Sprint 14 Update
+description: Updates from the teams work on Sprint 14
+slug: sprint-14-update
+hide_table_of_contents: true
+---
+
+Yesterday, July 19th, the team completed Sprint 14, which is simply our 14th [sprint](https://www.educba.com/what-is-agile-sprint/) of the year. This was one of more productive sprints, in terms of implementation, so far this year. We managed to release a new version of both the Faust.js library as well as the Faust WordPress plugin, we welcomed two new developers to the team and we worked hard to implement a way to help us better understand how folks are using the framework. Here's how it all breaks down:
+
+## Faust.js 0.15.7 and Faust WP 0.7.10
+
+The Faust WordPress plugin was updated to version 0.7.10 last week and all Faust JavaScript libraries were updated to version 0.15.7. These new versions didn't bring about any new features but they did solve some issues folks were seeing as well as updated some of the dependencies Faust relies on. You can see a full list of all the changes we made in our [release notes](https://github.com/wpengine/faustjs/releases).
+
+## Welcome new developers
+
+In addition to new releases, our team also welcomed two new developers to the team bringing our total to 5 full-time developers focused solely on Faust. You'll see their contributions in our [GitHub repo](https://github.com/wpengine/faustjs/) and they will help us bring the next evolution of Faust into your hands as quickly as possible.
+
+We're not done here, though. We still have one more position open on our team for a staff developer. If you're interested in helping take Faust to the next level, [apply now](https://wpengine.wd1.myworkdayjobs.com/en-US/WP_Engine/job/Software-Engineer-IV--ATLAS---Themes-_JR100226) and let's talk.
+
+## New telemetry in Faust.js
+
+The big goal of Faust.js was in implementing some basic telemetry into Faust so that our teams and stakeholders have some measure on how the product is actually being used. Note that this telemetry, while code complete, has not launched in a release yet.
+
+To implement the telemetry we're using [Google Analytics](https://marketingplatform.google.com/about/analytics/), a common analytics partner in WP Engine products, to collect data on version information and other build parameters solely from the JavaScript builds completed with Faust. **All analytics are opt-in only** so new users, once launched, will see a prompt asking you if you're willing to login. This can safely be bypassed, for those interested in doing so, without sending us any data. While we'd love to see you participate in helping us collect build data, and hope you'll do so, failing to opt-in means nothing at all will be transmitted to Google or elsewhere.
+
+You can expect to see this in a new release in the coming months as we first finish a comprehensive privacy policy for the feature.
+
+## What's next
+
+In Sprint 15, which started yesterday, the team is focusing on implementing content previews in the next version of Faust as well as reducing some technical debt that has lead to issues on our GitHub repo. Expect to see a new, faster, release as a result at some point in the next two weeks.
diff --git a/internal/faustjs.org/blog/2022-08-03-sprint-15-update.md b/internal/faustjs.org/blog/2022-08-03-sprint-15-update.md
new file mode 100644
index 000000000..6f2eaff9b
--- /dev/null
+++ b/internal/faustjs.org/blog/2022-08-03-sprint-15-update.md
@@ -0,0 +1,20 @@
+---
+title: Sprint 15 Update
+description: Updates from the teams work on Sprint 15
+slug: sprint-15-update
+hide_table_of_contents: true
+---
+
+Yesterday the team working on Faust finished Sprint 15 and started work on our next Sprint, 16, which we will be in for the next two weeks. The theme of the sprint was to finish porting the post previews feature to the new version of Faust as well as to address as many [GitHub issues](https://github.com/wpengine/faustjs/issues) as we could.
+
+## What we accomplished
+
+Unfortunately we haven't yet finished the new preview feature as complexities of integrating the feature with the new Apollo library slowed the work down more than we would have liked. We should be able to complete it in the coming days but it was not completed as part of the sprint as we would have liked.
+
+We did, however, catch up on our backlog of issues as planned. This included reducing the client bundle size and upgrading to GQty 2.3.0. We hope this work will make life a bit easier for folks currently using Faust in production.
+
+## What's next
+
+Next up we're focusing solely on finishing out "plugin" system for Faust. This is a series of hooks that will allow folks to build on Faust for their own projects. Maybe you want to add in a feature or swap out something we're doing? No problem. Just like WordPress plugins you'll be able to extend Faust to fit your needs and, if you're so inclined, the needs of the community in general.
+
+While the plugin system is our primary goal for these two weeks we're also still finishing up post previews and working to ensure we can get some basic telemetry data on how folks are using the framework. The latter is being done in GA4 but, due to changes in GA4, will require a bit more work for us to be able to implement it. On the positive side this will make analytics even more private due to a proxy that can mask IP address and other data. On the downside, building that proxy will mean more work for the team in the coming days. It will be worth it, however, as it can help us build the features you need in the future.
diff --git a/internal/faustjs.org/blog/2022-08-16-sprint-16-update.md b/internal/faustjs.org/blog/2022-08-16-sprint-16-update.md
new file mode 100644
index 000000000..629f8dc02
--- /dev/null
+++ b/internal/faustjs.org/blog/2022-08-16-sprint-16-update.md
@@ -0,0 +1,22 @@
+---
+title: Sprint 16 Update
+description: Updates from the teams work on Sprint 16
+slug: sprint-16-update
+hide_table_of_contents: true
+---
+
+Hello folks! I’m Terri, one of the new software engineers working on the team developing Faust. I’ll be supplying the update on the team’s progress the last two weeks on sprint 16, as well as a quick peek at what we're working on for the remainder of August.
+
+## What we accomplished
+
+Yesterday, August 16th, the plugin system code was completed for the new version of Faust. The goal of this new plugin system is to allow developers to provide easy-to-implement solutions for themselves and other users. A plugin for this new version of Faust is a simple class with a constructor for options, and an “apply” method. This method has a function as an argument called `callHook`, which is a callback function to apply logic to certain types of hooks. For example, a developer may want to alter what data is fetched in the seed query, or what templates get resolved in the template resolver. Each of these actions now have a corresponding “hook” to which custom functionality can be applied.
+
+In addition to this, plugins in the new system now have `@wordpress/hooks` behind an experimental flag, as well as tests that ensure that a developer’s experimental plugins have their apply methods called while those that don’t have an apply method fail silently when specified in the `experimentalPlugins` config property. Testing also now ensures that the possible lack of the `experimentalPlugins` property does not introduce any adverse effects, too, allowing developers to tinker with building plugins with less implementation.
+
+Beyond the plugin system for the new version of Faust, we also completed an architecture document for a service to handle GA4’s new requirements with telemetry, ensuring that the team has a plan for keeping data anonymous and building a reliable reporting system. We implemented post previews and authorization for previews, too, so folks can examine posts while in the block editor.
+
+## What's next
+
+The team is now closing in on a fix for the breaking changes introduced when Next.js took middleware out of beta. The handleSitemapRequests function used in conjunction with Next.js 12.2 will once again allow developers to easily proxy their WordPress sitemap to their headless frontend once these code changes are approved and merged.
+
+In Sprint 17, we are also working on planning out our approach for implementing support for Next.js file-based pages. Our current data fetching conventions and abstractions work well inside the template hierarchy system, but we want to support Next.js based pages too, while maintaining the same level of functionality. Having this flexibility will help developers create pages outside of the template hierarchy without needing to create a page for every route, putting a wider range of options on the table.
\ No newline at end of file
diff --git a/internal/faustjs.org/blog/2022-08-31-sprint-17-update.md b/internal/faustjs.org/blog/2022-08-31-sprint-17-update.md
new file mode 100644
index 000000000..f3b285ee3
--- /dev/null
+++ b/internal/faustjs.org/blog/2022-08-31-sprint-17-update.md
@@ -0,0 +1,24 @@
+---
+title: Sprint 17 Update
+description: Updates from the team's work on Sprint 17
+slug: sprint-17-update
+hide_table_of_contents: true
+---
+
+We finished Sprint 17 yesterday, our 17th 2-week Sprint of the year. Our current focus has been two-fold: first, to release a new version of Faust using Apollo as our GraphQL library and, second, to build a plan for how to best integrate Gutenberg (the block editor) into a headless site with the minimum amount of developer friction. As far as progress on both those endeavors is concerned, the Sprint was a success.
+
+## What we accomplished
+
+One of our more important features in Faust has been the support of Sitemaps as implemented by plugins such as [Yoast SEO](https://wordpress.org/plugins/wordpress-seo/) and others. While we've had the feature for a while, Next.js 12.2 [changed their middleware implementation rather significantly](https://nextjs.org/blog/next-12-2) leaving the feature broken for our users. We now have a fix in place that avoids using Next's middleware and hope to have it in your hands in the coming weeks.
+
+In addition to updating our sitemap feature, the team has also been learning Gutenberg development to better understand WordPress development as a whole. Most of our backgrounds are either in classic WordPress or in JavaScript, so Gutenberg, at least at the level we need to understand it, has been a learning experience for everyone this quarter. With the conclusion of Sprint 17 we feel we have enough experience with it to finally start looking at how we can use it to make headless development better. For example, what if you could re-use your components in both the editor and on your headless front-end? There are many questions and many avenues to pursue and, over the coming weeks, we'll be putting together a plan to do so. To me, personally, this is one of the most exciting possibilities for headless WordPress. Unlocking the potential of Gutenberg for headless sites will all for use and re-use of content on a scale that just isn't possible in classic WordPress and the potential is amazing.
+
+Finally, we also worked to scrub a number of bugs in the Sprint including upgrading dependencies and plenty of others. Look for the results in our next release coming soon.
+
+## What's next
+
+Our next Sprint will be focused on two things. First, better content previews for the next version of Faust. The new version will enable a whole new ability to easily develop headless WordPress sites, including its own plugin system and the ability to utilize a template system very similar to WordPress' own [template hierarchy](https://developer.wordpress.org/themes/basics/template-hierarchy/). Now we need to update our content previews to take advantage of it.
+
+Second, we're moving beyond learning Gutenberg development ourselves and will be spending time this upcoming Sprint developing a high-level plan for how to best utilize it in headless WordPress development. Expect to see the results of these plans starting in the 4th quarter of 2022.
+
+Finally, we'll be focusing heavily on documentation and other tasks to make sure you'll be able to hit the ground running when we re-release Faust at the end of September. We can't wait to show you what we've been working on here!
diff --git a/internal/faustjs.org/blog/2022-09-14-sprint-18-update.md b/internal/faustjs.org/blog/2022-09-14-sprint-18-update.md
new file mode 100644
index 000000000..43f880df4
--- /dev/null
+++ b/internal/faustjs.org/blog/2022-09-14-sprint-18-update.md
@@ -0,0 +1,18 @@
+---
+title: Sprint 18 Update
+description: Updates from the team's work on Sprint 18
+slug: sprint-18-update
+hide_table_of_contents: true
+---
+
+We're 1/2 way through September and nearly finished with the first version of something completely new. This past Sprint was focused on getting the next major version of Faust ready so that we can get it in your hands by the end of this month. We're super excited about it. It's going to change everything!
+
+## What we accomplished
+
+The final feature of the next version of Faust was completed, post previews. This leaves us at a "code complete" point for the new version which will be ready later this month. It has all the same features as Faust currently does including authentication and post previews but adds some major new capabilities including a template system that mimics WordPress' [template hierarchy](https://developer.wordpress.org/themes/basics/template-hierarchy/) and replaces GQty with the more capable [Apollo](https://www.apollographql.com) library to ensure your Faust-powered site can be as powerful as you need it to be.
+
+## What's next
+
+Sprint 19 is all about preparing for the release of the next version of Faust. The team will be splitting the code into a new repository, preparing a new site and setting up to launch the code with a brand new name.
+
+Why a new name? The new version we're finishing up isn't just big, it's huge and a new name helps reflect that change. In addition, it helps us make sure we can continue to more easily support your existing sites already on Faust. We're excited about the change and, once we can show you more, I think you will be too.
diff --git a/internal/faustjs.org/blog/2022-09-30-sprint-19-update.md b/internal/faustjs.org/blog/2022-09-30-sprint-19-update.md
new file mode 100644
index 000000000..16475295d
--- /dev/null
+++ b/internal/faustjs.org/blog/2022-09-30-sprint-19-update.md
@@ -0,0 +1,22 @@
+---
+title: Sprint 19 Update
+description: Updates from the team's work on Sprint 19
+slug: sprint-19-update
+hide_table_of_contents: true
+---
+
+This week the team finished Sprint 19, our latest 2 weeks of work, which was focused on polishing the new version of Faust and preparing to release it to you. We've been focusing on what to call the project, how to make sure those of you using existing Faust can continue to do so while needed as well as preparing plans for post-launch features and work that we want to focus on all while taking some time off and dodging hurricanes (you're reading this late as we're a fully-remote team and I am based in Sarasota, FL which was just hit by Hurricane Ian this week).
+
+## What we accomplished
+
+Most of our work was spent deciding how to best handle a new library that is vastly different than Faust has been built in the past. The syntax and other uses of moving from GQty to Apollo alone make things quite differently than it had been before. As a result we're working on solutions to ensure the new version is a separate install than what you've used in the past. This ensures, with a 4th quarter launch before the holidays, that your existing projects are safe and supported going forward. If you have, for example, "*" in your package.json for Faust (not a solution we recommend but, we realize, something a lot of people do), if we weren't careful that could break what you have. That won't be the case with the new version. Instead we're working on migration guides, package organization and more to ensure existing users are safe and supported and can migrate to the new library as needed.
+
+## What's next
+
+Sprint 20 is focused on preparing that new release. We want to have the new Faust into your hands in the next couple of weeks and that is what we're currently working on. This includes setting up new packages, finishing testing, prepping documentation and more. We've also cleaned up our backlog and will be working on filling out future epics to ensure work on new features, such as full support for Gutenberg and the Block Editor that go beyond anything you've seen yet in headless WordPress, can kick off in the coming weeks.
+
+Next week, on 1 October to be specific, we're also happy to announce we have an official lead developer on the team that builds Faust. If you're interacted with our support on Discord or elsewhere you've probably come across Blake Wilson. He's one of the original Faust developers and was instrumental both in the current version and the new version we're about to release. I'm happy to announce he's been promoted to Senior Software Engineer here at WP Engine and will officially be taking over the team lead spot for Faust as well.
+
+It's an exciting time for Faust and the team building it. Personally it took me a long time to understand the value of headless WordPress. Once I came to Atlas I could see the value but the tools were still too immature to really unlock its full potential. With the new version of Faust the rocket has lifted off and I am super excited that we're finally bringing you a full framework that can grow with your projects and with WordPress itself all while making headless WordPress development as easy and powerful as WordPress heavyweights like Genesis have done for the WordPress framework over the past decade.
+
+Let's do this!
diff --git a/internal/faustjs.org/blog/2022-10-12-sprint-20-update.md b/internal/faustjs.org/blog/2022-10-12-sprint-20-update.md
new file mode 100644
index 000000000..8331c3ce9
--- /dev/null
+++ b/internal/faustjs.org/blog/2022-10-12-sprint-20-update.md
@@ -0,0 +1,38 @@
+---
+title: Sprint 20 Update
+description: Updates from the team's work on Sprint 20
+slug: sprint-20-update
+hide_table_of_contents: true
+---
+
+It's alive!
+
+After a lot of work we're happy to announce that the new code for Faust is available on npm. You can find the core package [here](https://www.npmjs.com/package/@faustwp/core) and our new CLI package [here](https://www.npmjs.com/package/@faustwp/cli).
+
+
+
+While these are ready to use, please note we're putting the final polish on an updated documentation site so most of it, for now, is very much for those of you who really like to fiddle.
+
+Also note that this is a new npm organization. This means that your existing code will not auto-update. This new code is a major departure from how we had built Faust and, as a result, it will take some work to migrate your existing implementations.
+
+## What we accomplished
+
+This past sprint was all about getting the new version of Faust online. Until two weeks ago we had been engaged in a project to rename the framework but that was scrapped, for a few reasons, at the last minute leaving us scrambling a bit to launch the code with the Faust brand in such a way as to not risk anyone's site who might be using "*" or similar in their package.json.
+
+So what does new Faust have that makes it so different?
+
+First, it's built using [Apollo](https://www.apollographql.com) instead of GQty. This makes the whole project much more scalable and suitable for larger sites but also requires a lot of your existing Faust code to require migration to the new style which uses a different syntax and whole methodology for delivering your data.
+
+Next, Faust now makes all the issues we saw in trying to figure out routing between WordPress and Next.js much easier. We've even added a Next version of the [WordPress template hierarchy](https://developer.wordpress.org/themes/basics/template-hierarchy/) which makes creating the right template as simple as creating a single JavaScript file.
+
+Of course, if the theme of a switch to Apollo is scalability, we didn't want to just stop here. Faust now has a plugin system allowing you to build on top of Faust like you might have done with WordPress or any other modern system.
+
+Finally, Faust still has all the major features, including authentication and content previews, that you've come to rely on. Now they're all just more robust and more capable of handling the requirements of any WordPress site, even the most complicated sites.
+
+What we haven't finished yet, as I mentioned above, is all the documentation. Expect to see new and updated documentation available here in the coming weeks.
+
+## What's next
+
+Now that the code is live we're going to spend a sprint or more focusing on documentation and cleanup. Like any software product, Faust has been thoroughly tested but a larger user base will surely find bugs and we'll be watching for them and ready to fix them.
+
+Once we have our documentation in a better place we'll be pivoting to better supporting Gutenberg and the Block Editor. Imagine a whole block library built in and for headless. That's what we're working on for our next major feature. You'll be able to use the full power of the Block Editor in the WordPress Dashboard as well as be able to import existing front-end components as new blocks easily with only minimal conversion. It's going to be a huge gamechanger for headless WordPress and we can't wait to show it to you!
diff --git a/internal/faustjs.org/blog/2022-10-26-sprint-21-update.md b/internal/faustjs.org/blog/2022-10-26-sprint-21-update.md
new file mode 100644
index 000000000..4d50ff5ca
--- /dev/null
+++ b/internal/faustjs.org/blog/2022-10-26-sprint-21-update.md
@@ -0,0 +1,24 @@
+---
+title: Sprint 21 Update
+description: Updates from the team's work on Sprint 21
+slug: sprint-21-update
+hide_table_of_contents: true
+---
+
+Documentation, documentation, documentation.
+
+The theme of our last sprint was documentation and it showed. We're super close to launching new documentation for new Faust. You'll see the updates on [https://faustjs.org] in the coming weeks.
+
+
+
+## What we accomplished
+
+We worked hard this sprint to rewrite the Faust documentation to work with the new version of Faust. It's been a long process but we're confident that we're on the verge of a much more robust documentation site which will make working with Faust even easier.
+
+As part of the upcoming documentation change I did want to call out that, as the older version of Faust isn't going anywhere, neither is its documentation. Faustjs.org will be updated for new Faust and the existing documentation will be moved to a legacy domain to ensure its continued availability for any projects you may have in flight.
+
+In addition to documentation we also released new versions of the npm packages with minor bugfixes and a small change that significantly reduced the bundle size of the application generated during a build. You can see the full change log for the latest versions [here](https://github.com/wpengine/faustjs/releases).
+
+## What's next
+
+Next we're going to be putting the final touches on the new documentation so we can launch the site and start work to update the Blueprints to work with new Faust. Together this will make getting started on Faust much easier and we think you'll agree that new Faust is something special indeed.
diff --git a/internal/faustjs.org/docs/authentication.mdx b/internal/faustjs.org/docs/authentication.mdx
new file mode 100644
index 000000000..31febbfb0
--- /dev/null
+++ b/internal/faustjs.org/docs/authentication.mdx
@@ -0,0 +1,7 @@
+---
+slug: auth
+title: Authentication
+description: Use Faust.js' built-in authentication strategies to authenticate users from your WordPress backend
+---
+
+### This document is in progress. Check back soon for content!
\ No newline at end of file
diff --git a/internal/faustjs.org/docs/faq.mdx b/internal/faustjs.org/docs/faq.mdx
new file mode 100644
index 000000000..e2efb9f06
--- /dev/null
+++ b/internal/faustjs.org/docs/faq.mdx
@@ -0,0 +1,23 @@
+---
+slug: faq
+title: FAQ
+description: Frequently Asked Questions
+---
+
+## Frequently Asked Questions
+
+### If I need more support, where should I ask questions?
+
+Use one of the channels below to contact the Faust team for support.
+
+[GitHub](https://github.com/wpengine/faustjs) - Faust GitHub documentation and codebase.
+
+[Discord](https://discord.gg/J2khkF9XYK) - Interactive chat support on Discord.
+
+### Where can I find more information about development and future features for the WordPress plugin?
+
+Great question! The development team posts weekly summaries of sprints related to Faust, [here](https://faustjs.org/blog).
+
+### Why the name “Faust”?
+
+Johann Faust was a German printer and was instrumental in the invention of the printing press, along with his partner Johann Gutenberg. In the same way the printing press democratized the spread of information, the mission of Faust.js is to support and further the vision of WordPress to democratize publishing on the web.
diff --git a/internal/faustjs.org/docs/faustwp/seed-query.mdx b/internal/faustjs.org/docs/faustwp/seed-query.mdx
index 887ff8ee1..84900f65b 100644
--- a/internal/faustjs.org/docs/faustwp/seed-query.mdx
+++ b/internal/faustjs.org/docs/faustwp/seed-query.mdx
@@ -6,7 +6,7 @@ description: This section describes the FaustWP Seed Query.
The Seed Query is a request that is fired when a user is trying to visit a URL which requests data from WP for the given URL. With this data we are able to get a list of possible templates for the given route.
-### What is it used for?
+### What Is It Used For?
The Seed Query is used for resolving templates in the Faust template hierarchy.
diff --git a/internal/faustjs.org/docs/faustwp/settings.mdx b/internal/faustjs.org/docs/faustwp/settings.mdx
index 66cddf68d..510ec1f58 100644
--- a/internal/faustjs.org/docs/faustwp/settings.mdx
+++ b/internal/faustjs.org/docs/faustwp/settings.mdx
@@ -12,7 +12,7 @@ allows you to customize the behavior of the plugin by configuring certain featur
The following options are available to enable/disabled based on your requirements:
-### Disabling WordPress theme admin pages
+### Disabling WordPress Theme Admin Pages
This option is controlled by the `Disable WordPress theme admin pages` checkbox.
When enabled it removes certain wp-admin menu items that aren't supported in a headless environment.
@@ -28,7 +28,7 @@ It will also remove any features that require the `Customizer` which means that
If you still want to have access to those pages then, you can disable this setting.
-### Enabling Post and Category URL rewrites
+### Enabling Post and Category URL Rewrites
This option is controlled by the `Enable Post and Category URL rewrites` checkbox. When enabled it will
perform domain replacement of all terms, post, preview, category links from your `WordPress URL` into your headless `Front-end site URL` by using
@@ -44,7 +44,7 @@ will prevent the original content links from pointing to the headless url.
> **NOTE:** It is recommended to keep this setting enabled so that all links will be properly served by the headless site.
-### Enabling public route redirects
+### Enabling Public Route Redirects
This option is controlled by the `Enable public route redirects` checkbox. When enabled it will
redirect any public API requests to your `WordPress URL` into your headless `Front-end site URL` by using
@@ -58,7 +58,7 @@ then if you visit any page on your `WordPress URL` will be redirected to the hea
If you don't want this redirect to happen then you can disable this option which allows you to access the original WP site.
-### Using the WordPress domain for media URLs in post content
+### Using the WordPress Domain for Media URLs in Post Content
This option is controlled by the `Use the WordPress domain for media URLs in post content` checkbox and is disabled by default.
When enabled it will perform a `src` and `srcset` replacement of all media urls of the sites post/page content using
diff --git a/internal/faustjs.org/docs/getting-started.mdx b/internal/faustjs.org/docs/getting-started.mdx
index dcbe41b3b..86159b093 100644
--- a/internal/faustjs.org/docs/getting-started.mdx
+++ b/internal/faustjs.org/docs/getting-started.mdx
@@ -43,7 +43,7 @@ You can now visit [http://localhost:3000](http://localhost:3000) to see your new
Currently, the posts and pages you see are coming from our WordPress site at [https://faustexample.wpengine.com](https://faustexample.wpengine.com). In the next step, we'll show you how to hook up your own WordPress site.
-## Connecting your WordPress site
+## Connecting Your WordPress Site
The example app above loads WordPress content from the demo site at [https://faustexample.wpengine.com](https://faustexample.wpengine.com).
diff --git a/internal/faustjs.org/docs/migrationPath/overview.mdx b/internal/faustjs.org/docs/migrationPath/overview.mdx
index 17912509d..a7c54667c 100644
--- a/internal/faustjs.org/docs/migrationPath/overview.mdx
+++ b/internal/faustjs.org/docs/migrationPath/overview.mdx
@@ -1,4 +1,7 @@
---
slug: /migrationPath/overview
-title: Migrate from old version of Faust.js ( < v1.0.0 ) to Faust ( > v1.0.0 )
+title: Migration from Legacy Faust
---
+Migrate from old version of Faust.js to new Faust
+
+### This document is in progress. Check back soon for content!
\ No newline at end of file
diff --git a/internal/faustjs.org/docs/next/guides/post-page-previews.mdx b/internal/faustjs.org/docs/next/guides/post-page-previews.mdx
index 7e2557765..f4ef1754f 100644
--- a/internal/faustjs.org/docs/next/guides/post-page-previews.mdx
+++ b/internal/faustjs.org/docs/next/guides/post-page-previews.mdx
@@ -12,14 +12,14 @@ Your headless secret is a value that authenticates requests to WordPress. This s
### Copy your Headless Secret
-Find your Headless Secret in **WP-Admin -> Settings -> Faust**. Copy this value:
+Find your Headless Secret in `WP-Admin` -> `Settings` -> `Faust`. Copy this value:
-### Add your Headless Secret to your `.env.local` File
+### Add Your Headless Secret to Your `.env.local` File
Add the `FAUSTWP_SECRET_KEY` key to your `.env.local` file with the headless secret as the value. Your `.env.local` file should already have a value for `NEXT_PUBLIC_WORDPRESS_URL`. The file should look something like this:
@@ -31,7 +31,7 @@ NEXT_PUBLIC_WORDPRESS_URL=http://localhost:8080
FAUSTWP_SECRET_KEY=xxxx
```
-### Ensure you've created your `faust.config.js` file and are importing it in your `_app.js`
+### Create Your `faust.config.js` File Import It In `_app.js`
Like the [`next/getting-started`](https://github.com/wpengine/faustjs/tree/main/examples/next/faustwp-getting-started) Faust example, your [`faust.config.js`](https://github.com/wpengine/faustjs/blob/main/examples/next/faustwp-getting-started/faust.config.js) file.
@@ -66,7 +66,7 @@ import { apiRouter } from '@faustwp/core';
export default apiRouter;
```
-## Create your Preview Page
+## Create Your Preview Page
With your headless secret set and the `authorizeHandler` ready to handle requests, you can now create a Next.js [page](https://nextjs.org/docs/basic-features/pages) for previews. Create a file at `pages/preview.js` with the following:
@@ -127,7 +127,7 @@ if (props.loading) {
If you don't handle the loading state you may find that the post/page data will be undefined.
-### What happens if you don't use on the `asPreview` property?
+### Is the `asPreview` Property Necessary?
If you wish to disable post/page previews for a particular template hierarchy page you can simply ignore the `asPreview` parameter.
@@ -135,16 +135,16 @@ If you wish to disable post/page previews for a particular template hierarchy pa
Start by logging into your WordPress Admin. For this example, we'll create a new post.
-So far, I've added a title and a simple line of text for the content. To view this post as a preview on your front end, click the **Preview** link (1). From there, click, **Preview in new tab** (2):
+So far, I've added a title and a simple line of text for the content. To view this post as a preview on your front end, click the `Preview` link (1). From there, click, `Preview in new tab` (2):
-Notice the **Publish** button is also visible, meaning that you still need to publish the post. Therefore you can now view the post on the frontend without being authenticated.
+Notice the `Publish` button is also visible, meaning that you still need to publish the post. Therefore you can now view the post on the frontend without being authenticated.
-Clicking on **Preview in new tab** should take you to your post preview page with the current preview content:
+Clicking on `Preview in new tab` should take you to your post preview page with the current preview content:
- Built on top of Next.js and React to take advantage of state-of-the-art
- frontend tools
- >
- ),
- link: '/docs/next/getting-started',
- },
- {
- title: 'GraphQL',
+ title: 'Apollo',
description: (
<>
- Use GQty to fetch data from the WordPress GraphQL API without writing
- GraphQL queries.
+ Flexibly perform declarative queries to manipulate and structure data
+ using Apollo.
>
),
- link: '/docs/next/guides/fetching-data',
+ link: '/blog/the-future-of-faust#where-faustjs-is-going',
},
{
title: 'Previews',
description: (
<>
- Preview your posts and pages before publishing and rewrite WordPress
+ Preview posts and pages before publishing and rewrite WordPress
preview URLs to your frontend.
>
),
link: '/docs/next/guides/post-page-previews',
},
- {
- title: 'SSG and SSR',
- description: (
- <>
- Easily render pages on the server, or generate static pages at
- build-time.
- >
- ),
- link: '/docs/next/guides/ssr-ssg',
- },
- {
- title: 'React Hooks',
- description: (
- <>Fetch posts, categories, pages, and more using standard URL params.>
- ),
- link: '/docs/next/reference/hooks',
- },
{
title: 'WP Template Hierarchy',
description: (
<>Use chained requests, resolve custom post type templates, and more.>
),
- link: '',
+ link: '/docs/templates',
},
{
- title: 'Plugin System',
+ title: 'Seed Query',
description: (
- <>Use plugins to add quick and flexible functionality to your product.>
+ <>
+ Use a seed query to obtain a list of possible templates for any given
+ route.
+ >
),
- link: '',
+ link: '/docs/faustwp/seed-query',
},
{
- title: 'Custom Post Types',
+ title: 'Next.js',
description: (
<>
- Add custom post types to your WordPress site and easily fetch them from
- your frontend.
+ Build a static site with WordPress data outside the template hierarchy with Next.js file based pages.
>
),
- link: '/docs/next/guides/custom-post-types',
+ link: '/docs/next/reference/getNextStaticProps',
},
];
diff --git a/internal/faustjs.org/src/components/GetStarted/HomepageGetStarted.js b/internal/faustjs.org/src/components/GetStarted/HomepageGetStarted.js
index e10c4c2b1..b23ba54d6 100644
--- a/internal/faustjs.org/src/components/GetStarted/HomepageGetStarted.js
+++ b/internal/faustjs.org/src/components/GetStarted/HomepageGetStarted.js
@@ -30,7 +30,7 @@ export default function HomepageGetStarted() {
+ to="/docs/getting-started">
Get Started
diff --git a/internal/legacy.faustjs.org/docusaurus.config.js b/internal/legacy.faustjs.org/docusaurus.config.js
index 3cace0d22..736d3cbf9 100644
--- a/internal/legacy.faustjs.org/docusaurus.config.js
+++ b/internal/legacy.faustjs.org/docusaurus.config.js
@@ -16,6 +16,7 @@ module.exports = {
favicon: 'img/favicon.ico',
organizationName: 'wpengine', // Usually your GitHub org/user name.
projectName: 'faustjs', // Usually your repo name.
+ noIndex: process.env.SITE_NO_INDEX ?? false,
themeConfig: {
algolia: {
// If Algolia did not provide you any appId, use 'BH4D9OD16A'
@@ -26,14 +27,14 @@ module.exports = {
indexName: 'faustjs',
},
- // announcementBar: {
- // id: 'depreciation_notice',
- // content:
- // '⭐️ This version of Faust.js is being deprecated. Visit the new version at faustjs.org ⭐️',
- // backgroundColor: '#7e5cef',
- // textColor: '#FFF',
- // isCloseable: false,
- // },
+ announcementBar: {
+ id: 'depreciation_notice',
+ content:
+ '⭐️ This version of Faust.js is being deprecated. Visit the new version at faustjs.org ⭐️',
+ backgroundColor: '#7e5cef',
+ textColor: '#FFF',
+ isCloseable: false,
+ },
navbar: {
title: 'Faust.js™',
// logo: {
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/core.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/core.mdx
new file mode 100644
index 000000000..004b69397
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/core.mdx
@@ -0,0 +1,16 @@
+---
+slug: ./core
+title: Changelog for @faustjs/core
+description: A central place for Faust.js changelogs
+---
+
+import Changelog, { toc as ChangelogTOC } from '@site/.changelogs/core.md';
+
+
+
+export const toc = (() => {
+ return ChangelogTOC.map((item) => {
+ item.children = [];
+ return item;
+ });
+})();
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/faustwp.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/faustwp.mdx
new file mode 100644
index 000000000..05cadb0d2
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/faustwp.mdx
@@ -0,0 +1,16 @@
+---
+slug: ./faustwp
+title: Changelog for FaustWP
+description: A central place for Faust.js changelogs
+---
+
+import Changelog, { toc as ChangelogTOC } from '@site/.changelogs/faustwp.md';
+
+
+
+export const toc = (() => {
+ return ChangelogTOC.map((item) => {
+ item.children = [];
+ return item;
+ });
+})();
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/next.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/next.mdx
new file mode 100644
index 000000000..59aa6f352
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/next.mdx
@@ -0,0 +1,16 @@
+---
+slug: ./next
+title: Changelog for @faustjs/next
+description: A central place for Faust.js changelogs
+---
+
+import Changelog, { toc as ChangelogTOC } from '@site/.changelogs/next.md';
+
+
+
+export const toc = (() => {
+ return ChangelogTOC.map((item) => {
+ item.children = [];
+ return item;
+ });
+})();
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/react.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/react.mdx
new file mode 100644
index 000000000..941556667
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/changelog/react.mdx
@@ -0,0 +1,16 @@
+---
+slug: ./react
+title: Changelog for @faustjs/react
+description: A central place for Faust.js changelogs
+---
+
+import Changelog, { toc as ChangelogTOC } from '@site/.changelogs/react.md';
+
+
+
+export const toc = (() => {
+ return ChangelogTOC.map((item) => {
+ item.children = [];
+ return item;
+ });
+})();
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/core/reference/config.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/core/reference/config.mdx
new file mode 100644
index 000000000..a370769d7
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/core/reference/config.mdx
@@ -0,0 +1,102 @@
+---
+slug: /core/reference/config
+title: Faust.js core package config
+description: Faust.js provides a default configuration object for your site.
+---
+
+Faust.js provides a default configuration object for your site.
+This object uses as a parameter when exporting the result of the
+`coreConfig` in `faust.config.js`:
+
+```tsx
+import { config as coreConfig } from '@faustjs/core';
+
+if (!process.env.NEXT_PUBLIC_WORDPRESS_URL) {
+ console.error(
+ 'You must provide a NEXT_PUBLIC_WORDPRESS_URL environment variable, did you forget to load your .env.local file?',
+ );
+}
+
+/**
+ * @type {import("@faustjs/core").Config}
+ */
+export default coreConfig({
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ apiClientSecret: process.env.FAUSTWP_SECRET_KEY,
+});
+```
+
+## Config
+
+The Config object has the following properties:
+
+### `wpUrl`
+
+type: `string`
+
+Required: `true`
+
+This is your WordPress URL. This is typically defined in your `.env` file as `NEXT_PUBLIC_WORDPRESS_URL`.
+
+### `apiClientSecret`
+
+type: `string`
+
+Required: `true`
+
+This is your Headless Secret key that can be retrieved from the FaustWP settings Dashboard. This is typically defined in your `.env` file as `FAUSTWP_SECRET_KEY`.
+
+### `gqlUrl`
+
+type: `string`
+
+Required: `false`
+
+This is the value to the URL pathname of your GraphQL endpoint. This defaults to [wpurl](#wpurl) + `/graphql`.
+
+### `apiBasePath`
+
+type: `string`
+
+Required: `false`
+
+This is the value of the base API path of your endpoints for this application. This defaults to `/api/faust`.
+
+### `authType`
+
+type: `redirect | local`
+
+Required: `false`
+
+This is the value of the type of authentication you want to use. It can have two possible values: `redirect` or `local`.
+When `redirect` is set, the user being redirected to WordPress to authenticate. When `local` is set,
+the user initiating a login request from the Next.js application, uses the `useLogin` returns an authorization code used to request a refresh and access token.
+You can read more about the authentication strategies in the [auth guide](http://localhost:3000/docs/next/guides/auth) section of the docs.
+
+This defaults to `redirect`.
+
+### `loginPagePath`
+
+type: `string`
+
+Required: `false`
+
+This is the relative URL path of your frontend login page. This defaults to `/login`.
+
+### `disableLogging`
+
+type: `boolean`
+
+Required: `false`
+
+Set this value to `true` if you want to disable internal `console.log` statements. This defaults to `false`.
+
+### `applyRequestContext`
+
+type: `(url: string, init: RequestInit): Promise | RequestContext`
+
+Required: `false`
+
+Deprecated: `true`
+
+This property is not used anymore and has no effect. You should use this function in [getClient](/docs/next/guides/modifying-the-graphql-request) instead. This will be removed in subsequent versions of Faust.js.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/faustwp/settings.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/faustwp/settings.mdx
new file mode 100644
index 000000000..9f398ee07
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/faustwp/settings.mdx
@@ -0,0 +1,84 @@
+---
+slug: /faustwp/settings
+title: FaustWP Plugin Headless Settings
+description: This section describes the various WP Plugin Headless Settings.
+---
+
+The `Headless` page of the FaustWP Plugin (located within the WP Admin `Settings` Sidebar)
+allows you to customize the behavior of the plugin by configuring certain features. We explain those features in detail:
+
+
+## Features Explained
+
+The following options are available to enable/disabled based on your requirements:
+
+### Disabling WordPress theme admin pages
+
+This option is controlled by the `Disable WordPress theme admin pages` checkbox.
+When enabled it removes certain wp-admin menu items that aren't supported in a headless environment.
+For example, it will remove the following menu items:
+
+* `Appearance > Themes`
+* `Appearance > Theme Editor`
+* `Appearance > Widgets`
+* `Appearance > Customize`
+
+It will also remove any features that require the `Customizer` which means that the
+`Appearance` tab will only contain the menu options.
+
+If you still want to have access to those pages then, you can disable this setting.
+
+### Enabling Post and Category URL rewrites
+
+This option is controlled by the `Enable Post and Category URL rewrites` checkbox. When enabled it will
+perform domain replacement of all terms, post, preview, category links from your `WordPress URL` into your headless `Front-end site URL` by using
+relevant `link` filters.
+
+For example if your WP `WordPress URL` is `http://example.com` and your `Front-end site URL` is `http://headless.com`
+then it will replace all post/page/category links to point to the headless `Front-end site URL`:
+
+`http://example.com/posts/category/recipes/` -> `http://headless.com/posts/category/recipes/`
+
+If you don't want this replacement to happen then you can disable this option which
+will prevent the original content links from pointing to the headless url.
+
+> **NOTE:** It is recommended to keep this setting enabled so that all links will be properly served by the headless site.
+
+### Enabling public route redirects
+
+This option is controlled by the `Enable public route redirects` checkbox. When enabled it will
+redirect any public API requests to your `WordPress URL` into your headless `Front-end site URL` by using
+the [template_redirect](https://developer.wordpress.org/reference/hooks/template_redirect/) filter.
+
+For example if your WP `WordPress URL` is `http://example.com` and your `Front-end site URL` is `http://headless.com`
+then if you visit any page on your `WordPress URL` will be redirected to the headless `Front-end site URL` passing any query params as well:
+
+`http://example.com/posts/welcome-to-the-gutenberg-editor/` -> `http://headless.com/posts/welcome-to-the-gutenberg-editor`
+
+If you don't want this redirect to happen then you can disable this option which allows you to access the original WP site.
+
+
+### Using the WordPress domain for media URLs in post content
+
+This option is controlled by the `Use the WordPress domain for media URLs in post content` checkbox and is disabled by default.
+When enabled it will perform a `src` and `srcset` replacement of all media urls of the sites post/page content using
+the [the_content](https://developer.wordpress.org/reference/hooks/the_content/) filter to point back to the `WordPress URL` domain.
+
+For example, if your WP `WordPress URL` is `http://example.com` and your `Front-end site URL` is `http://headless.com`
+then any images served from headless `Front-end site URL` will be rewritten to point to the `WordPress URL`:
+
+`http://headless.com/wp-content/uploads/2020/07/bird.png` -> `http://example.com/wp-content/uploads/2020/07/bird.png`
+
+This happens when a user migrates a classical WP site a root domain of `example.com` to `headless.com`
+(to allow their headless front-end to be served from `example.com` and pull data from the WP instance that was moved to `headless.com`)
+then all media URLs in post content will be wrong.
+
+If for example you uploaded images to the post content their image srcs will still point to `example.com/wp-content/uploads/2020/07/bird.png`,
+resulting in a `404` because the WP instance no longer lives at `example.com`.
+
+You can enable this option to allow having the media content served by the classical
+WP site a root domain and when you switch the live domain to headless,
+you should disable the option to replace those links worrying about missing media.
+
+> **NOTE:** When moving your site to a new domain it is recommended to perform a search/replace on your website’s database.
+This is to ensure all hard-coded references of the old domain in your database point to your live production domain instead. [Read more about search/replace](https://wpengine.com/support/move-domain-new-environment/#Optional_Perform_a_search_and_replace)
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/going-to-production/deployment.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/going-to-production/deployment.mdx
new file mode 100644
index 000000000..5a7986675
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/going-to-production/deployment.mdx
@@ -0,0 +1,46 @@
+---
+slug: /going-to-production/deployment
+title: Deploy Your Faust.js App
+---
+
+## Picking The Right Node.js Version
+
+Faust.js supports Node.js v14.x and v16.x. Please make sure you are using a Node.js version that is compatible when deploying to avoid unexpected errors.
+
+## Building Your App
+
+Faust.js is build on top of [Next.js](https://nextjs.org/), so the build process is identical. Take a look at the [Next.js Build API](https://nextjs.org/docs/deployment#nextjs-build-api) for info relating to how Next.js generates an optimized production build.
+
+## Deploying To Atlas
+
+Atlas is the most effortless way to deploy a Faust.js app. Connect your GitHub repo and Atlas will automatically build and deploy your Faust.js project on each push. Some of the benefits you get out of the box are:
+
+- Automatic installation of required plugins ([FaustWP](https://wordpress.org/plugins/faustwp/), [WPGraphQL](https://wordpress.org/plugins/wp-graphql/), etc.)
+- Automatic setup of Faust.js environment variables
+- Automatic configuration of FaustWP headless settings
+- WordPress and your headless app live in the same place
+- Automatic rebuilds on code changes
+- Support for [custom domains](https://wpengine.com/support/add-domain-in-user-portal/)
+
+[Deploy your Faust.js app and try Atlas for free!](https://wpengine.com/atlas/#form)
+
+## Self Hosted
+
+You can also self host Faust.js apps on any hosting provider that supports Node.js.
+
+To self host your Faust.js app, you will need to first build the app, then start it. Make sure you have the `next build` and `next start` scripts specified in your `package.json` file:
+
+```json title="package.json"
+{
+ "scripts": {
+ "build": "next build",
+ "start": "next start"
+ }
+}
+```
+
+Then, from the Node.js server run `npm run build` to build the app and `npm run start` to start it.
+
+## Related
+
+- [Next.js: Deployment](https://nextjs.org/docs/deployment)
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/going-to-production/optimizations.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/going-to-production/optimizations.mdx
new file mode 100644
index 000000000..a110de4be
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/going-to-production/optimizations.mdx
@@ -0,0 +1,55 @@
+---
+slug: /going-to-production/optimizations
+title: Production Optimizations
+---
+
+Below you'll find some recommendations for optimizing your Faust.js app for production.
+
+- [Atlas Specific Optimizations](/docs/going-to-production/optimizations#atlas-specific-optimizations)
+- [Use Static Site Generation (SSG) When Possible](/docs/going-to-production/optimizations#use-static-site-generation-ssg-when-possible)
+- [Ensure Data Selections Are Placed Outside Conditionals](/docs/going-to-production/optimizations#ensure-data-selections-are-placed-outside-conditionals)
+- [Next.js Production Optimizations](/docs/going-to-production/optimizations#nextjs-production-optimizations)
+
+## Atlas Specific Optimizations
+
+Atlas is the most effortless way to deploy a Faust.js app. Below are some recommendations for optimizing your app for production.
+
+### Disable Next.js Compression
+
+Compression is already handled for you in Atlas, so disabling it in your Faust.js app will offload the responsibility from the Node.js process.
+
+```js title="next.config.js"
+const { withFaust } = require('@faustjs/next');
+
+/**
+ * @type {import('next').NextConfig}
+ **/
+module.exports = withFaust({
+ compress: false,
+});
+```
+
+## Use Static Site Generation (SSG) When Possible
+
+Static Site Generation (SSG) is a Next.js concept that generates a static HTML page for each page in your app that uses `getStaticProps`. This is incredibly efficient as you are not making wasteful requests to the WordPress GraphQL API, as your pages are already cached. Pairing SSG with Incremental Static Regeneration (ISR) will cause your pages to be regenerated in the background after a certain amount of time. [By default, Faust.js will revalidate your pages every 15 minutes.](/docs/next/guides/ssr-ssg#setting-up-incremental-static-regeneration-isr)
+
+Learn more:
+
+- [Next.js: Static Site Generation (SSG)](https://nextjs.org/docs/basic-features/data-fetching/get-static-props)
+- [Next.js: Incremental Static Regeneration (ISR)](https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration)
+
+## Ensure Data Selections Are Placed Outside Conditionals
+
+Faust.js uses [GQty](https://gqty.dev/) as it's GraphQL client. GQty works by using [proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) to determine what data selections you access from the `client`, and from there, constructs a GraphQL query.
+
+You should ensure that your data selections are all performed outside of conditionals (`if`, `switch`, etc. statements) so that GQty can detect them sever side. Data selections made inside of conditionals result in some GraphQL requests cascading to the client. This is appropriate when you need to fetch data specifically on the client side, but often times you wan't this data to be fetched server side where it can be cached.
+
+Refer to this GQty troubleshooting guide for ensuring that your data selections are outside of conditionals:
+
+- [GQty Troubleshooting: Data Selections & Conditionals](https://gqty.dev/docs/react/troubleshooting#data-selections--conditionals)
+
+## Next.js Production Optimizations
+
+Next.js has a "Going to Production" guide that goes into further detail on the optimizations you can make for your Faust.js app built on top of Next.js:
+
+- [Next.js: Going to Production](https://nextjs.org/docs/going-to-production#loading-performance)
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/gqty-intro.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/gqty-intro.mdx
new file mode 100644
index 000000000..9b6ba1b8b
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/gqty-intro.mdx
@@ -0,0 +1,81 @@
+---
+slug: /gqty-intro
+title: Introduction to GQty
+description: Introduction to GQty in Faust.js
+---
+
+Faust.js uses GQty under the hood for its GraphQL client.
+
+GQty is a new approach to a GraphQL client. Instead of defining queries by hand, GQty generates queries for you at runtime based on the data your app consumes. Take the following example:
+
+Your app consumes the `title` and `description` from `generalSettings`:
+
+```tsx title="Your App"
+import { client } from 'client'
+
+export default function App() {
+ const query = client.useQuery()
+
+ return(
+
{query.generalSettings.title}
+
{query.generalSettings.description}
+ )
+}
+```
+
+The following query is automatically generated and requested for you:
+
+```graphql
+query {
+ generalSettings {
+ title
+ description
+ }
+}
+```
+
+## React Hooks
+
+GQty has React Hooks for fetching data, mutations, subscriptions, and more:
+
+- [useQuery](https://gqty.dev/docs/react/fetching-data#usequery)
+- [usePaginatedQuery](https://gqty.dev/docs/react/fetching-data#usepaginatedquery)
+- [useTransactionQuery](https://gqty.dev/docs/react/fetching-data#usetransactionquery)
+- [useLazyQuery](https://gqty.dev/docs/react/fetching-data#uselazyquery)
+- [useRefetch](https://gqty.dev/docs/react/fetching-data#userefetch)
+- [useMutation](https://gqty.dev/docs/react/mutations#usemutation)
+- [useSubscription](https://gqty.dev/docs/react/subscriptions#usesubscription)
+
+Faust.js exports these hooks from the `client`. You can use them in your React components like so:
+
+```tsx
+import { client } from 'client';
+
+export default function App() {
+ const {
+ useQuery,
+ usePaginatedQuery,
+ useTransactionQuery,
+ useLazyQuery,
+ useRefetch,
+ useMutation,
+ useSubscription,
+ } = client;
+
+ return(
+ ...
+ )
+}
+```
+
+## Further Reading
+
+We recommend reading the ["What Is & Why"](https://gqty.dev/docs/intro) and ["How It Works"](https://gqty.dev/docs/intro/how-it-works) docs to get a better picture of how GQty works.
+
+Additionally, the following docs may be helpful:
+
+- [Features](https://gqty.dev/docs/intro/features)
+- [Fetching Data in React](https://gqty.dev/docs/react/fetching-data)
+- [React Suspense & Usage Without](https://gqty.dev/docs/react/suspense)
+- [Helper Functions](https://gqty.dev/docs/client/helper-functions)
+- [Troubleshooting](https://gqty.dev/docs/react/troubleshooting)
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/getting-started.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/getting-started.mdx
new file mode 100644
index 000000000..b23b466e0
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/getting-started.mdx
@@ -0,0 +1,100 @@
+---
+slug: /next/getting-started
+title: Getting Started with Next.js
+---
+
+# Getting Started with Next.js
+
+## Quick Start
+
+Please install our Next.js Getting Started example using the following command:
+
+### On MacOS, Linux, or WSL (bash):
+
+```bash
+npx create-next-app \
+ -e https://github.com/wpengine/faustjs/tree/main \
+ --example-path examples/next/getting-started \
+ --use-npm \
+ my-app
+cd my-app
+```
+
+### On Windows with [Powershell Core](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-7.1):
+
+```ps
+npx create-next-app `
+ -e https://github.com/wpengine/faustjs/tree/main `
+ --example-path examples/next/getting-started `
+ --use-npm `
+ my-app && cd my-app
+```
+
+> NOTE: If you are on Windows, we suggest using [Powershell Core](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-windows?view=powershell-7.1) and [Windows Terminal](https://www.microsoft.com/en-us/p/windows-terminal/9n0dx20hk701).
+
+Now, copy the sample environment template:
+
+```bash
+cp .env.local.sample .env.local
+```
+
+Finally, run the dev server:
+
+```bash
+npm run dev
+```
+
+You can now visit [http://localhost:3000](http://localhost:3000) to see the example site!
+
+
+
+
+
+Currently, the posts and pages you see are coming from our WordPress site at [https://headlessfw.wpengine.com](https://headlessfw.wpengine.com). In the next step, we'll show you how to hook up your own WordPress site.
+
+## Connecting your WordPress site
+
+The example app above loads WordPress content from the demo site at [https://headlessfw.wpengine.com](https://headlessfw.wpengine.com).
+
+To point it to a different WordPress site, first, [make sure you have setup the necessary WordPress plugins.](../tutorial/setup-faustjs#installing-plugins-on-wordpress)
+
+Once the necessary plugins have been installed, open the `.env.local` file you created earlier, it should look something like this:
+
+```bash
+# Your WordPress site URL
+NEXT_PUBLIC_WORDPRESS_URL=https://headlessfw.wpengine.com
+
+# Plugin secret found in WordPress Settings->Headless
+FAUSTWP_SECRET_KEY=YOUR_PLUGIN_SECRET
+```
+
+Update the `NEXT_PUBLIC_WORDPRESS_URL` value with your WordPress site URL (be sure to include `http://` or `https://`).
+
+Additionally, update the `FAUSTWP_SECRET_KEY` value with the secret key found in Settings → Headless in your WordPress admin area to support previews.
+
+
+
+## Setting Your Permalinks
+
+Finally, set your permalinks to the following structure in WP Admin -> Settings -> Permalinks:
+
+```
+/posts/%postname%/
+```
+
+
+
+You can learn more about modifying your permalink structure by viewing the [Permalinks Guide](/docs/next/guides/permalinks).
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/authentication.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/authentication.mdx
new file mode 100644
index 000000000..8c782e107
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/authentication.mdx
@@ -0,0 +1,248 @@
+---
+slug: /next/guides/auth
+title: Authentication
+description: Use Faust.js' built-in authentication strategies to authenticate users from your WordPress backend
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+Authentication can be a cumbersome process when building headless WordPress sites. Thankfully, Faust.js takes care of all your authentication needs in your Next.js application.
+
+## How It Works
+
+**TL;DR**: Authentication in Faust.js can happen in five main steps:
+
+1. User initiates request to authenticate data.
+2. Faust.js facilitates the request for an authorization code from the FaustWP plugin. This code is a short-lived token used to request a refresh and access token.
+3. Faust.js facilitates a refresh and access token request from the FaustWP plugin using the authorization code.
+4. Faust.js stores the refresh token in a secure, HTTP-only cookie. The token refresh requests a new access token when the current one expires
+5. Faust.js stores the access token in memory that you can use in subsequent authenticated requests.
+
+## Initial Setup
+
+Before you get started with implementing an authentication strategy, you'll need to setup the API Router. You can do this by creating a file, `src/pages/api/faust/[[...route]].ts`, with the following code:
+
+```ts title=src/pages/api/faust/[[...route]].ts
+import 'faust.config';
+import { apiRouter } from '@faustjs/core/api';
+
+export default apiRouter;
+```
+
+## Strategies
+
+There are two authentication strategies available in Faust.js: `redirect` and `local`.
+
+### Redirect Based Authentication
+
+
+
+
+
+Redirect-based authentication is the default strategy in Faust.js. This strategy involves the user being redirected to WordPress to authenticate. Once the user has shown, the user redirects back to the Next.js application with an authorization code you can then use to request a refresh and access token, thus completing the login process.
+
+This strategy is excellent for use cases where your authenticated users are admins/editors/etc. and do not necessarily need a "white label" login/register experience. Typically, you would use the redirect strategy if your primary reason for authentication is previewing.
+
+Since Redirect based authentication is the default authentication method, there is no configuration needed on your end to use it. It comes out of the box, and you'll see it in action when using previews or the [`useAuth`](/docs/next/reference/hooks/useAuth) hook.
+
+### Local Based Authentication
+
+
+
+
+
+Local Based Authentication is the second strategy available in Faust.js. This strategy involves the user initiating a login request from the Next.js application via the `useLogin` hook. Upon successful login, `useLogin` returns an authorization code used to request a refresh and access token, thus completing the login process.
+
+This strategy is excellent for use cases where you want to support a more "white label" login/register experience. This strategy routes un-authenticated requests to your specified Next.js login page. In addition, users who wish to login/register will not have to interact with WordPress or the WordPress backend at all, giving you the flexibility to implement and fine-tune your user flow.
+
+To use this strategy, you'll need to configure your `faust.config.js` file to use the `local` authentication strategy, in addition to the route of your Next.js login page. Take the following `faust.config.js` file, for example:
+
+```TSX title=faust.config.js {15,16}
+import { config as coreConfig } from '@faustjs/core';
+
+if (!process.env.NEXT_PUBLIC_WORDPRESS_URL) {
+ console.error(
+ 'You must provide a NEXT_PUBLIC_WORDPRESS_URL environment variable, did you forget to load your .env.local file?',
+ );
+}
+
+/**
+ * @type {import("@faustjs/core").Config}
+ */
+export default coreConfig({
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ apiClientSecret: process.env.FAUSTWP_SECRET_KEY,
+ authType: 'local',
+ loginPagePath: '/login',
+});
+```
+
+We define the `authType` to `local` to indicate to the Faust.js config that we use the `local` strategy for authentication. We also describe the `loginPagePath` to `/login` to mark the route of the Next.js login page. This strategy redirects unauthenticated requests to the `/login` route in your Next.js application.
+
+In your `login.tsx` page, you could take advantage of the `useLogin` hook to initiate a login request to the WordPress backend:
+
+```tsx title=pages/login.tsx {9,18}
+import { client } from 'client';
+import { useState } from 'react';
+
+export default function Login() {
+ const { useLogin } = client.auth;
+ const [usernameEmail, setUserNameEmail] = useState('');
+ const [password, setPassword] = useState('');
+
+ const { login, isLoading, data, error } = useLogin();
+
+ const errorMessage = data?.error || error?.message;
+
+ return (
+
+ );
+}
+```
+
+The `useLogin` hook exports an object with the following properties:
+
+- `login`: a function that initiates a request to the WordPress backend for an authorization code that accepts two arguments: `usernameEmail`, which is either the user's username or email as a string, and `password` as a string.
+- `isLoading`: a boolean that indicates whether the login request is in progress.
+- `data`: the response data from the login request.
+- `error`: the error from the login request.
+
+For a more detailed explanation of the `useLogin` hook, see the [`useLogin` hook docs](/docs/next/reference/hooks/useLogin) .
+
+Upon successful login, a secure, HTTP only cookie stores a refresh token and the access token in memory for subsequent authenticated requests. You can confirm a login request succeeded by checking for the `code` property in the `data` object.
+
+Additionally, if the login page URL contains a `redirect_uri` query parameter, it will redirect the user to the specified URL upon successful login.
+
+Finally, you can create a `logout.tsx` page to handle logout requests. This is done by using the `useLogout` hook:
+
+```tsx title="src/pages/logout.tsx"
+import { client } from 'client';
+import { useRouter } from 'next/router';
+import { useEffect } from 'react';
+export default function Logout() {
+ const router = useRouter();
+ const { isLoggedOut, logout } = client.auth.useLogout();
+ useEffect(() => {
+ if (isLoggedOut !== undefined) {
+ return;
+ }
+
+ // Initiate the logout process.
+ // This could also be called on a button click, for example, in a nav menu.
+ logout();
+ }, [isLoggedOut, logout]);
+
+ useEffect(() => {
+ if (isLoggedOut) {
+ // The user was successfully logged out. Redirect them.
+ router.push('/');
+ }
+ }, [router, isLoggedOut]);
+ return <>Logging out...>;
+}
+```
+
+The `useLogout` hook exports an object with the following properties:
+
+- `logout`: a function that initiates a request to the logout middleware to remove the refresh token from the cookie.
+- `isLoading`: a boolean that indicates whether the logout request is in progress.
+- `isLoggedOut`: a boolean that indicates whether the logout request was successful.
+
+
+
+## Making Authenticated Requests
+
+In the Faust.js client, you can use `useQuery`, `usePost`, `usePage`, etc., to request the WordPress backend.
+
+These are exported from the `client` like so:
+
+```tsx {1,4}
+import { client } from 'client';
+
+export default function Page() {
+ const { useQuery } = client;
+
+ return(
+ ...
+ )
+}
+```
+
+Requests using the above methodology will be un-authenticated.
+
+To make authenticated requests, use the `auth` property exported from the `client`. This property is essentially a replica of the `client`, except every request gets called with an access token:
+
+```TSX {1,4,5}
+import { client } from 'client';
+
+export default function Page() {
+ const { useMutation, usePreview, useAuth } = client.auth;
+ const { isLoading, isAuthenticated } = useAuth();
+
+ if (isLoading) {
+ return
Loading...
;
+ }
+
+ if (!isAuthenticated) {
+ return
You are not authenticated!
;
+ }
+
+ return
Authenticated content
;
+}
+```
+
+**Note:** The [`useAuth`](/docs/next/reference/hooks/useAuth) hook fetches the applicable tokens and ensures that the user is authenticated. Therefore, you should check for `isAuthenticated` before making authenticated requests, as doing so too early will result in a request without a valid access token.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/custom-post-types.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/custom-post-types.mdx
new file mode 100644
index 000000000..45837d894
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/custom-post-types.mdx
@@ -0,0 +1,300 @@
+---
+slug: /next/guides/custom-post-types
+title: Interacting with Custom Post Types
+description: Querying data in custom post types is just as easy as querying for posts or pages in Faust.js.
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+# Interacting with Custom Post Types
+
+Querying data in custom post types is just as easy as querying for posts or pages in Faust.js.
+
+Before we start, if you haven't already, [setup your WordPress site for headless](../../tutorial/setup-faustjs#installing-plugins-on-wordpress).
+
+## Create a Custom Post Type
+
+We'll be using the [Atlas Content Modeler](https://github.com/wpengine/atlas-content-modeler) plugin to create custom post types for this guide, but you can choose to create custom post types in any way you'd like.
+
+Atlas Content Modeler is a WordPress plugin to create custom post types and fields for headless WordPress sites. Start by downloading the plugin and activating it on your WordPress site [(Download)](https://wordpress.org/plugins/atlas-content-modeler/).
+
+Now, navigate to WP Admin -> Content Modeler.
+
+
+
+Let's create a custom post type for team members. Click the "Get Started" button, and fill out the fields to create a new Content Model. Be sure to mark "API Visibility" to "Public" so we can query the data.
+
+
+
+## Create Fields for the Custom Post Type
+
+Now that we've created the custom post type let's add some fields to it. From **WP-Admin -> Content Modeler**, select the Team Members custom post type.
+
+We'll add three fields:
+
+1. A Media field type. The name will be "Profile Pic" and the API identifier "profilePic".
+2. A Text field type. The name will be "Full Name" and the API identifier "fullName". We'll also select "Use this field as the entry title".
+3. A Rich Text field type. The name will be "Bio" and the API identifier "bio".
+
+
+
+## Add Some Team Members
+
+Now that you have created a custom post type and fields, you can start entering data. Navigate to **WP-Admin -> Team Members** to start creating!
+
+For this example, I've created two team members, Jane and John Doe, with bios and profile pics:
+
+
+
+## Clone the Starter Headless Project
+
+Thus far, you have created a WordPress site with the necessary headless plugins and data. Now, we need to create a frontend app to consume this data.
+
+We will use the getting started example project in Next.js, but the same concepts apply in other frontend frameworks.
+
+[Follow the steps in the getting started with Next.js usage guide to create a frontend app](../getting-started.mdx)
+
+Once your frontend app renders, the structure should look something like this:
+
+```
+my-app/
+ src/
+ client/
+ ..
+ pages/
+ ..
+ components/
+ ..
+ scss/
+ ..
+ public/
+ .env.local
+ .env.local.sample
+ .env.test.sample
+ .eslintrc
+ .gitignore
+ gqty.config.js
+ next-env.d.ts
+ package.json
+ README.md
+ tsconfig.json
+```
+
+### Regenerate the GraphQL Schema
+
+Your schema is a TypeScript representation of your WordPress site. Since we have added some custom post types and fields, we'll want to regenerate this schema to ensure it's up to date. To restore your schema from the Next.js getting started example, run:
+
+```bash
+npm run generate
+```
+
+[Learn more about generating your client/schema here.](fetching-data.mdx)
+
+#### Troubleshooting
+
+##### "GraphQL introspection is not allowed"
+
+If you run into the error message `GraphQL introspection is not allowed, but the query contained __schema or __type`, you will have to enable introspection temporarily.
+
+[Introspection is disabled by default in WPGraphQL.](https://www.wpgraphql.com/docs/security/#introspection-disabled-by-default) To enable it, go to WP Admin -> GraphQL -> Enable Public Introspection.
+
+If you are using something other than `WPGraphQL` you will need to refer to the documentation to enable introspection.
+
+Once the schema file generates, you can then disable introspection again.
+
+### Run the Dev Server
+
+Run the following command to start the dev server:
+
+```bash
+npm run dev
+```
+
+You should now be able to access the starter project at [http://localhost:3000](http://localhost:3000)
+
+### Create a Team Page
+
+We'll create a team page in `src/pages/team.tsx` to display the team members:
+
+```tsx title=src/pages/team.tsx
+import Head from 'next/head';
+import { Header, Footer } from 'components';
+import { client } from 'client';
+
+export default function Team() {
+ const { generalSettings } = client.useQuery();
+
+ return (
+ <>
+
+
+
+ Meet the Team - {generalSettings.title}
+
+
+
+
+
Team Members
+
+
+
+
+ >
+ );
+}
+```
+
+This will look something like:
+
+
+
+### Query for Team Members
+
+When querying custom post types in Faust.js, you can leverage the `useQuery` hook exported from the client. `useQuery` allows you to access all of WordPress' data. You'll also notice it's typed from your schema, making things super easy to find.
+
+
+
+Let's get the team members using the `useQuery` hook:
+
+```tsx title=src/pages/team.tsx {6,8}
+import Head from 'next/head';
+import { Header, Footer } from 'components';
+import { client } from 'client';
+
+export default function Team() {
+ const { useQuery } = client;
+ const { generalSettings } = useQuery();
+ const teamMembers = useQuery().teamMembers()?.nodes;
+
+ return (
+ <>
+
+
+
+ Meet the Team - {generalSettings.title}
+
+
+
+
+
Team Members
+
+
+
+
+ >
+ );
+}
+```
+
+Finally, we'll create a `teamMember.tsx` component to display each team member:
+
+```tsx title=/src/components/teamMember.tsx {1}
+import { TeamMember as TeamMemberType } from 'client';
+
+interface TeamMemberProps {
+ teamMember: TeamMemberType;
+}
+
+export default function TeamMember({ teamMember }: TeamMemberProps) {
+ return (
+
+
+
{teamMember?.fullName}
+
+
+ );
+}
+```
+
+Notice we are getting the `TeamMember` TypeScript type from the client and generated schema.
+
+### Put it all Together
+
+Finally, let's hook up the `TeamMember` component to the team page.
+
+```tsx title=src/pages/team.tsx {4,27-29}
+import Head from 'next/head';
+import { Header, Footer } from 'components';
+import { client } from 'client';
+import TeamMember from 'components/teamMember';
+
+export default function Team() {
+ const { useQuery } = client;
+ const { generalSettings } = useQuery();
+
+ const teamMembers = useQuery().teamMembers()?.nodes;
+
+ return (
+ <>
+
+
+
+ Meet the Team - {generalSettings.title}
+
+
+
+
+
Team Members
+
+ {teamMembers.map((teamMember) => (
+
+ ))}
+
+
+
+
+ >
+ );
+}
+```
+
+Now, head back to [http://localhost:3000/team](http://localhost:3000/team) to see your WordPress data come to life!
+
+
+
+## Learnings
+
+In this guide, we demonstrated:
+
+- How to create custom post types/fields using [Atlas Content Modeler](https://github.com/wpengine/atlas-content-modeler)
+- Creating data for your custom post types
+- Creating a starter frontend project to consume your WordPress data
+- Using the `useQuery` custom React hook in the framework to query your custom post type data in GraphQL
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/fetching-data.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/fetching-data.mdx
new file mode 100644
index 000000000..b3d6f092a
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/fetching-data.mdx
@@ -0,0 +1,289 @@
+---
+slug: /next/guides/fetching-data
+title: Fetching data from Headless WordPress with Faust.js
+description: Faust.js makes fetching data from Headless WordPress incredibly easy with GQty.
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+> **NOTE**: If you followed the instructions in the [Getting Started with Next.js](../getting-started.mdx) guide, you already have a working instance of the client. The following guide assumes you are setting up a client on an already existing application.
+
+Faust.js uses [GQty](https://gqty.dev/docs/react/fetching-data) as the primary way to fetch data from Headless WordPress. GQty is a [proxy-based](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) GraphQL client. GQty [preforms an invisible or skeleton render](https://gqty.dev/docs/intro/how-it-works) to identify what data is needed.
+
+## Setting Up Your Client
+
+GQty works primarily based on TypeScript typings generated using introspection on your GraphQL API. Using WPGraphQL as your Headless WordPress API, you can enable introspection and then generate typings for GQty. You will need to do the following:
+
+1. Run `npm install -D @gqty/cli dotenv-flow`
+1. Create a `generate` script in your `package.json` that runs `gqty generate`.
+1. Create a `gqty.config.js` file at the root of your project. Use the following example config:
+
+ ```js
+ require('dotenv-flow').config();
+
+ /**
+ * @type {import("@gqty/cli").GQtyConfig}
+ */
+ const config = {
+ react: false,
+ scalarTypes: { DateTime: 'string' },
+ introspection: {
+ endpoint: `${process.env.NEXT_PUBLIC_WORDPRESS_URL}/graphql`,
+ headers: {},
+ },
+ destination: './src/client/index.ts',
+ subscriptions: false,
+ javascriptOutput: false,
+ };
+
+ console.log(
+ `Using "${config.introspection.endpoint}" to generate schema...`,
+ );
+
+ module.exports = config;
+ ```
+
+1. Run `npm run generate`.
+
+If everything runs smoothly, you will end up with an `index.ts` and `schema.generated.ts` file in your `src/client` directory. The `index.ts` file contains your client code, and the `schema.generated.ts` file contains the typings for GQty. You can use the client as-is, but you will not get some of the benefits Faust.js provides on top of the standard GQty client. To use Faust.js with your Headless WordPress API, you will need to add some additional functionality. Replace the contents of `index.ts` with the following:
+
+```ts
+/**
+ * GQTY: You can safely modify this file and Query Fetcher based on your needs
+ */
+import type { IncomingMessage } from 'http';
+import { getClient } from '@faustjs/next';
+import {
+ generatedSchema,
+ scalarsEnumsHash,
+ GeneratedSchema,
+ SchemaObjectTypes,
+ SchemaObjectTypesNames,
+} from './schema.generated';
+
+export const client = getClient<
+ GeneratedSchema,
+ SchemaObjectTypesNames,
+ SchemaObjectTypes
+>({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+});
+
+export function serverClient(req: IncomingMessage) {
+ return getClient({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+ context: req,
+ });
+}
+
+export * from './schema.generated';
+```
+
+The code above is a modified version of the default `index.ts` file that GQty generates. The `getClient` function is a helper function that returns a client configured to work with the Headless WordPress API. Note the additional `serverClient` function used to create a client configured to work with the server by passing in the `IncomingMessage` object. This object allows Faust.js to read cookies on the server and pass them along to the Headless WordPress API.
+
+### Troubleshooting
+
+#### "GraphQL introspection is not allowed"
+
+If you run into the error message `GraphQL introspection is not allowed, but the query contained __schema or __type`, you will have to enable introspection temporarily.
+
+[Introspection is disabled by default in WPGraphQL.](https://www.wpgraphql.com/docs/security/#introspection-disabled-by-default) To enable it, go to WP Admin -> GraphQL -> Enable Public Introspection.
+
+If you are using something other than `WPGraphQL` you will need to refer to the documentation to enable introspection.
+
+Once the schema file has been generated, you can then disable introspection again.
+
+## Updating the GraphQL Schema Typings
+
+If you followed the steps above or started a project using the `examples/next/getting-started` boilerplate, you will have a `schema.generated.ts` file in your `src/client` directory. The typings in this file are generated from the Headless WordPress API. If you are using a different Headless WordPress API or adding additional queries or mutations to your existing Headless WordPress API, you will need to update the typings in this file. Possible reasons you might need to generate a new typings file include:
+
+1. Adding a plugin to your WordPress site that adds additional queries
+1. Using plugins like [`Atlas Content Modeler`](https://github.com/wpengine/atlas-content-modeler) that add additional queries based on custom content types you create
+
+To do this, you will need to run `gqty generate` again. Running `gqty generate` will update the typings in the `schema.generated.ts` file and leave the `index.ts` unchanged.
+
+## Providing the GQty Client to Faust.js
+
+Using the boilerplate client code will provide two different GQty clients that you can use depending upon whether you are on the client or server. However, you will still need to give the client to Faust.js to use to fetch data. To do this, you can use the `FaustProvider` component published by Faust.js, and provide it to the GQty client you want to use. This is done in your `_app.tsx` file as follows:
+
+```tsx title=src/pages/_app.tsx {2,9,11}
+import 'faust.config';
+import { FaustProvider } from '@faustjs/next';
+import { client } from 'client';
+import type { AppProps } from 'next/app';
+
+export default function MyApp({ Component, pageProps }: AppProps) {
+ return (
+ <>
+
+
+
+ >
+ );
+}
+```
+
+This code ensures Faust.js uses the correct client to make requests on your behalf.
+
+## Using the Client to Make Queries
+
+Assuming you have created a client using the Faust.js `getClient` function, you will be able to take advantage of many of the added features that Faust.js provides and the general features provided by GQty. You can read our [hooks for fetching data reference](../reference/hooks) for examples of using some of the built-in hooks using the Faust.js client, but the client will support any query your Headless WordPress API. Let's look at a few examples of how to use the client to make queries.
+
+### The useQuery Hook
+
+If you cannot use one of the [WordPress-specific hooks](../reference/hooks) you can use the `useQuery` hook to make a query to the Headless WordPress API. This hook helps make any query supported by your Headless WordPress API. It essentially exposes your entire generated GQL schema to you for you to use what you need. For example, say you have a `Header` component, and you want to fetch menu items from your "Primary" menu in WordPress. You could do so as follows:
+
+```tsx title=src/components/Header.tsx {4,12-15,30-36}
+import React from 'react';
+import styles from 'scss/components/Header.module.scss';
+import Link from 'next/link';
+import { client, MenuLocationEnum } from 'client';
+
+interface Props {
+ title?: string;
+ description?: string;
+}
+
+function Header({ title = 'My Site Title', description }: Props): JSX.Element {
+ const { menuItems } = client.useQuery();
+ const links = menuItems({
+ where: { location: MenuLocationEnum.PRIMARY },
+ }).nodes;
+
+ return (
+
+
+
+ );
+}
+
+export default Header;
+```
+
+The code above demonstrates how you can use the `useQuery` hook to make a query to the Headless WordPress API for `menuItems`, filter your `menuItems` to be only those for the `PRIMARY` menu, then use the results to render links in your `Header`. Notice there is no code regarding any server-side data fetching, but if your page [uses SSR or SSG](../guides/ssr-ssg.mdx), you will not have any client-side queries.
+
+### The useMutation Hook
+
+While Faust.js does not provide any WordPress-specific hooks for mutations, it does provide the `useMutation` hook. This hook is useful for making any mutation supported by your Headless WordPress API. For example, if you have a form on your site that admins can use to submit posts, it might look something similar to the following:
+
+```tsx title=src/components/Header.tsx {2,10-21,30-35}
+import React from 'react';
+import { client } from 'client';
+
+export interface FormData {
+ title: string;
+ content: string;
+}
+
+export function PostForm() {
+ const [submit, { isLoading, error }] = client.useMutation(
+ (mutation, { title, content }: FormData) => {
+ const result = mutation.createPost({
+ input: {
+ title: title,
+ content,
+ },
+ });
+
+ return result.post?.id;
+ },
+ );
+ const errorMessage = error?.message;
+
+ return (
+
+ );
+}
+```
+
+> **NOTE**: The above code is not a complete example of how you would implement form submissions to your Headless WordPress API, and it demonstrates how mutations work using the Faust.js client.
+
+The code above uses `useMutation` combined with a form to create new posts by calling the [WPGraphQL](https://www.wpgraphql.com/) Headless WordPress API.
+
+## Logging Queries
+
+Sometimes you want to understand what GraphQL queries do for debugging purposes. Faust.js provides this for you by exposing a `logQueries` function, and the following code demonstrates how you might use it.
+
+```ts title=src/client/index.ts {2, 21}
+import type { IncomingMessage } from 'http';
+import { getClient, logQueries } from '@faustjs/next';
+import {
+ generatedSchema,
+ scalarsEnumsHash,
+ GeneratedSchema,
+ SchemaObjectTypes,
+ SchemaObjectTypesNames,
+} from './schema.generated';
+
+export const client = getClient<
+ GeneratedSchema,
+ SchemaObjectTypesNames,
+ SchemaObjectTypes
+>({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+});
+
+if (process.env.NODE_ENV === 'development') {
+ logQueries(client);
+}
+```
+
+The `logQueries` function returns a function that you can call to turn the log off.
+
+```ts
+if (process.env.NODE_ENV === 'development') {
+ const unsubscribe = logQueries(client);
+
+ // queries are now logging
+ // ...
+
+ unsubscribe();
+
+ // queries no more extended log
+ // ...
+}
+```
+
+> **NOTE**: We recommend that you turn this off in production or write code to use `process.env.NODE_ENV` to log queries safely.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/handle-404s.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/handle-404s.mdx
new file mode 100644
index 000000000..73d26acbf
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/handle-404s.mdx
@@ -0,0 +1,62 @@
+---
+slug: /next/guides/handle-404s
+title: Handling 404s with is404
+description: Use a built-in Faust.js function to automatically determine if a page is a 404
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+# Handling 404s with is404
+
+With Next.js, you can return `{ notFound: true }` from `getServerSideProps` or `getStaticProps`, which will signal to Next.js that you want to send a `404 Not Found` response. When building a Headless WordPress site, you want to send a 404 in the following conditions:
+
+1. The user visits a `post` route for which no WordPress post exists.
+1. The user visits a `page` route for which no associated WordPress page (or custom frontend page) exists.
+1. The user visits a `category` route for which no associated WordPress category exists.
+
+To determine if you need to send a 404, you need to request WordPress for data and then decide if the response is enough to ensure you can render the page. Given that you will have dynamic Next.js pages for rendering `posts`, `pages`, and `categories` most of the time, you might think you have to do this work yourself. However, Faust.js makes this easy for you.
+
+Faust.js publishes an `is404` function that makes this easy for you. It functions similar to how the `usePost`, `usePage`, and `useCategory` hooks function, so it can determine the query you want to make based on URL params specified in your Next.js pages. The `is404` function has the following logic:
+
+### `is404` Logic for Posts:
+
+1. If `postId` is found in URL params, `is404` makes a request to retrieve a `post` from WordPress by `ID`. If no `post` is returned, `is404` returns `true`.
+1. If `postSlug` is found in URL params, `is404` makes a request to retrieve a `post` from WordPress by `SLUG`. If no `post` is returned, `is404` returns `true`.
+1. If `postUri` is found in URL params, `is404` requests to retrieve a `post` from WordPress by `URI`. If no `post` is returned, `is404` returns `true`.
+
+### `is404` Logic for Pages:
+
+1. If `pageId` is found in URL params, `is404` makes a request to retrieve a `page` from WordPress by `ID`. If no `page` is returned, `is404` returns `true`.
+1. If `pageUri` is found in URL params, `is404` requests to retrieve a `page` from WordPress by `URI`. If no `page` is returned, `is404` returns `true`.
+
+### `is404` Logic for Categories:
+
+1. If `categoryId` is found in URL params, `is404` makes a request to retrieve a `category` from WordPress by `ID`. If no `category` is returned, `is404` returns `true`.
+1. If `categorySlug` is found in URL params, `is404` requests to retrieve a `category` from WordPress by `SLUG`. If no `category` is returned, `is404` returns `true`.
+
+## How to use `is404`
+
+`is404` should be called in either `getStaticProps` or `getServerSideProps`. The reason for this is that these are the server-side functions where you need to tell Next.js to send a `404 Not Found` server response. Below is some code in the a `post` page that utilizes `is404` to return a `{ notFound: true }` if necessary:
+
+```tsx title=src/pages/posts/[postSlug].tsx
+import { getNextStaticProps, is404 } from '@faust/next';
+import { client } from 'client';
+
+export default function Page() {
+ return <>>;
+}
+
+export async function getStaticProps(context: GetStaticPropsContext) {
+ return getNextStaticProps(context, {
+ Page,
+ client,
+ notFound: await is404(context, { client }),
+ });
+}
+```
+
+The above file name is `[postSlug].tsx` which will ensure that `postSlug` ends up in the URL params. When `is404` is invoked, it will find the `postSlug` URL param and make a request to WordPress to retrieve the `post` by `SLUG` using the `postSlug` param. If no `post` is returned, `is404` will return `true` and `getStaticProps` will subsequently return `{ notFound: true }`.
+
+> **NOTE:** `is404` does not have any relation to the `404.tsx` page you can define with Next.js. [Customize your 404 page](https://nextjs.org/docs/advanced-features/custom-error-page#404-page) separately.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/logging-queries.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/logging-queries.mdx
new file mode 100644
index 000000000..8a512a1a9
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/logging-queries.mdx
@@ -0,0 +1,68 @@
+---
+slug: /next/guides/logging-queries
+title: Logging Queries
+description: You can log all the queries that are executed in Faust.js
+---
+
+In a development environment, you may want to log GraphQL queries that are being executed in your application. Faust.js provides a function, `logQueries`, to do this.
+
+`logQueries` is called within your `client/index.ts` file. Take the following `client/index.ts` example:
+
+```ts title="client/index.ts" {23-25}
+/**
+ * GQTY: You can safely modify this file and Query Fetcher based on your needs
+ */
+import type { IncomingMessage } from 'http';
+import {
+ getClient,
+ logQueries,
+} from '@faustjs/next';
+import {
+ generatedSchema,
+ scalarsEnumsHash,
+ GeneratedSchema,
+ SchemaObjectTypes,
+ SchemaObjectTypesNames,
+} from './schema.generated';
+
+export const client = getClient<
+ GeneratedSchema,
+ SchemaObjectTypesNames,
+ SchemaObjectTypes
+>({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+});
+
+if (process.env.NODE_ENV === 'development') {
+ logQueries(client);
+}
+
+export function serverClient(req: IncomingMessage) {
+ return getClient({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+ context: req,
+ });
+}
+
+export * from './schema.generated';
+```
+
+Note the conditional check for the node environment. It is recommended that you only log queries in a dev environment, and not in production.
+
+Additionally, the `logQueries` function returns a function than can be called to turn off the logger:
+
+```ts
+if (process.env.NODE_ENV === 'development') {
+ const unsubscribe = logQueries(client);
+
+ // queries are now logging
+ // ...
+
+ unsubscribe();
+
+ // queries no longer log
+ // ...
+}
+```
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/modifying-graphql-request.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/modifying-graphql-request.mdx
new file mode 100644
index 000000000..c1f0ae4e9
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/modifying-graphql-request.mdx
@@ -0,0 +1,48 @@
+---
+slug: /next/guides/modifying-the-graphql-request
+title: Modifying the GraphQL Request
+description: How to modify the GraphQL request before it is sent to WordPress
+---
+
+There may be some situations where you need to modify the request object of the GraphQL requests that get sent to WordPress. If you find yourself needing to add headers or other information to the request, you can do so by providing a function to `getClient` called `applyRequestContext`. Take the following default client example using `applyRequestContext`:
+
+```ts title=src/client/index.ts {21-27}
+/**
+ * GQTY: You can safely modify this file and Query Fetcher based on your needs
+ */
+import type { IncomingMessage } from 'http';
+import { getClient } from '@faustjs/next';
+import {
+ generatedSchema,
+ scalarsEnumsHash,
+ GeneratedSchema,
+ SchemaObjectTypes,
+ SchemaObjectTypesNames,
+} from './schema.generated';
+
+export const client = getClient<
+ GeneratedSchema,
+ SchemaObjectTypesNames,
+ SchemaObjectTypes
+>({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+ applyRequestContext: async (url, init) => {
+ // Make modifications to the request here as you see fit
+ console.log('url', url);
+ console.log('init', init);
+
+ return {url, init}
+ }
+});
+
+export function serverClient(req: IncomingMessage) {
+ return getClient({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+ context: req,
+ });
+}
+
+export * from './schema.generated';
+```
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/permalinks.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/permalinks.mdx
new file mode 100644
index 000000000..a566260ed
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/permalinks.mdx
@@ -0,0 +1,64 @@
+---
+slug: /next/guides/permalinks
+title: Permalinks
+description: Learn how to use WordPress Permalinks in conjunction with Faust.js
+---
+
+Permalinks are "pretty URLs" of your individual blog post or page on your WordPress site. Permalinks can be modified by going to WP Admin -> Settings -> Permalinks. From there, you can modify the options to change the permalink structure to your liking.
+
+
+
+Faust.js does not require your permalink structure to be anything specific. Instead, your permalinks should map to the structure of your [Next.js pages](https://nextjs.org/docs/basic-features/pages).
+
+For example, your permalink structure might look like this in WordPress:
+
+```
+/posts/%postname%/
+```
+
+Therefore, your Next.js pages structure should look like this:
+
+```bash {5,6}
+my-app/
+ pages/
+ _app.tsx
+ index.tsx
+ posts/
+ [postSlug].tsx
+ next-env.d.ts
+ package-lock.json
+ package.json
+ README.md
+ tsconfig.json
+```
+
+Notice the `posts` directory and the accompanying `[postSlug].tsx` file. Thus, your permalink structure (`/posts/%postname%/`) map to your Faust.js site posts structure (`/posts/[postSlug]`).
+
+As long as these two structures match, your permalink structure will work.
+
+## Example
+
+Lets say you wanted all of your posts to be under `/blog/`. You would modify your permalink structure to:
+
+```
+/blog/%postname%/
+```
+
+Then, in your Faust.js project, you would create a `/blog/` directory and create a `/blog/[postSlug].tsx` file for each of your posts.
+
+```bash {5,6}
+my-app/
+ pages/
+ _app.tsx
+ index.tsx
+ blog/
+ [postSlug].tsx
+ next-env.d.ts
+ package-lock.json
+ package.json
+ README.md
+ tsconfig.json
+```
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/post-page-previews.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/post-page-previews.mdx
new file mode 100644
index 000000000..56e5cf36a
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/post-page-previews.mdx
@@ -0,0 +1,164 @@
+---
+slug: /next/guides/post-page-previews
+title: Setting Up Post and Page Previews
+description: View WordPress preview post/page content on your headless frontend with Faust.js
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+Faust.js supports page and post previews, allowing you to view your WordPress content on the headless frontend as drafts or even before publishing.
+
+## Set Your Headless Secret
+
+Your headless secret is a value that authenticates requests to WordPress. This secret enables you to view content that doesn't publish on your Next.js frontend.
+
+### Copy your Headless Secret
+
+Find your Headless Secret in **WP-Admin -> Settings -> Headless**. Copy this value:
+
+
+
+### Add your Headless Secret to your `.env.local` File
+
+Add the `FAUSTWP_SECRET_KEY` key to your `.env.local` file with the headless secret as the value. Your `.env.local` file should already have a value for `NEXT_PUBLIC_WORDPRESS_URL`. The file should look something like this:
+
+```bash title=.env.local {13}
+# Your WordPress site URL
+NEXT_PUBLIC_WORDPRESS_URL=http://localhost:8080
+
+# Plugin secret found in WordPress Settings->Headless
+FAUSTWP_SECRET_KEY=xxxx
+```
+
+### Ensure you've created your `faust.config.js` file and are importing it in your `_app.tsx`
+
+Like the [`next/getting-started`](https://github.com/wpengine/faustjs/tree/main/examples/next/getting-started) Faust.js example, your [`faust.config.js`](https://github.com/wpengine/faustjs/blob/main/examples/next/getting-started/src/faust.config.js) file will live in the `src` directory.
+
+You'll need to import it at the top of your `_app.tsx` file to ensure the `config` is set, and your Faust.js app initializes appropriately.
+
+```tsx title=src/pages/_app.tsx {1}
+import 'faust.config';
+import { FaustProvider } from '@faustjs/next';
+import { client } from 'client';
+import type { AppProps } from 'next/app';
+
+export default function MyApp({ Component, pageProps }: AppProps) {
+ return (
+ <>
+
+
+
+ >
+ );
+}
+```
+
+## Create the Faust.js API Router
+
+Next, you will need to create the `apiRouter`. This sets up the Faust.js API endpoints needed to authenticate requests from WordPress. Create a page at `/src/pages/api/faust/[[...route]].ts` with the following:
+
+```ts
+import 'faust.config';
+import { apiRouter } from '@faustjs/core/api';
+
+export default apiRouter;
+```
+
+## Create your Preview Page
+
+With your headless secret set and the `authorizeHandler` ready to handle requests, you can now create a Next.js [page](https://nextjs.org/docs/basic-features/pages) for previews. Create a file at `/src/pages/preview.tsx` with the following:
+
+> **NOTE**: The `usePreviewNode` was introduced in `v0.15.1` and replaces the `usePreview` hook.
+> From now on you should be using this hook for showing preview content.
+
+```tsx title=src/pages/preview.tsx
+import { PageComponent } from 'pages/[...pageUri]';
+import { PostComponent } from 'pages/posts/[postSlug]';
+import type { Page, Post } from 'client';
+import { client } from 'client';
+
+export default function Preview() {
+ const { typeName, node } = client.auth.usePreviewNode();
+
+ if (client.useIsLoading() || node === undefined) {
+ return
loading...
;
+ }
+
+ if (node === null) {
+ return
Post not found
;
+ }
+
+ switch (typeName) {
+ case 'Page': {
+ return
+ }
+ case 'Post': {
+ return
+ }
+ // Add custom post types here as needed
+ default: {
+ throw new Error(`Unknown post type: ${typeName}`);
+ }
+ }
+}
+```
+
+Let's break down what is going on here:
+
+First, we are getting the `usePreviewNode` hook from the `auth` property of the `client` and we extract the typeName and node properties.
+
+```tsx
+const { typeName, node } = client.auth.usePreviewNode();
+```
+
+The `typeName` specifies the type of the node content (`Page`, `Post` or any `Custom Post Type`).
+The `node` on the other hand represents the actual data for that particular node content.
+Since Typescript cannot infer the type correctly (since it thinks that it's still a `Node` type), we need to cast it to the correct type before we pass it on as a property to the component.
+
+From there, we can make a determination if the result is a page or post, and render the appropriate component:
+
+```tsx
+switch (typeName) {
+ case 'Page': {
+ return ;
+ }
+ case 'Post': {
+ return ;
+ }
+ // Add custom post types here as needed
+ default: {
+ throw new Error(`Unknown post type: ${typeName}`);
+ }
+}
+```
+
+We abstract the page and post layouts into components to be reusable so there is no divergence between preview pages/posts and actual pages/posts.
+
+## Navigating to Preview Pages
+
+Start by logging into your WordPress Admin. For this example, we'll create a new post.
+
+So far, I've added a title and a simple line of text for the content. To view this post as a preview on your front end, click the **Preview** link (1). From there, click, **Preview in new tab** (2):
+
+
+
+Notice the **Publish** button is also visible, meaning that you still need to publish the post. Therefore you can now view the post on the frontend without being authenticated.
+
+Clicking on **Preview in new tab** should take you to your post preview page with the current preview content:
+
+
+
+> **NOTE**: If you are having problems viewing Custom Post Type (CPT) previews using the above example,
+> you need to make sure you have installed the latest version of the WPGraphQL plugin (> v1.6.11).
+> It especially contains a bug fix when the draft previews query returns null for CPTs without revisions.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/sitemaps.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/sitemaps.mdx
new file mode 100644
index 000000000..8ce2b5909
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/sitemaps.mdx
@@ -0,0 +1,232 @@
+---
+slug: /next/guides/sitemaps
+title: Sitemaps
+description: Generate sitemaps for your Faust.js site
+---
+
+Sitemaps can be a complicated process when using WordPress in a headless environment. Thankfully, Faust.js takes care of all your sitemap needs through a simple piece of Next.js middleware, [`handleSitemapRequests`](/docs/next/reference/handle-sitemap-requests).
+
+## How It Works
+
+`handleSitemapRequests` works by proxying your existing sitemaps from WordPress to your frontend, while replacing any WordPress URLs with your headless frontend's URL.
+
+This means there is no constraints in how your sitemaps are created on WordPress, giving you the flexibility to use plugins such as [Yoast](https://wordpress.org/plugins/wordpress-seo/) or [XML Sitemaps](https://wordpress.org/plugins/google-sitemap-generator/). As long as your WordPress sitemaps matches the following criteria, they will be proxied:
+
+- Conform to the [XML Sitemaps specification](https://www.sitemaps.org/protocol.html)
+- Has `sitemap` in their pathname (ex. `/page-sitemap.xml`)
+- Has `.xml` as their extension
+
+## Setup
+
+To get started, we'll first have to define a piece of middleware in our Next.js `pages` directory. The file must be named `_middleware.ts`:
+
+```tsx title="src/pages/_middleware.ts"
+import { NextRequest, NextResponse } from 'next/server';
+
+export default async function _middleware(req: NextRequest) {
+ return NextResponse.next();
+}
+```
+
+This is what a default Next.s middleware looks like. Having it at the root of the `pages` directory means that every request to your site will first go through this middleware. You can read more on Next.js middleware [here](https://nextjs.org/docs/middleware).
+
+The middleware above will currently do nothing, as it's an empty function that goes to the "next" middleware via `NextResponse.next()`. Let's add our sitemap handling code:
+
+```tsx title="src/pages/_middleware.ts"
+import { handleSitemapRequests } from '@faustjs/next/middleware';
+import { NextRequest, NextResponse } from 'next/server';
+
+export default async function _middleware(req: NextRequest) {
+ const sitemapRequest = await handleSitemapRequests(req, {
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ sitemapIndexPath: `/wp-sitemap.xml`,
+ });
+
+ if (sitemapRequest) {
+ return sitemapRequest;
+ }
+
+ return NextResponse.next();
+}
+```
+
+`handleSitemapRequests` accepts two required arguments. The first is the `req` object passed from the top level Next.js middleware function, and the second is a configuration object. There are two required properties in the configuration object. The first is `wpUrl`, which is the URL of your WordPress site. The second is `sitemapIndexPath`, which is the relative path to the sitemap index file that exists on your WordPress site.
+
+This is all the configuration you need to get started. As you can see, if you now go to `/wp-sitemap.xml` on your headless frontend, you will see the sitemap index file being proxied over with properly formatted URLs.
+
+## Additional Configuration
+
+### Ignoring Paths
+
+There will be instances in which you don't want to proxy over a specific path. For example, if you have a custom post type that you want to exclude from your sitemap, you can do so by adding it to the `sitemapPathsToIgnore` array.
+
+```tsx title="src/pages/_middleware.ts" {8}
+import { handleSitemapRequests } from '@faustjs/next/middleware';
+import { NextRequest, NextResponse } from 'next/server';
+
+export default async function _middleware(req: NextRequest) {
+ const sitemapRequest = await handleSitemapRequests(req, {
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ sitemapIndexPath: `/wp-sitemap.xml`,
+ sitemapPathsToIgnore: ['/wp-sitemap-users-1.xml'],
+ });
+
+ if (sitemapRequest) {
+ return sitemapRequest;
+ }
+
+ return NextResponse.next();
+}
+```
+
+You can additionally use a wildcard to ignore sitemap paths that may be paginated:
+
+```tsx title="src/pages/_middleware.ts" {8}
+import { handleSitemapRequests } from '@faustjs/next/middleware';
+import { NextRequest, NextResponse } from 'next/server';
+
+export default async function _middleware(req: NextRequest) {
+ const sitemapRequest = await handleSitemapRequests(req, {
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ sitemapIndexPath: `/wp-sitemap.xml`,
+ sitemapPathsToIgnore: ['/wp-sitemap-users-*'],
+ });
+
+ if (sitemapRequest) {
+ return sitemapRequest;
+ }
+
+ return NextResponse.next();
+}
+```
+
+### Defining Next.js Pages for Sitemaps
+
+The above code examples account for adding your WordPress content to your sitemap, but what about the file based pages you've created in Next.js? Say for an example we have `src/pages/about.tsx` and we'd like to include it in our sitemap. That can be done by creating a `pages` property in the `handleSitemapRequests` config object:
+
+```tsx title="src/pages/_middleware.ts" {8-12}
+import { handleSitemapRequests } from '@faustjs/next/middleware';
+import { NextRequest, NextResponse } from 'next/server';
+
+export default async function _middleware(req: NextRequest) {
+ const sitemapRequest = await handleSitemapRequests(req, {
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ sitemapIndexPath: `/wp-sitemap.xml`,
+ pages: [
+ {
+ path: '/about',
+ },
+ ],
+ });
+
+ if (sitemapRequest) {
+ return sitemapRequest;
+ }
+
+ return NextResponse.next();
+}
+```
+
+The `path` property is a relative path to the page you want to include in your sitemap and is the only required field. Take a look at the [reference doc](/docs/next/reference/handle-sitemap-requests#pages) for more of the available options.
+
+### Creating a `/robots.txt` Route
+
+There will most likely be instances where you will need to create a `/robots.txt` route. This is a file that tells search engines what to do with your site. We have a handy function that you can define in your `handleSitemapRequests` config object that has an argument of `sitemapUrl` to be used:
+
+```tsx title="src/pages/_middleware.ts" {8-15}
+import { handleSitemapRequests } from '@faustjs/next/middleware';
+import { NextRequest, NextResponse } from 'next/server';
+
+export default async function _middleware(req: NextRequest) {
+ const sitemapRequest = await handleSitemapRequests(req, {
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ sitemapIndexPath: `/wp-sitemap.xml`,
+ async robotsTxt(sitemapUrl) {
+ return `
+ User-agent: *
+ Allow: /
+
+ Sitemap: ${sitemapUrl}
+ `;
+ },
+ });
+
+ if (sitemapRequest) {
+ return sitemapRequest;
+ }
+
+ return NextResponse.next();
+}
+```
+
+## Examples
+
+Below you can find some drop in examples for different XML Sitemap configurations on WordPress.
+
+:::note
+
+Be sure to define your `pages` property in your `handleSitemapRequests` config object if you have any Next.js specific pages you want included in your sitemap.
+
+:::
+
+### Usage with default WordPress Sitemaps
+
+Below is a drop in configuration using default WordPress sitemaps. This assumes you want to ignore the "users" sitemap:
+
+```tsx title="src/pages/_middleware.ts"
+import { handleSitemapRequests } from '@faustjs/next/middleware';
+import { NextRequest, NextResponse } from 'next/server';
+
+export default async function _middleware(req: NextRequest) {
+ const sitemapRequest = await handleSitemapRequests(req, {
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ sitemapIndexPath: `/wp-sitemap.xml`,
+ sitemapPathsToIgnore: ['/wp-sitemap-users-*'],
+ async robotsTxt(sitemapUrl) {
+ return `
+ User-agent: *
+ Allow: /
+
+ Sitemap: ${sitemapUrl}
+ `;
+ },
+ });
+
+ if (sitemapRequest) {
+ return sitemapRequest;
+ }
+
+ return NextResponse.next();
+}
+```
+
+### Usage with Yoast
+
+Below is a drop in configuration using Yoast's sitemap. This assumes you want to ignore the "author" sitemap:
+
+```tsx title="src/pages/_middleware.ts"
+import { handleSitemapRequests } from '@faustjs/next/middleware';
+import { NextRequest, NextResponse } from 'next/server';
+
+export default async function _middleware(req: NextRequest) {
+ const sitemapRequest = await handleSitemapRequests(req, {
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ sitemapIndexPath: `/sitemap_index.xml`,
+ sitemapPathsToIgnore: ['/author-sitemap.xml'],
+ async robotsTxt(sitemapUrl) {
+ return `
+ User-agent: *
+ Allow: /
+
+ Sitemap: ${sitemapUrl}
+ `;
+ },
+ });
+
+ if (sitemapRequest) {
+ return sitemapRequest;
+ }
+
+ return NextResponse.next();
+}
+```
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/ssr-ssg.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/ssr-ssg.mdx
new file mode 100644
index 000000000..b0cb1c084
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/ssr-ssg.mdx
@@ -0,0 +1,257 @@
+---
+slug: /next/guides/ssr-ssg
+title: Server-side Rendering & Static Generation
+description: Use Faust.js and Next.js to statically generate your Headless WordPress site
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+Next.js supports Server-side Rendering (SSR) and Static Site Generation (SSG) out of the box for [pages](https://nextjs.org/docs/basic-features/pages). However, with Next.js you are responsible for defining `getStaticProps` or `getServersideProps`, fetching the necessary data, and providing it on `props`. Faust.js provides two functions that can be used for SSG and SSR respectively called `getNextStaticProps` and `getNextServerSideProps`.
+
+## SSG Using `getNextStaticProps`
+
+This helper function lets you build a static site with your WordPress data. The function should be returned from `getStaticProps`:
+
+```tsx
+export async function getStaticProps(context: GetStaticPropsContext) {
+ return getNextStaticProps(context, {
+ Page: MyPage,
+ client,
+ });
+}
+```
+
+The function accepts two arguments: the static props context, and an object with a `Page` key and `client` key. This should be your Next.js page component:
+
+```tsx {2,5,20,21}
+import { GetStaticPropsContext } from 'next';
+import { getNextStaticProps } from '@faustjs/next';
+import { client } from 'client';
+
+export default function MyPage() {
+ const { usePosts } = client;
+
+ return (
+ <>
+
Recent Posts
+ {usePosts()?.nodes.map((post) => (
+
{post.title()}
+ ))}
+ >
+ );
+}
+
+export async function getStaticProps(context: GetStaticPropsContext) {
+ return getNextStaticProps(context, {
+ Page: MyPage,
+ client,
+ });
+}
+```
+
+The reason `MyPage` and `client` are passed to `getNextStaticProps` is because under the hood Faust.js perform a skeleton render of the page component to know what data to fetch and what queries to build. The flow is as follows:
+
+1. The passed in `client` is used for all requests.
+1. A skeleton render of the `Page` component is invoked, with `next/router` context and the proper `client` for making requests provided.
+1. After rendering, the `client` cache is serialized and stored on `props`.
+1. The `props` are returned in the standard Next.js format, with `revalidate: 1`
+
+This allows the developer to not have to think about batching/constructing queries, or data fetching. You are able to write your page as if you will be using Client-side Rendering (CSR). Then, you add the `getStaticProps` function above and can take advantage of SSG!
+
+### How To Handle `getStaticPaths`
+
+Next.js supports [SSG with `getStaticPaths`](https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation) as well. This function is used to build a list of paths that can be used to statically generate your site. This function should be used when you have a dynamic page that needs to be statically generated (e.g. `[postSlug].tsx`). In the `getStaticPaths` function you have the option to return the paths that you have several options that inform Next.js how you want to statically generate your pages. Consider the following examples:
+
+#### Statically Generate All Your Pages Upon Request
+
+If you don't know exactly how you want to statically generate your site, a good option for `getStaticPaths` is to inform Next.js not to generate any HTML at build time, but to generated it on-the-fly as new requests come in. You can do this as follows:
+
+```tsx title=src/pages/posts/[postSlug]/index.tsx
+export function getStaticPaths() {
+ return {
+ paths: [],
+ fallback: 'blocking',
+ };
+}
+```
+
+The above code will tell Next.js not to generate any pages up front. Then, as requests come in they will be generated server-side and stored for subsequent requests. Read more about [`fallback: 'blocking'`](https://nextjs.org/docs/basic-features/data-fetching#fallback-blocking).
+
+#### Statically Generate **Some** Of Your Pages At Build Time Based On A Query
+
+Maybe you want to generate a specific set of posts during build time. Perhaps you want to generate the most recent posts, or maybe you want to generate posts that receive a lot of traffic. You can do this by providing paths to Next.js that are based on a query as follows:
+
+```tsx title=src/pages/posts/[postSlug]/index.tsx
+import { client } from 'client';
+
+export async function getStaticPaths() {
+ const values = await client.client.inlineResolved(() => {
+ return client.client.query
+ .posts({
+ first: 5,
+ })
+ ?.nodes?.map((node) => node?.uri);
+ });
+ const paths = [];
+
+ if (Array.isArray(values)) {
+ paths.push(
+ ...values
+ .filter((value) => {
+ return typeof value === 'string';
+ }),
+ );
+ }
+
+ return {
+ paths,
+ fallback: 'blocking',
+ };
+```
+
+> **NOTE**: The code above assumes you have your permalink structure set to `/posts/%postname%/` in WordPress. You can add additional logic here to format the proper URL if that is not the case.
+
+The code above will perform an inline query to WordPress in order to get the 5 most recent posts. Then it will create a list of paths based on the post URIs. In this case we are not rendering all the post pages up front, so some will be dynamically generated on-the-fly using the `fallback: 'blocking'` feature in Next.js.
+
+The above scenarios are most common, but there are other options for [`getStaticPaths`](https://nextjs.org/docs/basic-features/data-fetching#getstaticpaths-static-generation) that might be useful depending upon your needs.
+
+## SSR Using `getNextServerSideProps`
+
+This helper function lets you server side render your page with WordPress data. The function should be returned from `getServerSideProps`:
+
+```tsx
+export async function getServerSideProps(context: GetServerSidePropsContext) {
+ return getNextServerSideProps(context, {
+ Page: MyPage,
+ client,
+ });
+}
+```
+
+The function accepts two arguments: the server side props context, and an object with a `Page` key. This should be your Next.js page component:
+
+```tsx {2,5,20,21}
+import { GetServerSidePropsContext } from 'next';
+import { getNextServerSideProps } from '@faustjs/next';
+import { client } from 'client';
+
+export default function MyPage() {
+ const { usePosts } = client;
+
+ return (
+ <>
+
Recent Posts
+ {usePosts()?.nodes.map((post) => (
+
{post.title()}
+ ))}
+ >
+ );
+}
+
+export async function getServerSideProps(context: GetServerSidePropsContext) {
+ return getNextServerSideProps(context, {
+ Page: MyPage,
+ client,
+ });
+}
+```
+
+As mentioned in `getNextStaticProps`, the reason `MyPage` and `client` are passed to `getNextServerSideProps` is because under the hood Faust.js performs a skeleton render of the page component to know what data to fetch and what queries to build. This allows the developer to not have to think about batching/constructing queries, or data fetching.
+
+## Rehydration Using ``
+
+In order to properly facilitate SSR and SSG you must use the built-in component published in `faustjs/next` called `FaustProvider`. This component performs the following:
+
+1. Sets the `client` to be used with every request for WordPress data.
+1. Hydrates the `client` cache using the prepared cache snapshot from `getNextServerSideProps` or `getNextStaticProps`.
+1. Renders its `children`
+
+### Adding `` to your `_app.tsx`
+
+Using the `FaustProvider` component is easy, and if you are using an example `next` project published by Faust.js it will happen automatically. If you are adding `Faust.js` to your project, you will want to put `FaustProvider` at the top of your component tree. Typically in a Next.js app this means in your `pages/_app.tsx` file as follows:
+
+```tsx title=src/pages/_app.tsx {9,11}
+import 'faust.config';
+import { FaustProvider } from '@faustjs/next';
+import { client } from 'client';
+import type { AppProps } from 'next/app';
+
+export default function MyApp({ Component, pageProps }: AppProps) {
+ return (
+ <>
+
+
+
+ >
+ );
+}
+```
+
+## Configuring Custom Page Props And ISR
+
+### Custom Page Props
+
+If you need to send custom props to your page you can do so in the configuration options for both `getNextServerSideProps` and `getNextStaticProps`. Below is some example code demonstrating how to do this.
+
+```tsx {2,5-9,14,26-28}
+import { GetStaticPropsContext } from 'next';
+import { getNextStaticProps } from '@faustjs/next';
+import { client } from 'client';
+
+interface MyPageProps {
+ title: string;
+}
+
+export default function MyPage({ title }: MyPageProps) {
+ const { usePosts } = client;
+
+ return (
+ <>
+
{title}
+ {usePosts()?.nodes.map((post) => (
+
{post.title()}
+ ))}
+ >
+ );
+}
+
+export async function getStaticProps(context: GetStaticPropsContext) {
+ return getNextStaticProps(context, {
+ Page: MyPage,
+ client,
+ props: {
+ title: 'Recent Posts',
+ },
+ });
+}
+```
+
+You might want to use this to send props down based on calls to APIs you make outside of Faust.js.
+
+### Setting Up Incremental Static Regeneration (ISR)
+
+Next.js enables ISR with [getStaticProps](https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration) using a `revalidate` property. By default in Next.js ISR is disabled. Faust.js enables ISR, and by default it sets it to 15 minutes. What this means is your page will be cached for 15 minutes before being regenerated. [Read more on the Next.js site about ISR](https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration).
+
+With Faust.js you can configure ISR at both the page level and the global level. At the page level you can pass it along in the configuration options for `getNextStaticProps` as follows:
+
+```ts {4}
+return getNextStaticProps(context, {
+ Page: MyPage,
+ client,
+ revalidate: 60, // 60 seconds
+});
+```
+
+To configure ISR at a global level you can add the following code to your `faust.config`:
+
+```ts title=src/faust.config.js
+import { config as nextConfig } from '@faustjs/next';
+
+nextConfig({
+ revalidate: 60, // 60 seconds
+});
+```
+
+The code above will set the default ISR revalidate time for every page, and can be overridden on each page.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/testing-with-jest.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/testing-with-jest.mdx
new file mode 100644
index 000000000..215b78d96
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/guides/testing-with-jest.mdx
@@ -0,0 +1,228 @@
+---
+slug: /next/guides/testing-with-jest
+title: Testing with Jest
+description: How to test Faust.js apps with Jest
+---
+
+We recommend using Jest to test Faust.js apps. [Jest](https://jestjs.io/) is a JavaScript testing framework that uses minimal config, and provides a simple API for writing tests.
+
+## Setup
+
+The fastest way to get started is to clone our Faust.js example in the [Getting Started](/docs/next/getting-started) section. We'll assume you are starting from there. Now, let's setup Jest!
+
+### Install Dependencies
+
+Our Getting Started example uses Next.js 12, which has a built in configuration for Jest.
+
+To setup Jest, install the following dependencies:
+
+```bash
+npm install --save-dev jest@next jest-environment-jsdom@next @testing-library/react @testing-library/jest-dom
+```
+
+:::note
+
+We are installing `jest` and `jest-environment-jsdom` at the `next` tag. Faust.js uses ES modules under the hood, which is only supported in `jest@next` and `jest-environment-jsdom@next` currently.
+
+:::
+
+### Create The Jest Config File
+
+In your root directory, create a `jest.config.js` file with the following contents:
+
+```js title="jest.config.js"
+// jest.config.js
+const nextJest = require('next/jest');
+
+const createJestConfig = nextJest({
+ // Provide the path to your Next.js app to load next.config.js and .env files in your test environment
+ dir: './',
+});
+
+// Add any custom config to be passed to Jest
+const customJestConfig = {
+ // Add more setup options before each test is run
+ // setupFilesAfterEnv: ['/jest.setup.js'],
+ // if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
+ moduleDirectories: ['node_modules', '/src'],
+ testEnvironment: 'jest-environment-jsdom',
+};
+
+// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
+module.exports = createJestConfig(customJestConfig);
+```
+
+### Create Test Script
+
+Finally, add a script in your `package.json` file to run Jest tests:
+
+```json title="package.json" {4}
+{
+ // ... Rest of package.json
+ "scripts": {
+ "test": "jest"
+ }
+}
+```
+
+That's it! Now you can create tests and run Jest with `npm test`.
+
+## Example
+
+Let's create a basic test case to see how testing works in a Faust.js app with Jest.
+
+Take the following `Header.tsx` component:
+
+```tsx title="src/components/Header.tsx"
+import React from 'react';
+import styles from 'scss/components/Header.module.scss';
+import Link from 'next/link';
+import { client, MenuLocationEnum } from 'client';
+
+interface Props {
+ title?: string;
+ description?: string;
+}
+
+function Header({
+ title = 'Headless by WP Engine',
+ description,
+}: Props): JSX.Element {
+ const { menuItems } = client.useQuery();
+ const links = menuItems({
+ where: { location: MenuLocationEnum.PRIMARY },
+ }).nodes;
+
+ return (
+
+
+
+ );
+}
+
+export default Header;
+```
+
+As a generic example, let's create a test case that checks for the rendered navigation items. We'll test both the hardcoded items and the items received from GraphQL via GQty. Create a file called `src/components/Header.test.tsx`.
+
+We'll start off by mocking the Faust.js `client` module to return a mock GraphQL query result:
+
+```tsx {5-27}
+import React from 'react';
+import { render } from '@testing-library/react';
+import Header from './Header';
+
+jest.mock('client', () => {
+ const { MenuLocationEnum } = jest.requireActual('../client');
+
+ return {
+ client: {
+ useQuery: () => ({
+ menuItems: () => ({
+ nodes: [
+ {
+ label: 'Home',
+ url: 'http://localhost:3000/',
+ },
+ {
+ label: 'About',
+ url: 'http://localhost:3000/about',
+ },
+ ],
+ }),
+ }),
+ },
+ MenuLocationEnum,
+ };
+});
+```
+
+Then, we'll add a test case to ensure that our navigation items are accounted for:
+
+```tsx
+test('Header component renders menu items', () => {
+ const { getAllByRole } = render();
+
+ const menuItems = getAllByRole('listitem');
+ expect(menuItems).toHaveLength(3);
+
+ const menuNames = menuItems.map((item) => item.textContent);
+
+ expect(menuNames).toEqual(['Home', 'About', 'GitHub']);
+});
+```
+
+This leaves you with a final `Header.test.tsx` file that looks like:
+
+```tsx title="src/components/Header.test.tsx"
+import React from 'react';
+import { render } from '@testing-library/react';
+import Header from './Header';
+
+jest.mock('client', () => {
+ const { MenuLocationEnum } = jest.requireActual('../client');
+
+ return {
+ client: {
+ useQuery: () => ({
+ menuItems: () => ({
+ nodes: [
+ {
+ label: 'Home',
+ url: 'http://localhost:3000/',
+ },
+ {
+ label: 'About',
+ url: 'http://localhost:3000/about',
+ },
+ ],
+ }),
+ }),
+ },
+ MenuLocationEnum,
+ };
+});
+
+it('Header component renders menu items', () => {
+ const { getAllByRole } = render();
+
+ const menuItems = getAllByRole('listitem');
+ expect(menuItems).toHaveLength(3);
+
+ const menuNames = menuItems.map((item) => item.textContent);
+
+ expect(menuNames).toEqual(['Home', 'About', 'GitHub']);
+});
+```
+
+Finally, Use `npm run test` to run the test and see that it passes.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/api-router.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/api-router.mdx
new file mode 100644
index 000000000..5e236462a
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/api-router.mdx
@@ -0,0 +1,81 @@
+---
+slug: /next/reference/api-router
+title: Using the API Router
+description: The API Router sets up the API routes for Faust.js.
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+The API Router is a node middleware that handles all of the Faust.js related API routes for you.
+
+Currently, there are two API routes that are handled by the API Router:
+
+- `auth/token`: A route to handle a request for an authentication token
+- `auth/logout`: A route to handle a request to logout
+
+With the API router, we have the ability to add more routes as needed, without requiring any changes from the user.
+
+## Usage
+
+By default, the API router is expected to be mounted at `/api/faust`. This is the base path that the API router will use to handle all of the routes (i.e. `/api/faust/auth/token`).
+
+To configure this in Next.js, you would create a `faust` directory in your [api routes directory](https://nextjs.org/docs/api-routes/introduction), with a [catch-all route](https://nextjs.org/docs/routing/dynamic-routes#optional-catch-all-routes) file named `[[...route]].ts`. The complete file path would then be:
+
+```
+src/pages/api/faust/[[...route]].ts
+```
+
+Now, add the following content to your newly created `[[...route]].ts` file:
+
+```tsx title="src/pages/api/faust/[[...route]].ts"
+import 'faust.config';
+import { apiRouter } from '@faustjs/core/api';
+
+export default apiRouter;
+```
+
+Your API Router is now setup and ready to handle all Faust.js related API routes from `/api/faust/*`.
+
+### Modifying the API Router Base Path
+
+You may find a need to modify the base path of the API Router. For these use cases, the `apiBasePath` config option can be used.
+
+Say for example, you want to mount the API router at `/api/headless`. You would first specify this base path in your `faust.config.ts` file:
+
+```js title="faust.config.js" {15}
+import { config as coreConfig } from '@faustjs/core';
+
+if (!process.env.NEXT_PUBLIC_WORDPRESS_URL) {
+ console.error(
+ 'You must provide a NEXT_PUBLIC_WORDPRESS_URL environment variable, did you forget to load your .env.local file?',
+ );
+}
+
+/**
+ * @type {import("@faustjs/core").Config}
+ */
+export default coreConfig({
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ apiClientSecret: process.env.FAUSTWP_SECRET_KEY,
+ apiBasePath: '/api/headless',
+});
+```
+
+Then, you would replicate this path in your Next.js [API routes directory](https://nextjs.org/docs/api-routes/introduction), by creating a `headless` directory, and adding a `[[...route]].ts` file to it. The complete file path would then be:
+
+```
+src/pages/api/headless/[[...route]].ts
+```
+
+Finally, the content of `src/pages/api/headless/[[...route]].ts` would be:
+
+```ts title="src/pages/api/headless/[[...route]].ts"
+import 'faust.config';
+import { apiRouter } from '@faustjs/core/api';
+
+export default apiRouter;
+```
+
+Your API Router will now be handling all Faust.js related API routes from `/api/headless/*`.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/config.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/config.mdx
new file mode 100644
index 000000000..29aa920ef
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/config.mdx
@@ -0,0 +1,28 @@
+---
+slug: /next/reference/config
+title: Faust.js Next.js config
+description: Faust.js provides a default configuration object regarding Static Site Generation with Next.js
+---
+
+Faust.js provides a default configuration object regarding Static Site Generation when using the `getNextStaticProps`.
+
+The `config` object provides a default value for the [revalidate](https://nextjs.org/docs/api-reference/data-fetching/get-static-props#revalidate) property.
+By default, in Next.js this is `false` and the page re-generation will not happen.
+Using Faust.js when using the `getNextStaticProps` function it applies the `config` object to the result.
+
+```tsx
+export async function getStaticProps(context: GetStaticPropsContext) {
+ return getNextStaticProps(context, {
+ Page: MyPage,
+ client,
+ props: {
+ title: 'Recent Posts',
+ },
+ }); // here revalidate property is set to 15 minutes
+}
+```
+
+## Config
+The Config object has the following properties:
+
+* `revalidate`: The revalidate property is the amount in seconds after which a page re-generation can occur (defaults to 900 seconds).
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/expected-url-params.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/expected-url-params.mdx
new file mode 100644
index 000000000..5f3716ddf
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/expected-url-params.mdx
@@ -0,0 +1,93 @@
+---
+slug: /next/reference/expected-url-params
+title: Expected URL Params
+description: Faust.js has built-in URL params that it expects to be present in the URL, making it easier to get data from Headless WordPress.
+---
+
+When querying WordPress for data you are often going to use pieces of the current URL to determine what type of request to make. For example, if you have a list of posts in your site at `/posts` and your `Hello World` post can be found at `/posts/hello-world`, then the assumption is your `Hello World` post slug is `hello-world`. However, you still need a way to get the `hello-world` value from the URL in order to make a requests for the post. With Next.js you do this using `params` of [Static Props Context](https://nextjs.org/docs/basic-features/data-fetching#getstaticprops-static-generation) or [Server Side Props Context](https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering). Faust.js takes this one step further and has some predefined param names that you can use in order to have Faust.js find the URL params and make requests on your behalf. A lot of this is documented in our [hooks reference](./hooks). In general our hooks work based on an expected URL param of the content type and either `Id`, `Slug`, or `Uri` at the end. Below is the interface we look for:
+
+```tsx
+interface Params {
+ postId: string;
+ postSlug: string;
+ postUri: string[];
+ pageId: string;
+ pageUri: string[];
+ categoryId: string;
+ categorySlug: string;
+}
+```
+
+This means by building your [Next.js pages](https://nextjs.org/docs/basic-features/pages) with these params in mind, our hooks will just work without having to specify any IDs, slugs, etc.
+
+For example, say you have a page:
+
+```
+/src/pages/posts/[postSlug].tsx
+```
+
+Since `[postSlug]` is one of the params we look for, you can use the `usePost()` hook without any arguments and it will understand that it needs to get a post using the value stored in the `postSlug` param!
+
+```tsx title=/src/pages/posts/[postSlug].tsx {6}
+import { client, getNextStaticProps } from '@faustjs/next';
+import { GetStaticPropsContext } from 'next';
+
+export default function Page() {
+ const { usePost } = client();
+ const post = usePost();
+
+ return (
+
+
{post?.title()}
+
+
+ );
+}
+```
+
+The same can be done for `[postId]` only this time it will make a request using the `postId` param to get a post by ID.
+
+```tsx title=/src/pages/posts/[postId].tsx {6}
+import { client, getNextStaticProps } from '@faustjs/next';
+import { GetStaticPropsContext } from 'next';
+
+export default function Page() {
+ const { usePost } = client();
+ const post = usePost();
+
+ return (
+
+
{post?.title()}
+
+
+ );
+}
+```
+
+So your code doesn't change, but your file name does. Based on what you name the file, `usePost()` will make the proper request for data. This works with `usePage()` and `usePosts()` as well. So for `usePosts()` you might have something like the following:
+
+```tsx title=/src/pages/category/[categorySlug]/index.tsx {6}
+export default function Page() {
+ const { usePosts } = client();
+ const posts = usePosts();
+
+ return (
+ <>
+ {posts.nodes?.map((post) => (
+
+ ))}
+ >
+ );
+}
+```
+
+Notice the above file is `index.tsx`, but `[categorySlug]` is used in the URL. So the `usePosts()` hook will make a request using the `categorySlug` param to get posts for the category based on the value stored in `categorySlug`.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/faust-provider.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/faust-provider.mdx
new file mode 100644
index 000000000..e2bf4fc82
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/faust-provider.mdx
@@ -0,0 +1,71 @@
+---
+slug: /next/reference/faust-provider
+title: Using FaustProvider
+description: The FaustProvider React component wraps your app to provide context to Faust.js
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+The `` component is a React component that follows the [provider pattern](https://www.patterns.dev/posts/provider-pattern/), wrapping your Next.js app to provide the necessary context to Faust.js. This includes:
+
+- React Context for state management
+- GraphQL query cache
+- Necessary context for usage with Faust.js hooks
+
+## Props
+
+The `` React component requires the following props:
+
+- `client`: [The GQty client from your app](/docs/next/guides/fetching-data#setting-up-your-client)
+- `pageProps`: The Next.js `pageProps` that are passed from the [Next.js App component](https://nextjs.org/docs/advanced-features/custom-app)
+
+## Usage
+
+The `` should be called in your application's `_app.tsx` file. This file may live in either `src/pages/_app.tsx` or `pages/_app.tsx` depending on how you've setup your project. If your project doesn't yet have this file, you can use this as the default `_app.tsx` file:
+
+```tsx title="_app.tsx"
+import type { AppProps } from 'next/app';
+
+export default function MyApp({ Component, pageProps }: AppProps) {
+ return (
+
+ );
+}
+```
+
+With your `_app.tsx` file created, you can now import the `` component and wrap your app with it. The `` component should wrap everything in the return statement. You'll also need to import the `client`, as it is a required prop of the ``:
+
+```tsx title="_app.tsx" {1,2,7,9}
+import { FaustProvider } from '@faustjs/next';
+import { client } from 'client';
+import type { AppProps } from 'next/app';
+
+export default function MyApp({ Component, pageProps }: AppProps) {
+ return (
+
+
+
+ );
+}
+```
+
+Finally, we will import the Faust.js config at the top of the `_app.tsx` file to give our Faust.js app access to the config:
+
+```tsx title="_app.tsx" {1}
+import 'faust.config';
+import { FaustProvider } from '@faustjs/next';
+import { client } from 'client';
+import type { AppProps } from 'next/app';
+
+export default function MyApp({ Component, pageProps }: AppProps) {
+ return (
+
+
+
+ );
+}
+```
+
+With the above in place, your app is now ready to properly use Faust.js.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/getClient.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/getClient.mdx
new file mode 100644
index 000000000..42cbb077c
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/getClient.mdx
@@ -0,0 +1,208 @@
+---
+slug: /next/reference/getClient
+title: getClient()
+description: The getClient() function returns the GQty client that is used to query data.
+---
+
+## Description
+
+The `getClient()` function returns the GQty client that is used to query data.
+You need to export the instance of the client and then pass it to [FaustProvider](/docs/next/reference/faust-provider) `client` parameter.
+Behind the scenes, Faust.js will configure the client to perform SSR and SSG operations.
+
+## Parameters
+
+`getClient` accepts several optional parameters. We go through them one by one:
+
+### `schema`
+
+type: `object`
+
+Required: `false`
+
+This is the typescript schema object that is generated out of the `npm run generate` script. This is basically the GraphQL types, based on the structure of your WordPress site.
+You only want to run this script everytime you update the GraphQL schema in WordPress or when adding new CPTs.
+The `.schema.generated.ts` file contains several exported objects including the `generatedSchema` that you can import.
+
+### `scalarsEnumsHash`
+
+type: `object`
+
+Required: `false`
+
+This is the typescript object containing the [GraphQL scalar](https://graphql.org/learn/schema/) types that is generated out of the `npm run generate` script. GQty will use those scalars when querying the GraphQL endpoint.
+You only want to run this script everytime you update the GraphQL schema in WordPress or when adding new CPTs.
+The `.schema.generated.ts` file contains several exported objects including the `scalarsEnumsHash` that you can import.
+
+### `context`
+
+type: `object`
+
+Required: `false`
+
+This is an optional object that is of type [IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage).
+This represents the server context that contains information about the current incoming request.
+You want to use this parameter only when creating an instance of the client for server operations.
+
+```ts
+export function serverClient(req: IncomingMessage) {
+ return getClient({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+ context: req,
+ });
+}
+```
+
+### `applyRequestContext`
+
+type: `(url: string, init: RequestInit): Promise | RequestContext`
+
+Required: `false`
+
+A function that will be called just before the request made to the GraphQL endpoint. If you find yourself needing to add headers or other information to the request,
+then you can use this function to do that. You will need to return an object or a promise that returns the modified parameters.
+
+```ts
+export const client = getClient<
+ GeneratedSchema,
+ SchemaObjectTypesNames,
+ SchemaObjectTypes
+>({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+ applyRequestContext: async (url, init) => {
+ // Make modifications to the request here as you see fit
+ console.log('url', url);
+ console.log('init', init);
+
+ return { url, init };
+ },
+});
+```
+
+### `queryFetcher`
+
+type: `(query: string, variables?: Record) => Promise | ExecutionResult;`
+
+Required: `false`
+
+For already generated clients and for un-authenticated requests, you will be able to use this function if you want to manually modify the existing query function.
+
+```ts
+import { getGqlUrl } from 'faust.config';
+export const client = getClient<
+ GeneratedSchema,
+ SchemaObjectTypesNames,
+ SchemaObjectTypes
+>({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+ queryFetcher: async (query, variables) => {
+ const endpoint = getGqlUrl();
+ const response = await fetch(endpoint, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ query,
+ variables,
+ }),
+ });
+ const json = await response.json();
+ return json;
+ },
+});
+```
+
+### `authQueryFetcher`
+
+type: `(query: string, variables?: Record) => Promise | ExecutionResult;`
+
+Required: `false`
+
+Same as `queryFetcher` but this is for authenticated requests. You will be able to use this function if you want to manually modify the existing query function. Follow [this guide](/docs/next/guides/auth#making-authenticated-requests) to learn how to make authenticated requests.
+
+```ts
+import { getAccessToken } from '@faustjs/core/auth';
+import { getGqlUrl } from 'faust.config';
+export const client = getClient<
+ GeneratedSchema,
+ SchemaObjectTypesNames,
+ SchemaObjectTypes
+>({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+ authQueryFetcher: async (query, variables) => {
+ const token = getAccessToken();
+ const endpoint = getGqlUrl();
+ const response = await fetch(endpoint, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ Authorization: 'Bearer ' + token,
+ },
+ body: JSON.stringify({
+ query,
+ variables,
+ }),
+ });
+ const json = await response.json();
+ return json;
+ },
+});
+```
+
+## Return
+
+An Instance of `GQty` client for performing queries or mutations.
+
+## Usage
+
+To use `getClient`, create a `index.ts` file or any file name you want to use and call the `getClient` function with the provided parameters:
+
+```ts title="src/client/index.ts"
+import type { IncomingMessage } from 'http';
+import { getClient } from '@faustjs/next';
+import {
+ generatedSchema,
+ scalarsEnumsHash,
+ GeneratedSchema,
+ SchemaObjectTypes,
+ SchemaObjectTypesNames,
+} from './schema.generated';
+
+export const client = getClient<
+ GeneratedSchema,
+ SchemaObjectTypesNames,
+ SchemaObjectTypes
+>({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+});
+
+export function serverClient(req: IncomingMessage) {
+ return getClient({
+ schema: generatedSchema,
+ scalarsEnumsHash,
+ context: req,
+ });
+}
+```
+
+Then do not forget to pass this instance to the `FaustProvider`:
+
+```ts title=_app.tsx
+import { FaustProvider } from '@faustjs/next';
+import { client } from 'client';
+import type { AppProps } from 'next/app';
+
+export default function MyApp({ Component, pageProps }: AppProps) {
+ return (
+
+
+
+ );
+}
+```
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/getNextServerSideProps.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/getNextServerSideProps.mdx
new file mode 100644
index 000000000..d16b8a9a8
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/getNextServerSideProps.mdx
@@ -0,0 +1,42 @@
+---
+slug: /next/reference/getNextServerSideProps
+title: getNextServerSideProps
+description: The getNextServerSideProps function lets you server side render your page with WordPress data.
+---
+
+The `getNextServerSideProps` function lets you server side render your page with WordPress data.
+The function should be returned from [getServerSideProps](https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props) which is required by Next.js to perform Server-Side Rendering (SSR):
+
+```tsx
+export async function getServerSideProps(context: GetServerSidePropsContext) {
+ return getNextServerSideProps(context, {
+ Page: MyPage,
+ client,
+ });
+}
+```
+
+The `getNextServerSideProps` function accepts two arguments: the server side props `context`, and an object (type `GetNextServerSidePropsConfig`) with a `Page` key.
+This should be your Next.js page component.
+
+The reason `MyPage` and `client` are passed to `getNextServerSideProps` is because
+under the hood Faust.js performs a skeleton render of the page component to know what data to fetch and what queries to build.
+This allows the developer to not have to think about batching/constructing queries, or data fetching.
+
+## Context parameter
+
+This is the same object that Next.js provides in the `getServerSideProps`. You can read the [list of parameters here](https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props#context-parameter).
+
+## GetNextServerSidePropsConfig parameter
+
+The second argument of `getNextServerSideProps` is of type `GetNextServerSidePropsConfig` and accepts the following parameters:
+
+* `Page`: The current page component. It can be any valid React Element.
+* `client`: The GQty client.
+* `notFound`: The `notFound` boolean allows the page to return a 404 status and 404 Page. This is [used by Next.js](https://nextjs.org/docs/api-reference/data-fetching/get-server-side-props#notfound) to force a page return a 404 even if there was a successfully generated page before.
+* `redirect`: The `redirect` object allows redirecting to internal and external resources. It should match the shape of `{ destination: string, permanent: boolean }`.
+* `props`: The `props` object is any other key value pairs of properties where each value is received by the `Page` component.
+
+## getNextServerSideProps return values
+
+The `getNextServerSideProps` function returns an object that is required by the `getServerSideProps` function.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/getNextStaticProps.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/getNextStaticProps.mdx
new file mode 100644
index 000000000..633984d65
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/getNextStaticProps.mdx
@@ -0,0 +1,41 @@
+---
+slug: /next/reference/getNextStaticProps
+title: getNextStaticProps
+description: The getNextStaticProps function lets you build a static site with your WordPress data.
+---
+
+The `getNextStaticProps` function lets you build a static site with your WordPress data. The function should be returned from `getStaticProps`:
+
+```tsx
+export async function getStaticProps(context: GetStaticPropsContext) {
+ return getNextStaticProps(context, {
+ Page: MyPage,
+ client,
+ });
+}
+```
+
+The `getNextStaticProps` function accepts two arguments: the server side props `context`, and an object (type `GetNextStaticPropsConfig` which extends the `GetNextServerSidePropsConfig` type) with a `Page` key.
+This should be your Next.js page component.
+
+The reason `MyPage` and `client` are passed to `getNextStaticProps` is because
+under the hood Faust.js perform a skeleton render of the page component to know what data to fetch and what queries to build.
+
+## Context parameter
+
+This is the same object that Next.js provides in `getStaticProps`. You can read the [list of parameters here](https://nextjs.org/docs/api-reference/data-fetching/get-static-props#context-parameter).
+
+## GetNextServerSidePropsConfig parameter
+
+The second argument of `getNextStaticProps` is of type `GetNextStaticPropsConfig` and accepts the following parameters:
+
+* `Page`: The current page component. It can be any valid React Element.
+* `client`: The GQty client.
+* `revalidate`: The revalidate property is the amount in seconds after which a page re-generation can occur. By default, it is set to 900 seconds(15 minutes).
+* `props`: The `props` object is any other key value pairs of properties where each value is received by the `Page` component.
+
+Because the `GetNextStaticPropsConfig` type extends `GetNextServerSidePropsConfig`, it can also accept any other properties of the [getNextServerSideProps](/docs/next/reference/getNextServerSideProps).
+
+## getNextServerSideProps return values
+
+The `getNextStaticProps` function returns an object that is required by the `getStaticProps` function.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/handle-sitemap-requests.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/handle-sitemap-requests.mdx
new file mode 100644
index 000000000..9159be1c9
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/handle-sitemap-requests.mdx
@@ -0,0 +1,157 @@
+---
+slug: /next/reference/handle-sitemap-requests
+title: Using handleSitemapRequests
+description: Reference documentation on using the handleSitemapRequests middleware and its options.
+---
+
+The `handleSitemapRequests` helper function is a [Next.js middleware](https://nextjs.org/docs/middleware) that handles proxying sitemap requests from your WordPress site to your headless frontend.
+
+## Usage
+
+To use `handleSitemapRequests`, create a `_middleware.ts` file at the top of your `pages` directory with the following content:
+
+```ts title="src/pages/_middleware.ts"
+import { handleSitemapRequests } from '@faustjs/next/middleware';
+import { NextRequest, NextResponse } from 'next/server';
+
+export default async function _middleware(req: NextRequest) {
+ const sitemapRequest = await handleSitemapRequests(req, {
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ sitemapIndexPath: '/wp-sitemap.xml',
+ });
+
+ if (sitemapRequest) {
+ return sitemapRequest;
+ }
+
+ return NextResponse.next();
+}
+```
+
+## Config
+
+`handleSitemapRequests` accepts two required arguments. The first is the Next.js request object ([`NextRequest`](https://nextjs.org/docs/api-reference/next/server#nextrequest)), which comes from the top level default export. The second is a configuration object. This configuration object accepts the following properties:
+
+### `wpUrl`
+
+type: `string`
+
+Required: `true`
+
+This is your WordPress URL. This is typically defined in your `.env` file as `NEXT_PUBLIC_WORDPRESS_URL`.
+
+:::tip
+
+[Next.js middleware is very particular about what imports and APIs can be used.](https://nextjs.org/docs/api-reference/edge-runtime#unsupported-apis) Typically we could get the `wpUrl` from the Faust.js `config` object, but it's not currently possible with the Next.js middleware constraints.
+
+:::
+
+### `sitemapIndexPath`
+
+type: `string`
+
+Required: `true`
+
+This is the relative path to the sitemap index file that exists on your WordPress site. WordPress has built-in support for sitemaps, and the default index is available at `/wp-sitemap.xml`:
+
+```ts
+handleSitemapRequests(req, {
+ sitemapIndexPath: '/wp-sitemap.xml',
+});
+```
+
+Alternatively, you may be using a plugin to handle your sitemaps. In that case, you want to use the sitemap index path that the plugin has defined. For example, [Yoast SEO](https://yoast.com/) creates a sitemap index file at `/sitemap_index.xml`:
+
+```ts
+handleSitemapRequests(req, {
+ sitemapIndexPath: '/sitemap_index.xml',
+});
+```
+
+### `sitemapPathsToIgnore`
+
+type: `string[]`
+
+An array of pathnames to ignore when proxying sitemaps from your WordPress site.
+
+Useful if you have URLs in your WordPress sitemap index that don't correlate to the URL structure of your headless frontend.
+
+For example, the default WordPress sitemap index includes a sitemap for users: `/wp-sitemap-users-1.xml`. In most cases, your headless frontend is unlikely to have an archive for users. Ignoring this path will prevent the sitemap index from including sitemaps with URLs of user pages that do not exist.
+
+```ts
+handleSitemapRequests(req, {
+ sitemapPathsToIgnore: ['/wp-sitemap-users-1.xml'],
+});
+```
+
+Additionally, you can provide a wildcard to ignore all paths that start with a certain string:
+
+```ts
+handleSitemapRequests(req, {
+ sitemapPathsToIgnore: ['/wp-sitemap-users-*'],
+});
+```
+
+:::note
+
+The wildcard (`*`) character must always be the last character in the pathname.
+
+:::
+
+### `pages`
+
+type: `{path: string; lastmod?: string; changefreq?: string; priority?: number}[]`
+
+An array of objects that define [Next.js file based pages](https://nextjs.org/docs/basic-features/pages) that you would like to include in your sitemap. For example, you may have a custom page called `/src/pages/about.tsx`. You'd like to include this in your sitemap, so you would add it to the `pages` array:
+
+```ts
+handleSitemapRequests(req, {
+ pages: [
+ {
+ path: '/about',
+ },
+ ],
+});
+```
+
+The `path` property is the relative path to the page and the only required property. You can additionally specify the `lastmod`, `changefreq` and `priority` properties for additional configuration:
+
+```ts
+handleSitemapRequests(req, {
+ pages: [
+ {
+ path: '/about',
+ lastmod: '2020-01-01',
+ changefreq: 'monthly',
+ priority: 0.5,
+ },
+ ],
+});
+```
+
+When the `pages` array is provided and not empty, a sitemap is generated at `/sitemap-faust-pages.xml` with the provided URLs.
+
+### `replaceUrls`
+
+Type: `boolean`
+
+By default, this option is set to `true`. When enabled, the helper function will replace your WordPress site URL with your headless frontend URL in your proxied sitemaps.
+
+### `robotsTxt`
+
+type: `(sitemapUrl: string) => Promise`
+
+The `robotsTxt` option is an async function that returns a string that will be used as the `/robots.txt` route for your headless frontend. The function also accepts a single argument, `sitemapUrl`, which can be used when defining your robots.txt content:
+
+```ts
+handleSitemapRequests(req, {
+ async robotsTxt(sitemapUrl) {
+ return `
+ User-agent: *
+ Allow: /
+
+ Sitemap: ${sitemapUrl}
+ `;
+ },
+});
+```
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/gqty-hooks.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/gqty-hooks.mdx
new file mode 100644
index 000000000..f9994a0fd
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/gqty-hooks.mdx
@@ -0,0 +1,25 @@
+---
+slug: /next/reference/hooks/gqty-hooks
+title: GQty Hooks
+description: How to use the GQty related hooks for fetching data
+---
+
+There may be instances where the built in Faust.js hooks do not satisfy your data fetching requirements. Thankfully, GQty publishes the following hooks that can be used for custom queries, mutations, or subscriptions:
+
+- [`useQuery`](https://gqty.dev/docs/react/fetching-data#usequery)
+ - Make any query request to the Headless WordPress API
+- [`useLazyQuery`](https://gqty.dev/docs/react/fetching-data#uselazyquery)
+- [`useTransactionQuery`](https://gqty.dev/docs/react/fetching-data#usetransactionquery)
+- [`useMutation`](https://gqty.dev/docs/react/mutations#usemutation)
+ - Make any mutation request to the Headless WordPress API
+- [`useSubscription`](https://gqty.dev/docs/react/subscriptions#usesubscription)
+
+For example, you may want to get a list of your content types:
+
+```tsx
+const { useQuery } = client;
+
+const contentTypes = useQuery().contentTypes()?.nodes;
+```
+
+`useQuery`, along with all the other hooks, are typed. So you'll be able to see exactly what kind of data you have access to via your IDE's intellisense.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/hooks.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/hooks.mdx
new file mode 100644
index 000000000..c58d87eb2
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/hooks.mdx
@@ -0,0 +1,15 @@
+---
+slug: /next/reference/hooks
+title: Hooks
+description: Hooks for Faust.js
+---
+
+Faust.js provides a number of hooks that make interacting with your headless WordPress site a little easier.
+
+- [`usePost`](/docs/next/reference/hooks/usePost): Fetch a post from WordPress
+- [`usePosts`](/docs/next/reference/hooks/usePosts): Fetch multiple posts from WordPress
+- [`usePage`](/docs/next/reference/hooks/usePage): Fetch a page from WordPress
+- [`usePreview`](/docs/next/reference/hooks/usePreview): Fetch preview data from WordPress
+- [`useAuth`](/docs/next/reference/hooks/useAuth): Facilitate authentication with WordPress
+- [`useLogin`](/docs/next/reference/hooks/useLogin): Facilitate login with WordPress
+- [`useLogout`](/docs/next/reference/hooks/useLogout): Facilitate logout with WordPress
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/useAuth.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/useAuth.mdx
new file mode 100644
index 000000000..afe330225
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/useAuth.mdx
@@ -0,0 +1,90 @@
+---
+slug: /next/reference/hooks/useAuth
+title: useAuth
+description: The useAuth hook provides a way to ensure that the user is authenticated.
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+The `useAuth` hook provides a way to guarantee a users' authentication state, thus allowing you to control how a page's content is rendered.
+
+The `useAuth` hook accepts 1 argument of `UseAuthOptions`, which is an object that contains the following properties:
+
+```ts
+const options = {
+ // Specify if the useAuth hook should facilitate the redirect to the appropriate url.
+ shouldRedirect: true;
+}
+```
+
+By default, if the user is not authenticated, the page will redirect to the WordPress backend if the `authType` is `redirect`, and to the `loginPagePath` if `authType` is `local`.
+
+However, if the `shouldRedirect` option is `false`, the `useAuth` hook will **not** facilitate the redirect.
+
+The example below shows how to use the `useAuth` hook to render a page that requires authentication. If a user is authenticated, they will be shown the content. Otherwise, they will be redirected to the appropriate URL to authenticate:
+
+```tsx title=src/pages/gated-content.tsx {5}
+import { client } from 'client';
+
+export default function Gated() {
+ const { useAuth } = client.auth;
+ const { isLoading, isAuthenticated } = useAuth();
+
+ if (isLoading) {
+ return
Loading...
;
+ }
+
+ return
Authenticated content
;
+}
+```
+
+Additionally, the example below shows how to use `useAuth` with the `shouldRedirect` option set to `false`. This will disable the automatic redirect to the appropriate URL to authenticate, and allows you to control how the page's content is rendered in an unauthenticated state:
+
+```tsx title=src/pages/gated-content.tsx {5-7,13-15}
+import { client } from 'client';
+
+export default function Gated() {
+ const { useAuth } = client.auth;
+ const { isLoading, isAuthenticated, authResult } = useAuth({
+ shouldRedirect: false,
+ });
+
+ if (isLoading) {
+ return
Loading...
;
+ }
+
+ if (!isAuthenticated) {
+ return
You are not authenticated! Please login.
;
+ }
+
+ return
Authenticated content
;
+}
+```
+
+`useAuth` exports an object with the following properties:
+
+- `isLoading`: A boolean that indicates whether the `useAuth` function is currently checking if a user is authenticated.
+- `isAuthenticated`: A boolean that indicates whether the user is authenticated.
+- `authResult`: The result from checking if there is an authenticated user.
+
+ If there is an authenticated user, the `authResult` will be `true`. Otherwise, the `authResult` will be an object with the following properties:
+
+ ```js title="The authResult object when there is no authenticated user"
+ {
+ /**
+ * An absolute URL to the WordPress backend that the user should be redirected to in order to authenticate.
+ * This property is used for the "redirect" based authentication strategy
+ */
+ redirect: 'xxxx';
+
+ /*
+ * A relative URL path to the local login page as specified in the `loginPagePath` option.
+ * This property is used for the "local" based authentication strategy
+ */
+ login: 'xxxx';
+ }
+ ```
+
+ The `authResult` can be helpful if you want to handle the redirection yourself, instead of the `useAuth` hook.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/useLogin.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/useLogin.mdx
new file mode 100644
index 000000000..0a8e69655
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/useLogin.mdx
@@ -0,0 +1,81 @@
+---
+slug: /next/reference/hooks/useLogin
+title: useLogin
+description: The useLogin hook provides a way to log in a user
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+The `useLogin` hook provides an abstraction around obtaining an authorization code and fetching refresh/access tokens from WordPress, thus logging in a user to your Headless frontend.
+
+The following example shows how to use the `useLogin` hook to login a user:
+
+```tsx title=pages/login.tsx {9,18}
+import { client } from 'client';
+import { useState } from 'react';
+
+export default function Login() {
+ const { useLogin } = client.auth;
+ const [usernameEmail, setUserNameEmail] = useState('');
+ const [password, setPassword] = useState('');
+
+ const { login, isLoading, data, error } = useLogin();
+
+ const errorMessage = data?.error || error?.message;
+
+ return (
+
+ );
+}
+```
+
+`useLogin` exports an object with the following properties:
+
+- `login`: A function that initiates a request to obtain an authorization code via a GraphQL mutation by the provided `usernameEmail` and `password` arguments. Note that the `usernameEmail` argument is a string that can be either a username or an email address.
+- `isLoading`: A boolean that indicates whether the `login` function is currently fetching an authorization code.
+- `data`: An object that contains the response data from the `login` function.
+- `error`: An object that contains the error data from the `login` function.
+
+When an authorization code is successfully fetched, `useLogin` will facilitate the request to the FaustWP plugin's authorize endpoint to obtain the refresh/access tokens. From there, the tokens are stored properly, and the user is logged in.
+
+Additionally, if the login page URL contains a `redirect_uri` query parameter, the user will be redirected to the `redirect_uri` URL after the login is successful.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/useLogout.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/useLogout.mdx
new file mode 100644
index 000000000..182cf46a4
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/useLogout.mdx
@@ -0,0 +1,46 @@
+---
+slug: /next/reference/hooks/useLogout
+title: useLogout Hook
+description: The useLogout hook provides a way to logout a user
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+The `useLogout` hook provides a way to logout a user from your headless frontend.
+
+The following example shows how you could use the `useLogout` hook in a `logout.tsx` page:
+
+```tsx title="src/pages/logout.tsx"
+import { client } from 'client';
+import { useRouter } from 'next/router';
+import { useEffect } from 'react';
+export default function Logout() {
+ const router = useRouter();
+ const { isLoggedOut, logout } = client.auth.useLogout();
+ useEffect(() => {
+ if (isLoggedOut !== undefined) {
+ return;
+ }
+
+ // Initiate the logout process.
+ // This could also be called on a button click, for example, in a nav menu.
+ logout();
+ }, [isLoggedOut, logout]);
+
+ useEffect(() => {
+ if (isLoggedOut) {
+ // The user was successfully logged out. Redirect them.
+ router.push('/');
+ }
+ }, [router, isLoggedOut]);
+ return <>Logging out...>;
+}
+```
+
+`useLogout` exports an object with the following properties:
+
+- `logout`: a function that initiates a request to logout the user by clearing their refresh token from the cookie.
+- `isLoggedOut`: `undefiend` until the `logout` function is called. Then a `boolean` that indicates whether the user was successfully logged out
+- `isLoading`: A boolean that indicates whether the `logout` function is currently logging out the user.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePage.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePage.mdx
new file mode 100644
index 000000000..2e2c19562
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePage.mdx
@@ -0,0 +1,61 @@
+---
+slug: /next/reference/hooks/usePage
+title: usePage Hook
+description: The usePage hook provides a standard way to get a wordpress page
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+The `usePage` hook provides the standard interface for getting a page from your Headless WordPress API. It also allows you to pass-in no arguments. When you do not pass arguments into `usePage` it will attempt to look at the URL params in order to determine how to get a page from your Headless WordPress API. In Next.js this means you will need to name your page file in a particular way in order to get the proper URL params. Below are the possible names that will work automatically with Faust.js:
+
+- `[pageId].tsx`
+- `[...pageUri].tsx`
+
+Using the above names, Faust.js is able to apply the following logic to determine how to get a page from your Headless WordPress API:
+
+1. If `pageId` is found in the URL params, Faust.js makes a request to retrieve a `page` from WordPress by `ID`
+1. If `pageUri` is found in the URL params, Faust.js makes a request to retrieve a `page` from WordPress by `URI`
+
+The following is an example of how to use the `usePage` hook with a `pageUri`:
+
+```tsx title=/src/pages/[...pageUri].tsx {5,6}
+import { getNextStaticProps } from '@faustjs/next';
+import { client } from 'client';
+
+export default function Page() {
+ const { usePage } = client;
+ const page = usePage();
+
+ return (
+
+
{page?.title()}
+
+
+ );
+}
+```
+
+The above code will also work with `pageId` and `pageUri` depending upon what URL scheme you want to use. You may also want to fetch a specific page. Doing that might look similar to the following:
+
+```tsx {6-10}
+import { getNextStaticProps } from '@faustjs/next';
+import { GetStaticPropsContext } from 'next';
+import { client, PageIdType } from 'client';
+
+export default function Page() {
+ const { usePage } = client;
+ const page = usePage({
+ id: 'hello-world',
+ idType: PageIdType.URI,
+ });
+
+ return (
+
+
{page?.title()}
+
+
+ );
+}
+```
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePost.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePost.mdx
new file mode 100644
index 000000000..00c01ee6b
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePost.mdx
@@ -0,0 +1,63 @@
+---
+slug: /next/reference/hooks/usePost
+title: usePost Hook
+description: The usePost hook provides a standard way to get a WordPress post
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+The `usePost` hook provides the standard interface for getting a post from your Headless WordPress API. It also allows you to pass-in no arguments. When you do not pass arguments into `usePost` it will attempt to look at the URL params in order to determine how to get a post from your Headless WordPress API. In Next.js this means you will need to name your post page file in a particular way in order to get the proper URL params. Below are the possible names that will work automatically with Faust.js:
+
+- `[postId].tsx`
+- `[postSlug].tsx`
+- `[...postUri].tsx`
+
+Using the above names, Faust.js is able to apply the following logic to determine how to get a post from your Headless WordPress API:
+
+1. If `postId` is found in the URL params, Faust.js makes a request to retrieve a `post` from WordPress by `ID`
+1. If `postSlug` is found in the URL params, Faust.js makes a request to retrieve a `post` from WordPress by `SLUG`
+1. If `postUri` is found in the URL params, Faust.js makes a request to retrieve a `post` from WordPress by `URI`
+
+The following is an example of how to use the `usePost` hook with a `postSlug`:
+
+```tsx title=/src/pages/posts/[postSlug].tsx {5,6}
+import { getNextStaticProps } from '@faustjs/next';
+import { client } from 'client';
+
+export default function Page() {
+ const { usePost } = client;
+ const post = usePost();
+
+ return (
+
+
{post?.title()}
+
+
+ );
+}
+```
+
+The above code will also work with `postId` and `postUri` depending upon what URL scheme you want to use. You may also want to fetch a specific post. Doing that might look similar to the following:
+
+```tsx {6-10}
+import { getNextStaticProps } from '@faustjs/next';
+import { GetStaticPropsContext } from 'next';
+import { client, PostIdType } from 'client';
+
+export default function Page() {
+ const { usePost } = client;
+ const post = usePost({
+ id: 'hello-world',
+ idType: PostIdType.SLUG,
+ });
+
+ return (
+
+
{post?.title()}
+
+
+ );
+}
+```
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePosts.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePosts.mdx
new file mode 100644
index 000000000..5703b5ba1
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePosts.mdx
@@ -0,0 +1,69 @@
+---
+slug: /next/reference/hooks/usePosts
+title: usePosts Hook
+description: The usePosts hook provides a standard way to get multiple WordPress posts
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+The `usePosts` hook provides the standard interface for getting a list of posts from your Headless WordPress API. It also allows you to pass-in no arguments. When you do not pass arguments into `usePosts` it will attempt to look at the URL params in order to determine how to get a list of posts from your Headless WordPress API. In Next.js this means you will need to name your post page file in a particular way in order to get the proper URL params. Below are the possible names that will work automatically with Faust.js:
+
+1. If `categoryId` is found in the URL params, a request is made to retrieve a list of posts for a `category` by `ID`
+1. If `categorySlug` is found in the URL params, a request is made to retrieve a list of posts for a `category` by `SLUG`
+1. If no URL params are found, a request is made to retrieve a list of posts without any filters
+
+The following is an example of how to use the `usePosts` hook with no URL params:
+
+```tsx title=src/pages/index.tsx {6-8,14-16}
+import { getNextStaticProps } from '@faustjs/next';
+import { client } from 'client';
+
+export default function Home() {
+ const { usePosts } = client;
+ const posts = usePosts({
+ first: 6,
+ });
+
+ return (
+ <>
+
Recent Posts
+
+ {posts?.nodes.map((post) => (
+
{post.title()}
+ ))}
+
+ >
+ );
+}
+```
+
+The code above will get the first 6 posts from the Headless WordPress API. If you want to create a page that would pull posts associated with a specific category you can use the following code:
+
+```tsx title=src/pages/category/[categorySlug].tsx {6-8,14-16}
+import { getNextStaticProps } from '@faustjs/next';
+import { client } from 'client';
+
+export default function Home() {
+ const { usePosts } = client;
+ const posts = usePosts({
+ first: 6,
+ });
+
+ return (
+ <>
+
Recent Posts
+
+ {posts?.nodes.map((post) => (
+
{post.title()}
+ ))}
+
+ >
+ );
+}
+```
+
+The code above will get the first 6 posts from the Headless WordPress API that are for the `categorySlug` defined in the URL params.
+
+For an example of `usePosts` with pagination, [take a look at our Next.js getting started example.](https://github.com/wpengine/faustjs/blob/main/examples/next/getting-started/src/pages/posts/index.tsx#L18-L23)
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePreview.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePreview.mdx
new file mode 100644
index 000000000..023551917
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePreview.mdx
@@ -0,0 +1,48 @@
+---
+slug: /next/reference/hooks/usePreview
+title: usePreview Hook
+description: The usePreview hook provides a way to get post preview data from WordPress
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+:::caution Deprecation Notice
+
+`usePreview` has been deprecated in favor of [`usePreviewNode`](/docs/next/reference/hooks/usePreviewNode)
+
+:::
+
+The `usePreview` hook provides an abstraction around getting a preview `page` or `post` from the Headless WordPress API. When calling the `usePreview` hook on an appropriate preview page, the hook will determine if the preview is a `page` or `post` and will make a request to retrieve the proper preview content.
+
+The following example shows how to use the `usePreview` hook to render either a `post` or `page` from WordPress:
+
+
+
+```tsx title=src/pages/preview.tsx {14-17}
+import { PageComponent } from 'pages/[...pageUri]';
+import { PostComponent } from 'pages/posts/[postSlug]';
+import { client } from 'client';
+
+export default function Preview() {
+ const { usePreview } = client.auth;
+ const result = usePreview();
+
+ if (client.useIsLoading() || !result) {
+ return
loading...
;
+ }
+
+ if (result.type === 'page') {
+ if (!result.page) {
+ return <>Not Found>;
+ }
+
+ return ;
+ }
+
+ if (!result.post) {
+ return <>Not Found>;
+ }
+
+ return ;
+}
+```
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePreviewNode.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePreviewNode.mdx
new file mode 100644
index 000000000..20703f1d2
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/hooks/usePreviewNode.mdx
@@ -0,0 +1,93 @@
+---
+slug: /next/reference/hooks/usePreviewNode
+title: usePreviewNode Hook
+description: The usePreviewNode hook provides a way to get post preview data from WordPress for any post type
+---
+
+import BaseUrlNotice from '@site/src/mdx/base-url-notice.mdx';
+
+
+
+The `usePreviewNode` hook provides an abstraction around getting preview data for any post type. When calling the `usePreviewNode` hook on an appropriate preview page, the hook will ensure authorization, make a request to determine the post type, then make a subsequent request to retrieve the proper preview data. When using 0.7.2 of FaustWP or later, preview data will be retrieved with one request.
+
+The `usePreviewNode` hook will return an object with the following properties:
+
+- `typeName`: The GraphQL type name of the preview node (e.g. `Post`, `Page`). Notice the GraphQL types are capitalized.
+- `node`: The preview node in question. Faust.js is unable to determine the proper GraphQL type for this node, as the types live in your `schema.generated.ts` file. As a result, casting this node to the proper type is recommended.
+
+The following example shows how to use the `usePreviewNode` hook to render the default `post`/`page` post types:
+
+```tsx title="src/pages/preview.tsx"
+import { PageComponent } from 'pages/[...pageUri]';
+import { PostComponent } from 'pages/posts/[postSlug]';
+import { client, Page, Post } from 'client';
+
+export default function Preview() {
+ const isLoading = client.useIsLoading();
+ const { typeName, node } = client.auth.usePreviewNode();
+
+ if (isLoading || node === undefined) {
+ return
loading...
;
+ }
+
+ if (node === null) {
+ return
Post not found
;
+ }
+
+ switch (typeName) {
+ case 'Page': {
+ return ;
+ }
+ case 'Post': {
+ return ;
+ }
+ default: {
+ throw new Error(`Unspecified post type preview: ${typeName}`);
+ }
+ }
+}
+```
+
+Additionally, the `usePreviewNode` hook can be used to get preview data for any custom post type. Say we have a custom post type called `Event`:
+
+```tsx title="src/pages/preview.tsx" {24-32}
+import { PageComponent } from 'pages/[...pageUri]';
+import { PostComponent } from 'pages/posts/[postSlug]';
+import { client, Page, Post, Event } from 'client';
+
+export default function Preview() {
+ const isLoading = client.useIsLoading();
+ const { typeName, node } = client.auth.usePreviewNode();
+
+ if (isLoading || node === undefined) {
+ return
+ >
+ );
+ }
+ // Add additional custom post types here as needed
+ default: {
+ throw new Error(`Unspecified post type preview: ${typeName}`);
+ }
+ }
+}
+```
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/is404.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/is404.mdx
new file mode 100644
index 000000000..9f487de49
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/is404.mdx
@@ -0,0 +1,29 @@
+---
+slug: /next/reference/is404
+title: is404()
+description: The is404() function helps you determine when Next.js should return a 404 response.
+---
+
+## Description
+
+Determines when a dynamic post, page, or category route is requested for which no corresponding WordPress post, page, or category exists.
+
+See [Expected URL Params](./expected-url-params) for more on how dynamic routes are mapped to a specific page, post, or category in WordPress.
+
+:::note
+This function is only useful on routes that include one of the [expected URL params](./expected-url-params).
+If none of the expected URL params are present in the provided context, `is404()` will always return `true`.
+:::
+
+## Parameters
+
+- `Context`: Either the `GetStaticPropsContext` or the `GetServerSidePropsContext` from Next.js, depending on which function you are resolving props from.
+- `Is404Config`: An object with a `client` property containing [your GQty client](../guides/fetching-data#setting-up-your-client).
+
+## Return
+
+Returns `true` when the requested WordPress post, page, or category does not exist.
+
+## Usage
+
+View the guide on [Handling 404s with is404](../guides/handle-404s) for a detailed description and example code.
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/with-faust.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/with-faust.mdx
new file mode 100644
index 000000000..277343081
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/next/reference/with-faust.mdx
@@ -0,0 +1,77 @@
+---
+slug: /next/reference/with-faust
+title: Using withFaust
+description: withFaust is a helper function that merges your next.config.js with Faust related configuration.
+---
+
+The `withFaust` helper function is used to merge your `next.config.js` config with necessary Faust.js configuration.
+
+## Usage
+
+To use `withFaust`, create a `next.config.js` file in your project root with the following content:
+
+```js title="next.config.js"
+const { withFaust } = require('@faustjs/next');
+
+/**
+ * @type {import('next').NextConfig}
+ **/
+module.exports = withFaust();
+```
+
+If you already have a `next.config.js` file, you can use the first argument of `withFaust` to merge in your existing config.
+
+Take the following example, where we have a custom `next.config.js` handling a rewrite:
+
+```js title="next.config.js"
+const { withFaust } = require('@faustjs/next');
+
+const nextConfig = {
+ async rewrites() {
+ return [
+ {
+ source: '/about',
+ destination: '/',
+ },
+ ];
+ },
+};
+
+/**
+ * @type {import('next').NextConfig}
+ **/
+module.exports = withFaust(nextConfig);
+```
+
+## Additional Options
+
+`withFaust` also accepts a second argument for `withFaustConfig`. `withFaustConfig` represented as a TypeScript interface looks like:
+
+```ts
+interface WithFaustConfig {
+ // Where preview links will be redirected to.
+ previewDestination?: string;
+}
+```
+
+For example, if you wanted to change the default preview destination from `/preview` to `/previews`, you can do so by passing the following to `withFaust`:
+
+```js title="next.config.js"
+const { withFaust } = require('@faustjs/next');
+
+const nextConfig = {};
+
+const withFaustConfig = {
+ previewDestination: '/previews',
+};
+
+/**
+ * @type {import('next').NextConfig}
+ **/
+module.exports = withFaust(nextConfig, withFaustConfig);
+```
+
+:::note
+If you change the `previewDestination` path, do not forget to create an associated `page` with the same name for that destination.
+Otherwise the framework will redirect to a non existing page and it will show a `404` response.
+:::
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/release-notes.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/release-notes.mdx
new file mode 100644
index 000000000..1d6b423af
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/release-notes.mdx
@@ -0,0 +1,224 @@
+---
+slug: release-notes
+title: Faust.js 0.9.0 - 0.12.0
+description: The former location of Faust.js release notes
+---
+
+## Changelogs
+
+For package versions greater than 0.12.0, visit the individual changelog pages:
+
+- [@faustjs/core](./changelog/core)
+- [@faustjs/next](./changelog/next)
+- [@faustjs/react](./changelog/react)
+
+## Release Notes
+
+### Faust.js 0.12.0 - Oct 5, 2021
+
+For a full list of features/changes, visit the releases on GitHub:
+
+- [@faustjs/core@0.12.0](https://github.com/wpengine/faustjs/releases/tag/%40faustjs%2Fcore%400.12.0)
+- [@faustjs/next@0.12.0](https://github.com/wpengine/faustjs/releases/tag/%40faustjs%2Fnext%400.12.0)
+- [@faustjs/react@0.12.0](https://github.com/wpengine/faustjs/releases/tag/%40faustjs%2Freact%400.12.0)
+
+#### Breaking Changes
+
+First, you will need to create a new file at your [Next.js pages directory](https://nextjs.org/docs/basic-features/pages), `src/pages/api/faust/[[...route]].ts` with the following content:
+
+```ts title="src/pages/api/faust/[[...route]].ts"
+import 'faust.config';
+import { apiRouter } from '@faustjs/core/api';
+
+export default apiRouter;
+```
+
+Then, you will want to delete the `src/pages/api/auth/wpe-headless.ts` file if it exists.
+
+Finally, replace your current `src/faust.config.js` file with the following:
+
+```js title="src/faust.config.js" {1,12}
+import { config as coreConfig } from '@faustjs/core';
+
+if (!process.env.NEXT_PUBLIC_WORDPRESS_URL) {
+ console.error(
+ 'You must provide a NEXT_PUBLIC_WORDPRESS_URL environment variable, did you forget to load your .env.local file?',
+ );
+}
+
+/**
+ * @type {import("@faustjs/core").Config}
+ */
+export default coreConfig({
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ apiClientSecret: process.env.WP_HEADLESS_SECRET,
+});
+```
+
+**Notice**: `headlessConfig` has been renamed to just `config`
+
+[Take a look at the Getting Started example for a closer look at these breaking changes.](https://github.com/wpengine/faustjs/tree/main/examples/next/getting-started)
+
+### Faust.js 0.11.0 - Sept 23, 2021
+
+#### Features
+
+- `GQty` has been updated to `2.0.1` to bring support to [`Unions` and `Interfaces` with the `$on` property](https://github.com/gqty-dev/gqty/releases). ([#491](https://github.com/wpengine/faustjs/pull/491))
+
+#### Breaking Changes
+
+Please update the `@gqty/cli` package in your `package.json` to `2.0.1` and run `npm run generate`.
+
+### Faust.js 0.10.2 - Sept 13, 2021
+
+#### Fixes
+
+- Fixed the `WithRevisions` interface to use proper `Maybe<>` type checks ([#452](https://github.com/wpengine/faustjs/pull/452/files))
+
+### Faust.js 0.10.1 - Sept 10, 2021
+
+#### Fixes
+
+- Fixed an issue where the `ObjectTypeNames` client interface was incompatible with `@faustjs/core` ([#445](https://github.com/wpengine/faustjs/pull/445))
+
+#### Chore & Maintenance
+
+- Updated `@faustjs` package dependencies to their latest versions ([#440](https://github.com/wpengine/faustjs/pull/440))
+
+### Faust.js 0.10.0 - Sept 08, 2021
+
+Release `0.10.0` of the NPM packages include **BREAKING CHANGES**. Existing users of Faust.js will need to make the following changes:
+
+#### Step 1 - Update the WPE Headless Plugin
+
+Ensure that you are on version `0.6.0` or later of the WPE Headless Plugin.
+
+#### Step 2 - Update `preview.tsx` file
+
+If you started from the `next/getting-started` example, replace the contents of `src/pages/preview.tsx` with the following:
+
+```tsx
+import { PageComponent } from './[...pageUri]';
+import { PostComponent } from './posts/[postSlug]';
+import { client } from 'client';
+
+export default function Preview() {
+ const { usePreview } = client.auth;
+ const result = usePreview();
+
+ if (client.useIsLoading() || !result) {
+ return
loading...
;
+ }
+
+ if (result.type === 'page') {
+ if (!result.page) {
+ return <>Not Found>;
+ }
+
+ return ;
+ }
+
+ if (!result.post) {
+ return <>Not Found>;
+ }
+
+ return ;
+}
+```
+
+#### Step 3 - Create `next.config.js` file
+
+In the root of your project, alongside `package.json`, create a `next.config.js` file with the following contents:
+
+```js
+const { withFaust } = require('@faustjs/next');
+
+/**
+ * @type {import('next').NextConfig}
+ **/
+module.exports = withFaust();
+```
+
+If you already have an existing `next.config.js` file, you can place it within the first argument of the `withFaust` function, like so:
+
+```js
+const { withFaust } = require('@faustjs/next');
+
+/**
+ * @type {import('next').NextConfig}
+ **/
+module.exports = withFaust({
+ // Your Next.js config here
+});
+```
+
+#### Step 4 - Update `gqty.config.js` file
+
+In the root of your project, alongside `package.json`, replace the `gqty.config.js` file with the following:
+
+```js
+require('dotenv-flow').config();
+
+/**
+ * @type {import("@gqty/cli").GQtyConfig}
+ */
+const config = {
+ react: false,
+ scalarTypes: { DateTime: 'string' },
+ introspection: {
+ endpoint: `${process.env.NEXT_PUBLIC_WORDPRESS_URL}/graphql`,
+ headers: {},
+ },
+ destination: './src/client/index.ts',
+ subscriptions: false,
+ javascriptOutput: false,
+};
+
+console.log(`Using "${config.introspection.endpoint}" to generate schema...`);
+
+module.exports = config;
+```
+
+### Faust.js 0.9.0 - Aug 27, 2021
+
+Release `0.9.0` of the NPM packages include **BREAKING CHANGES**. Existing users of Faust.js will need to update their [`faust.config.js`](https://github.com/wpengine/faustjs/blob/main/examples/next/getting-started/src/faust.config.js) file to use ESM syntax, opposed to CJS syntax.
+
+For example, users will need to replace their current `faust.config.js` file:
+
+```tsx
+const { headlessConfig } = require('@faustjs/core');
+
+if (!process.env.NEXT_PUBLIC_WORDPRESS_URL) {
+ console.error(
+ 'You must provide a NEXT_PUBLIC_WORDPRESS_URL environment variable, did you forget to load your .env file?',
+ );
+}
+
+/**
+ * @type {import("@faustjs/core").HeadlessConfig}
+ */
+module.exports = headlessConfig({
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ apiClientSecret: process.env.WP_HEADLESS_SECRET,
+});
+```
+
+With the following code:
+
+```tsx
+import { headlessConfig } from '@faustjs/core';
+
+if (!process.env.NEXT_PUBLIC_WORDPRESS_URL) {
+ console.error(
+ 'You must provide a NEXT_PUBLIC_WORDPRESS_URL environment variable, did you forget to load your .env file?',
+ );
+}
+
+/**
+ * @type {import("@faustjs/core").HeadlessConfig}
+ */
+export default headlessConfig({
+ wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL,
+ apiClientSecret: process.env.WP_HEADLESS_SECRET,
+});
+```
diff --git a/internal/legacy.faustjs.org/versioned_docs/version-development/support-channels.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/support-channels.mdx
new file mode 100644
index 000000000..bf8af1b00
--- /dev/null
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/support-channels.mdx
@@ -0,0 +1,26 @@
+---
+slug: support-channels
+title: Support Channels
+description: Discover the Faust Support Channels
+---
+
+## Need Faust support? Look no further!
+
+Use one of the channels below to contact us for support.
+
+
+ GitHub
+ - Faust GitHub documentation and codebase.
+
+ Discord
+ - Interactive chat support on Discord.
+
+---
+
+Premium Users get the above plus chat support, a Solutions Architect, and a Technical Account Manager.
diff --git a/internal/faustjs.org/docs/tutorial/basic-headless-site.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/basic-headless-site.mdx
similarity index 100%
rename from internal/faustjs.org/docs/tutorial/basic-headless-site.mdx
rename to internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/basic-headless-site.mdx
diff --git a/internal/faustjs.org/docs/tutorial/dev-env-setup.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/dev-env-setup.mdx
similarity index 100%
rename from internal/faustjs.org/docs/tutorial/dev-env-setup.mdx
rename to internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/dev-env-setup.mdx
diff --git a/internal/faustjs.org/docs/tutorial/first-react-component.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/first-react-component.mdx
similarity index 100%
rename from internal/faustjs.org/docs/tutorial/first-react-component.mdx
rename to internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/first-react-component.mdx
diff --git a/internal/faustjs.org/docs/tutorial/nextjs-intro.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/nextjs-intro.mdx
similarity index 100%
rename from internal/faustjs.org/docs/tutorial/nextjs-intro.mdx
rename to internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/nextjs-intro.mdx
diff --git a/internal/faustjs.org/docs/tutorial/querying-data.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/querying-data.mdx
similarity index 100%
rename from internal/faustjs.org/docs/tutorial/querying-data.mdx
rename to internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/querying-data.mdx
diff --git a/internal/faustjs.org/docs/tutorial/setup-faustjs.mdx b/internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/setup-faustjs.mdx
similarity index 98%
rename from internal/faustjs.org/docs/tutorial/setup-faustjs.mdx
rename to internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/setup-faustjs.mdx
index 82053641e..f5201d94d 100644
--- a/internal/faustjs.org/docs/tutorial/setup-faustjs.mdx
+++ b/internal/legacy.faustjs.org/versioned_docs/version-development/tutorial/setup-faustjs.mdx
@@ -89,11 +89,11 @@ You'll also need a `.env.local` file to hold your environment variables:
# Your WordPress site URL
NEXT_PUBLIC_WORDPRESS_URL=http://your-wordpress-site.com
-# Plugin secret found in WordPress Settings->Faust
+# Plugin secret found in WordPress Settings->Headless
FAUSTWP_SECRET_KEY=YOUR_PLUGIN_SECRET
```
-Replace the `NEXT_PUBLIC_WORDPRESS_URL` value with the URL of your WordPress site. Additionally, grab the Headless Secret from WordPress Settings -> Faust and replace it with the `FAUSTWP_SECRET_KEY` value.
+Replace the `NEXT_PUBLIC_WORDPRESS_URL` value with the URL of your WordPress site. Additionally, grab the Headless Secret from WordPress Settings -> Headless and replace it with the `FAUSTWP_SECRET_KEY` value.