有WooGraphQL的無頭商店: 第5章 第2章

banner

注意: 此教程包含更早的 WooGraphQL 出放, 已不更新 。 有相關的相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相相相相關相相相相關相關相相關相相相相關相相相關相相相相關相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相

(克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克克

表格

  1. 为您的無頭通訊應用程式設定文字通訊
  2. 为發展而建立和啟用您的eCommerce App
  3. 有 WooGraphQL 的商店上市頁面
  4. 建立使用者登入和通訊
  5. 建立產品頁面和墨盒選項

歡迎收看相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相相相關相相相相相關相相相相相相相相相相相關相相相相相相關相相關相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相 下一章是建立通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通訊通相接通相通相接通相通相通相接相接相通相通相通相通相通相通相通相通相通相通相通相通相通相通相通相通相通通相通相通相通相通相通相通相通相通相通相通 有好幾個工具能被取用 有好幾個能被取出 有影/有影 用于部件,并 GraphQL 代碼產生器 以處理 GraphQL 操作。

二. 为发展而建立和建立通商應用程式

在用 WooGraphQL 設定了您的 WooCommerce 商店后, 您應該被留作 GraphQL 端點 : https://site-name/graphql如果您要用上一章所放入的開發相機 http://localhost:8080/wp/graphql有了 就開始吧

建立下一個.js應用程式

我們先建立下一個. js應用程式并設定出一些必要的設定

1. 首先, 在您的端口中執行以下命令以產生新的 Next.js 應用程式: npx create-next-app@latest 并跟蹤提示并通航到新建立的專案目錄 。

2. 然后,安裝 dotenv-flowdeepmerge npm 套接字由您端口中執行以下命令所提供: npm i dotenv-flow deepmerge

3. 建立新的 .env.local 在您專案的根目錄中以相關細節填入:

GRAPHQL_ENDPOINT=[GRAPHQL_ENDPOINT]
FRONTEND_URL=[NEXT_APP_URL]
BACKEND_URL=[WP_URL]
SITE_NAME=[SITE_NAME]
SITE_DESCRIPTION=[SITE_DESCRIPTION]

有同樣的相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相當相相當相相相當相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相

4. 建立新的 next.config.js 在您專案的根目錄中新增以下碼:

/**
 * @type {import('next').NextConfig}
 */
const nextConfig = {
    reactStrictMode: true,
    swcMinify: true,
    images: {
        dangerouslyAllowSVG: true,
        formats: ['image/avif', 'image/webp'],
        domains: ['localhost'],
        minimumCacheTTL: 60,
        disableStaticImages: true,
    },
    env: {
        GRAPHQL_ENDPOINT: process.env.GRAPHQL_ENDPOINT,
        FRONTEND_URL: process.env.FRONTEND_URL,
        BACKEND_URL: process.env.BACKEND_URL,
        SITE_NAME: process.env.SITE_NAME,
        SITE_DESCRIPTION: process.env.SITE_DESCRIPTION,
    },
}

module.exports = nextConfig;

5. 更新 content 在您的屬性中 tailwind.config.js 有以下檔案:

...
content: [
    './ui/**/*.{ts,tsx}',
    './server/**/*.{ts,tsx}',
    './client/**/*.{ts,tsx}',
    './app/**/*.{ts,tsx}',
]
...

安裝 shadcn/ui 元件

有活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活 shadcn/ui 相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相 這是如何安裝和配置它。

1. 執行陰影-入影指令: npx shadcn-ui@latest init 就去取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取取.

2. 打開 components.json 它被產生并被取而代之:

{
    "$schema": "https://ui.shadcn.com/schema.json",
    "style": "new-york",
    "rsc": true,
    "tailwind": {
        "config": "tailwind.config.js",
        "css": "app/globals.css",
        "baseColor": "slate",
        "cssVariables": true
    },
    "aliases": {
        "components": "/",
        "utils": "@/utils/ui"
    }
}

3. 重新命名 lib/utils.ts 檔案到 /utils/ui.ts 并建立 /ui 目錄。

4. 在您的專案中新增所必要的元件:

npx shadcn-ui@latest add aspect-ratio
npx shadcn-ui@latest add badge
npx shadcn-ui@latest add button
npx shadcn-ui@latest add card
npx shadcn-ui@latest add form
npx shadcn-ui@latest add input
npx shadcn-ui@latest add label
npx shadcn-ui@latest add radio-group
npx shadcn-ui@latest add select
npx shadcn-ui@latest add sheet
npx shadcn-ui@latest add slider
npx shadcn-ui@latest add tabs
npx shadcn-ui@latest add toast

建立其他 UI 元件

我們會為我們的應用程式再製作一些相關元件.

1. 建立新的 ui/Image/index.ts 檔案并新增以下代碼:

    'use client';
    export * from './Image';

2. 建立新的 ui/Image/Image.tsx 檔案并新增以下代碼:

import { useState } from 'react';
import NextImage from 'next/image';
import { cn } from '@/utils/ui';
import { LoadingSpinner } from '@/ui/LoadingSpinner';
import { AspectRatio } from "@/ui/aspect-ratio"

export type ImageProps = {
    className?: string;
    src: string;
    sizes?: string;
    width?: number;
    height?: number;
    ratio?: number;
    alt: string;
    style?: JSX.IntrinsicElements['img']['style']
    fill?: boolean;
    priority?: boolean;
}

export function Image(props: ImageProps) {
    const [isLoading, setLoading] = useState(true);

    const {
        className = '',
        src,
        alt,
        sizes,
        width,
        height,
        ratio,
        style,
        fill = true,
        priority,
    } = props;

    return (
        <div
            className={cn(
                'overflow-hidden group relative',
                className && className,
            )}
            style={style}
>
            <AspectRatio ratio={ratio}>
                {isLoading && (
                    <LoadingSpinner className="position absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"/>
                )}
                <NextImage
                    src={src}
                    alt={alt}
                    width={width as number}
                    height={height as number}
                    sizes={sizes}
                    className={cn(
                        'group-hover:opacity-75 object-cover',
                        'duration-700 ease-in-out',
                        isLoading
                        ? 'grayscale blur-2xl scale-110'
                        : 'grayscale-0 blur-0 scale-100',
                    )}
                    fill={fill}
                    onLoadingComplete={() => setLoading(false)}
                    priority={priority}
/>
            </AspectRatio>
        </div>
    );
}

3. 建立新的 ui/LoadingSpinner/index.ts 檔案并新增以下代碼:

    export * from './LoadingSpinner';

4. 建立新的 ui/LoadingSpinner/LoadingSpinner.tsx 檔案并新增以下代碼:

export interface LoadingSpinnerProps {
    className?: string;
    noText?: boolean;
    color?: string;
}

export function LoadingSpinner({ className = '', noText = false, color = 'amber-400' }: LoadingSpinnerProps) {
    return (
        <div aria-label="Loading..." role="status" className={`relative flex items-center justify-center space-x-2 ${className}`}>
        <svg className="h-6 w-6 animate-spin stroke-amber-600" viewBox="0 0 256 256">
            <line x1="128" y1="32" x2="128" y2="64" strokeLinecap="round" strokeLinejoin="round" strokeWidth="24"/>
            <line
                x1="195.9"
                y1="60.1"
                x2="173.3"
                y2="82.7"
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth="24"
/>
            <line x1="224" y1="128" x2="192" y2="128" strokeLinecap="round" strokeLinejoin="round" strokeWidth="24"/>
            <line
                x1="195.9"
                y1="195.9"
                x2="173.3"
                y2="173.3"
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth="24"
/>
            <line x1="128" y1="224" x2="128" y2="192" strokeLinecap="round" strokeLinejoin="round" strokeWidth="24"/>
            <line
                x1="60.1"
                y1="195.9"
                x2="82.7"
                y2="173.3"
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth="24"
/>
            <line x1="32" y1="128" x2="64" y2="128" strokeLinecap="round" strokeLinejoin="round" strokeWidth="24"/>
            <line
                x1="60.1"
                y1="60.1"
                x2="82.7"
                y2="82.7"
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth="24"
/>
        </svg>
            {!noText && <span className="text-xs font-medium text-gray-500">Loading...</span>}
        </div>
    );
}

5. 建立新的 ui/NavLink/index.ts 檔案并新增以下代碼:

export * from './NavLink';

6. 建立新的 ui/NavLink/NavLink.tsx 檔案并新增以下代碼:

import { PropsWithChildren } from 'react';
import Link from 'next/link';
import { cn } from '@woographql/utils/ui';

export const linkClassName = 'transition-colors group-hover:text-blue-400';

export interface NavLinkProps {
    href: string;
    className?: string;
    shallow?: boolean;
    prefetch?: boolean;
}

export function NavLink(props: PropsWithChildren<NavLinkProps>) {
    const {
        children,
        href,
        className,
        shallow,
        prefetch,
    } = props;
    return (
        <Link
            className={cn(
                className,
                linkClassName,
            )}
            href={href}
            shallow={shallow}
            prefetch={prefetch}
>
            {children}
        </Link>
    );
}

安裝并設定圖克QL 碼產生器

最后需要建立 GraphQL 代碼產生器 (代码) 以產生已輸入的 GraphQL 操作。 Codgen 有活生生的活生生活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活活 它會以所提供 GraphQL 端點相關的程式碼被設定出 。 在我們的應用程式中, 它會被用於產生 GraphQL 端點的 TypeScript 類型; 在 GraphQL 操作中會產生 TS 類型; 以及 整齊的包裝, 它能使所執行的操作被用到的微風 graphql-request 文庫。

1. 在您的端口中執行以下命令以安裝 GraphQL 碼產生器和需要的一些外掛程式:

npm i -D npm-run-all @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-graphql-request

2. 建立新的 codegen.ts 在您專案的根目錄中新增以下碼:

import type { CodegenConfig } from '@graphql-codegen/cli';
import dotenv from 'dotenv-flow';

dotenv.config({ silent: true }); 
const config: CodegenConfig = {
    schema: process.env.GRAPHQL_ENDPOINT,
    documents: ['graphql/**/*.graphql'],
    verbose: true,
    overwrite: true,
    generates: {
        'graphql/generated.ts': {
            plugins: [
                'typescript',
                'typescript-operations',
                'typescript-graphql-request',
            ],
            config: {
                namingConvention: 'keep',
            }
        }
    }
}
export default config;

3. 更新 scripts 在您的屬性中 package.json 包含產生 GraphQL 操作和包裝的文稿的檔案:

{
    ...
    "scripts": {
        "next:dev": "next dev",
        "next:build": "next build",
        "start": "next start",
        "lint": "next lint",
        "codegen:dev": "graphql-codegen --config codegen.ts --watch",
        "codegen:build": "graphql-codegen --config codegen.ts",
        "dev": "run-p codegen:dev next:dev",
        "build": "NODE_ENV=production run-s codegen:build next:build",
    },
    ...
}

4. 建立新的 graphql/index.ts 檔案并新增以下代碼:

 export * from './generated';
 export * from './client';

5. 建立新的 graphql/main.graphql 檔案并新增以下代碼:

fragment MenuItemContent on MenuItem {
  id
  uri
  title
  label
  cssClasses
}

fragment MenuItemRecursive on MenuItem {
  ...MenuItemContent
  childItems {
    nodes {
      ...MenuItemContent
    }
  }
}

fragment MenuContent on Menu {
  id
  name
  locations
  slug
  menuItems(first: 20, where: {parentId: 0}) {
    nodes {
      ...MenuItemRecursive
    }
  }
}

fragment CustomerContent on Customer {
  id
  sessionToken
  firstName
  shipping {
    postcode
    state
    city
    country
  }
}

fragment ProductContentSlice on Product {
  id
  databaseId
  name
  slug
  type
  image {
    id
    sourceUrl(size:WOOCOMMERCE_THUMBNAIL)
    altText
  }
  ... on SimpleProduct {
    price
    regularPrice
    soldIndividually
  }
  ... on VariableProduct {
    price
    regularPrice
    soldIndividually
  }
}

fragment ProductVariationContentSlice on ProductVariation {
  id
  databaseId
  name
  slug
  image {
    id
    sourceUrl(size:WOOCOMMERCE_THUMBNAIL)
    altText
  }
  price
  regularPrice
}

fragment ProductContentSmall on Product {
  id
  databaseId
  slug
  name
  type
  shortDescription(format: RAW)
  image {
    id
    sourceUrl(size:WOOCOMMERCE_THUMBNAIL)
    altText
  }
  productCategories(first: 20) {
    nodes {
      id
      slug
      name
    }
  }
  productTags(first: 20) {
    nodes {
      id
      slug
      name
    }
  }
  allPaColor(first: 100) {
    nodes {
      id
      slug
      name
    }
  }
  ... on SimpleProduct {
    onSale
    stockStatus
    price
    rawPrice: price(format: RAW)
    regularPrice
    salePrice
    soldIndividually
  }
  ... on VariableProduct {
    onSale
    stockStatus
    price
    rawPrice: price(format: RAW)
    regularPrice
    salePrice
    soldIndividually
  }
}

fragment ProductContentFull on Product {
  id
  databaseId
  slug
  name
  type
  description
  shortDescription(format: RAW)
  image {
    id
    sourceUrl
    altText
  }
  galleryImages {
    nodes {
      id
      sourceUrl(size:WOOCOMMERCE_THUMBNAIL)
      altText
    }
  }
  productTags(first: 20) {
    nodes {
      id
      slug
      name
    }
  }
  attributes {
    nodes {
      id
      attributeId
      ... on LocalProductAttribute {
        name
        label
        options
        variation
      }
      ... on GlobalProductAttribute {
        name
        label
        options
        variation
        slug
        terms(first: 100) {
          nodes {
            id
            name
            slug
          }
        }
      }
    }
  }
  ... on SimpleProduct {
    onSale
    stockStatus
    price
    rawPrice: price(format: RAW)
    regularPrice
    salePrice
    stockStatus
    stockQuantity
    soldIndividually
    defaultAttributes(first: 100) {
      nodes {
        id
        attributeId
        name
        value
        label
      }
    }
  }
  ... on VariableProduct {
    onSale
    price
    rawPrice: price(format: RAW)
    regularPrice
    salePrice
    stockStatus
    stockQuantity
    soldIndividually
    defaultAttributes(first: 100) {
      nodes {
        id
        attributeId
        label
        name
        value
      }
    }
    variations(first: 50) {
      nodes {
        id
        databaseId
        name
        price
        rawPrice: price(format: RAW)
        regularPrice
        salePrice
        onSale
        attributes {
          nodes {
            name
            label
            value
          }
        }
        image {
          id
          sourceUrl
          altText
        }
      }
    }
  }
}

fragment VariationContent on ProductVariation {
  id
  name
  slug
  price
  regularPrice
  salePrice
  stockStatus
  stockQuantity
  onSale
  image {
    id
    sourceUrl
    altText
  }
}

fragment CartItemContent on CartItem {
  key
  product {
    node {
      ...ProductContentSlice
    }
  }
  variation {
    attributes {
      id
      label
      name
      value
    }
    node {
      ...ProductVariationContentSlice
    }
  }
  quantity
  total
  subtotal
  subtotalTax
  extraData {
    key
    value
  }
}

fragment CartContent on Cart {
  contents(first: 100) {
    itemCount
    nodes {
      ...CartItemContent
    }
  }
  appliedCoupons {
    code
    discountAmount
    discountTax
  }
  needsShippingAddress
  availableShippingMethods {
    packageDetails
    supportsShippingCalculator
    rates {
      id
      instanceId
      methodId
      label
      cost
    }
  }
  subtotal
  subtotalTax
  shippingTax
  shippingTotal
  total
  totalTax
  feeTax
  feeTotal
  discountTax
  discountTotal
}

fragment CustomerFields on Customer {
    id
    databaseId
    firstName
    lastName
    displayName
    email
    sessionToken
    metaData {
      key
      value
    }
}

query GetTopNav {
  menu(id: "primary", idType: LOCATION) {
    ...MenuContent
  }
}

query GetProducts($first: Int, $after: String, $where: RootQueryToProductConnectionWhereArgs) {
  products(first: $first, after: $after, where: $where) {
    pageInfo {
      endCursor
      hasNextPage
    }
    edges {
      cursor
      node {
        ...ProductContentSmall
      }
    }
    nodes {
      ...ProductContentSmall
    }
  }
}

query GetProduct($id: ID!, $idType: ProductIdTypeEnum) {
  product(id: $id, idType: $idType) {
    ...ProductContentFull
  }
}

query GetShopCategories($first: Int, $after: String, $where: RootQueryToProductCategoryConnectionWhereArgs) {
  productCategories(first: $first, after: $after, where: $where) {
    pageInfo {
      hasNextPage
      endCursor
    }
    edges {
      node {
        id
        name
        slug
      }
    }
    nodes {
      id
      name
      slug
    }
  }
}

query GetShopTags($first: Int, $after: String, $where: RootQueryToProductTagConnectionWhereArgs) {
  productTags(first: $first, after: $after, where: $where) {
    pageInfo {
      hasNextPage
      endCursor
    }
    edges {
      node {
        id
        name
        slug
      }
    }
    nodes {
      id
      name
      slug
    }
  }
}

query GetShopColors($first: Int, $after: String, $where: RootQueryToPaColorConnectionWhereArgs) {
  allPaColor(first: $first, after: $after, where: $where) {
    pageInfo {
      hasNextPage
      endCursor
    }
    edges {
      node {
        id
        name
        slug
      }
    }
    nodes {
      id
      name
      slug
    }
  }
}

query GetSession {
  cart {
    ...CartContent
  }
  customer {
    ...CustomerContent
  }
}

mutation AddToCart(
  $productId: Int!,
  $variationId: Int,
  $quantity: Int,
  $variation: [ProductAttributeInput],
  $extraData: String
) {
  addToCart(
    input: {
      productId: $productId,
      variationId: $variationId,
      quantity: $quantity,
      variation: $variation,
      extraData: $extraData
    }
  ) {
    cart {
      ...CartContent
    }
    cartItem {
      ...CartItemContent
    }
  }
}

mutation UpdateCartItemQuantities($items: [CartItemQuantityInput]) {
  updateItemQuantities(input: {items: $items}) {
    cart {
      ...CartContent
    }
    items {
      ...CartItemContent
    }
  }
}

mutation RemoveItemsFromCart($keys: [ID], $all: Boolean) {
  removeItemsFromCart(input: {keys: $keys, all: $all}) {
    cart {
      ...CartContent
    }
    cartItems {
      ...CartItemContent
    }
  }
}

mutation Login($username: String!, $password: String!) {
  login(input: { username: $username, password: $password }) {
    authToken
    refreshToken
    customer {
      ...CustomerFields
    }
  }
}

mutation RefreshAuthToken($refreshToken: String!) {
  refreshJwtAuthToken(input: { jwtRefreshToken: $refreshToken }) {
    authToken
  }
}

mutation UpdateSession($input: UpdateSessionInput!) {
  updateSession(input: $input) {
    session {
      id
      key
      value
    }
  }
}

6. 建立新的 graphql/client.ts 檔案并新增以下代碼:

import { GraphQLClient } from 'graphql-request';
import deepmerge from 'deepmerge';

import {
    RootQueryToProductConnectionWhereArgs,
    Product,
    ProductCategory,
    PaColor,
    getSdk,
    RootQueryToProductCategoryConnectionWhereArgs,
    RootQueryToPaColorConnectionWhereArgs,
    ProductIdTypeEnum,
} from './generated';

let client: GraphQLClient;
export function getClient() {
    const endpoint = process.env.GRAPHQL_ENDPOINT
    if (!endpoint) {
        throw new Error('GRAPHQL_ENDPOINT is not defined')
    }

    if (!client) {
        client = new GraphQLClient(endpoint);
    }

    return client;
}

export function getClientWithSdk() {
    return getSdk(getClient());
}

const initialConnectionResults = {
    pageInfo: {
        hasNextPage: true,
        endCursor: null,
    },
    edges: [],
    nodes: [],
};

export async function fetchProducts(
    pageSize: number, 
    pageLimit = 0,
    where?: RootQueryToProductConnectionWhereArgs
) {
    try {
        const client = getClientWithSdk();
        let data = { products: initialConnectionResults }
        let after = '';
        let count = 0
        while(data.products.pageInfo.hasNextPage && (pageLimit === 0 || count < pageLimit)) {
            const next = await client.GetProducts({
                first: pageSize,
                after,
                where,
            });

            data = deepmerge(data, next);
            after = next.products?.pageInfo.endCursor || '';
            count++;
        }

        return (data.products.nodes) as Product[];
    } catch (err) {
        console.error(err || 'Failed to fetch product listing!!!');
    }
}

export async function fetchCategories(
    pageSize: number,
    pageLimit = 0,
    where?: RootQueryToProductCategoryConnectionWhereArgs
) {
    try {
        const client = getClientWithSdk();
        let data = { productCategories: initialConnectionResults }
        let after = '';
        let count = 0
        while(data.productCategories.pageInfo.hasNextPage && (pageLimit === 0 || count < pageLimit)) {
        const next = await client.GetShopCategories({
            first: pageSize,
            after,
            where,
        });

            data = deepmerge(data, next);
            after = next.productCategories?.pageInfo.endCursor || '';
            count++;
        }

        return (data.productCategories.nodes) as ProductCategory[];

    } catch (err) {
        console.error(err || 'Failed to fetch product categories!!!');
    }
}

export async function fetchColors(
    pageSize: number,
    pageLimit = 0,
    where?: RootQueryToPaColorConnectionWhereArgs
) {
    try {
        const client = getClientWithSdk();
        let data = { allPaColor: initialConnectionResults }
        let after = '';
        let count = 0
        while(data.allPaColor.pageInfo.hasNextPage && (pageLimit === 0 || count < pageLimit)) {
        const next = await client.GetShopColors({
            first: pageSize,
            after,
            where
        });

            data = deepmerge(data, next);
            after = next.allPaColor?.pageInfo.endCursor || '';
            count++;
        }

        return (data.allPaColor.nodes) as PaColor[];
    } catch (err) {
        console.error(err || 'Failed to fetch product color attributes!!!');
    }
}

export async function fetchProductBy(slug: string, idType: ProductIdTypeEnum) {
    try {
        const client = getClientWithSdk();
        const data = await client.GetProduct({
            id: slug,
            idType: idType,
        });

        if (!data.product) {
            throw new Error('Product not found!!!');
        }

        return data.product as Product;
    } catch (err) {
        console.error(err || 'Failed to fetch product data!!!');
    }
}

第 二 部 分

恭喜! 您已成功使用您 WooCommerce 商店的 GraphQL 端點設定了通訊發展的 Next.js 應用程式 。 您已安裝并設定了 shadcn/ui 有相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相關相相關相相關相關相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相 您的應用程式已準備好再由您使用 GraphQL 的 WooCommerce 商店進一步發展并整合 。

接下一章



Leave a Reply

Your email address will not be published. Required fields are marked *