diff --git a/src/pages/docs/how-to/basic-setup/index.mdx b/src/pages/docs/how-to/basic-setup/index.mdx index da5205d1..2bf913bb 100644 --- a/src/pages/docs/how-to/basic-setup/index.mdx +++ b/src/pages/docs/how-to/basic-setup/index.mdx @@ -71,24 +71,27 @@ export default setConfig({ ### E. Create Faust API route -Create an API route for Faust.js to use. You can do this by creating a file in `pages/api/faust/[[...route]].js`, with the following code: +Create an API route for Faust.js to use. You can do this by creating a file in `src/pages/api/faust/[[...route]].js`, with the following code: -```js title="pages/api/faust/[[...route]].js" -import "../../../faust.config"; +```js title="src/pages/api/faust/[[...route]].js" +import "../../faust.config"; // Adjust path as necessary export { apiRouter as default } from "@faustwp/core"; ``` +> [!IMPORTANT] Important +> If you're not using a `src` folder in your project, you can omit "src/" from the file path above. And the same applies for other file paths mentioned throughout this doc. + ### F. Update `_app.js` file -Once the API router is set up, head to `pages/_app.js` and add this code to the file: +Once the API router is set up, head to `src/pages/_app.js`. Add the `import` statements, wrap your app in the `FaustProvider`, and pass `key={router.asPath}` to `Component`, as shown below. -```js title="pages/_app.js" +```js title="src/pages/_app.js" import { useRouter } from "next/router"; import { FaustProvider } from "@faustwp/core"; import "../faust.config"; -export default function MyApp({ Component, pageProps }) { +export default function App({ Component, pageProps }) { const router = useRouter(); return ( @@ -105,6 +108,8 @@ export default function MyApp({ Component, pageProps }) { In order for Faust.js to run the GraphQL queries it needs to determine the correct template to use, it needs to have a list of all the types available in the GraphQL schema. We'll generate this list of types now. +In your WordPress admin sidebar, go to `GraphQL` > `Settings`. Check the `Enable Public Introspection` box if it's not checked already and save your changes. Enabling introspection is required for the `npm run generate` command below to work. + Add the following generate script to your Next.js project's `package.json` file, in the scripts block: ```json title="package.json" @@ -124,7 +129,7 @@ Run `npm run generate` on the command line. Confirm that a possibleTypes.json ha ### B. Add a template -Create a new `wp-templates` folder in the root of your project. This is where your template files will be stored. We'll start by adding a template for rendering single blog posts. +Create a new `src/wp-templates` folder (or add the `/wp-templates` folder in the root project folder if you don't use a `/src` folder). This is where your template files will be stored. We'll start by adding a template for rendering single blog posts. Inside the `wp-templates` folder, create a `single.js` file that contains the following code. @@ -167,10 +172,10 @@ In the `SingleTemplate` component, we receive the props, destructure the `title` Finally, we have to make Faust.js aware that this template exists. To do that, create an `index.js` file inside the `wp-templates` folder with this code inside: ```js title="wp-templates/index.js" -import single from "./single"; +import SingleTemplate from "./single"; const templates = { - single, + single: SingleTemplate, }; export default templates; @@ -180,7 +185,7 @@ export default templates; Create a `[...wordpressNode].js` file inside your `pages` folder. Add the following code to it. -```js title="pages/[...wordpressNode].js" +```js title="src/pages/[...wordpressNode].js" import { getWordPressProps, WordPressTemplate } from "@faustwp/core"; export default function Page(props) { @@ -201,7 +206,7 @@ export async function getStaticPaths() { This catch-all route tells Next.js to use the templates to render pages. -Note that it is still possible to override this with hardcoded pages. For example, if you have a page in your WordPress site with a URI of `/about`, Faust.js will render that page using the relevant template in your project's `wp-templates` folder. However, if you add a `pages/about.js` file to your project, Next.js will render the `/about` path in your app using that file instead. +Note that it is still possible to override this with hardcoded pages. For example, if you have a page in your WordPress site with a URI of `/about`, Faust.js will render that page using the relevant template in your project's `wp-templates` folder. However, if you add a `src/pages/about.js` file to your project, Next.js will render the `/about` path in your app using that file instead. ### D. Test your template diff --git a/src/pages/docs/nav.json b/src/pages/docs/nav.json index dda5b06a..3141c1f2 100644 --- a/src/pages/docs/nav.json +++ b/src/pages/docs/nav.json @@ -1,8 +1,12 @@ [ { - "title": "Getting Started", + "title": "Introduction", "route": "/docs/" }, + { + "title": "Learn Faust.js", + "route": "/docs/tutorial/learn-faust/" + }, { "title": "How-To Guides", "route": "/docs/how-to/", diff --git a/src/pages/docs/tutorial/learn-faust/images/faust-front-end-site-url.png b/src/pages/docs/tutorial/learn-faust/images/faust-front-end-site-url.png new file mode 100644 index 00000000..3ee5931b Binary files /dev/null and b/src/pages/docs/tutorial/learn-faust/images/faust-front-end-site-url.png differ diff --git a/src/pages/docs/tutorial/learn-faust/images/faust-secret-key-setting.png b/src/pages/docs/tutorial/learn-faust/images/faust-secret-key-setting.png new file mode 100644 index 00000000..81841ebd Binary files /dev/null and b/src/pages/docs/tutorial/learn-faust/images/faust-secret-key-setting.png differ diff --git a/src/pages/docs/tutorial/learn-faust/images/install-content-blocks-plugin.png b/src/pages/docs/tutorial/learn-faust/images/install-content-blocks-plugin.png new file mode 100644 index 00000000..36c74cd2 Binary files /dev/null and b/src/pages/docs/tutorial/learn-faust/images/install-content-blocks-plugin.png differ diff --git a/src/pages/docs/tutorial/learn-faust/images/permalink-settings.png b/src/pages/docs/tutorial/learn-faust/images/permalink-settings.png new file mode 100644 index 00000000..f016d800 Binary files /dev/null and b/src/pages/docs/tutorial/learn-faust/images/permalink-settings.png differ diff --git a/src/pages/docs/tutorial/learn-faust/images/preview-link.png b/src/pages/docs/tutorial/learn-faust/images/preview-link.png new file mode 100644 index 00000000..57dbeefe Binary files /dev/null and b/src/pages/docs/tutorial/learn-faust/images/preview-link.png differ diff --git a/src/pages/docs/tutorial/learn-faust/images/template-hierarchy.png b/src/pages/docs/tutorial/learn-faust/images/template-hierarchy.png new file mode 100644 index 00000000..2092b74a Binary files /dev/null and b/src/pages/docs/tutorial/learn-faust/images/template-hierarchy.png differ diff --git a/src/pages/docs/tutorial/learn-faust/images/wpgraphql-introspection.png b/src/pages/docs/tutorial/learn-faust/images/wpgraphql-introspection.png new file mode 100644 index 00000000..4e54b233 Binary files /dev/null and b/src/pages/docs/tutorial/learn-faust/images/wpgraphql-introspection.png differ diff --git a/src/pages/docs/tutorial/learn-faust/index.mdx b/src/pages/docs/tutorial/learn-faust/index.mdx new file mode 100644 index 00000000..b2b9c48c --- /dev/null +++ b/src/pages/docs/tutorial/learn-faust/index.mdx @@ -0,0 +1,427 @@ +export const metadata = { + title: "Learn Faust.js", + description: "Tutorial to learn about the core features of Faust.js.", +}; + +This tutorial introduces you to the core features of Faust.js. You'll begin with a pre-configured Next.js project and learn how to implement these features yourself: + +- [Template Hierarchy](#template-hierarchy) +- [Authentication & Post previews](#authentication--post-previews) +- [Blocks](#blocks) + +By the end of this tutorial, you'll be able to configure your Next.js app and apply your newfound knowledge to integrate Faust.js features into your own projects. + +## Prerequisites + +In order to complete this tutorial, you should: + +- Be familiar with HTML, CSS, JavaScript, [WordPress](https://wordpress.org/), [React](https://react.dev/), and [Next.js](https://nextjs.org/) +- Be familiar with [cloning a repository from GitHub](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository) +- Be comfortable running commands on the [command line](https://en.wikipedia.org/wiki/Command-line_interface) +- Have [Node.js and NPM](https://nodejs.org/) installed on your computer + +You should also not have any other projects running on port `3000` or `8881`, since the links in this tutorial point to pages on those ports. + +## Set up + +The steps below will get you up-and-running with the pre-built app you will use for the tutorial. + +### 1. Install the Next.js app + +- Run the command below to set up the example Next.js app we will use for the tutorial. + +```sh +npx create-next-app \ + -e https://github.com/wpengine/faustjs/tree/canary \ + --example-path examples/next/tutorial \ + --use-npm +``` + +- When asked for the name of your project, enter `faust-tutorial`. +- When asked if it's okay to install the `create-next-app` package, answer `y` to confirm. + +### 2. Set up headless WordPress backend + +Initial set up steps: + +- `cd` into the `/faust-tutorial` project folder. +- Run `npm run wp-dev`. This command uses the [`wp-now`](https://www.npmjs.com/package/@wp-now/wp-now) NPM package and the included `faust-tutorial-blueprint.json` blueprint file to set up a local WordPress environment. +- When asked if it's okay to install the `@wp-now/wp-now` package, answer `y` to confirm. + +After a moment, you should have a WordPress site up-and-running. + +By navigating to http://localhost:8881/wp-admin/plugins.php, You can see that the required [FaustWP](https://wordpress.org/plugins/faustwp/) and [WPGraphQL](https://wordpress.org/plugins/wp-graphql/) plugins have already been installed for you. + +Next, we'll just configure a few last things in WordPress. + +- Activate the FaustWP and WPGraphQL plugins. +- In the WordPress admin sidebar, go to `Settings` > `Permalinks`. Check the radio button for `Custom Structure`, enter `/blog/%postname%/` in the text field, and save your changes. With this setting, our blog posts will have URLs such as http://localhost:3000/blog/hello-world/. +  +- Head to `GraphQL` > `Settings`. Check the box for `Enable Public Introspection` and click the save button. This allows Faust.js to run an "introspection query" on your WordPress backend to get a list of the available GraphQL types and fields. +  +- Finally, head to to `Settings` > `Faust` to access the Faust.js settings page. Set the `Front-end site URL` setting to `http://localhost:3000` and save your changes. This lets Faust know the URL for your decoupled frontend app, which we'll set up next. +  + +### 3. Set up Faust.js frontend + +Follow these steps to set up your Faust.js frontend: + +- Open a separate terminal window from the one running your WordPress backend to run the commands that follow. +- Run `npm install` to install the Next.js app's NPM packages. +- In a separate terminal window from the one running your WordPress backend, run `npm install` to install the Next.js app's NPM packages. +- Find the `.env.local.example` file and rename it to `.env.local`. This is where we'll store our environment variables. +- Once again, in the WordPress admin sidebar, go to `Settings` > `Faust` to access the Faust.js settings page. Copy the value you see for the `Secret Key` and paste that in as the value of `FAUST_SECRET_KEY` in your `.env.local` file and save it. Faust.js uses this secret key to send authenticated request to WordPress. +  +  + +  + + Your `.env.local` file should now look like this, where `ABC123` is the secret key you copied from the Faust settings page: + +```env title=".env.local" +# Your WordPress site URL +NEXT_PUBLIC_WORDPRESS_URL=http://localhost:8881 + +# Plugin secret found in WordPress Settings->Faust +FAUST_SECRET_KEY=ABC123 +``` + +- Run `npm run generate` on the command line. Confirm that a `possibleTypes.json` has been generated in the `/faust-tutorial` project folder. +- Run `npm run dev` to start up your frontend app. You should now be able to visit http://localhost:3000 and see your app running. + +## Template Hierarchy + +WordPress is well-known for its [template hierarchy](https://developer.wordpress.org/themes/basics/template-hierarchy/) feature. It enables WordPress to dynamically select the most appropriate template for rendering a page based on its content type. Faust.js allows you to leverage the template hierarchy in your frontend app. + +The following image is helpful for visualizing how WordPress' template hierarchy feature works. The logic starts on the left side of this flowchart and progresses to the right. A series of conditionals are run to determine the appropriate page template to use. Just disregard the ".php" file extensions you see, since templates in our headless WP project will be ".js" files instead. + + + +Open the project in a code editor and find the `wp-templates` folder. This is the folder where you can place page template files you'd like to use. We've provided a `single.js` file for you. As you can see in the template hierarchy flowchart, the "single" page template is used to render single blog post pages. You can see this page template in action by viewing http://localhost:3000/blog/hello-world/. That page should display the contents for the "Hello world" blog post. + +#### Add a template + +Next, you'll learn how to create your own template. Let's add one for rendering single pages (the "Page" post type in WordPress). + +By referencing the template hierarchy image above, you can see that we can target pages by adding a template named `page`. Inside of the `wp-templates` folder, add a new `page.js` file for our new template. + +Copy the `gql` import and the `SingleTemplate` component from `wp-templates/single.js` and paste them into `wp-templates/page.js`. Rename the `SingleTemplate` component to `PageTemplate`. Our new page template should now look like this: + +```jsx title="wp-templates/page.js" +import { gql } from "@apollo/client"; + +export default function PageTemplate(props) { + const { title, content } = props.data.page; + + return ( + <> +
Loading...
; +} +``` + +This tells React to render a "Loading" message if the component is still loading. This momentary data fetching delay occurs because draft blog posts are client-side rendered (CSR) rather than server-side rendered (SSR). + +Update the `Component.variables` function to return a new `asPreview` variable that is set to the value of `ctx?.asPreview`: + +```jsx title="src/wp-templates/single.js" +SingleTemplate.variables = ({ databaseId }, ctx) => { + return { + databaseId, + asPreview: ctx?.asPreview, // [!code ++] + }; +}; +``` + +Inside of the `GetPost` GraphQL query, accept a new `$asPreview: Boolean = false` argument. Pass that value into the `post` query by adding `asPreview: $asPreview`, as shown below. + +```jsx title="src/wp-templates/single.js" +SingleTemplate.query = gql` + query GetPost($uri: ID!, $asPreview: Boolean = false) { + post(id: $uri, idType: URI, asPreview: $asPreview) { + title + content + } + } +`; +``` + +Your `single` template file should now look like this: + +```jsx title="src/wp-templates/single.js" +import { gql } from "@apollo/client"; + +export default function SingleTemplate(props) { + const { title, content } = props.data.post; + + if (props.loading) { + returnLoading...
; + } + + return ( + <> +Loading...
; + } + + return ( + <> ++ Welcome to WordPress. This is your first post. Edit or delete it, then start + writing! +
+