diff --git a/examples/next/woocommerce/.wp-env.json b/examples/next/woocommerce/.wp-env.json new file mode 100644 index 00000000..e977541a --- /dev/null +++ b/examples/next/woocommerce/.wp-env.json @@ -0,0 +1,37 @@ +{ + "phpVersion": "8.0", + "plugins": [ + "https://github.com/wp-graphql/wp-graphql/releases/latest/download/wp-graphql.zip", + "https://github.com/AxeWP/wp-graphql-headless-login/releases/latest/download/wp-graphql-headless-login.zip", + "https://github.com/woocommerce/woocommerce/releases/latest/download/woocommerce.zip", + "https://downloads.wordpress.org/plugin/wpgraphql-ide.latest-stable.zip", + "https://github.com/wp-graphql/wp-graphql-woocommerce/releases/download/v0.21.2/wp-graphql-woocommerce.zip" + ], + "themes": [ + "https://downloads.wordpress.org/theme/storefront.latest-stable.zip" + ], + "env": { + "development": { + "port": 8890 + }, + "tests": { + "port": 8891 + } + }, + "config": { + "WP_DEBUG": true, + "SCRIPT_DEBUG": false, + "GRAPHQL_DEBUG": true, + "WP_DEBUG_LOG": true, + "WP_DEBUG_DISPLAY": false, + "SAVEQUERIES": false + }, + "mappings": { + "db": "./wp-env/db", + "wp-content/uploads": "./wp-env/uploads", + ".htaccess": "./wp-env/setup/.htaccess" + }, + "lifecycleScripts": { + "afterStart": "wp-env run cli -- wp rewrite structure '/%postname%/' && wp-env run cli -- wp rewrite flush" + } +} diff --git a/examples/next/woocommerce/README.md b/examples/next/woocommerce/README.md new file mode 100644 index 00000000..b7440d61 --- /dev/null +++ b/examples/next/woocommerce/README.md @@ -0,0 +1,164 @@ +# Next.js WooCommerce example - template hierarchy, data fetching and authentication with Apollo +This example demonstrates a complete headless WooCommerce solution with Next.js, showcasing essential e-commerce functionality including shopping cart management, checkout flow, and user authentication. Built with WordPress template hierarchy and modern data fetching patterns using both native fetch and Apollo Client. + +## Features + +- **E-commerce Core**: Add to cart, remove items, checkout process, and thank you page +- **Authentication**: Username/password login in headless WordPress environment +- **Template Hierarchy**: WordPress template system integration with Next.js +- **Data Fetching**: Dual approach with native fetch and Apollo Client +- **GraphQL Integration**: Powered by WPGraphQL, WPGraphQL Headless Login, and WooGraphQL plugins + +## Screenshots + +After following the installation steps, you should have the example webpage as shown in the screenshots below: + +| | | +| :---------------------------------------------: | :--------------------------------------------------------: | +| ![login](./screenshots/login.png)
Login page | ![logged](./screenshots/logged.png "Posts")
After login | + +## Project Structure + +``` +. +├── example-app/ # Next.js application folder containing frontend code +│ └── src/ +│ ├── components/ # Reusable React components +│ ├── lib/ # Apollo Client configuration, client and helpers +│ └── pages/ # Next.js page routes +│ └── wp-templates/ # Next.js WordPress template hierarchy +├── .wp-env.json # wp-env configuration file +└── wp-env + └── db + └── database.sql # WordPress database including all demo data for the example +``` + +## Quick Start with wp-env + +### Prerequisites + +- Node.js (v18+ recommended) +- [Docker](https://www.docker.com/) (required for wp-env) + +**Note:** Ensure Docker is running (`docker ps`) before proceeding. + +### Setup Repository and Packages + +1. Clone the repository: + ```bash + git clone https://github.com/wpengine/hwptoolkit.git + ``` + +2. Install dependencies: + ```bash + cd hwptoolkit && npm install + ``` + +3. Configure environment variables: + ```bash + echo "NEXT_PUBLIC_WORDPRESS_URL=http://localhost:8890" > examples/next/woocommerce/example-app/.env + ``` + +### Build and Start the Application + +1. Navigate to the example directory: + ```bash + cd examples/next/woocommerce + ``` + +2. Build and start everything: + ```bash + npm run example:build + ``` + +This command will: +- Start [wp-env](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-env/) +- Import the database from [wp-env/db/database.sql](wp-env/db/database.sql) +- Install Next.js dependencies +- Start the development server + +### Access Your Application + +| Frontend | Admin | +| ------------------------------------------------ | ------------------------------------------------------------------ | +| [http://localhost:3000/](http://localhost:3000/) | [http://localhost:8890/wp-admin/](http://localhost:8890/wp-admin/) | + +> **Admin Credentials:** Username: `admin` | Password: `password` + +### Command Reference + +| Command | Description | +| --------------------- | ----------------------------------------------------------------------------------------------------------------------- | +| `example:build` | Prepares the environment by starting WordPress, importing the database, and starting the application. | +| `example:dev` | Runs the Next.js development server. | +| `example:dev:install` | Installs the required Next.js packages. | +| `example:start` | Starts WordPress and the Next.js development server. | +| `example:stop` | Stops the WordPress environment. | +| `example:prune` | Rebuilds and restarts the application by destroying and recreating the WordPress environment. | +| `wp:start` | Starts the WordPress environment. | +| `wp:stop` | Stops the WordPress environment. | +| `wp:destroy` | Completely removes the WordPress environment. | +| `wp:db:query` | Executes a database query within the WordPress environment. | +| `wp:db:export` | Exports the WordPress database to `wp-env/db/database.sql`. | +| `wp:db:import` | Imports the WordPress database from `wp-env/db/database.sql`. | + +> **Tip:** Run `npm run wp-env` for additional wp-env commands. See the [official documentation](https://www.npmjs.com/package/@wordpress/env) for more details. + +### Database Access + +To access the database via phpMyAdmin, add this to your wp-env configuration: +```json +"phpmyadminPort": 11111 +``` + +Check if port 11111 is available: `lsof -i :11111` + +## Manual WordPress Setup + +### Prerequisites + +- **Node.js** (v18+ recommended) +- **Package manager**: npm, yarn, pnpm, or bun +- **WordPress instance** with required plugins with php 8.0 due to WPGraphQL for WooCommerce + +### Required WordPress Plugins + +Install and activate these plugins in your WordPress admin: + +1. **WPGraphQL** - Exposes WordPress data via GraphQL +2. **WPGraphQL Headless Login** - Enables authentication for headless setups +3. **WPGraphQL for WooCommerce (WooGraphQL)** - Adds WooCommerce GraphQL support + +### Plugin Configuration + +1. Navigate to **GraphQL** → **Settings** in your WordPress admin +2. Under **WPGraphQL Headless Login**, enable **Credentials Authentication** +3. When installing WooCommerce no extra additional plugins or add-ons are required. +4. [Optional] Go in WP Admin -> All Products -> Import and use the `sample_products.csv` from `/wp-env/` folder. + + + ![Enable Credentials Authentication](./screenshots/enable-credentials-auth.png) + +### Environment Setup + +Create a `.env` file in the `example-app` directory: + +```env +NEXT_PUBLIC_WORDPRESS_URL=https://your-wordpress-site.com +``` + +> **Important:** Use your actual WordPress URL without a trailing slash. + +### Getting Started + +1. **Install dependencies:** + ```bash + npm install + # or yarn install / pnpm install / bun install + ``` + +2. **Start development server:** + ```bash + npm run dev + # or yarn dev / pnpm dev / bun dev + ``` diff --git a/examples/next/woocommerce/example-app/.gitignore b/examples/next/woocommerce/example-app/.gitignore new file mode 100644 index 00000000..2629d477 --- /dev/null +++ b/examples/next/woocommerce/example-app/.gitignore @@ -0,0 +1,43 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +package-lock.json diff --git a/examples/next/woocommerce/example-app/codegen.ts b/examples/next/woocommerce/example-app/codegen.ts new file mode 100644 index 00000000..94d63426 --- /dev/null +++ b/examples/next/woocommerce/example-app/codegen.ts @@ -0,0 +1,32 @@ +import type { CodegenConfig } from "@graphql-codegen/cli"; +import dotenv from "dotenv"; +import path from 'path'; +dotenv.config({path: path.resolve(process.cwd(), '.env.local')}); + +const baseUrl = + process.env.NEXT_PUBLIC_WORDPRESS_URL || "https://your-wordpress-site.com"; +const graphqlPath = process.env.NEXT_PUBLIC_GRAPHQL_PATH || "/graphql"; +const introspectionToken = process.env.GRAPHQL_INTROSPECTION_TOKEN || ""; + +const config: CodegenConfig = { + schema: [ + { + [`${baseUrl}${graphqlPath}`]: { + headers: { + Authorization: introspectionToken, + }, + }, + }, + ], + documents: ["src/**/*.jsx"], + generates: { + "possibleTypes.json": { + plugins: ["fragment-matcher"], + config: { + module: "commonjs", + apolloClientVersion: 3, + }, + }, + }, +}; +export default config; diff --git a/examples/next/woocommerce/example-app/components.json b/examples/next/woocommerce/example-app/components.json new file mode 100644 index 00000000..6ba0a554 --- /dev/null +++ b/examples/next/woocommerce/example-app/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": false, + "tailwind": { + "config": "", + "css": "src/styles/globals.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/examples/next/woocommerce/example-app/disable-introspection-with-token.code-snippets.json b/examples/next/woocommerce/example-app/disable-introspection-with-token.code-snippets.json new file mode 100644 index 00000000..da020267 --- /dev/null +++ b/examples/next/woocommerce/example-app/disable-introspection-with-token.code-snippets.json @@ -0,0 +1,14 @@ +{ + "generator": "Code Snippets v3.6.8", + "date_created": "2025-03-06 10:59", + "snippets": [ + { + "id": 8, + "name": "disable-introspection-with-token", + "code": "use WPGraphQL\\Server\\ValidationRules\\DisableIntrospection as BaseDisableIntrospection;\n\nadd_filter('graphql_introspection_token', function () {\n return 'your-secure-introspection-token'; // PLEASE CHANGE ME!!!\n});\n\n/**\n * Class DisableIntrospectionRule\n *\n * Custom rule to disable GraphQL introspection unless a valid token is provided.\n */\nclass DisableIntrospectionRule extends BaseDisableIntrospection {\n public function __construct() {\n // Register the custom validation rule.\n add_filter('graphql_validation_rules', [$this, 'add_custom_validation_rule']);\n }\n\n /**\n * Adds the custom validation rule for disabling introspection.\n *\n * @param array $rules Existing validation rules.\n * @return array Modified validation rules.\n */\n public function add_custom_validation_rule(array $rules): array {\n $rules['disable_introspection'] = $this;\n return $rules;\n }\n\n /**\n * Determines if the introspection should be disabled.\n *\n * @return bool True if introspection should be disabled, false otherwise.\n */\n public function isEnabled(): bool {\n // Check if introspection is already allowed by parent rules\n $is_rule_enabled = parent::isEnabled();\n\n // If introspection is already allowed, there is no need for further checks\n if (!$is_rule_enabled) {\n return false;\n }\n\n // Retrieve the authorization header\n $introspection_token_header = isset($_SERVER['HTTP_AUTHORIZATION']) \n ? sanitize_text_field($_SERVER['HTTP_AUTHORIZATION']) \n : '';\n // If no token is provided, keep introspection disabled\n if (empty($introspection_token_header)) {\n return true;\n }\n\n // Retrieve the stored introspection token\n $introspection_token = apply_filters('graphql_introspection_token', '');\n\n // If no token is configured, keep introspection disabled\n if (empty($introspection_token)) {\n return true;\n }\n\n // Compare the provided token with the stored token\n return !hash_equals($introspection_token_header, $introspection_token);\n }\n}\n\n// Initialize the custom validation rule\nnew DisableIntrospectionRule();", + "active": true, + "modified": "2025-03-06 10:59:20", + "revision": "10" + } + ] +} \ No newline at end of file diff --git a/examples/next/woocommerce/example-app/eslint.config.mjs b/examples/next/woocommerce/example-app/eslint.config.mjs new file mode 100644 index 00000000..348c45a2 --- /dev/null +++ b/examples/next/woocommerce/example-app/eslint.config.mjs @@ -0,0 +1,14 @@ +import { dirname } from "path"; +import { fileURLToPath } from "url"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +const eslintConfig = [...compat.extends("next/core-web-vitals")]; + +export default eslintConfig; diff --git a/examples/next/woocommerce/example-app/jsconfig.json b/examples/next/woocommerce/example-app/jsconfig.json new file mode 100644 index 00000000..b8d6842d --- /dev/null +++ b/examples/next/woocommerce/example-app/jsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/examples/next/woocommerce/example-app/next.config.mjs b/examples/next/woocommerce/example-app/next.config.mjs new file mode 100644 index 00000000..4514853b --- /dev/null +++ b/examples/next/woocommerce/example-app/next.config.mjs @@ -0,0 +1,29 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + images: { + remotePatterns: [ + // Dev + { + protocol: "http", + hostname: "localhost", + port: "8890", + pathname: "/wp-content/uploads/**", + }, + { + protocol: "http", + hostname: "127.0.0.1", + port: "8890", + pathname: "/wp-content/uploads/**", + }, + // ✅ Production + { + protocol: "https", + hostname: "your-production-site.com", + pathname: "/wp-content/uploads/**", + }, + ], + }, +}; + +export default nextConfig; diff --git a/examples/next/woocommerce/example-app/package.json b/examples/next/woocommerce/example-app/package.json new file mode 100644 index 00000000..e5606288 --- /dev/null +++ b/examples/next/woocommerce/example-app/package.json @@ -0,0 +1,40 @@ +{ + "name": "apollo-authentication-example-app", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack", + "build": "next build", + "start": "next start", + "lint": "next lint", + "generate": "graphql-codegen" + }, + "dependencies": { + "@apollo/client": "3.13.1", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "crypto-hash": "^3.1.0", + "graphql": "16.10.0", + "lucide-react": "^0.477.0", + "next": "^15.2.4", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "sass": "^1.90.0", + "tailwind-merge": "^3.0.2", + "tailwindcss-animate": "^1.0.7" + }, + "devDependencies": { + "@babel/helpers": "^7.27.0", + "@eslint/eslintrc": "^3", + "@graphql-codegen/cli": "^5.0.5", + "@graphql-codegen/fragment-matcher": "^5.1.0", + "@tailwindcss/postcss": "^4", + "dotenv": "16.4.7", + "eslint": "^9", + "eslint-config-next": "15.2.0", + "tailwindcss": "^4" + }, + "resolutions": { + "@babel/runtime": "7.27.0" + } +} diff --git a/examples/next/woocommerce/example-app/possibleTypes.json b/examples/next/woocommerce/example-app/possibleTypes.json new file mode 100644 index 00000000..b3b212d9 --- /dev/null +++ b/examples/next/woocommerce/example-app/possibleTypes.json @@ -0,0 +1,1126 @@ +{ + "possibleTypes": { + "BlockWithSupportsAnchor": [ + "CoreAudio", + "CoreAudioAttributes", + "CoreButton", + "CoreButtonAttributes", + "CoreButtons", + "CoreButtonsAttributes", + "CoreCode", + "CoreCodeAttributes", + "CoreColumn", + "CoreColumnAttributes", + "CoreColumns", + "CoreColumnsAttributes", + "CoreCover", + "CoreCoverAttributes", + "CoreFile", + "CoreFileAttributes", + "CoreGallery", + "CoreGalleryAttributes", + "CoreGroup", + "CoreGroupAttributes", + "CoreHeading", + "CoreHeadingAttributes", + "CoreImage", + "CoreImageAttributes", + "CoreList", + "CoreListAttributes", + "CoreListItem", + "CoreListItemAttributes", + "CoreMediaText", + "CoreMediaTextAttributes", + "CoreParagraph", + "CoreParagraphAttributes", + "CorePreformatted", + "CorePreformattedAttributes", + "CorePullquote", + "CorePullquoteAttributes", + "CoreQuote", + "CoreQuoteAttributes", + "CoreSeparator", + "CoreSeparatorAttributes", + "CoreSocialLinks", + "CoreSocialLinksAttributes", + "CoreSpacer", + "CoreSpacerAttributes", + "CoreTable", + "CoreTableAttributes", + "CoreVerse", + "CoreVerseAttributes", + "CoreVideo", + "CoreVideoAttributes" + ], + "CategoryConnection": [ + "CategoryToAncestorsCategoryConnection", + "CategoryToCategoryConnection", + "PostToCategoryConnection", + "RootQueryToCategoryConnection" + ], + "CategoryConnectionEdge": [ + "CategoryToAncestorsCategoryConnectionEdge", + "CategoryToCategoryConnectionEdge", + "CategoryToParentCategoryConnectionEdge", + "PostToCategoryConnectionEdge", + "RootQueryToCategoryConnectionEdge" + ], + "CategoryConnectionPageInfo": [ + "CategoryToAncestorsCategoryConnectionPageInfo", + "CategoryToCategoryConnectionPageInfo", + "PostToCategoryConnectionPageInfo", + "RootQueryToCategoryConnectionPageInfo" + ], + "CommentConnection": [ + "CommentToCommentConnection", + "MediaItemToCommentConnection", + "PageToCommentConnection", + "PostToCommentConnection", + "RootQueryToCommentConnection", + "UserToCommentConnection" + ], + "CommentConnectionEdge": [ + "CommentToCommentConnectionEdge", + "CommentToParentCommentConnectionEdge", + "MediaItemToCommentConnectionEdge", + "PageToCommentConnectionEdge", + "PostToCommentConnectionEdge", + "RootQueryToCommentConnectionEdge", + "UserToCommentConnectionEdge" + ], + "CommentConnectionPageInfo": [ + "CommentToCommentConnectionPageInfo", + "MediaItemToCommentConnectionPageInfo", + "PageToCommentConnectionPageInfo", + "PostToCommentConnectionPageInfo", + "RootQueryToCommentConnectionPageInfo", + "UserToCommentConnectionPageInfo" + ], + "Commenter": [ + "CommentAuthor", + "User" + ], + "CommenterConnectionEdge": [ + "CommentToCommenterConnectionEdge" + ], + "Connection": [ + "CategoryToAncestorsCategoryConnection", + "CategoryToCategoryConnection", + "CategoryToContentNodeConnection", + "CategoryToPostConnection", + "CommentToCommentConnection", + "ContentNodeToEnqueuedScriptConnection", + "ContentNodeToEnqueuedStylesheetConnection", + "ContentTypeToContentNodeConnection", + "ContentTypeToTaxonomyConnection", + "CorePostTermsToTermNodeConnection", + "HierarchicalContentNodeToContentNodeAncestorsConnection", + "HierarchicalContentNodeToContentNodeChildrenConnection", + "MediaItemToCommentConnection", + "MenuItemToMenuItemConnection", + "MenuToMenuItemConnection", + "PageToCommentConnection", + "PageToRevisionConnection", + "PostFormatToContentNodeConnection", + "PostFormatToPostConnection", + "PostToCategoryConnection", + "PostToCommentConnection", + "PostToPostConnection", + "PostToPostFormatConnection", + "PostToRevisionConnection", + "PostToTagConnection", + "PostToTermNodeConnection", + "RootQueryToCategoryConnection", + "RootQueryToCommentConnection", + "RootQueryToContentNodeConnection", + "RootQueryToContentTypeConnection", + "RootQueryToEnqueuedScriptConnection", + "RootQueryToEnqueuedStylesheetConnection", + "RootQueryToMediaItemConnection", + "RootQueryToMenuConnection", + "RootQueryToMenuItemConnection", + "RootQueryToPageConnection", + "RootQueryToPluginConnection", + "RootQueryToPostConnection", + "RootQueryToPostFormatConnection", + "RootQueryToRevisionsConnection", + "RootQueryToTagConnection", + "RootQueryToTaxonomyConnection", + "RootQueryToTermNodeConnection", + "RootQueryToThemeConnection", + "RootQueryToUserConnection", + "RootQueryToUserRoleConnection", + "TagToContentNodeConnection", + "TagToPostConnection", + "TaxonomyToContentTypeConnection", + "TaxonomyToTermNodeConnection", + "TermNodeToEnqueuedScriptConnection", + "TermNodeToEnqueuedStylesheetConnection", + "UserToCommentConnection", + "UserToEnqueuedScriptConnection", + "UserToEnqueuedStylesheetConnection", + "UserToMediaItemConnection", + "UserToPageConnection", + "UserToPostConnection", + "UserToRevisionsConnection", + "UserToUserRoleConnection" + ], + "ContentNode": [ + "MediaItem", + "Page", + "Post" + ], + "ContentNodeConnection": [ + "CategoryToContentNodeConnection", + "ContentTypeToContentNodeConnection", + "HierarchicalContentNodeToContentNodeAncestorsConnection", + "HierarchicalContentNodeToContentNodeChildrenConnection", + "PostFormatToContentNodeConnection", + "RootQueryToContentNodeConnection", + "RootQueryToRevisionsConnection", + "TagToContentNodeConnection", + "UserToRevisionsConnection" + ], + "ContentNodeConnectionEdge": [ + "CategoryToContentNodeConnectionEdge", + "CommentToContentNodeConnectionEdge", + "ContentTypeToContentNodeConnectionEdge", + "HierarchicalContentNodeToContentNodeAncestorsConnectionEdge", + "HierarchicalContentNodeToContentNodeChildrenConnectionEdge", + "HierarchicalContentNodeToParentContentNodeConnectionEdge", + "NodeWithRevisionsToContentNodeConnectionEdge", + "PostFormatToContentNodeConnectionEdge", + "RootQueryToContentNodeConnectionEdge", + "RootQueryToRevisionsConnectionEdge", + "TagToContentNodeConnectionEdge", + "UserToRevisionsConnectionEdge" + ], + "ContentNodeConnectionPageInfo": [ + "CategoryToContentNodeConnectionPageInfo", + "ContentTypeToContentNodeConnectionPageInfo", + "HierarchicalContentNodeToContentNodeAncestorsConnectionPageInfo", + "HierarchicalContentNodeToContentNodeChildrenConnectionPageInfo", + "PostFormatToContentNodeConnectionPageInfo", + "RootQueryToContentNodeConnectionPageInfo", + "RootQueryToRevisionsConnectionPageInfo", + "TagToContentNodeConnectionPageInfo", + "UserToRevisionsConnectionPageInfo" + ], + "ContentTemplate": [ + "DefaultTemplate", + "Template_PageNoTitle", + "Template_PageWithSidebar", + "Template_PageWithWideImage", + "Template_SingleWithSidebar" + ], + "ContentTypeConnection": [ + "RootQueryToContentTypeConnection", + "TaxonomyToContentTypeConnection" + ], + "ContentTypeConnectionEdge": [ + "ContentNodeToContentTypeConnectionEdge", + "RootQueryToContentTypeConnectionEdge", + "TaxonomyToContentTypeConnectionEdge" + ], + "ContentTypeConnectionPageInfo": [ + "RootQueryToContentTypeConnectionPageInfo", + "TaxonomyToContentTypeConnectionPageInfo" + ], + "DatabaseIdentifier": [ + "Category", + "Comment", + "CommentAuthor", + "MediaItem", + "Menu", + "MenuItem", + "Page", + "Post", + "PostFormat", + "Tag", + "User" + ], + "Edge": [ + "CategoryToAncestorsCategoryConnectionEdge", + "CategoryToCategoryConnectionEdge", + "CategoryToContentNodeConnectionEdge", + "CategoryToParentCategoryConnectionEdge", + "CategoryToPostConnectionEdge", + "CategoryToTaxonomyConnectionEdge", + "CommentToCommentConnectionEdge", + "CommentToCommenterConnectionEdge", + "CommentToContentNodeConnectionEdge", + "CommentToParentCommentConnectionEdge", + "ContentNodeToContentTypeConnectionEdge", + "ContentNodeToEditLastConnectionEdge", + "ContentNodeToEditLockConnectionEdge", + "ContentNodeToEnqueuedScriptConnectionEdge", + "ContentNodeToEnqueuedStylesheetConnectionEdge", + "ContentTypeToContentNodeConnectionEdge", + "ContentTypeToTaxonomyConnectionEdge", + "CorePostTermsToTaxonomyConnectionEdge", + "CorePostTermsToTermNodeConnectionEdge", + "HierarchicalContentNodeToContentNodeAncestorsConnectionEdge", + "HierarchicalContentNodeToContentNodeChildrenConnectionEdge", + "HierarchicalContentNodeToParentContentNodeConnectionEdge", + "MediaItemToCommentConnectionEdge", + "MenuItemToMenuConnectionEdge", + "MenuItemToMenuItemConnectionEdge", + "MenuItemToMenuItemLinkableConnectionEdge", + "MenuToMenuItemConnectionEdge", + "NodeWithAuthorToUserConnectionEdge", + "NodeWithFeaturedImageToMediaItemConnectionEdge", + "NodeWithRevisionsToContentNodeConnectionEdge", + "PageToCommentConnectionEdge", + "PageToPreviewConnectionEdge", + "PageToRevisionConnectionEdge", + "PostFormatToContentNodeConnectionEdge", + "PostFormatToPostConnectionEdge", + "PostFormatToTaxonomyConnectionEdge", + "PostToCategoryConnectionEdge", + "PostToCommentConnectionEdge", + "PostToParentConnectionEdge", + "PostToPostConnectionEdge", + "PostToPostFormatConnectionEdge", + "PostToPreviewConnectionEdge", + "PostToRevisionConnectionEdge", + "PostToTagConnectionEdge", + "PostToTermNodeConnectionEdge", + "RootQueryToCategoryConnectionEdge", + "RootQueryToCommentConnectionEdge", + "RootQueryToContentNodeConnectionEdge", + "RootQueryToContentTypeConnectionEdge", + "RootQueryToEnqueuedScriptConnectionEdge", + "RootQueryToEnqueuedStylesheetConnectionEdge", + "RootQueryToMediaItemConnectionEdge", + "RootQueryToMenuConnectionEdge", + "RootQueryToMenuItemConnectionEdge", + "RootQueryToPageConnectionEdge", + "RootQueryToPluginConnectionEdge", + "RootQueryToPostConnectionEdge", + "RootQueryToPostFormatConnectionEdge", + "RootQueryToRevisionsConnectionEdge", + "RootQueryToTagConnectionEdge", + "RootQueryToTaxonomyConnectionEdge", + "RootQueryToTermNodeConnectionEdge", + "RootQueryToThemeConnectionEdge", + "RootQueryToUserConnectionEdge", + "RootQueryToUserRoleConnectionEdge", + "TagToContentNodeConnectionEdge", + "TagToPostConnectionEdge", + "TagToTaxonomyConnectionEdge", + "TaxonomyToContentTypeConnectionEdge", + "TaxonomyToTermNodeConnectionEdge", + "TermNodeToEnqueuedScriptConnectionEdge", + "TermNodeToEnqueuedStylesheetConnectionEdge", + "UserToCommentConnectionEdge", + "UserToEnqueuedScriptConnectionEdge", + "UserToEnqueuedStylesheetConnectionEdge", + "UserToMediaItemConnectionEdge", + "UserToPageConnectionEdge", + "UserToPostConnectionEdge", + "UserToRevisionsConnectionEdge", + "UserToUserRoleConnectionEdge" + ], + "EditorBlock": [ + "CoreArchives", + "CoreAudio", + "CoreAvatar", + "CoreBlock", + "CoreButton", + "CoreButtons", + "CoreCalendar", + "CoreCategories", + "CoreCode", + "CoreColumn", + "CoreColumns", + "CoreCommentAuthorName", + "CoreCommentContent", + "CoreCommentDate", + "CoreCommentEditLink", + "CoreCommentReplyLink", + "CoreCommentTemplate", + "CoreComments", + "CoreCommentsPagination", + "CoreCommentsPaginationNext", + "CoreCommentsPaginationNumbers", + "CoreCommentsPaginationPrevious", + "CoreCommentsTitle", + "CoreCover", + "CoreDetails", + "CoreEmbed", + "CoreFile", + "CoreFootnotes", + "CoreFreeform", + "CoreGallery", + "CoreGroup", + "CoreHeading", + "CoreHomeLink", + "CoreHtml", + "CoreImage", + "CoreLatestComments", + "CoreLatestPosts", + "CoreLegacyWidget", + "CoreList", + "CoreListItem", + "CoreLoginout", + "CoreMediaText", + "CoreMissing", + "CoreMore", + "CoreNavigation", + "CoreNavigationLink", + "CoreNavigationSubmenu", + "CoreNextpage", + "CorePageList", + "CorePageListItem", + "CoreParagraph", + "CorePattern", + "CorePostAuthor", + "CorePostAuthorBiography", + "CorePostAuthorName", + "CorePostComments", + "CorePostCommentsForm", + "CorePostContent", + "CorePostDate", + "CorePostExcerpt", + "CorePostFeaturedImage", + "CorePostNavigationLink", + "CorePostTemplate", + "CorePostTerms", + "CorePostTitle", + "CorePreformatted", + "CorePullquote", + "CoreQuery", + "CoreQueryNoResults", + "CoreQueryPagination", + "CoreQueryPaginationNext", + "CoreQueryPaginationNumbers", + "CoreQueryPaginationPrevious", + "CoreQueryTitle", + "CoreQuote", + "CoreReadMore", + "CoreRss", + "CoreSearch", + "CoreSeparator", + "CoreShortcode", + "CoreSiteLogo", + "CoreSiteTagline", + "CoreSiteTitle", + "CoreSocialLink", + "CoreSocialLinks", + "CoreSpacer", + "CoreTable", + "CoreTagCloud", + "CoreTemplatePart", + "CoreTermDescription", + "CoreTextColumns", + "CoreVerse", + "CoreVideo", + "CoreWidgetGroup", + "CreateBlockBlockA", + "CreateBlockBlockB" + ], + "EnqueuedAsset": [ + "EnqueuedScript", + "EnqueuedStylesheet" + ], + "EnqueuedScriptConnection": [ + "ContentNodeToEnqueuedScriptConnection", + "RootQueryToEnqueuedScriptConnection", + "TermNodeToEnqueuedScriptConnection", + "UserToEnqueuedScriptConnection" + ], + "EnqueuedScriptConnectionEdge": [ + "ContentNodeToEnqueuedScriptConnectionEdge", + "RootQueryToEnqueuedScriptConnectionEdge", + "TermNodeToEnqueuedScriptConnectionEdge", + "UserToEnqueuedScriptConnectionEdge" + ], + "EnqueuedScriptConnectionPageInfo": [ + "ContentNodeToEnqueuedScriptConnectionPageInfo", + "RootQueryToEnqueuedScriptConnectionPageInfo", + "TermNodeToEnqueuedScriptConnectionPageInfo", + "UserToEnqueuedScriptConnectionPageInfo" + ], + "EnqueuedStylesheetConnection": [ + "ContentNodeToEnqueuedStylesheetConnection", + "RootQueryToEnqueuedStylesheetConnection", + "TermNodeToEnqueuedStylesheetConnection", + "UserToEnqueuedStylesheetConnection" + ], + "EnqueuedStylesheetConnectionEdge": [ + "ContentNodeToEnqueuedStylesheetConnectionEdge", + "RootQueryToEnqueuedStylesheetConnectionEdge", + "TermNodeToEnqueuedStylesheetConnectionEdge", + "UserToEnqueuedStylesheetConnectionEdge" + ], + "EnqueuedStylesheetConnectionPageInfo": [ + "ContentNodeToEnqueuedStylesheetConnectionPageInfo", + "RootQueryToEnqueuedStylesheetConnectionPageInfo", + "TermNodeToEnqueuedStylesheetConnectionPageInfo", + "UserToEnqueuedStylesheetConnectionPageInfo" + ], + "HierarchicalContentNode": [ + "MediaItem", + "Page" + ], + "HierarchicalNode": [ + "Category", + "MediaItem", + "Page" + ], + "HierarchicalTermNode": [ + "Category" + ], + "LoginClientOptions": [ + "FacebookClientOptions", + "GithubClientOptions", + "GoogleClientOptions", + "InstagramClientOptions", + "LinkedinClientOptions", + "Oauth2GenericClientOptions", + "PasswordClientOptions", + "SiteTokenClientOptions" + ], + "LoginOptions": [ + "FacebookLoginOptions", + "GithubLoginOptions", + "GoogleLoginOptions", + "InstagramLoginOptions", + "LinkedinLoginOptions", + "Oauth2GenericLoginOptions", + "PasswordLoginOptions", + "SiteTokenLoginOptions" + ], + "MediaItemConnection": [ + "RootQueryToMediaItemConnection", + "UserToMediaItemConnection" + ], + "MediaItemConnectionEdge": [ + "NodeWithFeaturedImageToMediaItemConnectionEdge", + "RootQueryToMediaItemConnectionEdge", + "UserToMediaItemConnectionEdge" + ], + "MediaItemConnectionPageInfo": [ + "RootQueryToMediaItemConnectionPageInfo", + "UserToMediaItemConnectionPageInfo" + ], + "MenuConnection": [ + "RootQueryToMenuConnection" + ], + "MenuConnectionEdge": [ + "MenuItemToMenuConnectionEdge", + "RootQueryToMenuConnectionEdge" + ], + "MenuConnectionPageInfo": [ + "RootQueryToMenuConnectionPageInfo" + ], + "MenuItemConnection": [ + "MenuItemToMenuItemConnection", + "MenuToMenuItemConnection", + "RootQueryToMenuItemConnection" + ], + "MenuItemConnectionEdge": [ + "MenuItemToMenuItemConnectionEdge", + "MenuToMenuItemConnectionEdge", + "RootQueryToMenuItemConnectionEdge" + ], + "MenuItemConnectionPageInfo": [ + "MenuItemToMenuItemConnectionPageInfo", + "MenuToMenuItemConnectionPageInfo", + "RootQueryToMenuItemConnectionPageInfo" + ], + "MenuItemLinkable": [ + "Category", + "Page", + "Post", + "Tag" + ], + "MenuItemLinkableConnectionEdge": [ + "MenuItemToMenuItemLinkableConnectionEdge" + ], + "MenuItemObjectUnion": [ + "Category", + "Page", + "Post", + "Tag" + ], + "Node": [ + "Category", + "Comment", + "CommentAuthor", + "ContentType", + "EnqueuedScript", + "EnqueuedStylesheet", + "MediaItem", + "Menu", + "MenuItem", + "Page", + "Plugin", + "Post", + "PostFormat", + "Tag", + "Taxonomy", + "Theme", + "User", + "UserRole" + ], + "NodeWithAuthor": [ + "MediaItem", + "Page", + "Post" + ], + "NodeWithComments": [ + "MediaItem", + "Page", + "Post" + ], + "NodeWithContentEditor": [ + "Page", + "Post" + ], + "NodeWithEditorBlocks": [ + "Page", + "Post" + ], + "NodeWithExcerpt": [ + "Post" + ], + "NodeWithFeaturedImage": [ + "Page", + "Post" + ], + "NodeWithPageAttributes": [ + "Page" + ], + "NodeWithPageEditorBlocks": [ + "Page" + ], + "NodeWithPostEditorBlocks": [ + "Post" + ], + "NodeWithRevisions": [ + "Page", + "Post" + ], + "NodeWithTemplate": [ + "MediaItem", + "Page", + "Post" + ], + "NodeWithTitle": [ + "MediaItem", + "Page", + "Post" + ], + "NodeWithTrackbacks": [ + "Post" + ], + "OneToOneConnection": [ + "CategoryToParentCategoryConnectionEdge", + "CategoryToTaxonomyConnectionEdge", + "CommentToCommenterConnectionEdge", + "CommentToContentNodeConnectionEdge", + "CommentToParentCommentConnectionEdge", + "ContentNodeToContentTypeConnectionEdge", + "ContentNodeToEditLastConnectionEdge", + "ContentNodeToEditLockConnectionEdge", + "CorePostTermsToTaxonomyConnectionEdge", + "HierarchicalContentNodeToParentContentNodeConnectionEdge", + "MenuItemToMenuConnectionEdge", + "MenuItemToMenuItemLinkableConnectionEdge", + "NodeWithAuthorToUserConnectionEdge", + "NodeWithFeaturedImageToMediaItemConnectionEdge", + "NodeWithRevisionsToContentNodeConnectionEdge", + "PageToPreviewConnectionEdge", + "PostFormatToTaxonomyConnectionEdge", + "PostToParentConnectionEdge", + "PostToPreviewConnectionEdge", + "TagToTaxonomyConnectionEdge" + ], + "PageConnection": [ + "PageToRevisionConnection", + "RootQueryToPageConnection", + "UserToPageConnection" + ], + "PageConnectionEdge": [ + "PageToPreviewConnectionEdge", + "PageToRevisionConnectionEdge", + "RootQueryToPageConnectionEdge", + "UserToPageConnectionEdge" + ], + "PageConnectionPageInfo": [ + "PageToRevisionConnectionPageInfo", + "RootQueryToPageConnectionPageInfo", + "UserToPageConnectionPageInfo" + ], + "PageEditorBlock": [ + "CoreArchives", + "CoreAudio", + "CoreAvatar", + "CoreBlock", + "CoreButton", + "CoreButtons", + "CoreCalendar", + "CoreCategories", + "CoreCode", + "CoreColumn", + "CoreColumns", + "CoreCommentAuthorName", + "CoreCommentContent", + "CoreCommentDate", + "CoreCommentEditLink", + "CoreCommentReplyLink", + "CoreCommentTemplate", + "CoreComments", + "CoreCommentsPagination", + "CoreCommentsPaginationNext", + "CoreCommentsPaginationNumbers", + "CoreCommentsPaginationPrevious", + "CoreCommentsTitle", + "CoreCover", + "CoreDetails", + "CoreEmbed", + "CoreFile", + "CoreFootnotes", + "CoreFreeform", + "CoreGallery", + "CoreGroup", + "CoreHeading", + "CoreHomeLink", + "CoreHtml", + "CoreImage", + "CoreLatestComments", + "CoreLatestPosts", + "CoreLegacyWidget", + "CoreList", + "CoreListItem", + "CoreLoginout", + "CoreMediaText", + "CoreMissing", + "CoreMore", + "CoreNavigation", + "CoreNavigationLink", + "CoreNavigationSubmenu", + "CoreNextpage", + "CorePageList", + "CorePageListItem", + "CoreParagraph", + "CorePattern", + "CorePostAuthor", + "CorePostAuthorBiography", + "CorePostAuthorName", + "CorePostComments", + "CorePostCommentsForm", + "CorePostContent", + "CorePostDate", + "CorePostExcerpt", + "CorePostFeaturedImage", + "CorePostNavigationLink", + "CorePostTemplate", + "CorePostTerms", + "CorePostTitle", + "CorePreformatted", + "CorePullquote", + "CoreQuery", + "CoreQueryNoResults", + "CoreQueryPagination", + "CoreQueryPaginationNext", + "CoreQueryPaginationNumbers", + "CoreQueryPaginationPrevious", + "CoreQueryTitle", + "CoreQuote", + "CoreReadMore", + "CoreRss", + "CoreSearch", + "CoreSeparator", + "CoreShortcode", + "CoreSiteLogo", + "CoreSiteTagline", + "CoreSiteTitle", + "CoreSocialLink", + "CoreSocialLinks", + "CoreSpacer", + "CoreTable", + "CoreTagCloud", + "CoreTemplatePart", + "CoreTermDescription", + "CoreTextColumns", + "CoreVerse", + "CoreVideo", + "CoreWidgetGroup", + "CreateBlockBlockA", + "CreateBlockBlockB" + ], + "PageInfo": [ + "CategoryToAncestorsCategoryConnectionPageInfo", + "CategoryToCategoryConnectionPageInfo", + "CategoryToContentNodeConnectionPageInfo", + "CategoryToPostConnectionPageInfo", + "CommentToCommentConnectionPageInfo", + "ContentNodeToEnqueuedScriptConnectionPageInfo", + "ContentNodeToEnqueuedStylesheetConnectionPageInfo", + "ContentTypeToContentNodeConnectionPageInfo", + "ContentTypeToTaxonomyConnectionPageInfo", + "CorePostTermsToTermNodeConnectionPageInfo", + "HierarchicalContentNodeToContentNodeAncestorsConnectionPageInfo", + "HierarchicalContentNodeToContentNodeChildrenConnectionPageInfo", + "MediaItemToCommentConnectionPageInfo", + "MenuItemToMenuItemConnectionPageInfo", + "MenuToMenuItemConnectionPageInfo", + "PageToCommentConnectionPageInfo", + "PageToRevisionConnectionPageInfo", + "PostFormatToContentNodeConnectionPageInfo", + "PostFormatToPostConnectionPageInfo", + "PostToCategoryConnectionPageInfo", + "PostToCommentConnectionPageInfo", + "PostToPostConnectionPageInfo", + "PostToPostFormatConnectionPageInfo", + "PostToRevisionConnectionPageInfo", + "PostToTagConnectionPageInfo", + "PostToTermNodeConnectionPageInfo", + "RootQueryToCategoryConnectionPageInfo", + "RootQueryToCommentConnectionPageInfo", + "RootQueryToContentNodeConnectionPageInfo", + "RootQueryToContentTypeConnectionPageInfo", + "RootQueryToEnqueuedScriptConnectionPageInfo", + "RootQueryToEnqueuedStylesheetConnectionPageInfo", + "RootQueryToMediaItemConnectionPageInfo", + "RootQueryToMenuConnectionPageInfo", + "RootQueryToMenuItemConnectionPageInfo", + "RootQueryToPageConnectionPageInfo", + "RootQueryToPluginConnectionPageInfo", + "RootQueryToPostConnectionPageInfo", + "RootQueryToPostFormatConnectionPageInfo", + "RootQueryToRevisionsConnectionPageInfo", + "RootQueryToTagConnectionPageInfo", + "RootQueryToTaxonomyConnectionPageInfo", + "RootQueryToTermNodeConnectionPageInfo", + "RootQueryToThemeConnectionPageInfo", + "RootQueryToUserConnectionPageInfo", + "RootQueryToUserRoleConnectionPageInfo", + "TagToContentNodeConnectionPageInfo", + "TagToPostConnectionPageInfo", + "TaxonomyToContentTypeConnectionPageInfo", + "TaxonomyToTermNodeConnectionPageInfo", + "TermNodeToEnqueuedScriptConnectionPageInfo", + "TermNodeToEnqueuedStylesheetConnectionPageInfo", + "UserToCommentConnectionPageInfo", + "UserToEnqueuedScriptConnectionPageInfo", + "UserToEnqueuedStylesheetConnectionPageInfo", + "UserToMediaItemConnectionPageInfo", + "UserToPageConnectionPageInfo", + "UserToPostConnectionPageInfo", + "UserToRevisionsConnectionPageInfo", + "UserToUserRoleConnectionPageInfo" + ], + "PluginConnection": [ + "RootQueryToPluginConnection" + ], + "PluginConnectionEdge": [ + "RootQueryToPluginConnectionEdge" + ], + "PluginConnectionPageInfo": [ + "RootQueryToPluginConnectionPageInfo" + ], + "PostConnection": [ + "CategoryToPostConnection", + "PostFormatToPostConnection", + "PostToPostConnection", + "PostToRevisionConnection", + "RootQueryToPostConnection", + "TagToPostConnection", + "UserToPostConnection" + ], + "PostConnectionEdge": [ + "CategoryToPostConnectionEdge", + "PostFormatToPostConnectionEdge", + "PostToParentConnectionEdge", + "PostToPostConnectionEdge", + "PostToPreviewConnectionEdge", + "PostToRevisionConnectionEdge", + "RootQueryToPostConnectionEdge", + "TagToPostConnectionEdge", + "UserToPostConnectionEdge" + ], + "PostConnectionPageInfo": [ + "CategoryToPostConnectionPageInfo", + "PostFormatToPostConnectionPageInfo", + "PostToPostConnectionPageInfo", + "PostToRevisionConnectionPageInfo", + "RootQueryToPostConnectionPageInfo", + "TagToPostConnectionPageInfo", + "UserToPostConnectionPageInfo" + ], + "PostEditorBlock": [ + "CoreArchives", + "CoreAudio", + "CoreAvatar", + "CoreBlock", + "CoreButton", + "CoreButtons", + "CoreCalendar", + "CoreCategories", + "CoreCode", + "CoreColumn", + "CoreColumns", + "CoreCommentAuthorName", + "CoreCommentContent", + "CoreCommentDate", + "CoreCommentEditLink", + "CoreCommentReplyLink", + "CoreCommentTemplate", + "CoreComments", + "CoreCommentsPagination", + "CoreCommentsPaginationNext", + "CoreCommentsPaginationNumbers", + "CoreCommentsPaginationPrevious", + "CoreCommentsTitle", + "CoreCover", + "CoreDetails", + "CoreEmbed", + "CoreFile", + "CoreFootnotes", + "CoreFreeform", + "CoreGallery", + "CoreGroup", + "CoreHeading", + "CoreHomeLink", + "CoreHtml", + "CoreImage", + "CoreLatestComments", + "CoreLatestPosts", + "CoreLegacyWidget", + "CoreList", + "CoreListItem", + "CoreLoginout", + "CoreMediaText", + "CoreMissing", + "CoreMore", + "CoreNavigation", + "CoreNavigationLink", + "CoreNavigationSubmenu", + "CoreNextpage", + "CorePageList", + "CorePageListItem", + "CoreParagraph", + "CorePattern", + "CorePostAuthor", + "CorePostAuthorBiography", + "CorePostAuthorName", + "CorePostComments", + "CorePostCommentsForm", + "CorePostContent", + "CorePostDate", + "CorePostExcerpt", + "CorePostFeaturedImage", + "CorePostNavigationLink", + "CorePostTemplate", + "CorePostTerms", + "CorePostTitle", + "CorePreformatted", + "CorePullquote", + "CoreQuery", + "CoreQueryNoResults", + "CoreQueryPagination", + "CoreQueryPaginationNext", + "CoreQueryPaginationNumbers", + "CoreQueryPaginationPrevious", + "CoreQueryTitle", + "CoreQuote", + "CoreReadMore", + "CoreRss", + "CoreSearch", + "CoreSeparator", + "CoreShortcode", + "CoreSiteLogo", + "CoreSiteTagline", + "CoreSiteTitle", + "CoreSocialLink", + "CoreSocialLinks", + "CoreSpacer", + "CoreTable", + "CoreTagCloud", + "CoreTemplatePart", + "CoreTermDescription", + "CoreTextColumns", + "CoreVerse", + "CoreVideo", + "CoreWidgetGroup", + "CreateBlockBlockA", + "CreateBlockBlockB" + ], + "PostFormatConnection": [ + "PostToPostFormatConnection", + "RootQueryToPostFormatConnection" + ], + "PostFormatConnectionEdge": [ + "PostToPostFormatConnectionEdge", + "RootQueryToPostFormatConnectionEdge" + ], + "PostFormatConnectionPageInfo": [ + "PostToPostFormatConnectionPageInfo", + "RootQueryToPostFormatConnectionPageInfo" + ], + "Previewable": [ + "Page", + "Post" + ], + "TagConnection": [ + "PostToTagConnection", + "RootQueryToTagConnection" + ], + "TagConnectionEdge": [ + "PostToTagConnectionEdge", + "RootQueryToTagConnectionEdge" + ], + "TagConnectionPageInfo": [ + "PostToTagConnectionPageInfo", + "RootQueryToTagConnectionPageInfo" + ], + "TaxonomyConnection": [ + "ContentTypeToTaxonomyConnection", + "RootQueryToTaxonomyConnection" + ], + "TaxonomyConnectionEdge": [ + "CategoryToTaxonomyConnectionEdge", + "ContentTypeToTaxonomyConnectionEdge", + "CorePostTermsToTaxonomyConnectionEdge", + "PostFormatToTaxonomyConnectionEdge", + "RootQueryToTaxonomyConnectionEdge", + "TagToTaxonomyConnectionEdge" + ], + "TaxonomyConnectionPageInfo": [ + "ContentTypeToTaxonomyConnectionPageInfo", + "RootQueryToTaxonomyConnectionPageInfo" + ], + "TermNode": [ + "Category", + "PostFormat", + "Tag" + ], + "TermNodeConnection": [ + "CorePostTermsToTermNodeConnection", + "PostToTermNodeConnection", + "RootQueryToTermNodeConnection", + "TaxonomyToTermNodeConnection" + ], + "TermNodeConnectionEdge": [ + "CorePostTermsToTermNodeConnectionEdge", + "PostToTermNodeConnectionEdge", + "RootQueryToTermNodeConnectionEdge", + "TaxonomyToTermNodeConnectionEdge" + ], + "TermNodeConnectionPageInfo": [ + "CorePostTermsToTermNodeConnectionPageInfo", + "PostToTermNodeConnectionPageInfo", + "RootQueryToTermNodeConnectionPageInfo", + "TaxonomyToTermNodeConnectionPageInfo" + ], + "ThemeConnection": [ + "RootQueryToThemeConnection" + ], + "ThemeConnectionEdge": [ + "RootQueryToThemeConnectionEdge" + ], + "ThemeConnectionPageInfo": [ + "RootQueryToThemeConnectionPageInfo" + ], + "UniformResourceIdentifiable": [ + "Category", + "Comment", + "ContentType", + "MediaItem", + "Page", + "Post", + "PostFormat", + "Tag", + "User" + ], + "UserConnection": [ + "RootQueryToUserConnection" + ], + "UserConnectionEdge": [ + "ContentNodeToEditLastConnectionEdge", + "ContentNodeToEditLockConnectionEdge", + "NodeWithAuthorToUserConnectionEdge", + "RootQueryToUserConnectionEdge" + ], + "UserConnectionPageInfo": [ + "RootQueryToUserConnectionPageInfo" + ], + "UserRoleConnection": [ + "RootQueryToUserRoleConnection", + "UserToUserRoleConnection" + ], + "UserRoleConnectionEdge": [ + "RootQueryToUserRoleConnectionEdge", + "UserToUserRoleConnectionEdge" + ], + "UserRoleConnectionPageInfo": [ + "RootQueryToUserRoleConnectionPageInfo", + "UserToUserRoleConnectionPageInfo" + ], + "WPPageInfo": [ + "CategoryToAncestorsCategoryConnectionPageInfo", + "CategoryToCategoryConnectionPageInfo", + "CategoryToContentNodeConnectionPageInfo", + "CategoryToPostConnectionPageInfo", + "CommentToCommentConnectionPageInfo", + "ContentNodeToEnqueuedScriptConnectionPageInfo", + "ContentNodeToEnqueuedStylesheetConnectionPageInfo", + "ContentTypeToContentNodeConnectionPageInfo", + "ContentTypeToTaxonomyConnectionPageInfo", + "CorePostTermsToTermNodeConnectionPageInfo", + "HierarchicalContentNodeToContentNodeAncestorsConnectionPageInfo", + "HierarchicalContentNodeToContentNodeChildrenConnectionPageInfo", + "MediaItemToCommentConnectionPageInfo", + "MenuItemToMenuItemConnectionPageInfo", + "MenuToMenuItemConnectionPageInfo", + "PageToCommentConnectionPageInfo", + "PageToRevisionConnectionPageInfo", + "PostFormatToContentNodeConnectionPageInfo", + "PostFormatToPostConnectionPageInfo", + "PostToCategoryConnectionPageInfo", + "PostToCommentConnectionPageInfo", + "PostToPostConnectionPageInfo", + "PostToPostFormatConnectionPageInfo", + "PostToRevisionConnectionPageInfo", + "PostToTagConnectionPageInfo", + "PostToTermNodeConnectionPageInfo", + "RootQueryToCategoryConnectionPageInfo", + "RootQueryToCommentConnectionPageInfo", + "RootQueryToContentNodeConnectionPageInfo", + "RootQueryToContentTypeConnectionPageInfo", + "RootQueryToEnqueuedScriptConnectionPageInfo", + "RootQueryToEnqueuedStylesheetConnectionPageInfo", + "RootQueryToMediaItemConnectionPageInfo", + "RootQueryToMenuConnectionPageInfo", + "RootQueryToMenuItemConnectionPageInfo", + "RootQueryToPageConnectionPageInfo", + "RootQueryToPluginConnectionPageInfo", + "RootQueryToPostConnectionPageInfo", + "RootQueryToPostFormatConnectionPageInfo", + "RootQueryToRevisionsConnectionPageInfo", + "RootQueryToTagConnectionPageInfo", + "RootQueryToTaxonomyConnectionPageInfo", + "RootQueryToTermNodeConnectionPageInfo", + "RootQueryToThemeConnectionPageInfo", + "RootQueryToUserConnectionPageInfo", + "RootQueryToUserRoleConnectionPageInfo", + "TagToContentNodeConnectionPageInfo", + "TagToPostConnectionPageInfo", + "TaxonomyToContentTypeConnectionPageInfo", + "TaxonomyToTermNodeConnectionPageInfo", + "TermNodeToEnqueuedScriptConnectionPageInfo", + "TermNodeToEnqueuedStylesheetConnectionPageInfo", + "UserToCommentConnectionPageInfo", + "UserToEnqueuedScriptConnectionPageInfo", + "UserToEnqueuedStylesheetConnectionPageInfo", + "UserToMediaItemConnectionPageInfo", + "UserToPageConnectionPageInfo", + "UserToPostConnectionPageInfo", + "UserToRevisionsConnectionPageInfo", + "UserToUserRoleConnectionPageInfo" + ] + } +} \ No newline at end of file diff --git a/examples/next/woocommerce/example-app/postcss.config.mjs b/examples/next/woocommerce/example-app/postcss.config.mjs new file mode 100644 index 00000000..c7bcb4b1 --- /dev/null +++ b/examples/next/woocommerce/example-app/postcss.config.mjs @@ -0,0 +1,5 @@ +const config = { + plugins: ["@tailwindcss/postcss"], +}; + +export default config; diff --git a/examples/next/woocommerce/example-app/public/favicon.ico b/examples/next/woocommerce/example-app/public/favicon.ico new file mode 100644 index 00000000..718d6fea Binary files /dev/null and b/examples/next/woocommerce/example-app/public/favicon.ico differ diff --git a/examples/next/woocommerce/example-app/public/file.svg b/examples/next/woocommerce/example-app/public/file.svg new file mode 100644 index 00000000..004145cd --- /dev/null +++ b/examples/next/woocommerce/example-app/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/next/woocommerce/example-app/public/globe.svg b/examples/next/woocommerce/example-app/public/globe.svg new file mode 100644 index 00000000..567f17b0 --- /dev/null +++ b/examples/next/woocommerce/example-app/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/next/woocommerce/example-app/public/next.svg b/examples/next/woocommerce/example-app/public/next.svg new file mode 100644 index 00000000..5174b28c --- /dev/null +++ b/examples/next/woocommerce/example-app/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/next/woocommerce/example-app/public/vercel.svg b/examples/next/woocommerce/example-app/public/vercel.svg new file mode 100644 index 00000000..77053960 --- /dev/null +++ b/examples/next/woocommerce/example-app/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/next/woocommerce/example-app/public/window.svg b/examples/next/woocommerce/example-app/public/window.svg new file mode 100644 index 00000000..b2b2a44f --- /dev/null +++ b/examples/next/woocommerce/example-app/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/next/woocommerce/example-app/src/components/Cart/Cart.js b/examples/next/woocommerce/example-app/src/components/Cart/Cart.js new file mode 100644 index 00000000..31af32a2 --- /dev/null +++ b/examples/next/woocommerce/example-app/src/components/Cart/Cart.js @@ -0,0 +1,616 @@ +import React, { useState } from 'react'; +import Image from 'next/image'; +import Link from 'next/link'; +import { useCartQuery } from '@/lib/woocommerce/cartQuery'; +import { useCartMutations, useOtherCartMutations } from '@/lib/woocommerce/cart'; + +export default function Cart() { + const { data, loading, error, refetch } = useCartQuery(); + const { updateItemQuantities, removeItemsFromCart, loading: mutationLoading } = useCartMutations(); + const { applyCoupon, removeCoupons, loading: couponLoading } = useOtherCartMutations(); + + const [couponCode, setCouponCode] = useState(''); + const [updatingItems, setUpdatingItems] = useState({}); + + const cart = data?.cart; + const cartItems = cart?.contents?.nodes || []; + + + console.log('Cart data:', cart); + console.log('Cart error:', error); + + + const handleQuantityUpdate = async (cartKey, newQuantity) => { + if (newQuantity < 1) { + handleRemoveItem(cartKey); + return; + } + + setUpdatingItems(prev => ({ ...prev, [cartKey]: true })); + + try { + const { data } = await updateItemQuantities({ + variables: { + input: { + items: [ + { + key: cartKey, + quantity: newQuantity, + }, + ], + }, + }, + }); + + if (data?.updateItemQuantities) { + await refetch(); + } + } catch (error) { + console.error('Error updating quantity:', error); + } finally { + setUpdatingItems(prev => ({ ...prev, [cartKey]: false })); + } + }; + + + const handleRemoveItem = async (cartKey) => { + setUpdatingItems(prev => ({ ...prev, [cartKey]: true })); + + try { + const { data } = await removeItemsFromCart({ + variables: { + input: { + keys: [cartKey], + }, + }, + }); + + if (data?.removeItemsFromCart) { + await refetch(); + } + } catch (error) { + console.error('Error removing item:', error); + } finally { + setUpdatingItems(prev => ({ ...prev, [cartKey]: false })); + } + }; + + + const handleApplyCoupon = async (e) => { + e.preventDefault(); + if (!couponCode.trim()) return; + + try { + const { data } = await applyCoupon({ + variables: { + input: { + code: couponCode, + }, + }, + }); + + if (data?.applyCoupon) { + setCouponCode(''); + await refetch(); + } + } catch (error) { + console.error('Error applying coupon:', error); + } + }; + + + const handleRemoveCoupon = async (couponCode) => { + try { + const { data } = await removeCoupons({ + variables: { + input: { + codes: [couponCode], + }, + }, + }); + + if (data?.removeCoupons) { + await refetch(); + } + } catch (error) { + console.error('Error removing coupon:', error); + } + }; + + if (loading) return
Loading cart...
; + + if (error) { + console.error('Cart GraphQL Error:', error); + return ( +
+

Error loading cart

+

{error.message}

+ +
+ ); + } + + if (!cart || cart.isEmpty) { + return ( +
+

Your cart is empty

+

Add some products to get started!

+ + Continue Shopping + +
+ ); + } + + return ( +
+
+

Shopping Cart

+ + {/* Cart Items */} +
+ {cartItems.map((item) => { + const product = item.product.node; + const variation = item.variation?.node; + const isUpdating = updatingItems[item.key]; + + return ( +
+ {/* Product Image */} +
+ {variation?.image?.altText +
+ + {/* Product Info */} +
+ + {product.name} + + {variation && ( +

{variation.name}

+ )} +

+ {variation?.price || product.price} +

+
+ + {/* Quantity Controls */} +
+ + {item.quantity} + +
+ + {/* Item Total */} +
+ {item.total} + +
+
+ ); + })} +
+ + {/* Cart Summary */} +
+
+

Order Summary

+ +
+ Subtotal: + {cart.subtotal} +
+ + {cart.discountTotal && cart.discountTotal !== "0" && ( +
+ Discount: + -{cart.discountTotal} +
+ )} + + {cart.shippingTotal && cart.shippingTotal !== "0" && ( +
+ Shipping: + {cart.shippingTotal} +
+ )} + + {cart.totalTax && cart.totalTax !== "0" && ( +
+ Tax: + {cart.totalTax} +
+ )} + +
+ Total: + {cart.total} +
+
+ + {/* Applied Coupons */} + {cart.appliedCoupons && cart.appliedCoupons.length > 0 && ( +
+

Applied Coupons

+ {cart.appliedCoupons.map((coupon) => ( +
+ {coupon.code} + -{coupon.discountAmount} + +
+ ))} +
+ )} + + {/* Coupon Form */} +
+ setCouponCode(e.target.value)} + className="coupon-input" + /> + +
+ + {/* Checkout Button */} + + Proceed to Checkout + +
+
+ + +
+ ); +} \ No newline at end of file diff --git a/examples/next/woocommerce/example-app/src/components/Footer/Footer.js b/examples/next/woocommerce/example-app/src/components/Footer/Footer.js new file mode 100644 index 00000000..1fd32964 --- /dev/null +++ b/examples/next/woocommerce/example-app/src/components/Footer/Footer.js @@ -0,0 +1,66 @@ +import { useQuery, gql } from "@apollo/client"; + +const SETTINGS_QUERY = gql` + query FooterSettingsQuery { + generalSettings { + title + } + } +`; + +export default function Footer({ footerData }) { + const settingsData = footerData?.settings; + + //CSR maybe? + // const { + // data: footerData, + // loading, + // error, + // } = useQuery(SETTINGS_QUERY, { + // fetchPolicy: "cache-first", + // }, + // }); + + return ( + + ); +} diff --git a/examples/next/woocommerce/example-app/src/components/Header/Header.js b/examples/next/woocommerce/example-app/src/components/Header/Header.js new file mode 100644 index 00000000..bf7f9a37 --- /dev/null +++ b/examples/next/woocommerce/example-app/src/components/Header/Header.js @@ -0,0 +1,111 @@ +"use client"; +import Link from "next/link"; +import NavigationItem from "./NavigationItem"; +import { flatListToHierarchical } from "@/lib/utils"; +import { useRouter } from "next/router"; +import { useAuth } from "@/lib/auth/AuthProvider"; + +export default function Header({ headerData }) { + const router = useRouter(); + + const settingsData = headerData?.settings; + const navigationData = headerData?.navigation; + + if (!headerData) { + return; + } + //auth + const { tokens, isLoading, logout, refreshAuth } = useAuth(); + const isAuthenticated = !!tokens?.authToken; + + const siteInfo = { + title: settingsData?.generalSettings?.title || "My Site", + }; + + const flatMenuItems = navigationData?.menu?.menuItems?.nodes || []; + const menuItems = flatListToHierarchical(flatMenuItems); + + const isActive = (item) => { + if (!item.uri) return false; + let cleanUri = item.uri.startsWith("/") ? item.uri.substring(1) : item.uri; + cleanUri = cleanUri.endsWith("/") ? cleanUri.slice(0, -1) : cleanUri; + return `/${cleanUri}` === router.asPath; + }; + + return ( +
+
+
+ + {siteInfo.title} + +
+ + +
+ + +
+ ); +} diff --git a/examples/next/woocommerce/example-app/src/components/Header/NavigationItem.js b/examples/next/woocommerce/example-app/src/components/Header/NavigationItem.js new file mode 100644 index 00000000..56c8cec0 --- /dev/null +++ b/examples/next/woocommerce/example-app/src/components/Header/NavigationItem.js @@ -0,0 +1,82 @@ +import Link from 'next/link'; +import { useMemo } from 'react'; + +export default function NavigationItem({ + item, + isActive = false, + level = 0 +}) { + + // Computed equivalents + const hasChildren = useMemo(() => { + return item.children && item.children.length > 0; + }, [item.children]); + + const dropdownClass = useMemo(() => { + return level === 0 ? "dropdown-top" : "dropdown-submenu"; + }, [level]); + + // Handle CSS classes array + const getLinkClasses = (cssClasses) => { + const baseClasses = ['nav-link']; + if (isActive) baseClasses.push('active'); + if (cssClasses) baseClasses.push(...cssClasses); + return baseClasses.join(' '); + }; + + const getDropdownItemClasses = (cssClasses) => { + const baseClasses = ['dropdown-item']; + if (isActive) baseClasses.push('active'); + if (cssClasses) baseClasses.push(...cssClasses); + return baseClasses.join(' '); + }; + + return ( +
+ {/* Regular menu item */} + + {item.label} + {/* Add dropdown indicator if there are children */} + {hasChildren && ( + + {level === 0 ? "▼" : "▶"} + + )} + + + {/* Dropdown menu for children, if any */} + {hasChildren && ( +
+ {item.children.map((child) => ( +
+ {/* Recursive case: if the child has children, render another NavigationItem */} + {child.children && child.children.length > 0 ? ( + + ) : ( + /* Base case: if the child has no children, render a simple link */ + + {child.label} + + )} +
+ ))} +
+ )} +
+ ); +} \ No newline at end of file diff --git a/examples/next/woocommerce/example-app/src/components/Layout.js b/examples/next/woocommerce/example-app/src/components/Layout.js new file mode 100644 index 00000000..a117b004 --- /dev/null +++ b/examples/next/woocommerce/example-app/src/components/Layout.js @@ -0,0 +1,15 @@ +import Header from "@/components/Header/Header"; +import Footer from "@/components/Footer/Footer"; +export default function Layout(pageProps) { + return ( + <> +
+
+
+ {pageProps.children} +
+
+