{"id":31322,"date":"2023-11-22T09:19:11","date_gmt":"2023-11-22T15:19:11","guid":{"rendered":"https:\/\/wpengine.com\/builders\/?p=31322"},"modified":"2024-11-14T12:27:49","modified_gmt":"2024-11-14T18:27:49","slug":"app-router-and-auth-support-in-faust-js-with-next-js-14","status":"publish","type":"post","link":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/","title":{"rendered":"App Router and Auth Support in Faust.js with Next.js 14"},"content":{"rendered":"\n<p>Next.js 14 introduces a new paradigm in the project structure and the development of sites and applications. With the new version of Next.js being adapted, Faust.js also must coincide to support this.<\/p>\n\n\n\n<p>In this article, I will give you an overview of the support of Next 14 with Faust.js including:<\/p>\n\n\n\n<div class=\"wp-block-group has-polar-background-color has-background is-layout-flow wp-container-core-group-is-layout-7a03825d wp-block-group-is-layout-flow\" style=\"padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--40);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--40)\">\n<p class=\"has-large-font-size\"><strong>Table of Contents<\/strong><\/p>\n\n\n\n<ul id=\"Prerequisites\" class=\"wp-block-list\">\n<li><a href=\"#stable-server-action\">Stable Server Actions<\/a><\/li>\n\n\n\n<li><a href=\"#wpgraphql-mutations\">WPGraphQL Mutations with Server Actions<\/a><\/li>\n\n\n\n<li><a href=\"#auth\">Authentication<\/a><\/li>\n\n\n\n<li><a href=\"#apollo-client-experimental\">Apollo Client Experimental Support<\/a><\/li>\n\n\n\n<li><a href=\"#forms-on-the-server\">Forms<\/a><\/li>\n\n\n\n<li><a href=\"#nesting-server-client-components\">Using Client Components &nbsp;(Nesting Client &amp; Server)<\/a><\/li>\n\n\n\n<li><a href=\"#nested-layouts\">Nested Layouts<\/a><\/li>\n<\/ul>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Getting Started<\/h2>\n\n\n\n<p>To benefit from this post, you should be familiar with the basics of WordPress development,<a href=\"https:\/\/www.wpgraphql.com\/\"> WPGraphQL<\/a>, <a href=\"http:\/\/nextjs.org\/docs(opens in a new tab)\">Next.js 14<\/a>, and <a href=\"https:\/\/www.apollographql.com\/docs\/react\/\">Apollo Client<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Configure Your WordPress Site<\/strong><\/h3>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Set up a WordPress site on <a href=\"https:\/\/wpengine.com\/local\/\">local<\/a>, <a href=\"https:\/\/wpengine.com\/\">WP Engine<\/a>, or any host of your choice<\/li>\n\n\n\n<li><a href=\"https:\/\/www.wpgraphql.com\/\">Install and activate the WPGraphQL plugin<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/wordpress.org\/plugins\/faustwp\/\">Install and activate the Faust.js plugin<\/a><\/li>\n<\/ol>\n\n\n\n<div class=\"wp-block-group has-base-color has-text-color has-background has-link-color wp-elements-688844c5591b0d750f2228c71fe3f5ec has-global-padding is-layout-constrained wp-container-core-group-is-layout-c825ac28 wp-block-group-is-layout-constrained\" style=\"border-radius:12px;background-color:#180038;margin-bottom:var(--wp--preset--spacing--30);padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--30)\">\n<div class=\"wp-block-group alignwide is-content-justification-left is-layout-flex wp-container-core-group-is-layout-682063c7 wp-block-group-is-layout-flex\" style=\"padding-top:0;padding-right:0;padding-bottom:0;padding-left:0\">\n<div class=\"wp-block-group is-nowrap is-layout-flex wp-container-core-group-is-layout-e4830150 wp-block-group-is-layout-flex\">\n<div class=\"wp-block-outermost-icon-block\"><div class=\"icon-container\" style=\"width:38px\"><svg fill=\"none\" viewBox=\"0 0 38 30\" aria-label=\"Frost logo\"><path fill=\"currentColor\" fill-rule=\"evenodd\" d=\"M18.149.498c-.043.01-.16.025-.259.033-.406.03-.933.112-1.53.238-.205.043-.769.198-.98.269-.114.039-.574.207-.618.226l-.292.124c-.3.128-.74.346-1.01.502a4.92 4.92 0 0 1-.206.115 10.57 10.57 0 0 0-4.878 6.728c-.018.106-.035.118-.237.165-.17.039-.23.055-.54.147C3.36 10.302.453 13.9.037 18.401c-.045.49-.05 8.792-.006 9.065.18 1.094.97 1.87 2.052 2.012.375.049 4.136.05 4.527.002 1.185-.148 2.032-1.046 2.102-2.228.055-.925.614-1.62 1.403-1.745.29-.046.37-.05.528-.022.905.158 1.437.76 1.5 1.7.083 1.249.888 2.135 2.084 2.294.363.048 4.162.048 4.518 0 .633-.086 1.262-.421 1.616-.862l.124-.154c.13-.156.29-.575.341-.885.046-.277.047-8.617.002-8.907-.183-1.17-1.208-1.979-2.505-1.979-.386 0-1.057-.13-1.593-.306a5.82 5.82 0 0 1-3.868-4.496c-.16-.907-.112-1.586.187-2.655.417-1.494 1.717-2.941 3.22-3.585l.158-.068c.28-.121.809-.268 1.214-.336a5.03 5.03 0 0 1 1.98.042c2.288.53 3.911 2.078 4.476 4.272.198.768.189.427.19 7.436.002 3.432.012 6.28.023 6.399.304 3.24 2.565 5.63 5.713 6.037.829.107 1.116.107 1.8-.001 2.037-.322 3.807-1.829 4.698-4.001l.046-.112c.148-.36.347-1.107.407-1.53.119-.823.073-1.372-.15-1.817-.255-.508-.802-.924-1.493-1.137-.253-.078-.998-.08-1.2-.005-.026.01-.11.037-.183.06-.666.202-1.24.854-1.493 1.696-.03.101-.093.523-.093.63 0 .044-.02.162-.046.26-.44 1.724-2.917 1.715-3.316-.013-.03-.128-.034-.905-.034-6.275 0-6.296-.005-6.684-.089-7.276a11.333 11.333 0 0 0-.114-.742c-.012-.05-.042-.186-.066-.304-.734-3.596-3.431-6.625-6.951-7.805a9.125 9.125 0 0 0-.855-.246 7.503 7.503 0 0 0-.888-.179 18.617 18.617 0 0 0-.877-.117c-.28-.033-.874-.046-.977-.02Zm-.047 8.132c-1.224.212-1.998 1.382-1.8 2.72.027.186.034.213.115.462.554 1.717 3.03 1.998 3.992.452.055-.088.1-.165.1-.172 0-.006.025-.064.056-.128.131-.27.214-.68.214-1.052 0-1.52-1.194-2.539-2.677-2.282Zm-9.55 5.116c.577 2.153 2.094 4.3 3.988 5.648.78.554 1.328.849 2.38 1.28.077.031.556.195.675.23l.247.07.236.069.101.03.006 1.66c.006 1.695.002 1.779-.078 1.615-.772-1.58-2.366-2.836-4.134-3.256-.626-.149-.883-.178-1.552-.178-2.132.001-4.114 1.027-5.234 2.711-.17.254-.36.57-.412.686-.101.22-.1.256-.1-2.611 0-3 .005-3.148.129-3.748a5.873 5.873 0 0 1 1.94-3.294 5.92 5.92 0 0 1 1.518-.927c.222-.091.262-.09.29.015Z\" clip-rule=\"evenodd\"><\/path><\/svg><\/div><\/div>\n\n\n\n<p class=\"has-large-font-size\" style=\"font-style:normal;font-weight:800;letter-spacing:-1px\">WPGraphQL<\/p>\n<\/div>\n\n\n\n<p class=\"has-small-font-size wp-container-content-c86e52ed\" style=\"line-height:1.5\">An extendable GraphQL <br>schema &amp; API for WordPress.<\/p>\n\n\n\n<div class=\"wp-block-buttons is-horizontal is-content-justification-center is-nowrap is-layout-flex wp-container-core-buttons-is-layout-3bdbf2e2 wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button is-style-outline-base\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/wpeng.in\/wpgraphql-builders\/\" style=\"border-radius:99px;padding-top:10px;padding-right:24px;padding-bottom:10px;padding-left:24px\" target=\"_blank\" rel=\"noreferrer noopener\">Download<\/a><\/div>\n<\/div>\n<\/div>\n<\/div>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Faust.js Experimental App Router Setup<\/strong><\/h4>\n\n\n\n<p>Get started by downloading the example project by running:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>npx create-next-app \\\n<\/span><\/span><span class='shcb-loc'><span>    -e https:<span class=\"hljs-comment\">\/\/github.com\/wpengine\/faustjs\/tree\/main \\<\/span>\n<\/span><\/span><span class='shcb-loc'><span>    --example-path examples\/next\/app-router \\\n<\/span><\/span><span class='shcb-loc'><span>    --<span class=\"hljs-keyword\">use<\/span>-<span class=\"hljs-title\">npm<\/span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Once you download the example project, cd into the project you named it and run this command: <code>npm install --legacy-peer-deps<\/code>&nbsp;due to conflicts in dependencies for now.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>.env.local File Set-Up<\/strong><\/h4>\n\n\n\n<p>Copy the example\u2019s <code>.env.local.sample<\/code> file, ensuring you rename the file <code>.env.local<\/code>.<\/p>\n\n\n\n<p>You\u2019ll see an example <code>NEXT_PUBLIC_WORDPRESS_URL<\/code> in this file. Set this to your WordPress site\u2019s URL.<\/p>\n\n\n\n<p>You\u2019ll also see a <code>NEXT_PUBLIC_URL<\/code> set to <code>http:\/\/localhost:3000<\/code>. You can keep that as is for now.<\/p>\n\n\n\n<p>Get your <code>FAUST_SECRET_KEY<\/code> from your<code> WordPress Settings-&gt;Faust<\/code> and set it in.<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"369\" src=\"https:\/\/lh7-us.googleusercontent.com\/nLSidtX6yrSjy2Vv6WX9VTf7qQJmSKwIApv54m47sDLvheicOtegh2G98XEc7aXCer63aLoMvsEv1fLGOTqEqYya-1ObW9ZPcMpjrVhTlO52bxCiIDgzD1Hjg5fmpNrbJgB2X3M5N8XxrJmLatBoTNY\"><\/p>\n\n\n\n<div class=\"wp-block-group has-base-color has-text-color has-background has-link-color wp-elements-1c64e8656e2adf26d6fee6632ed30e85 has-global-padding is-layout-constrained wp-container-core-group-is-layout-c825ac28 wp-block-group-is-layout-constrained\" style=\"border-radius:12px;background-color:#1a8bec;margin-bottom:var(--wp--preset--spacing--30);padding-top:var(--wp--preset--spacing--30);padding-right:var(--wp--preset--spacing--30);padding-bottom:var(--wp--preset--spacing--30);padding-left:var(--wp--preset--spacing--30)\">\n<div class=\"wp-block-group alignwide is-content-justification-left is-layout-flex wp-container-core-group-is-layout-8b72b8c1 wp-block-group-is-layout-flex\" style=\"padding-top:0;padding-right:0;padding-bottom:0;padding-left:0\">\n<div class=\"wp-block-group is-nowrap is-layout-flex wp-container-core-group-is-layout-b97f5b79 wp-block-group-is-layout-flex\">\n<div class=\"wp-block-outermost-icon-block\"><div class=\"icon-container\" style=\"width:52px\"><svg fill=\"none\" viewBox=\"0 0 51 52\" aria-label=\"Frost logo\"><path fill=\"#0076DC\" d=\"M51 26C51 11.917 39.583.5 25.5.5S0 11.917 0 26s11.417 25.5 25.5 25.5S51 40.083 51 26Z\"><\/path><path fill=\"#fff\" d=\"M18.693 43a8.4 8.4 0 0 1-3.701-.944 4.91 4.91 0 0 1-2.044-2.11 2.946 2.946 0 0 1 1.095-3.778 3.386 3.386 0 0 1 4.287.68c.36.423.691.87.991 1.336l.047.071c1.228-2.833 1.785-5.765 2.361-8.838.27-1.417.553-2.875.902-4.325l-2.658-.207a.733.733 0 0 1-.675-.723 1.916 1.916 0 0 1 .52-1.487 1.889 1.889 0 0 1 1.496-.387l.76.07a1.337 1.337 0 0 0 1.416-1.005c.118-.472.232-.944.35-1.45.401-1.99.998-3.937 1.78-5.811 2.001-4.382 5.622-6.01 10.202-4.594.9.28 1.714.787 2.36 1.473a3.41 3.41 0 0 1 .907 2.497 2.973 2.973 0 0 1-1.02 2.082 3.157 3.157 0 0 1-2.318.709 3.485 3.485 0 0 1-2.389-1.214 8.862 8.862 0 0 1-1.067-1.775c-.113-.222-.221-.472-.34-.666-.042-.075-.084-.15-.122-.23l-.302.032-2.116 9.797 2.673.17a.723.723 0 0 1 .67.604 1.78 1.78 0 0 1-.316 1.591 1.716 1.716 0 0 1-1.516.401l-.359-.037-.472-.047c-1.005-.076-1.36.24-1.59 1.416-.1.51-.2 1.02-.293 1.53-.444 2.303-.898 4.683-1.535 6.982a16.486 16.486 0 0 1-2.2 4.835C22.97 41.862 20.955 43 18.693 43Zm-2.946-6.383a2.262 2.262 0 0 0-1.204.34 2.002 2.002 0 0 0-.755 2.568 3.97 3.97 0 0 0 1.62 1.695c3.304 1.624 6.26.878 8.295-2.11a15.411 15.411 0 0 0 2.072-4.552c.628-2.266 1.082-4.627 1.516-6.912l.297-1.53c.227-1.156.709-2.317 2.587-2.176l.51.052.35.038c.368.038.632 0 .736-.113a.854.854 0 0 0 .095-.614l-2.743-.175a.732.732 0 0 1-.652-.878l2.285-10.703 1.653-.189.141.312c.076.165.152.325.236.472.085.146.241.472.36.694.252.564.57 1.098.944 1.59a2.55 2.55 0 0 0 1.742.879 2.229 2.229 0 0 0 1.624-.472 2.031 2.031 0 0 0 .698-1.417 2.484 2.484 0 0 0-.67-1.808 4.557 4.557 0 0 0-1.94-1.204c-4.127-1.28-7.262.133-9.065 4.084a30.694 30.694 0 0 0-1.723 5.637c-.114.473-.232.978-.35 1.464a2.266 2.266 0 0 1-2.412 1.714l-.76-.07a1.034 1.034 0 0 0-.775.145.888.888 0 0 0-.208.581l2.734.198a.728.728 0 0 1 .652.898c-.373 1.51-.666 3.045-.945 4.532-.6 3.12-1.213 6.35-2.606 9.442a.714.714 0 0 1-1.232.114l-.288-.425c-.277-.43-.583-.84-.916-1.228a2.536 2.536 0 0 0-1.903-.873Z\"><\/path><\/svg><\/div><\/div>\n\n\n\n<p class=\"has-x-large-font-size\" style=\"font-style:normal;font-weight:800;letter-spacing:-1px\">Faust.js<\/p>\n<\/div>\n\n\n\n<p class=\"has-small-font-size wp-container-content-c86e52ed\" style=\"line-height:1.5\">The JavaScript framework<br>specifically for WordPress.<\/p>\n\n\n\n<div class=\"wp-block-buttons is-content-justification-right is-nowrap is-layout-flex wp-container-core-buttons-is-layout-b315634e wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button is-style-outline-base\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/wpeng.in\/faust-builders\/\" style=\"border-radius:99px;padding-top:10px;padding-right:24px;padding-bottom:10px;padding-left:24px\" target=\"_blank\" rel=\"noreferrer noopener\">Download \u2192<\/a><\/div>\n<\/div>\n<\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">Faust.js App Router Example Project<\/h2>\n\n\n\n<p>This is the file structure when opening up the code base on the Faust.js experimental package:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh7-us.googleusercontent.com\/IxNIya3eMYtKZwECCervVJSz7ve0H1Qpc2SLWOppQ7HMIZQxWJKcvkDXPGu8SDl8HBu_npFkaxvgvX_Rf8-VAcbh1MgZinIcgHVbgenV4hNj24CjK6riFALdM9qbrVI7zqKjjhfG6MpsmZ9lc6a1SaI\" width=\"624\" height=\"875\"><\/p>\n\n\n\n<p>We have route segments, a dynamic route segment, and authentication out of the box.&nbsp; If you are unfamiliar with the basics of Next.js 14 and the roles of files and folders, please refer to <a href=\"https:\/\/wpengine.com\/builders\/next-js-13-and-wpgraphql-in-headless-wordpress\/\">my article here on that subject<\/a>.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"stable-server-action\">Fetching Data<\/h2>\n\n\n\n<p>Faust.js uses the experimental <a href=\"https:\/\/www.npmjs.com\/package\/@apollo\/experimental-nextjs-app-support\">Apollo Client support for Next.js 14<\/a>.&nbsp; <a href=\"https:\/\/faustjs.org\/reference\/getclient\/\">getClient<\/a> is a function that returns an <code>ApolloClient<\/code>, specifically for use in React Server Components (RSC). When making authenticated requests in the Next.js App Router from an RSC, the <a href=\"https:\/\/faustjs.org\/reference\/getauthclient\/\">getAuthClient<\/a> is used instead. Both are part of the <code>@faustwp\/experimental-app-router<\/code> package.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"auth\"><strong>Authentication<\/strong><\/h2>\n\n\n\n<p>Let\u2019s break down authentication In the example project. Under the folder <code>my-account<\/code>, you\u2019ll find an example of <code>getAuthClient<\/code> in action in the <code>page.tsx<\/code> file:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { PleaseLogin } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/components\/please-login\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { gql } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@apollo\/client\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { getAuthClient, onLogout } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@faustwp\/experimental-app-router\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Page<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> client = <span class=\"hljs-keyword\">await<\/span> getAuthClient();\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">if<\/span> (!client) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PleaseLogin<\/span> \/&gt;<\/span><\/span>;\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> { data } = <span class=\"hljs-keyword\">await<\/span> client.query({\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">query<\/span>: gql<span class=\"hljs-string\">`<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      query GetViewerPublishedPosts {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">        viewer {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">          name<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\"><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">          publishedPosts: posts(where: { status: PUBLISH }) {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">            nodes {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">              id<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">              title<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">            }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">          }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">        }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    `<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>  });\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex justify-center mb-2\"<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span>&gt;<\/span>Welcome {data.viewer.name}!<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex justify-center mb-4\"<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"font-bold underline text-blue-900\"<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          My Post Titles List<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex justify-center mb-12\"<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          {data.viewer.publishedPosts.nodes.map((post) =&gt; (<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{post.id}<\/span>&gt;<\/span>{post.title}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          ))}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">action<\/span>=<span class=\"hljs-string\">{onLogout}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex justify-center\"<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-green-500 hover:bg-green-600 text-white font-semibold px-4 py-2 rounded\"<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        &gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          Logout<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><\/p>\n\n\n\n<p>At the top of the file we import the GraphQL template literal from the Apollo Client and the <code>getAuthClient <\/code>function from Faust.js.<\/p>\n\n\n\n<p>Following the imports, we define an asynchronous default function named <code>Page<\/code> which will be the function used as the component.&nbsp;<\/p>\n\n\n\n<p>We then get the Apollo Client by calling the <code>getAuthClient<\/code> function asynchronously and store it in the client variable.<\/p>\n\n\n\n<p>After that, we have an authentication check if the client instance is null or undefined.&nbsp; If it is, this means the user is not authenticated and we render a JSX fragment to inform the user that they must be authenticated.&nbsp; If they are not authenticated, it directs them to a login page which is a component located in our <code>app\/components<\/code> directory.&nbsp;<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">if<\/span> (!client) {\n<\/span><\/span><span class='shcb-loc'><span>    \t\t\t<span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PleaseLogin<\/span> \/&gt;<\/span><\/span>;\n<\/span><\/span><span class='shcb-loc'><span>  \t\t\t}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The next thing is some data fetching as we execute a GraphQL query asynchronously using the Apollo Client instance where we fetch the logged-in user&#8217;s name, post IDs, and titles.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span> <span class=\"hljs-keyword\">const<\/span> { data } = <span class=\"hljs-keyword\">await<\/span> client.query({\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-attr\">query<\/span>: gql<span class=\"hljs-string\">`<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      query GetViewerPublishedPosts {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">        viewer {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">          name<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\"><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">          publishedPosts: posts(where: { status: PUBLISH }) {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">            nodes {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">              id<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">              title<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">            }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">          }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">        }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    `<\/span>,\n<\/span><\/span><span class='shcb-loc'><span>  });\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Lastly, we render the JSX elements with the post&#8217;s data.<\/p>\n\n\n\n<p>Let\u2019s see what this part looks like in the browser.&nbsp; Run <code>npm run dev<\/code> in terminal and you should see this page if you try to visit <a href=\"http:\/\/localhost:3000\/my-account\">http:\/\/localhost:3000\/my-account<\/a> without logging in:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh7-us.googleusercontent.com\/ElQCH6ydNmkDTQ6ITWgUt5ba2hpXOx-f_QXeaNx9ycoOKPkCQXQ2V3Qp1aatvYKFhSs3lT1nfQCsJBvUhYK7awvq9oBHK1_P1g59BDI3KVwzjg0LMChLjwAyAZA52MIu5o2h4ndOODrhxlIUBeGu1Uw\" width=\"671\" height=\"361\"><\/p>\n\n\n\n<p>Once you log in, you should see this authenticated user\u2019s landing page:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/lh7-us.googleusercontent.com\/ghatIUlYtxgRMfAIwvLgSYTv8ms6If6gfuoHJindnunRwCs2fGGX_qmHHXjqaick7QcfX6mgh7XL93-Ldsglgr458pbLPBrpXGfw0hBz_B119Top2OLL1V4cvx25q4O3CwWVx2QKBZ4mZmAJGUbnyGk\" width=\"624\" height=\"369\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Login Server Action<\/h2>\n\n\n\n<p>Authentication in the experimental App Router is powered by two utilities, <code>onLogin<\/code> and <code>onLogout<\/code>. These are built on Next.js server actions and perform an action to log a user in and out using cookie caching and cookie removal, respectively.&nbsp; Let\u2019s navigate to <code>app\/login\/actions.ts<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-string\">\"use server\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { onLogin } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@faustwp\/experimental-app-router\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { redirect } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\/navigation\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">loginAction<\/span>(<span class=\"hljs-params\">prevData: any, formData: FormData<\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> onLogin(formData);\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">if<\/span> (res.error) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">return<\/span> res;\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  redirect(<span class=\"hljs-string\">\"\/my-account\"<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><\/p>\n\n\n\n<p>At the very top of the file, we have the <code>'use server'<\/code> directive by Next.js to indicate that this component should only run on the server.  In this case, we are using this for server-side auth handling without exposing sensitive logic to the client.<\/p>\n\n\n\n<p>Our imports are next with the <code>onLogin<\/code> function from Faust.js for handling the login process and <code>redirect<\/code> from Next.js to perform server-side redirection to the <code>my-account<\/code> path.<\/p>\n\n\n\n<p>Following our imports, we have an async function called <code>loginAction<\/code> that will be called in response to a form submission.  The function takes two parameters.  <code>prevData<\/code> which is of type <code>any<\/code> and is used to pass any previous state or data.  <code>formData<\/code> is an instance of <code>FormData<\/code> and carries the data from the login form.<\/p>\n\n\n\n<p>Next, we call the <code>onLogin<\/code> function with <code>formData as its argument.  <\/code>This returns a promise that resolves to the result of the login attempt.<\/p>\n\n\n\n<p>Then, an <code>if<\/code> statement checks if the response object contains a<code> error prop.  <\/code>If there is an error, the function returns the response object which will include the error details on the client.<\/p>\n\n\n\n<p>Lastly, if there is no error, the <code>redirect<\/code> function is called to navigate the user to the <code>my-account<\/code> route which is done server-side, telling the user&#8217;s browser to navigate to that path as a result of the login action being processed.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Login Page File on the Client<\/h3>\n\n\n\n<p>Now that we have our Server Action to handle the login functionality on the server, we can use it in a client-side component for the page UI that will show on the browser to allow the user to input their login credentials and submit the data to authenticate.  <\/p>\n\n\n\n<p>Navigate to <code>app\/login\/page.tsx<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-string\">\"use client\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { useFormState, useFormStatus } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react-dom\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { loginAction } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/actions\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">SubmitButton<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> status = useFormStatus();\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-green-500 hover:bg-green-600 text-white font-semibold px-4 py-2 rounded\"<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{status.pending}<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">    &gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\">      {status.pending ? \"Loading...\" : \"Login\"}<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span>  );\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Page<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> &#91;state, formAction] = useFormState(loginAction, {});\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex justify-center\"<\/span>&gt;<\/span>Login Here<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">action<\/span>=<span class=\"hljs-string\">{formAction}<\/span>&gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">fieldset<\/span>&gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"usernameEmail\"<\/span>&gt;<\/span>Username or Email<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"name\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"usernameEmail\"<\/span> \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">fieldset<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">fieldset<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"password\"<\/span>&gt;<\/span>Password<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"password\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"password\"<\/span> \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">fieldset<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SubmitButton<\/span> \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        {state.error &amp;&amp; (<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">dangerouslySetInnerHTML<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">__html:<\/span> <span class=\"hljs-attr\">state.error<\/span> }}&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        )}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><\/p>\n\n\n\n<p>The top of the file starts with the <code>'use client'<\/code> directive which ensures that this component will only run on the client.  After that, we have our imports:<\/p>\n\n\n\n<p><a href=\"https:\/\/react.dev\/reference\/react-dom\/hooks\/useFormState\">The <code>useFormState<\/code> hook comes from <code>react-dom<\/code> <\/a>and allows you to update state based on the result of a form action.  <a href=\"https:\/\/react.dev\/reference\/react-dom\/hooks\/useFormStatus\">The <code>useFormStatus<\/code> hook also comes from react-dom<\/a> and this gives you status information of the last form submission.  Both are still in experimental canary branches.<\/p>\n\n\n\n<p>The <code>loginAction<\/code> is from our <code>actions.ts<\/code> file we made in this same directory to handle the login logic on the server.<\/p>\n\n\n\n<p>Following that, we have a functional component that defines a <code>SubmitButton<\/code> which is responsible for rendering the submit button on the form.  We then call the <code>useFormStatus<\/code> hook to get the current status of the form.  It returns an object with a <code>pending<\/code> prop that indicates whether a form submission is in progress.<\/p>\n\n\n\n<p>After that, we have our button element that displays the text &#8216;Login&#8217; or &#8216;Loading&#8217; depending on if a form submission is pending.  This uses the <code>pending<\/code> status to disable the button during submission to prevent duplicate submissions.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">SubmitButton<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> status = useFormStatus();\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-green-500 hover:bg-green-600 text-white font-semibold px-4 py-2 rounded\"<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{status.pending}<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">    &gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\">      {status.pending ? \"Loading...\" : \"Login\"}<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span>  );\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><\/p>\n\n\n\n<p>The <code>Page<\/code> component is next which serves as the main component for this page file.<\/p>\n\n\n\n<p>In this component, we initialize form state management using the <code>useFormState<\/code> hook with <code>loginAction<\/code> as the handler for form submissions.<\/p>\n\n\n\n<p>Then we return JSX that renders the form and input fields with the submit button.  <br>In the form element, it uses the <code>action<\/code> property that calls a function to run on the server.&nbsp; In this case, our function being called is <code>formAction <\/code>which will handle the form submission on the server and this is tied to the <code>loginAction<\/code> we are importing from our Server Action.<\/p>\n\n\n\n<p>Lastly, we have the <code>SubmitButton <\/code>component that we created at the top of this file as well as a line that conditionally renders an error message if there is an error in the form&#8217;s state.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span> <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex justify-center\"<\/span>&gt;<\/span>Login Here<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">action<\/span>=<span class=\"hljs-string\">{formAction}<\/span>&gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">fieldset<\/span>&gt;<\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"usernameEmail\"<\/span>&gt;<\/span>Username or Email<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"name\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"usernameEmail\"<\/span> \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">fieldset<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">fieldset<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"password\"<\/span>&gt;<\/span>Password<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"password\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"password\"<\/span> \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">fieldset<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SubmitButton<\/span> \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        {state.error &amp;&amp; (<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">dangerouslySetInnerHTML<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">__html:<\/span> <span class=\"hljs-attr\">state.error<\/span> }}&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        )}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><\/p>\n\n\n\n<p>This is what the flow looks like when you run it in the browser:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/dxrwygxse\/image\/upload\/v1700664203\/GIFnext14faustlogin_khchzn.gif\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"wpgraphql-mutations\">Handling WPGraphQL Mutations with Server Actions<\/h2>\n\n\n\n<p>We have gone over the boilerplate code that comes with the Faust.js App Router support package.&nbsp; Now, let\u2019s take it and build on top of it, writing our own server action.<\/p>\n\n\n\n<p>In this section, we will create functionality in our application that allows the user who is authenticated to create a post in a drafted state and then see the drafted post on a page via WPGraphQL mutation.<\/p>\n\n\n\n<p>In order to follow along in this section, you can clone down and copy my GitHub repo here: <a href=\"https:\/\/github.com\/Fran-A-Dev\/next-14-faust-auth-example\">https:\/\/github.com\/Fran-A-Dev\/next-14-faust-auth-example<\/a><\/p>\n\n\n\n<p>The first file we want to look at is our file running the Server Action located at <code>app\/my-account\/create-post\/actions.ts<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-string\">\"use server\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { ApolloClient, gql, NormalizedCacheObject } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@apollo\/client\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { redirect } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\/navigation\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { revalidatePath } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\/cache\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> CREATE_POST_MUTATION = gql<span class=\"hljs-string\">`<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">  mutation CreatePost($title: String!, $content: String!) {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    createPost(<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      input: { content: $content, title: $title, status: DRAFT, authorId: \"1\" }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    ) {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      post {<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">        title<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">        content<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">      }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">    }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">  }<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-string\">`<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">createClient<\/span>(<span class=\"hljs-params\"><\/span>): <span class=\"hljs-title\">Promise<\/span>&lt;<span class=\"hljs-title\">ApolloClient<\/span>&lt;<span class=\"hljs-title\">NormalizedCacheObject<\/span>&gt;&gt; <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> client = <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">import<\/span>(<span class=\"hljs-string\">\"@faustwp\/experimental-app-router\"<\/span>).then(\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-function\">(<span class=\"hljs-params\">{ getAuthClient }<\/span>) =&gt;<\/span> getAuthClient()\n<\/span><\/span><span class='shcb-loc'><span>  );\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> client;\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">addDraftPost<\/span>(<span class=\"hljs-params\">formData: FormData<\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> client = <span class=\"hljs-keyword\">await<\/span> createClient();\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">try<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">const<\/span> { data } = <span class=\"hljs-keyword\">await<\/span> client.mutate({\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">mutation<\/span>: CREATE_POST_MUTATION,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">variables<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">title<\/span>: formData.get(<span class=\"hljs-string\">\"title\"<\/span>),\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">content<\/span>: formData.get(<span class=\"hljs-string\">\"content\"<\/span>),\n<\/span><\/span><span class='shcb-loc'><span>      },\n<\/span><\/span><span class='shcb-loc'><span>    });\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">if<\/span> (data?.createPost?.post) {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">\"Draft post created:\"<\/span>, data.createPost.post);\n<\/span><\/span><span class='shcb-loc'><span>    }\n<\/span><\/span><span class='shcb-loc'><span>  } <span class=\"hljs-keyword\">catch<\/span> (error) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">\"Could not create draft post.\"<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>  } <span class=\"hljs-keyword\">finally<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    revalidatePath(<span class=\"hljs-string\">\"\/my-account\/drafts\"<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>    redirect(<span class=\"hljs-string\">\"\/my-account\/drafts\"<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>At the top of the file, we use the directive to indicate that this code will run on the server.<\/p>\n\n\n\n<p>We import the necessary modules and functions from the Apollo Client and Next.js for our GraphQL client and redirect as well as revalidation on the server for the new updated path when the user adds a post and gets redirected to that path.<\/p>\n\n\n\n<p><br>Then we define our WPGraphQL mutation called <code>CREATE_POST_MUTATION<\/code> which is used to create a new post with a title and content in a draft status.<\/p>\n\n\n\n<p><br>This asynchronous function, <code>createClient<\/code>, dynamically imports the Apollo client from the <code>\"@faustwp\/experimental-app-router\"<\/code> module and returns it. The Apollo client will be used to make authenticated WPGraphQL requests.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">createClient<\/span>(<span class=\"hljs-params\"><\/span>): <span class=\"hljs-title\">Promise<\/span>&lt;<span class=\"hljs-title\">ApolloClient<\/span>&lt;<span class=\"hljs-title\">NormalizedCacheObject<\/span>&gt;&gt; <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> client = <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-keyword\">import<\/span>(<span class=\"hljs-string\">\"@faustwp\/experimental-app-router\"<\/span>).then(\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-function\">(<span class=\"hljs-params\">{ getAuthClient }<\/span>) =&gt;<\/span> getAuthClient()\n<\/span><\/span><span class='shcb-loc'><span>  );\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> client;\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Then we have a <code>addDraftPost<\/code> server action that is asynchronous and does the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>It initializes the Apollo client by calling the previously defined <code>createClient<\/code> function.<\/li>\n\n\n\n<li>It tries to execute the <code>CREATE_POST_MUTATION<\/code> using the provided <code>formData<\/code> (which should have the title and content of the post). If the mutation is successful, it logs the details of the created draft post.<\/li>\n\n\n\n<li>If any error occurs during the mutation, it throws an error indicating that the draft post could not be created.<\/li>\n\n\n\n<li>Regardless of success or failure, it will revalidate the cache for the path <code>\"\/my-account\/drafts\"<\/code> and then redirect the user to the same path.<\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">addDraftPost<\/span>(<span class=\"hljs-params\">formData: FormData<\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> client = <span class=\"hljs-keyword\">await<\/span> createClient();\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">try<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">const<\/span> { data } = <span class=\"hljs-keyword\">await<\/span> client.mutate({\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">mutation<\/span>: CREATE_POST_MUTATION,\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-attr\">variables<\/span>: {\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">title<\/span>: formData.get(<span class=\"hljs-string\">\"title\"<\/span>),\n<\/span><\/span><span class='shcb-loc'><span>        <span class=\"hljs-attr\">content<\/span>: formData.get(<span class=\"hljs-string\">\"content\"<\/span>),\n<\/span><\/span><span class='shcb-loc'><span>      },\n<\/span><\/span><span class='shcb-loc'><span>    });\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">if<\/span> (data?.createPost?.post) {\n<\/span><\/span><span class='shcb-loc'><span>      <span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">\"Draft post created:\"<\/span>, data.createPost.post);\n<\/span><\/span><span class='shcb-loc'><span>    }\n<\/span><\/span><span class='shcb-loc'><span>  } <span class=\"hljs-keyword\">catch<\/span> (error) {\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"hljs-keyword\">throw<\/span> <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">\"Could not create draft post.\"<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>  } <span class=\"hljs-keyword\">finally<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>    revalidatePath(<span class=\"hljs-string\">\"\/my-account\/drafts\"<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>    redirect(<span class=\"hljs-string\">\"\/my-account\/drafts\"<\/span>);\n<\/span><\/span><span class='shcb-loc'><span>  }\n<\/span><\/span><span class='shcb-loc'><span>}\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"forms-on-the-server\">Forms On The Server<\/h3>\n\n\n\n<p>Now that we have made our server action to run our WPGraphQL mutation and redirect every time a drafted post is successfully created, let\u2019s add it to our form so it works.<\/p>\n\n\n\n<p>The first file we will take a look at will be at <code>app\/my-account\/create-post\/CreatePost.tsx:<\/code><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> SubmitButton <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@\/components\/SubmitButton\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { addDraftPost } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/actions\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">CreatePost<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">action<\/span>=<span class=\"hljs-string\">{addDraftPost}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-1\/2\"<\/span>&gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>&gt;<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>Title:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> <span class=\"hljs-attr\">required<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"title\"<\/span> \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>Content:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">textarea<\/span> <span class=\"hljs-attr\">required<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"content\"<\/span> \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SubmitButton<\/span> \/&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">}<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Starting at the top of the file we import our <code>SubmitButton<\/code> component that handles the form button submission and the <code>addDraftPost<\/code> function from the <code>actions.ts<\/code> file which is the server action we created.<\/p>\n\n\n\n<p>Then we define the default function called <code>CreatePost<\/code> which renders a form that the user can input data into.&nbsp;&nbsp;<\/p>\n\n\n\n<p>In the form element, the <code>action<\/code> prop is set to the <code>addDraftPost <\/code>function to call that function and handle the form submission on the server as we did earlier with our login form.<\/p>\n\n\n\n<p>Lastly, we have our submit button for the user to press and submit the draft post data.<\/p>\n\n\n\n<p>Next, let\u2019s take a look at the <code>SubmitButton<\/code> component we are importing into this file from the components directory.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Nesting Components (Client &amp; Server)<\/h3>\n\n\n\n<p>We have our WPGraphQL mutation that runs on the server to add a post in a drafted state.  We also added Server Action to our <code>CreatePost <\/code>component to handle the post-data form submissions.  <br><\/p>\n\n\n\n<p>Similar to how Faust.js earlier in the article created a <code>SubmitButton<\/code> function in the same file as the login page, we will do it on the client in a separate file which will live in the components directory.  Navigate to  <code>app\/components\/SubmitButton.tsx:<\/code><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-code-table shcb-line-numbers\"><span class='shcb-loc'><span><span class=\"hljs-string\">\"use client\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> React <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">import<\/span> { useFormStatus } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react-dom\"<\/span>;\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"hljs-keyword\">const<\/span> SubmitButton: React.FC = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">const<\/span> { pending } = useFormStatus();\n<\/span><\/span><span class='shcb-loc'><span>\n<\/span><\/span><span class='shcb-loc'><span>  <span class=\"hljs-keyword\">return<\/span> (\n<\/span><\/span><span class='shcb-loc'><span>    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{pending}<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">      <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-green-500 hover:bg-green-600 text-white font-semibold px-4 py-2 rounded\"<\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\">    &gt;<\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\">      {pending ? <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>Submitting...<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span> : <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">span<\/span>&gt;<\/span>Submit<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">span<\/span>&gt;<\/span>}<\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">  );<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\">};<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> SubmitButton;<\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><span class='shcb-loc'><span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><span class=\"hljs-tag\"><\/span><\/span><\/span><\/span><\/span><\/span>\n<\/span><\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>At the top of the file, we have the <code>\u201cuse client\u201d<\/code> directive since this will be a client component.<\/p>\n\n\n\n<p>Next, we import the React library and the <code>useFormStatus<\/code> hook which will provide us information about the status of a form, in our case if it is pending or not.<\/p>\n\n\n\n<p>Following that, the <code>SubmitButton<\/code> component is defined as a functional component.&nbsp; Within the component, the <code>useFormStatus<\/code> hook is invoked to get the status of a form.&nbsp; The hook returns an object and it destructures the <code>pending<\/code> property from this object.&nbsp; If pending is true, it indicates that the form is in the process of being submitted, otherwise it is false and there is no ongoing operation.<\/p>\n\n\n\n<p>Lastly, we return JSX in a button element.&nbsp; The disabled attribute of the button is based on the pending value.&nbsp; If pending is true the button will be disabled and if it is false the button will be enabled.<\/p>\n\n\n\n<p>The button\u2019s inner content changes based on the pending status. If the form is in the process of being submitted it shows \u201cSubmitting\u201d, otherwise it shows \u201cSubmit\u201d.<\/p>\n\n\n\n<p>This is what the user flow should look like in the browser:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/dxrwygxse\/image\/upload\/v1700665613\/ScreenFlow_zi4sri.gif\" alt=\"\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Nested Layouts<\/h2>\n\n\n\n<p>Next.js 14 makes it easy to <a href=\"https:\/\/nextjs.org\/docs\/app\/building-your-application\/routing\/pages-and-layouts#nesting-layouts\">nest layouts between route segments<\/a>.&nbsp; This will allow us to keep a root layout that wraps nested layouts.<\/p>\n\n\n\n<p>In our example here, we have a different layout and nav bar for the <code>my-accounts<\/code> route segment. The parent layout wraps around the nested layouts.<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"287\" height=\"367\" src=\"https:\/\/lh7-us.googleusercontent.com\/Gqq36o-ORLohTSGS-3rJIn6Yc65JQ6JwF_AlYm42LZG8sycv2ralSHLN3uwIHcK-9te05zYzcjsPCPzDgjTErcAP__r_akXLL8hpmKkopI9LnaosCjiwgY1TiC8TA2l17NsEcV3xRIBK6Bvg_RijRpQ\"><\/p>\n\n\n\n<p>This comes in handy when you have a use case like this example where you have a public home page where any user can view it with a nav bar and layout which would be the parent.&nbsp; But when a user registers and becomes authenticated on an application, you want to give them a different nav bar and layout because they will have different access to features they would navigate to once authenticated.<\/p>\n\n\n\n<p>This is the user\u2019s layout and navigation that is not authenticated:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"327\" src=\"https:\/\/lh7-us.googleusercontent.com\/b56rcGs7DmK_TMbUCfHnrXBTWitzSLU3fJmYM2vetJU5EJK6kJtEyj5b8lUVeM9pSa_-GuGq_kERX0ONXIFl1b-iTKaa1AN95HgrMPCjA0s5ct7pgaRamjsMu9WEvlDSJHfW9J-rkocWHRRo_jB0tbo\"><\/p>\n\n\n\n<p>The Yoda image and navigation are for unauthenticated users with links to the home page and login page.<\/p>\n\n\n\n<p>When a user is authenticated, they get this layout and navigation with a Darth Vader image and links to draft post capabilities and viewing drafts:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" width=\"624\" height=\"369\" src=\"https:\/\/lh7-us.googleusercontent.com\/tMq3qcKnMqO_C3y385xarsGwsmoskPuo-CY8hPo780nr63PBUcz_H1bdAlm_c_Ug2OFYiuWOnEcpLIoPAHqvfCyASStqmpaoMbnkeeS8WWtda2RQyGivyhx3HsPgCr2eDzskyHFyhlbwRgFF8MYuus0\"><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Faust.js with its App Router support for Next.14 is a new version of the headless WordPress framework on top of the latest version of Next.&nbsp; It introduces authentication handling out of the box,&nbsp; new ways to handle data, route segmentation, and files as well as rendering methods.&nbsp;&nbsp;<\/p>\n\n\n\n<p>Overall, it makes it easier for developers to have a quicker time to <code>\u2018Hello World\u2019 <\/code>when creating headless WordPress applications.<\/p>\n\n\n\n<p>As always, stoked to hear your feedback and any questions you might have on headless WordPress! Hit us up in our <a href=\"https:\/\/discord.com\/invite\/J2khkF9XYK\">Discord<\/a>!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Next.js 14 introduces a new paradigm in the project structure and the development of sites and applications. With the new version of Next.js being adapted, Faust.js also must coincide to [&hellip;]<\/p>\n","protected":false},"author":20,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_EventAllDay":false,"_EventTimezone":"","_EventStartDate":"","_EventEndDate":"","_EventStartDateUTC":"","_EventEndDateUTC":"","_EventShowMap":false,"_EventShowMapLink":false,"_EventURL":"","_EventCost":"","_EventCostDescription":"","_EventCurrencySymbol":"","_EventCurrencyCode":"","_EventCurrencyPosition":"","_EventDateTimeSeparator":"","_EventTimeRangeSeparator":"","_EventOrganizerID":[],"_EventVenueID":[],"_OrganizerEmail":"","_OrganizerPhone":"","_OrganizerWebsite":"","_VenueAddress":"","_VenueCity":"","_VenueCountry":"","_VenueProvince":"","_VenueState":"","_VenueZip":"","_VenuePhone":"","_VenueURL":"","_VenueStateProvince":"","_VenueLat":"","_VenueLng":"","_VenueShowMap":false,"_VenueShowMapLink":false,"footnotes":""},"categories":[23],"tags":[39,25,42,26],"class_list":["post-31322","post","type-post","status-publish","format-standard","hentry","category-headless","tag-apollo","tag-faust-js","tag-next-js-14","tag-wpgraphql"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>App Router and Auth Support in Faust.js with Next.js 14 - Builders<\/title>\n<meta name=\"description\" content=\"Next.js 14 with Faust.js in headless WordPress featuring authentication, server actions and mutations\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"App Router and Auth Support in Faust.js with Next.js 14 - Builders\" \/>\n<meta property=\"og:description\" content=\"Next.js 14 with Faust.js in headless WordPress featuring authentication, server actions and mutations\" \/>\n<meta property=\"og:url\" content=\"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/\" \/>\n<meta property=\"og:site_name\" content=\"Builders\" \/>\n<meta property=\"article:published_time\" content=\"2023-11-22T15:19:11+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-11-14T18:27:49+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/lh7-us.googleusercontent.com\/nLSidtX6yrSjy2Vv6WX9VTf7qQJmSKwIApv54m47sDLvheicOtegh2G98XEc7aXCer63aLoMvsEv1fLGOTqEqYya-1ObW9ZPcMpjrVhTlO52bxCiIDgzD1Hjg5fmpNrbJgB2X3M5N8XxrJmLatBoTNY\" \/>\n<meta name=\"author\" content=\"Francis Agulto\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@wpebuilders\" \/>\n<meta name=\"twitter:site\" content=\"@wpebuilders\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Francis Agulto\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/\"},\"author\":{\"name\":\"Francis Agulto\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/person\\\/bcdcb4ac0b215c34b6b30e440a24dc54\"},\"headline\":\"App Router and Auth Support in Faust.js with Next.js 14\",\"datePublished\":\"2023-11-22T15:19:11+00:00\",\"dateModified\":\"2024-11-14T18:27:49+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/\"},\"wordCount\":2254,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/lh7-us.googleusercontent.com\\\/nLSidtX6yrSjy2Vv6WX9VTf7qQJmSKwIApv54m47sDLvheicOtegh2G98XEc7aXCer63aLoMvsEv1fLGOTqEqYya-1ObW9ZPcMpjrVhTlO52bxCiIDgzD1Hjg5fmpNrbJgB2X3M5N8XxrJmLatBoTNY\",\"keywords\":[\"Apollo\",\"Faust.js\",\"Next.js 14\",\"WPGraphQL\"],\"articleSection\":[\"Headless\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/\",\"name\":\"App Router and Auth Support in Faust.js with Next.js 14 - Builders\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/lh7-us.googleusercontent.com\\\/nLSidtX6yrSjy2Vv6WX9VTf7qQJmSKwIApv54m47sDLvheicOtegh2G98XEc7aXCer63aLoMvsEv1fLGOTqEqYya-1ObW9ZPcMpjrVhTlO52bxCiIDgzD1Hjg5fmpNrbJgB2X3M5N8XxrJmLatBoTNY\",\"datePublished\":\"2023-11-22T15:19:11+00:00\",\"dateModified\":\"2024-11-14T18:27:49+00:00\",\"description\":\"Next.js 14 with Faust.js in headless WordPress featuring authentication, server actions and mutations\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/#primaryimage\",\"url\":\"https:\\\/\\\/lh7-us.googleusercontent.com\\\/nLSidtX6yrSjy2Vv6WX9VTf7qQJmSKwIApv54m47sDLvheicOtegh2G98XEc7aXCer63aLoMvsEv1fLGOTqEqYya-1ObW9ZPcMpjrVhTlO52bxCiIDgzD1Hjg5fmpNrbJgB2X3M5N8XxrJmLatBoTNY\",\"contentUrl\":\"https:\\\/\\\/lh7-us.googleusercontent.com\\\/nLSidtX6yrSjy2Vv6WX9VTf7qQJmSKwIApv54m47sDLvheicOtegh2G98XEc7aXCer63aLoMvsEv1fLGOTqEqYya-1ObW9ZPcMpjrVhTlO52bxCiIDgzD1Hjg5fmpNrbJgB2X3M5N8XxrJmLatBoTNY\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/app-router-and-auth-support-in-faust-js-with-next-js-14\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"App Router and Auth Support in Faust.js with Next.js 14\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#website\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/\",\"name\":\"Builders\",\"description\":\"Reimagining the way we build with WordPress.\",\"publisher\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#organization\",\"name\":\"WP Engine\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/wp-content\\\/uploads\\\/2024\\\/05\\\/WP-Engine-Horizontal@2x.png\",\"contentUrl\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/wp-content\\\/uploads\\\/2024\\\/05\\\/WP-Engine-Horizontal@2x.png\",\"width\":348,\"height\":68,\"caption\":\"WP Engine\"},\"image\":{\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/wpebuilders\",\"https:\\\/\\\/www.youtube.com\\\/channel\\\/UCh1WuL54XFb9ZI6m6goFv1g\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/#\\\/schema\\\/person\\\/bcdcb4ac0b215c34b6b30e440a24dc54\",\"name\":\"Francis Agulto\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/0c8a05c76944fc987d57296c96dc368055844527088c0aa44297edbfa8b82546?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/0c8a05c76944fc987d57296c96dc368055844527088c0aa44297edbfa8b82546?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/0c8a05c76944fc987d57296c96dc368055844527088c0aa44297edbfa8b82546?s=96&d=mm&r=g\",\"caption\":\"Francis Agulto\"},\"description\":\"Fran Agulto is a Developer Advocate at WP Engine. He is a lover of all things headless WordPress, Rock Climbing, and overall being stoked for people that love what they do and share that stoke with others! Follow me on Twitter for cool stoked headless WP!\",\"url\":\"https:\\\/\\\/wpengine.com\\\/builders\\\/author\\\/francis-agultowpengine-com-2-2-2-2-2-2-2-2-2-2-2-3\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"App Router and Auth Support in Faust.js with Next.js 14 - Builders","description":"Next.js 14 with Faust.js in headless WordPress featuring authentication, server actions and mutations","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/","og_locale":"en_US","og_type":"article","og_title":"App Router and Auth Support in Faust.js with Next.js 14 - Builders","og_description":"Next.js 14 with Faust.js in headless WordPress featuring authentication, server actions and mutations","og_url":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/","og_site_name":"Builders","article_published_time":"2023-11-22T15:19:11+00:00","article_modified_time":"2024-11-14T18:27:49+00:00","og_image":[{"url":"https:\/\/lh7-us.googleusercontent.com\/nLSidtX6yrSjy2Vv6WX9VTf7qQJmSKwIApv54m47sDLvheicOtegh2G98XEc7aXCer63aLoMvsEv1fLGOTqEqYya-1ObW9ZPcMpjrVhTlO52bxCiIDgzD1Hjg5fmpNrbJgB2X3M5N8XxrJmLatBoTNY","type":"","width":"","height":""}],"author":"Francis Agulto","twitter_card":"summary_large_image","twitter_creator":"@wpebuilders","twitter_site":"@wpebuilders","twitter_misc":{"Written by":"Francis Agulto","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/#article","isPartOf":{"@id":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/"},"author":{"name":"Francis Agulto","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/person\/bcdcb4ac0b215c34b6b30e440a24dc54"},"headline":"App Router and Auth Support in Faust.js with Next.js 14","datePublished":"2023-11-22T15:19:11+00:00","dateModified":"2024-11-14T18:27:49+00:00","mainEntityOfPage":{"@id":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/"},"wordCount":2254,"commentCount":0,"publisher":{"@id":"https:\/\/wpengine.com\/builders\/#organization"},"image":{"@id":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/#primaryimage"},"thumbnailUrl":"https:\/\/lh7-us.googleusercontent.com\/nLSidtX6yrSjy2Vv6WX9VTf7qQJmSKwIApv54m47sDLvheicOtegh2G98XEc7aXCer63aLoMvsEv1fLGOTqEqYya-1ObW9ZPcMpjrVhTlO52bxCiIDgzD1Hjg5fmpNrbJgB2X3M5N8XxrJmLatBoTNY","keywords":["Apollo","Faust.js","Next.js 14","WPGraphQL"],"articleSection":["Headless"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/","url":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/","name":"App Router and Auth Support in Faust.js with Next.js 14 - Builders","isPartOf":{"@id":"https:\/\/wpengine.com\/builders\/#website"},"primaryImageOfPage":{"@id":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/#primaryimage"},"image":{"@id":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/#primaryimage"},"thumbnailUrl":"https:\/\/lh7-us.googleusercontent.com\/nLSidtX6yrSjy2Vv6WX9VTf7qQJmSKwIApv54m47sDLvheicOtegh2G98XEc7aXCer63aLoMvsEv1fLGOTqEqYya-1ObW9ZPcMpjrVhTlO52bxCiIDgzD1Hjg5fmpNrbJgB2X3M5N8XxrJmLatBoTNY","datePublished":"2023-11-22T15:19:11+00:00","dateModified":"2024-11-14T18:27:49+00:00","description":"Next.js 14 with Faust.js in headless WordPress featuring authentication, server actions and mutations","breadcrumb":{"@id":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/#primaryimage","url":"https:\/\/lh7-us.googleusercontent.com\/nLSidtX6yrSjy2Vv6WX9VTf7qQJmSKwIApv54m47sDLvheicOtegh2G98XEc7aXCer63aLoMvsEv1fLGOTqEqYya-1ObW9ZPcMpjrVhTlO52bxCiIDgzD1Hjg5fmpNrbJgB2X3M5N8XxrJmLatBoTNY","contentUrl":"https:\/\/lh7-us.googleusercontent.com\/nLSidtX6yrSjy2Vv6WX9VTf7qQJmSKwIApv54m47sDLvheicOtegh2G98XEc7aXCer63aLoMvsEv1fLGOTqEqYya-1ObW9ZPcMpjrVhTlO52bxCiIDgzD1Hjg5fmpNrbJgB2X3M5N8XxrJmLatBoTNY"},{"@type":"BreadcrumbList","@id":"https:\/\/wpengine.com\/builders\/app-router-and-auth-support-in-faust-js-with-next-js-14\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/wpengine.com\/builders\/"},{"@type":"ListItem","position":2,"name":"App Router and Auth Support in Faust.js with Next.js 14"}]},{"@type":"WebSite","@id":"https:\/\/wpengine.com\/builders\/#website","url":"https:\/\/wpengine.com\/builders\/","name":"Builders","description":"Reimagining the way we build with WordPress.","publisher":{"@id":"https:\/\/wpengine.com\/builders\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/wpengine.com\/builders\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/wpengine.com\/builders\/#organization","name":"WP Engine","url":"https:\/\/wpengine.com\/builders\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/logo\/image\/","url":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2024\/05\/WP-Engine-Horizontal@2x.png","contentUrl":"https:\/\/wpengine.com\/builders\/wp-content\/uploads\/2024\/05\/WP-Engine-Horizontal@2x.png","width":348,"height":68,"caption":"WP Engine"},"image":{"@id":"https:\/\/wpengine.com\/builders\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/wpebuilders","https:\/\/www.youtube.com\/channel\/UCh1WuL54XFb9ZI6m6goFv1g"]},{"@type":"Person","@id":"https:\/\/wpengine.com\/builders\/#\/schema\/person\/bcdcb4ac0b215c34b6b30e440a24dc54","name":"Francis Agulto","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/0c8a05c76944fc987d57296c96dc368055844527088c0aa44297edbfa8b82546?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/0c8a05c76944fc987d57296c96dc368055844527088c0aa44297edbfa8b82546?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/0c8a05c76944fc987d57296c96dc368055844527088c0aa44297edbfa8b82546?s=96&d=mm&r=g","caption":"Francis Agulto"},"description":"Fran Agulto is a Developer Advocate at WP Engine. He is a lover of all things headless WordPress, Rock Climbing, and overall being stoked for people that love what they do and share that stoke with others! Follow me on Twitter for cool stoked headless WP!","url":"https:\/\/wpengine.com\/builders\/author\/francis-agultowpengine-com-2-2-2-2-2-2-2-2-2-2-2-3\/"}]}},"_links":{"self":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts\/31322","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/comments?post=31322"}],"version-history":[{"count":0,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/posts\/31322\/revisions"}],"wp:attachment":[{"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/media?parent=31322"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/categories?post=31322"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpengine.com\/builders\/wp-json\/wp\/v2\/tags?post=31322"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}