├── .gitignore ├── README.md ├── express ├── README.md ├── app.js ├── babel.config.js ├── docs │ └── img │ │ ├── express-app.png │ │ └── usage-screenshot.png ├── package-lock.json ├── package.json ├── templates │ └── index.js └── yarn.lock ├── faust ├── .env.local.sample ├── .eslintrc ├── .gitignore ├── README.md ├── gqty.config.js ├── next-env.d.ts ├── next.config.js ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ └── images │ │ └── headless_hero_background.jpg ├── src │ ├── client │ │ ├── index.ts │ │ └── schema.generated.ts │ ├── components │ │ ├── CTA.tsx │ │ ├── Footer.tsx │ │ ├── Header.tsx │ │ ├── Heading.tsx │ │ ├── Hero.tsx │ │ ├── Pagination.tsx │ │ ├── Posts.tsx │ │ └── index.ts │ ├── faust.config.js │ ├── lib │ │ └── utils │ │ │ └── flatListToHierarchical.js │ ├── pages │ │ ├── 404.tsx │ │ ├── [...pageUri].tsx │ │ ├── _app.tsx │ │ ├── _document.tsx │ │ ├── api │ │ │ └── faust │ │ │ │ └── [[...route]].ts │ │ ├── category │ │ │ └── [categorySlug] │ │ │ │ ├── [paginationTerm] │ │ │ │ └── [categoryCursor].tsx │ │ │ │ └── index.tsx │ │ ├── custom-page.tsx │ │ ├── index.tsx │ │ ├── posts │ │ │ ├── [postSlug] │ │ │ │ ├── [postCursor].tsx │ │ │ │ └── index.tsx │ │ │ └── index.tsx │ │ └── preview.tsx │ └── scss │ │ ├── _typography.scss │ │ ├── _variables.scss │ │ ├── components │ │ ├── CTA.module.scss │ │ ├── Footer.module.scss │ │ ├── Header.module.scss │ │ ├── Hero.module.scss │ │ └── Posts.module.scss │ │ ├── main.scss │ │ └── pages │ │ ├── home.module.scss │ │ └── posts.module.scss ├── tsconfig.json └── yarn.lock ├── gatsby └── README.md ├── next-apollo ├── .gitignore ├── .nvmrc ├── README.md ├── components │ ├── ActionPreview │ │ └── ActionPreview.js │ ├── DocsLayout │ │ └── DocsLayout.js │ ├── DocsNav │ │ └── DocsNav.js │ ├── DynamicHeroIcon │ │ └── DynamicHeroIcon.js │ ├── ExtensionPreview │ │ └── ExtensionPreview.js │ ├── FilterPreview │ │ └── FilterPreview.js │ ├── FunctionPreview │ │ └── FunctionPreview.js │ ├── Heading │ │ └── Heading.js │ ├── HomepageCta │ │ └── HomepageCta.js │ ├── HomepageFeatures │ │ └── HomepageFeatures.js │ ├── HomepageFrameworks │ │ └── HomepageFrameworks.js │ ├── HomepageHero │ │ └── HomepageHero.js │ ├── HomepageTrust │ │ └── HomepageTrust.js │ ├── PostPreview │ │ └── PostPreview.js │ ├── PostPreviewCategoryLink │ │ └── PostPreviewCategoryLink.js │ ├── RecipePreview │ │ └── RecipePreview.js │ ├── SiteFooter │ │ └── SiteFooter.js │ ├── SiteHeader │ │ └── SiteHeader.js │ ├── SiteLayout │ │ └── SiteLayout.js │ ├── SiteLogo │ │ └── SiteLogo.js │ ├── TableOfContents │ │ └── TableOfContents.js │ └── ThemeToggle │ │ └── ThemeToggle.js ├── docs │ ├── authentication-and-authorization.mdx │ ├── build-extension.mdx │ ├── build-your-first-wpgraphql-extension.mdx │ ├── categories-and-tags.mdx │ ├── comments.mdx │ ├── connections.mdx │ ├── contributing.mdx │ ├── custom-post-types.mdx │ ├── custom-taxonomies.mdx │ ├── customizing-wpgraphiql.mdx │ ├── debugging.mdx │ ├── default-types-and-fields.mdx │ ├── docs-nav-menu.yaml │ ├── faqs.mdx │ ├── graphql-resolvers.mdx │ ├── hierarchical-data.mdx │ ├── index.js │ ├── interacting-with-wpgraphql.mdx │ ├── interfaces.mdx │ ├── intro-to-graphql.mdx │ ├── intro-to-wordpress.mdx │ ├── introduction.mdx │ ├── media.mdx │ ├── menus.mdx │ ├── mutations.mdx │ ├── performance.mdx │ ├── plugins.mdx │ ├── posts-and-pages.mdx │ ├── quick-start.mdx │ ├── request-lifecycle.mdx │ ├── security.mdx │ ├── settings.mdx │ ├── support.mdx │ ├── testing.mdx │ ├── themes.mdx │ ├── upgrading.mdx │ ├── use-with-php.mdx │ ├── users.mdx │ ├── using-data-from-custom-database-tables.mdx │ ├── widgets.mdx │ ├── wordpress-as-an-application-data-graph.mdx │ ├── wp-graphiql.mdx │ ├── wpgraphql-concepts.mdx │ └── wpgraphql-vs-wp-rest-api.mdx ├── graphql.config.js ├── hooks │ └── useIsomorphicLayoutEffect.js ├── jsconfig.json ├── lib │ ├── data │ │ └── apollo.js │ ├── helpers │ │ ├── flatListToHierarchical.js │ │ └── parse-docs.js │ └── mdx │ │ └── components.js ├── navs │ ├── README.md │ └── documentation.js ├── netlify.toml ├── next.config.js ├── package.json ├── pages │ ├── 404.js │ ├── [...WordPressNode].js │ ├── _app.js │ ├── _document.js │ ├── api │ │ └── hello.js │ ├── blog.js │ ├── developer-reference.js │ ├── docs │ │ └── [slug].js │ └── index.js ├── possibleTypes.json ├── postcss.config.js ├── prettier.config.js ├── public │ ├── application-data-graph.png │ ├── categories-delete-not-allowed.png │ ├── categories-delete-success.png │ ├── categories-mutation-create-not-allowed.png │ ├── categories-mutation-create-success.png │ ├── categories-mutation-update-not-allowed.png │ ├── categories-mutation-update-success.png │ ├── categories-query-by-global-id.png │ ├── categories-query-edges-nodes.png │ ├── categories-query-nodes.png │ ├── comments-mutation-closed-failure.png │ ├── comments-mutation-delete-denied.png │ ├── comments-mutation-delete.png │ ├── comments-mutation-duplicate-error.png │ ├── comments-mutation-not-allowed.png │ ├── comments-mutation-public-user.png │ ├── comments-mutation-restore-not-allowed.png │ ├── comments-mutation-restore-success.png │ ├── comments-mutation-success.png │ ├── comments-query-post.png │ ├── connections-graph.png │ ├── data-graph-category-term-connections.png │ ├── data-graph-category-terms-connection-complex.png │ ├── data-graph-category-terms.png │ ├── data-graph-hello-world.png │ ├── data-graph-query-filter.png │ ├── debugging-graphql-query-logs.png │ ├── debugging-graphql-response.png │ ├── debugging-graphql-trace-log.png │ ├── debugging-graphql-unexpected-token.png │ ├── debugging-output-graphql-debug.png │ ├── debugging-setting-enable-graphql-query-logs.png │ ├── debugging-setting-enable-graphql.png │ ├── debugging-setting-graphql-enable-tracing.png │ ├── debugging-unexpected-token.gif │ ├── extension-graphiql-explorer-custom-type.png │ ├── extension-graphiql-explorer-search.png │ ├── extension-query-custom-field.png │ ├── extension-query-custom-type.png │ ├── extension-wordpress-admin-screen.png │ ├── extension-wordpress-plugin-dir.png │ ├── extension-wordpress-plugin-filename.png │ ├── favicon.ico │ ├── graphiql-auth-switch.gif │ ├── graphiql-full-window-mode.gif │ ├── graphiql-ide-screenshot.png │ ├── graphiql-query-composer.gif │ ├── graphiql-query-posts.png │ ├── interacting-fetch-graphql-from-browser-console-1024x619.gif │ ├── interacting-wordpress-admin-graphiql.png │ ├── intro-graphql-MenuItems.gif │ ├── intro-graphql-fragments.png │ ├── logo-wpgraphql.png │ ├── logo-wpgraphql.svg │ ├── logos │ │ ├── logo-angular.png │ │ ├── logo-apollo.png │ │ ├── logo-credit-karma.png │ │ ├── logo-denverpost.svg │ │ ├── logo-dfuzr.png │ │ ├── logo-ember.png │ │ ├── logo-funkhaus.png │ │ ├── logo-gatsby.png │ │ ├── logo-harness.png │ │ ├── logo-hope-lab.png │ │ ├── logo-nevernull.webp │ │ ├── logo-nextjs.png │ │ ├── logo-players-tribune.png │ │ ├── logo-quartz.jpg │ │ ├── logo-react.png │ │ ├── logo-svelte.png │ │ ├── logo-twincities.png │ │ ├── logo-valu-digital.png │ │ ├── logo-vue.png │ │ ├── logo-webdev-studios.png │ │ ├── logo-zeek.svg │ │ └── logo-zillow.png │ ├── media-query-by-global-id.png │ ├── media-query-by-source-url.png │ ├── media-query-items.png │ ├── media-query-post-featured-image.png │ ├── menus-query-by-global-id.png │ ├── menus-query-by-name.png │ ├── menus-query-filter-location.png │ ├── menus-query-items.png │ ├── plugins-query-authenticated.png │ ├── plugins-query-global-id.png │ ├── plugins-query-id-without-access.png │ ├── plugins-query-unauthenticated.png │ ├── posts-mutation-create-not-allowed.png │ ├── posts-mutation-create-success.png │ ├── posts-mutation-delete-not-allowed.png │ ├── posts-mutation-delete-success.png │ ├── posts-mutation-update-not-allowed.png │ ├── posts-mutation-update-success.png │ ├── posts-query-by-database-id.png │ ├── posts-query-by-global-id.png │ ├── posts-query-by-slug.png │ ├── posts-query-by-uri.png │ ├── posts-query-edges-node.png │ ├── posts-query-filter-by-author.png │ ├── posts-query-filter-by-keyword.png │ ├── posts-query-filter-by-title.png │ ├── posts-query-nodes.png │ ├── query-multiple-root-resources.png │ ├── query-posts.png │ ├── query-with-graphql.png │ ├── quick-graphiql-ide-wordpress.png │ ├── quick-graphiql-ide.png │ ├── quick-graphiql-search-posts.gif │ ├── quick-wp-graphql-first-query.gif │ ├── settings-mutation-authorized.png │ ├── settings-mutation-not-authorized.png │ ├── settings-wordpress-general-page-title.png │ ├── tags-query-by-name.png │ ├── tags-query-by-uri.png │ ├── tags-query-nodes.png │ ├── testing-codeception-screenshot.png │ ├── themes-authenticated-user.png │ ├── themes-not-authenticated-user.png │ ├── users-create-success.png │ ├── users-create-user-unsuccessful.png │ ├── users-delete-success.png │ ├── users-delete-unsuccessful.png │ ├── users-mutation-register-disabled.png │ ├── users-mutation-register-success.png │ ├── users-mutation-reset-password-invalid.png │ ├── users-query-by-global-id.png │ ├── users-query.png │ ├── users-registration-email.png │ ├── users-update-success.png │ ├── users-update-unsuccessful.png │ ├── users-wordpress-new-password.png │ ├── users-wordpress-reset-password.png │ ├── vercel.svg │ ├── wpgraphql-acf-search-schema.gif │ ├── wpgraphql-nested-query.gif │ ├── wpgraphql-query-100-posts-graphql.png │ ├── wpgraphql-query-100-posts-rest.png │ ├── wpgraphql-query-acf-flex.gif │ ├── wpgraphql-query-batch-postman.png │ ├── wpgraphql-query-github.png │ ├── wpgraphql-query-multiple-resources.png │ ├── wpgraphql-query-types-fields.png │ ├── wpgraphql-wordpress-dashboard.png │ └── wpgraphql-wordpress-rest-api-acf.png ├── redirects.json ├── scripts │ ├── build-rss.js │ └── getPossibleTypes.js ├── styles │ ├── Home.module.css │ └── globals.css ├── tailwind.config.js ├── templates │ ├── Archive │ │ └── Archive.js │ ├── Author │ │ └── Author.js │ ├── Category │ │ └── Category.js │ ├── Index │ │ └── Index.js │ ├── SingleRecipe │ │ └── SingleRecipe.js │ └── Singular │ │ └── Singular.js ├── wp-next │ ├── README.md │ ├── index.js │ └── template.js └── yarn.lock └── remix-run ├── .eslintrc ├── .gitignore ├── .nvmrc ├── README.md ├── app ├── WordPressNode.jsx ├── context │ └── apollo.js ├── entry.client.jsx ├── entry.server.jsx ├── root.jsx ├── routes │ ├── $.jsx │ ├── blog.jsx │ ├── developer-reference.jsx │ └── index.jsx └── styles │ └── app.css ├── components ├── DocsLayout │ └── DocsLayout.js ├── DocsNav │ └── DocsNav.js ├── DynamicHeroIcon │ └── DynamicHeroIcon.js ├── Heading │ └── Heading.js ├── HomepageCta │ └── HomepageCta.js ├── HomepageFeatures │ └── HomepageFeatures.js ├── HomepageFrameworks │ └── HomepageFrameworks.js ├── HomepageHero │ └── HomepageHero.js ├── HomepageTrust │ └── HomepageTrust.js ├── PostPreview │ └── PostPreview.js ├── SiteFooter │ └── SiteFooter.js ├── SiteHeader │ └── SiteHeader.js ├── SiteLayout │ └── SiteLayout.js ├── SiteLogo │ └── SiteLogo.js ├── TableOfContents │ └── TableOfContents.js └── ThemeToggle │ └── ThemeToggle.js ├── hooks └── useIsomorphicLayoutEffect.js ├── jsconfig.json ├── lib ├── data │ └── apollo.js ├── helpers │ ├── flatListToHierarchical.js │ └── parse-docs.js └── mdx │ └── components.js ├── package.json ├── possibleTypes.json ├── public ├── application-data-graph.png ├── categories-delete-not-allowed.png ├── categories-delete-success.png ├── categories-mutation-create-not-allowed.png ├── categories-mutation-create-success.png ├── categories-mutation-update-not-allowed.png ├── categories-mutation-update-success.png ├── categories-query-by-global-id.png ├── categories-query-edges-nodes.png ├── categories-query-nodes.png ├── comments-mutation-closed-failure.png ├── comments-mutation-delete-denied.png ├── comments-mutation-delete.png ├── comments-mutation-duplicate-error.png ├── comments-mutation-not-allowed.png ├── comments-mutation-public-user.png ├── comments-mutation-restore-not-allowed.png ├── comments-mutation-restore-success.png ├── comments-mutation-success.png ├── comments-query-post.png ├── connections-graph.png ├── data-graph-category-term-connections.png ├── data-graph-category-terms-connection-complex.png ├── data-graph-category-terms.png ├── data-graph-hello-world.png ├── data-graph-query-filter.png ├── debugging-graphql-query-logs.png ├── debugging-graphql-response.png ├── debugging-graphql-trace-log.png ├── debugging-graphql-unexpected-token.png ├── debugging-output-graphql-debug.png ├── debugging-setting-enable-graphql-query-logs.png ├── debugging-setting-enable-graphql.png ├── debugging-setting-graphql-enable-tracing.png ├── debugging-unexpected-token.gif ├── extension-graphiql-explorer-custom-type.png ├── extension-graphiql-explorer-search.png ├── extension-query-custom-field.png ├── extension-query-custom-type.png ├── extension-wordpress-admin-screen.png ├── extension-wordpress-plugin-dir.png ├── extension-wordpress-plugin-filename.png ├── favicon.ico ├── graphiql-auth-switch.gif ├── graphiql-full-window-mode.gif ├── graphiql-ide-screenshot.png ├── graphiql-query-composer.gif ├── graphiql-query-posts.png ├── interacting-fetch-graphql-from-browser-console-1024x619.gif ├── interacting-wordpress-admin-graphiql.png ├── intro-graphql-MenuItems.gif ├── intro-graphql-fragments.png ├── logo-wpgraphql.png ├── logo-wpgraphql.svg ├── logos │ ├── logo-angular.png │ ├── logo-apollo.png │ ├── logo-credit-karma.png │ ├── logo-denverpost.svg │ ├── logo-dfuzr.png │ ├── logo-ember.png │ ├── logo-funkhaus.png │ ├── logo-gatsby.png │ ├── logo-harness.png │ ├── logo-hope-lab.png │ ├── logo-nevernull.webp │ ├── logo-nextjs.png │ ├── logo-players-tribune.png │ ├── logo-quartz.jpg │ ├── logo-react.png │ ├── logo-svelte.png │ ├── logo-twincities.png │ ├── logo-valu-digital.png │ ├── logo-vue.png │ ├── logo-webdev-studios.png │ ├── logo-zeek.svg │ └── logo-zillow.png ├── media-query-by-global-id.png ├── media-query-by-source-url.png ├── media-query-items.png ├── media-query-post-featured-image.png ├── menus-query-by-global-id.png ├── menus-query-by-name.png ├── menus-query-filter-location.png ├── menus-query-items.png ├── plugins-query-authenticated.png ├── plugins-query-global-id.png ├── plugins-query-id-without-access.png ├── plugins-query-unauthenticated.png ├── posts-mutation-create-not-allowed.png ├── posts-mutation-create-success.png ├── posts-mutation-delete-not-allowed.png ├── posts-mutation-delete-success.png ├── posts-mutation-update-not-allowed.png ├── posts-mutation-update-success.png ├── posts-query-by-database-id.png ├── posts-query-by-global-id.png ├── posts-query-by-slug.png ├── posts-query-by-uri.png ├── posts-query-edges-node.png ├── posts-query-filter-by-author.png ├── posts-query-filter-by-keyword.png ├── posts-query-filter-by-title.png ├── posts-query-nodes.png ├── query-multiple-root-resources.png ├── query-posts.png ├── query-with-graphql.png ├── quick-graphiql-ide-wordpress.png ├── quick-graphiql-ide.png ├── quick-graphiql-search-posts.gif ├── quick-wp-graphql-first-query.gif ├── settings-mutation-authorized.png ├── settings-mutation-not-authorized.png ├── settings-wordpress-general-page-title.png ├── tags-query-by-name.png ├── tags-query-by-uri.png ├── tags-query-nodes.png ├── testing-codeception-screenshot.png ├── themes-authenticated-user.png ├── themes-not-authenticated-user.png ├── users-create-success.png ├── users-create-user-unsuccessful.png ├── users-delete-success.png ├── users-delete-unsuccessful.png ├── users-mutation-register-disabled.png ├── users-mutation-register-success.png ├── users-mutation-reset-password-invalid.png ├── users-query-by-global-id.png ├── users-query.png ├── users-registration-email.png ├── users-update-success.png ├── users-update-unsuccessful.png ├── users-wordpress-new-password.png ├── users-wordpress-reset-password.png ├── vercel.svg ├── wpgraphql-acf-search-schema.gif ├── wpgraphql-nested-query.gif ├── wpgraphql-query-100-posts-graphql.png ├── wpgraphql-query-100-posts-rest.png ├── wpgraphql-query-acf-flex.gif ├── wpgraphql-query-batch-postman.png ├── wpgraphql-query-github.png ├── wpgraphql-query-multiple-resources.png ├── wpgraphql-query-types-fields.png ├── wpgraphql-wordpress-dashboard.png └── wpgraphql-wordpress-rest-api-acf.png ├── remix.config.js ├── scripts ├── build-rss.js └── getPossibleTypes.js ├── server.js ├── styles └── app.css ├── tailwind.config.js ├── templates ├── Archive │ └── Archive.js ├── Author │ └── Author.js ├── Category │ └── Category.js ├── Index │ └── Index.js └── Singular │ └── Singular.js ├── vercel.json ├── wp-remix ├── README.md ├── index.js └── template.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | remix-run/old 3 | remix-run/cache 4 | remix-run/build 5 | remix-run/public -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WPGraphQL Template Hierarchy Debugger 2 | 3 | This is a project to demonstrate how to re-create the WordPress template hierarchy with Headless WordPress using WPGraphQL. 4 | 5 | ## Examples 6 | 7 | - Express.js (see the `/express` directory) 8 | - Gatsby.js (future) 9 | - NextJS (future) 10 | - Remix Run (future) 11 | -------------------------------------------------------------------------------- /express/README.md: -------------------------------------------------------------------------------- 1 | # Express JS - WordPress Template Hierarchy 2 | 3 | This project shows how ExpressJS can be used to re-create the WordPress template hierarchy using WPGraphQL. 4 | 5 | ## Run the app 6 | 7 | 1. Install dependencies by running `npm install` or `yarn` 8 | 2. Run the app by running `npm run start` or `yarn start` 9 | 3. Visit `http://localhost:3000` in your browser. 10 | 11 | You should see something like so: 12 | 13 | ![Screenshot of the Express App](./docs/img/express-app.png) 14 | 15 | ## Use the App 16 | 17 | Copy the path of any resource from demo.wpgraphql.com and add it as the path to `localhost:3000`. 18 | 19 | For example, take the path for the blog post at 20 | `https://demo.wpgraphql.com/blog/tiled-gallery/` 21 | 22 | and enter it into your browser like so: 23 | 24 | `http://localhost:3000/blog/tiled-gallery/` 25 | 26 | You should see the template hierarchy for this path, like so: 27 | 28 | ![Screenshot of the Express App being used](./docs/img/usage-screenshot.png) 29 | -------------------------------------------------------------------------------- /express/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | compact: true, 3 | presets: [ 4 | [ 5 | '@babel/env', 6 | { 7 | modules: false, 8 | targets: { 9 | node: 'current', 10 | }, 11 | }, 12 | ], 13 | '@babel/react', 14 | '@babel/typescript', 15 | ], 16 | plugins: [ 17 | '@babel/proposal-object-rest-spread', 18 | '@babel/proposal-class-properties', 19 | '@babel/proposal-optional-chaining', 20 | '@babel/syntax-dynamic-import', 21 | 'macros', 22 | ], 23 | env: { 24 | test: { 25 | plugins: [ 26 | '@babel/transform-modules-commonjs', 27 | '@babel/syntax-dynamic-import', 28 | '@babel/plugin-transform-runtime', 29 | ], 30 | }, 31 | }, 32 | }; -------------------------------------------------------------------------------- /express/docs/img/express-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonbahl/headless-wp-template-hierarchy/1a489a4e2e40b62af454c0f76e3720b7871e78e7/express/docs/img/express-app.png -------------------------------------------------------------------------------- /express/docs/img/usage-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonbahl/headless-wp-template-hierarchy/1a489a4e2e40b62af454c0f76e3720b7871e78e7/express/docs/img/usage-screenshot.png -------------------------------------------------------------------------------- /express/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wp-express", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "nodemon app.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "express": "^4.17.1", 14 | "node-fetch": "^2.6.6", 15 | "nodemon": "^2.0.15", 16 | "whatwg-fetch": "^3.6.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /express/templates/index.js: -------------------------------------------------------------------------------- 1 | const Index = () => { 2 | return ( 3 |
Index Template!
4 | ) 5 | } 6 | 7 | export default Index; -------------------------------------------------------------------------------- /faust/.env.local.sample: -------------------------------------------------------------------------------- 1 | # Your WordPress site URL 2 | NEXT_PUBLIC_WORDPRESS_URL=https://headlessfw.wpengine.com 3 | 4 | # Plugin secret found in WordPress Settings->Headless 5 | FAUSTWP_SECRET_KEY=YOUR_PLUGIN_SECRET 6 | -------------------------------------------------------------------------------- /faust/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next" 3 | } 4 | -------------------------------------------------------------------------------- /faust/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # dotenv files 28 | .env 29 | .env.test 30 | .env.production 31 | .env.local 32 | .env.development.local 33 | .env.test.local 34 | .env.production.local 35 | 36 | # vercel 37 | .vercel 38 | -------------------------------------------------------------------------------- /faust/README.md: -------------------------------------------------------------------------------- 1 | # FaustJS 2 | 3 | NOTE: I wasn't able to get this to a working state yet. use at your own risk. -------------------------------------------------------------------------------- /faust/gqty.config.js: -------------------------------------------------------------------------------- 1 | require('dotenv-flow').config(); 2 | 3 | /** 4 | * @type {import("@gqty/cli").GQtyConfig} 5 | */ 6 | const config = { 7 | react: false, 8 | scalarTypes: { DateTime: 'string' }, 9 | introspection: { 10 | endpoint: `${process.env.NEXT_PUBLIC_WORDPRESS_URL}/graphql`, 11 | headers: {}, 12 | }, 13 | destination: './src/client/index.ts', 14 | subscriptions: false, 15 | javascriptOutput: false, 16 | }; 17 | 18 | console.log(`Using "${config.introspection.endpoint}" to generate schema...`); 19 | 20 | module.exports = config; 21 | -------------------------------------------------------------------------------- /faust/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /faust/next.config.js: -------------------------------------------------------------------------------- 1 | const { withFaust } = require('@faustjs/next'); 2 | 3 | /** 4 | * @type {import('next').NextConfig} 5 | **/ 6 | module.exports = withFaust(); 7 | -------------------------------------------------------------------------------- /faust/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "next-headless-getting-started", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "clean": "rimraf .next node_modules", 10 | "lint": "next lint", 11 | "generate": "gqty generate", 12 | "wpe-build": "next build" 13 | }, 14 | "dependencies": { 15 | "@faustjs/core": "^0.15.1", 16 | "@faustjs/next": "^0.15.1", 17 | "next": "^12.0.7", 18 | "normalize.css": "^8.0.1", 19 | "react": "^17.0.2", 20 | "react-dom": "^17.0.2", 21 | "sass": "^1.44.0" 22 | }, 23 | "devDependencies": { 24 | "@gqty/cli": "^2.3.1", 25 | "@types/react": "^17.0.37", 26 | "dotenv-flow": "3.2.0", 27 | "eslint": "^8.4.1", 28 | "eslint-config-next": "^12.0.7", 29 | "rimraf": "^3.0.2", 30 | "typescript": "^4.5.2" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /faust/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonbahl/headless-wp-template-hierarchy/1a489a4e2e40b62af454c0f76e3720b7871e78e7/faust/public/favicon.ico -------------------------------------------------------------------------------- /faust/public/images/headless_hero_background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jasonbahl/headless-wp-template-hierarchy/1a489a4e2e40b62af454c0f76e3720b7871e78e7/faust/public/images/headless_hero_background.jpg -------------------------------------------------------------------------------- /faust/src/client/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * GQTY: You can safely modify this file and Query Fetcher based on your needs 3 | */ 4 | import type { IncomingMessage } from 'http'; 5 | import { getClient } from '@faustjs/next'; 6 | import { 7 | generatedSchema, 8 | scalarsEnumsHash, 9 | GeneratedSchema, 10 | SchemaObjectTypes, 11 | SchemaObjectTypesNames, 12 | } from './schema.generated'; 13 | 14 | export const client = getClient< 15 | GeneratedSchema, 16 | SchemaObjectTypesNames, 17 | SchemaObjectTypes 18 | >({ 19 | schema: generatedSchema, 20 | scalarsEnumsHash, 21 | }); 22 | 23 | export function serverClient(req: IncomingMessage) { 24 | return getClient({ 25 | schema: generatedSchema, 26 | scalarsEnumsHash, 27 | context: req, 28 | }); 29 | } 30 | 31 | export * from './schema.generated'; 32 | -------------------------------------------------------------------------------- /faust/src/components/CTA.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from 'scss/components/CTA.module.scss'; 3 | import Heading, { HeadingProps } from './Heading'; 4 | 5 | interface Props { 6 | title: string; 7 | buttonText?: string; 8 | buttonURL?: string; 9 | children?: React.ReactNode; 10 | headingLevel?: HeadingProps['level']; 11 | } 12 | 13 | function CTA({ 14 | title = 'Get in touch', 15 | buttonText, 16 | buttonURL, 17 | children, 18 | headingLevel = 'h1', 19 | }: Props): JSX.Element { 20 | return ( 21 |
22 |
23 | 24 | {title} 25 | 26 |
27 |
{children}
28 | {buttonText && buttonURL && ( 29 | 34 | )} 35 |
36 |
37 |
38 | ); 39 | } 40 | 41 | export default CTA; 42 | -------------------------------------------------------------------------------- /faust/src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from 'scss/components/Footer.module.scss'; 3 | 4 | interface Props { 5 | copyrightHolder?: string; 6 | } 7 | 8 | function Footer({ copyrightHolder = 'Company Name' }: Props): JSX.Element { 9 | const year = new Date().getFullYear(); 10 | 11 | return ( 12 |
13 |
14 |

{`© ${year} ${copyrightHolder}. All rights reserved.`}

15 |
16 |
17 | ); 18 | } 19 | 20 | export default Footer; 21 | -------------------------------------------------------------------------------- /faust/src/components/Heading.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | // HeadingProps constrains headings to levels h1-h6. 4 | interface HeadingProps extends React.HTMLAttributes { 5 | level: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6'; 6 | } 7 | 8 | // Heading allows components to pass a heading level via props. 9 | function Heading({ 10 | level = 'h1', 11 | children, 12 | className, 13 | }: HeadingProps): JSX.Element { 14 | const H = ({ ...props }: React.HTMLAttributes) => 15 | React.createElement(level, props, children); 16 | 17 | return {children}; 18 | } 19 | 20 | export default Heading; 21 | export type { HeadingProps }; 22 | -------------------------------------------------------------------------------- /faust/src/components/Hero.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from 'scss/components/Hero.module.scss'; 3 | 4 | interface Props { 5 | title: string; 6 | id?: string; 7 | bgImage?: string; 8 | buttonText?: string; 9 | buttonURL?: string; 10 | button2Text?: string; 11 | button2URL?: string; 12 | children?: React.ReactNode; 13 | } 14 | 15 | function Hero({ 16 | title = 'Hero Title', 17 | id, 18 | bgImage, 19 | buttonText, 20 | buttonURL, 21 | button2Text, 22 | button2URL, 23 | children, 24 | }: Props): JSX.Element { 25 | return ( 26 |
31 |
32 |

{title}

33 |
34 |
{children}
35 | {buttonText && buttonURL && ( 36 |

37 | 38 | {buttonText} 39 | 40 |

41 | )} 42 | {button2Text && button2URL && ( 43 |

44 | 45 | {button2Text} 46 | 47 |

48 | )} 49 |
50 |
51 |
52 | ); 53 | } 54 | 55 | export default Hero; 56 | -------------------------------------------------------------------------------- /faust/src/components/Pagination.tsx: -------------------------------------------------------------------------------- 1 | import Link from 'next/link'; 2 | import type { WPPageInfo } from 'client'; 3 | 4 | interface NextPageNavigationProps { 5 | href: string; 6 | } 7 | 8 | function NextPageNavigation(props: NextPageNavigationProps) { 9 | return ( 10 | 11 | Next Page → 12 | 13 | ); 14 | } 15 | 16 | interface PreviousPageNavigationProps { 17 | href: string; 18 | } 19 | 20 | function PreviousPageNavigation(props: PreviousPageNavigationProps) { 21 | return ( 22 | 23 | ← Previous Page 24 | 25 | ); 26 | } 27 | 28 | export interface PaginationProps { 29 | pageInfo: WPPageInfo; 30 | basePath: string; 31 | } 32 | 33 | export default function Pagination({ pageInfo, basePath }: PaginationProps) { 34 | const previousPageUrl = `${basePath}/before/${pageInfo?.startCursor}`; 35 | const nextPageUrl = `${basePath}/after/${pageInfo?.endCursor}`; 36 | 37 | return ( 38 | 55 | ); 56 | } 57 | -------------------------------------------------------------------------------- /faust/src/components/index.ts: -------------------------------------------------------------------------------- 1 | import CTA from './CTA'; 2 | import Footer from './Footer'; 3 | import Header from './Header'; 4 | import Hero from './Hero'; 5 | import Posts from './Posts'; 6 | import Pagination from './Pagination'; 7 | 8 | export { CTA, Footer, Header, Hero, Posts, Pagination }; 9 | -------------------------------------------------------------------------------- /faust/src/faust.config.js: -------------------------------------------------------------------------------- 1 | import { config as coreConfig } from '@faustjs/core'; 2 | 3 | if (!process.env.NEXT_PUBLIC_WORDPRESS_URL) { 4 | console.error( 5 | 'You must provide a NEXT_PUBLIC_WORDPRESS_URL environment variable, did you forget to load your .env.local file?', 6 | ); 7 | } 8 | 9 | /** 10 | * @type {import("@faustjs/core").Config} 11 | */ 12 | export default coreConfig({ 13 | wpUrl: process.env.NEXT_PUBLIC_WORDPRESS_URL, 14 | apiClientSecret: process.env.FAUSTWP_SECRET_KEY, 15 | }); 16 | -------------------------------------------------------------------------------- /faust/src/lib/utils/flatListToHierarchical.js: -------------------------------------------------------------------------------- 1 | export const flatListToHierarchical = ( 2 | data = [], 3 | {idKey='key',parentKey='parentId',childrenKey='children'} = {} 4 | ) => { 5 | const tree = []; 6 | const childrenOf = {}; 7 | data.forEach((item) => { 8 | const newItem = {...item}; 9 | const { [idKey]: id, [parentKey]: parentId = 0 } = newItem; 10 | childrenOf[id] = childrenOf[id] || []; 11 | newItem[childrenKey] = childrenOf[id]; 12 | parentId 13 | ? ( 14 | childrenOf[parentId] = childrenOf[parentId] || [] 15 | ).push(newItem) 16 | : tree.push(newItem); 17 | }); 18 | return tree; 19 | }; -------------------------------------------------------------------------------- /faust/src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { client } from 'client'; 3 | import { Header, Hero, Footer } from '../components'; 4 | 5 | export default function Page(): JSX.Element { 6 | const { useQuery } = client; 7 | const generalSettings = useQuery().generalSettings; 8 | 9 | return ( 10 | <> 11 |
15 |
16 | 17 |
18 |
19 |
20 |

21 | The page you were looking for does not exist or is no longer 22 | available. 23 |

24 |
25 |
26 |
27 |
28 |