What is Faust.js?: The Headless WordPress Framework

Jeff Everhart Avatar

·

Building a headless WordPress site can be a daunting task. You know you want to use a modern JavaScript framework (React, Vue, etc) that allows you and your team to leverage component-based architecture to iterate quickly. But starting from the ground floor means you have to implement mechanisms for previews, authentication, fetching data, and more from scratch. These tasks are not easy: supporting authentication alone means you must set up validate and invalidate sessions, generate access tokens, and provide a means of logging in/out. The list goes on.

Re-introducing Faust.js

Faust.js is an open-source framework from WP Engine, built on top of Next.js and React. It initially launched in the fall of 2021, but after a year of iterating with developers, Faust.js has been re-imagined to be more extensible and developer-friendly.

Faust.js aims to solve the problems mentioned above by providing easy-to-use helper functions and APIs that save you time when scaffolding a headless WordPress project, so you can focus on shipping sites. Let’s take a closer look at some of the benefits. 👀

Benefits

Streamlined Data Fetching

The initial version of Faust.js was built on a GraphQL library called GQty that provided some interesting features for developers. However, as Faust.js gained more usage in real-world scenarios, the team found that GQty was difficult for developers to debug beyond very straightforward use cases. Along with that, its method of constructing queries conflicted with the mental model many developers had of first using the GraphiQL IDE to compose and test queries.

To better align developer expectations with the concepts in Faust, GQty has been replaced with Apollo along with some syntactic sugar to make organizing page component queries easier.

Faust.js augments these data-fetching helper features with additional helpers that let us build on top of Next.js using functions like getNextStaticProps.

All of these changes to Faust’s data-fetching primitives have received a lot of support from the developer community, but if you’re fond of traditional WordPress theming practices, the new version of the framework includes its own take on the WordPress template hierarchy.

Template Hierarchy

It might seem surprising to see a headless WordPress framework reach for patterns in the thing it’s supposed to be decoupled from, but there are a lot of benefits in this mental model that we can bring into headless sites.

Since most JavaScript frameworks implement routing in a similar fashion, developers spend a lot of time wiring up individual routes to queries for specific content, like pages/blog/[slug].js and pages/blog/categories/[slug].js, but still struggling to manage more complex routes, like nested parent/child pages for example.

But WordPress as a CMS actually handles a lot of that routing for us as we create content using a WPGraphQL field called the URI. Now, instead of implementing bespoke routing in our headless site, what if we could look at a particular request, of any path depth, see if WordPress manages that URI, and use that info to decide what type of template should render the content?

That’s what Faust.js implements in its own take on the WordPress template hierarchy. The template hierarchy, which is used in traditional WordPress theming, takes a URL that a user might visit, and figures out the most appropriate template to render that content using the hierarchy outlined below. In the template hierarchy, specificity matters: for example, both a Post and a SpaceLaunch custom post type can resolve to single.js, but if we want a template specific to only space launch posts, we create a single-spaceLaunch.js file that will be applied to content that matches that type.

But how does Faust implement this using Next.js? If we look at the screenshot of part of the Faust.js directory structure, we can see that we have a unique route in our pages directory: [...wordpressNode].js.

This is called a catch-all route in Next.js, and it’s used to allow us to handle any and all of the possible URIs that WordPress creates for our content. Since both regular and dynamic routes are evaluated before catch-all routes, it’s easy to override this pattern by specifying another route that will match your URI patterns.

Once a URI makes it to the [...wordpressNode].js route, Faust.js resolves some data to determine the most appropriate template to render. This is done using a very lightweight GraphQL query called the seed query:

From there, Faust.js resolves to a component contained in the wp-templates folder to fetch the additional data needed to render the template. The naming convention of the JS components in the wp-templates folder mimics the logic of the WordPress template hierarchy.

For many developers, this new feature will be an amazing boost to their workflows. Personally, I like how this mental model builds on the knowledge I already have about WordPress while leaning into features of the CMS that eliminate some of the manual plumbing required to bootstrap a headless site.

But we get that not all headless developers may feel similar nostalgia, which is why this feature is easy to override and the data-fetching niceties available in the wp-templates directory can be used with regular page components as well.

Plugin Architecture

One of the best things about WordPress is the plugin ecosystem, and one of the loudest pieces of feedback we heard about Faust.js was something like, it’s good but we need [insert specific thing here] because […organizational reasons]. Obviously, there are only so many use cases a framework can natively support, but the development team decided to make Faust.js easier to extend with its own plugin system.

To write a custom Faust plugin, you create a new class like MyPlugin below that has an apply method, then use addFilter to tap into Faust’s options and modify them on the fly.

From there, we tell our Faust.js app to use our plugin by providing it to the configuration:

To look at an example of this in the wild, WPGraphQL’s Jason Bahl created a Faust.js plugin to modify Apollo’s default behavior to use persisted queries.

Authentication

Faust.js offers two strategies for authentication: redirect-based authentication and local-based authentication.

Redirect-based authentication uses your WordPress backend for logging in and redirects the user back to your headless frontend once successfully authenticated. This is a simple authentication strategy that requires no configuration and works best when you need authentication for admin-related tasks, for example, previews.

Local-based authentication works by facilitating login/registration on the headless WordPress frontend. Faust.js provides React hooks like useLogin and useLogout to create a session. Local-based authentication is best used when you want a “white label” authentication experience.

Previews

Faust.js also offers support for previews out of the box! By simply setting up your preview page in your Next.js pages directory, you can view preview data from WordPress on your headless site. This is incredibly useful for publishers, as they can visualize how content looks on the headless site without interacting with developers.

Not only does Faust.js handle all of the authentication glue between Next.js and WordPress, but it also rewrites links inside the CMS so your content publishers won’t have to think about anything:

All of the existing preview links inside of WP admin work as you’d expect them to.

Sitemaps

In a headless architecture, you typically pull data from a CMS, in addition to file-based page routing to create a fully headless experience. The downside here is managing a sitemap that contains both your file-based page routes in addition to content in your CMS. Faust.js offers some helper functions that do this for you.

Faust.js does this by proxying the sitemap index from your WordPress backend, replacing the WordPress URLs with your frontend URL. Additionally, you can remove certain types of content (say your headless frontend doesn’t have a user archive for example), and specify pages you have created through file-based routing. By proxying the sitemap index from WordPress, you could use the default WordPress sitemap, or a custom solution like Yoast SEO.

This tutorial on implementing sitemaps in Faust.js walks you through how to get this working quickly.

Accompanying WP Plugin

In addition to the Faust.js framework, we also built FaustWP, which helps facilitate other headless capabilities from the WordPress side. The FaustWP plugin is required for authentication and previews, but also provides options for disabling the “theme” admin pages, route redirects from your WordPress backend to your headless frontend, and more!

FaustWP is available for download on the WordPress.org plugin repo. Check it out here!

How do I get started?

The best place to get started with Faust.js is to follow the Getting Started guide in the Faust docs. We also would love to hear your feedback, thoughts, and projects you are doing in Headless WordPress so hit us up in our Discord!