Để lấy tất cả trang con (bao gồm cả cấp 1, cấp 2, cấp 3,...) của một trang cụ thể trong WordPress

Để lấy tất cả trang con (bao gồm cả cấp 1, cấp 2, cấp 3,...) của một trang cụ thể trong WordPress bằng GraphQL, bạn cần sử dụng plugin như WPGraphQL, và truy vấn phải sử dụng đệ quy (nếu được hỗ trợ) hoặc truy cập qua các cấp con cụ thể.

Tuy nhiên, WPGraphQL không hỗ trợ đệ quy tự động, nên bạn phải lặp các cấp con thủ công nếu số cấp đã biết. Dưới đây là ví dụ minh họa:

Muốn trích xuất tất cả các trang con (bao gồm cả các cấp độ sâu hơn như "Test 2.1", "Test 2.2") từ kết quả GraphQL đã cung cấp và đưa chúng vào một mảng phẳng.

Dưới đây là cách bạn có thể thực hiện điều đó bằng JavaScript (hoặc ngôn ngữ lập trình tương tự) để xử lý dữ liệu JSON đã nhận được:

const graphQLResult = {
  "data": {
    "page": {
      "id": "cG9zdDo1OA==",
      "uri": "/en/test/",
      "children": {
        "edges": [
          {
            "node": {
              "id": "cG9zdDo4NQ==",
              "excerpt": "",
              "title": "Test 1",
              "children": {
                "nodes": [
                  {
                    "id": "cG9zdDo5MA==",
                    "excerpt": "",
                    "featuredImage": null,
                    "title": "Test 2.2"
                  },
                  {
                    "id": "cG9zdDo4Nw==",
                    "excerpt": "",
                    "featuredImage": null,
                    "title": "Test 2.1"
                  }
                ]
              }
            }
          }
        ]
      }
    }
  }
};

function getAllChildren(pageData) {
  const childrenArray = [];

  function traverseChildren(nodes) {
    if (!nodes) {
      return;
    }

    nodes.forEach(node => {
      // Thêm thông tin của trang con hiện tại vào mảng
      childrenArray.push({
        id: node.id,
        excerpt: node.excerpt,
        title: node.title,
        featuredImage: node.featuredImage // Bao gồm featuredImage nếu có
      });

      // Nếu có các trang con tiếp theo, đệ quy
      if (node.children && node.children.nodes) {
        traverseChildren(node.children.nodes);
      }
    });
  }

  // Bắt đầu duyệt từ các con trực tiếp của trang "test"
  if (graphQLResult.data.page && graphQLResult.data.page.children && graphQLResult.data.page.children.edges) {
    graphQLResult.data.page.children.edges.forEach(edge => {
      // Đảm bảo rằng node tồn tại trước khi xử lý
      if (edge.node) {
        // Thêm trang con trực tiếp (Test 1)
        childrenArray.push({
          id: edge.node.id,
          excerpt: edge.node.excerpt,
          title: edge.node.title,
          featuredImage: edge.node.featuredImage
        });

        // Duyệt các con của Test 1 (Test 2.1, Test 2.2)
        if (edge.node.children && edge.node.children.nodes) {
          traverseChildren(edge.node.children.nodes);
        }
      }
    });
  }

  return childrenArray;
}

const allChildPages = getAllChildren(graphQLResult);
console.log(allChildPages);

Kết quả đầu ra (từ console.log(allChildPages)):

[
  { id: 'cG9zdDo4NQ==', excerpt: '', title: 'Test 1', featuredImage: undefined },
  { id: 'cG9zdDo5MA==', excerpt: '', title: 'Test 2.2', featuredImage: null },
  { id: 'cG9zdDo4Nw==', excerpt: '', title: 'Test 2.1', featuredImage: null }
]

Giải thích:

  1. graphQLResult: Đây là đối tượng JSON chứa kết quả từ truy vấn GraphQL của bạn.

  2. getAllChildren(pageData):

    • Hàm này sẽ nhận đối tượng kết quả GraphQL làm đầu vào.

    • childrenArray: Một mảng trống để lưu trữ tất cả các trang con đã tìm thấy.

    • traverseChildren(nodes): Đây là một hàm đệ quy.

      • Nó duyệt qua từng node trong danh sách nodes được cung cấp.

      • Với mỗi node, nó lấy các thông tin cần thiết (id, excerpt, title, featuredImage) và thêm vào childrenArray.

      • Nếu node đó có thêm children (tức là nó có các trang con riêng), hàm traverseChildren sẽ được gọi lại với nodes của các trang con đó, tạo ra quá trình đệ quy để duyệt qua tất cả các cấp.

    • Logic chính:

      • Đầu tiên, nó kiểm tra xem graphQLResult.data.page và các children.edges có tồn tại hay không.

      • Sau đó, nó duyệt qua các edge trong children.edges (đây là các trang con trực tiếp của "Test", trong trường hợp này là "Test 1").

      • Nó thêm "Test 1" vào childrenArray.

      • Cuối cùng, nó gọi traverseChildren để xử lý các trang con của "Test 1" (là "Test 2.1" và "Test 2.2"), đảm bảo rằng tất cả các cấp độ đều được đưa vào mảng.

Cách tiếp cận này hiệu quả để làm phẳng cấu trúc cây và lấy tất cả các trang con vào một mảng duy nhất, dễ dàng để xử lý tiếp.

Khai báo với typescript

Bạn muốn khai báo hàm getAllChildren với TypeScript, dựa trên cấu trúc dữ liệu GraphQL mà bạn đã cung cấp trước đó. Hàm này sẽ duyệt đệ quy qua các trang con để thu thập tất cả chúng vào một mảng phẳng.

Dưới đây là cách bạn có thể khai báo và triển khai hàm getAllChildren bằng TypeScript:


Khai báo Type và Hàm getAllChildren

Để khai báo hàm này một cách rõ ràng trong TypeScript, trước tiên chúng ta cần định nghĩa các interface (kiểu dữ liệu) cho cấu trúc dữ liệu mà GraphQL trả về. Điều này giúp TypeScript hiểu rõ hình dạng của dữ liệu và cung cấp tính năng tự động hoàn thành, kiểm tra lỗi tĩnh.

TypeScript

// 1. Định nghĩa các Interfaces cho dữ liệu GraphQL

interface FeaturedImageNode {
  sourceUrl: string | null;
  title?: string; // Tiêu đề ảnh có thể có hoặc không
}

interface FeaturedImage {
  node: FeaturedImageNode | null;
}

interface Language {
  code: string;
}

interface Translation {
  slug: string;
  language: Language;
}

// Định nghĩa interface cho một trang (page)
interface PageNode {
  id: string;
  excerpt: string;
  title: string;
  uri?: string; // URI có thể không có ở mọi cấp độ tùy thuộc truy vấn
  slug?: string; // Slug có thể không có ở mọi cấp độ
  featuredImage: FeaturedImage | null;
  language?: Language; // Ngôn ngữ có thể có hoặc không
  translations?: Translation[]; // Dịch thuật có thể có hoặc không
  children?: { // Các trang con
    nodes?: PageNode[]; // Đây là nơi xảy ra đệ quy
    edges?: { // Nếu bạn truy vấn dùng edges
      node: PageNode;
    }[];
  };
}

// Định nghĩa interface cho cấu trúc GraphQL đầy đủ
interface GraphQLPageResult {
  data: {
    page: PageNode;
  };
}

// 2. Khai báo và triển khai hàm getAllChildren

/**
 * Thu thập tất cả các trang con (bao gồm cả các cấp độ sâu hơn) từ một cấu trúc GraphQL phân cấp.
 *
 * @param graphQLResult Kết quả GraphQL chứa dữ liệu trang cha và các trang con.
 * @returns Một mảng phẳng chứa tất cả các trang con được tìm thấy.
 */
function getAllChildren(graphQLResult: GraphQLPageResult): PageNode[] {
  const childrenArray: PageNode[] = [];

  // Hàm đệ quy để duyệt và thu thập các trang con
  function traverseChildren(nodes: PageNode[] | undefined) {
    if (!nodes) {
      return;
    }

    nodes.forEach(node => {
      // Thêm thông tin của trang con hiện tại vào mảng
      // Clone đối tượng node để tránh tham chiếu nếu bạn cần chỉnh sửa sau này
      childrenArray.push({
        id: node.id,
        excerpt: node.excerpt,
        title: node.title,
        uri: node.uri,
        slug: node.slug,
        featuredImage: node.featuredImage,
        language: node.language,
        translations: node.translations,
      });

      // Nếu có các trang con tiếp theo (nested children), đệ quy
      if (node.children && node.children.nodes) {
        traverseChildren(node.children.nodes);
      } else if (node.children && node.children.edges) { // Xử lý nếu định dạng là edges
        traverseChildren(node.children.edges.map(edge => edge.node));
      }
    });
  }

  // Bắt đầu duyệt từ các con trực tiếp của trang gốc
  const rootPageChildren = graphQLResult.data.page?.children;

  if (rootPageChildren?.nodes) {
    traverseChildren(rootPageChildren.nodes);
  } else if (rootPageChildren?.edges) { // Xử lý nếu định dạng là edges
    traverseChildren(rootPageChildren.edges.map(edge => edge.node));
  }

  return childrenArray;
}

// --- Ví dụ sử dụng (dựa trên kết quả GraphQL bạn đã cung cấp) ---

const sampleGraphQLResult: GraphQLPageResult = {
  "data": {
    "page": {
      "id": "cG9zdDo1OA==",
      "uri": "/en/test/",
      "excerpt": "", // Thêm các trường cần thiết nếu không có trong truy vấn gốc
      "title": "Test", // Thêm tiêu đề của trang gốc
      "featuredImage": null,
      "children": {
        "edges": [
          {
            "node": {
              "id": "cG9zdDo4NQ==",
              "excerpt": "",
              "title": "Test 1",
              "featuredImage": null, // Đảm bảo có featuredImage để khớp interface
              "children": {
                "nodes": [
                  {
                    "id": "cG9zdDo5MA==",
                    "excerpt": "",
                    "featuredImage": null,
                    "title": "Test 2.2"
                  },
                  {
                    "id": "cG9zdDo4Nw==",
                    "excerpt": "",
                    "featuredImage": null,
                    "title": "Test 2.1"
                  }
                ]
              }
            }
          }
        ]
      }
    }
  }
};

const allChildPages = getAllChildren(sampleGraphQLResult);
console.log(allChildPages);

Giải thích:

  1. Định nghĩa Interfaces (PageNode, GraphQLPageResult, v.v.):

    • Đây là bước quan trọng nhất của TypeScript. Chúng ta tạo ra các "khuôn mẫu" để mô tả chính xác cấu trúc của dữ liệu mà bạn mong đợi từ GraphQL.

    • PageNode là interface trung tâm, mô tả một đối tượng trang với các thuộc tính như id, title, excerpt, featuredImage, và quan trọng nhất là children.

    • Thuộc tính children trong PageNode được định nghĩa đệ quy để có thể chứa một mảng các PageNode khác, phản ánh cấu trúc phân cấp. Tôi đã bao gồm cả nodesedges để phù hợp với các định dạng trả về khác nhau của WPGraphQL.

    • GraphQLPageResult là interface bao bọc toàn bộ kết quả GraphQL, đảm bảo cấu trúc data.page được xác định.

  2. Hàm getAllChildren(graphQLResult: GraphQLPageResult): PageNode[]:

    • Kiểu tham số: Hàm nhận một đối tượng graphQLResult có kiểu GraphQLPageResult. TypeScript sẽ kiểm tra xem đối tượng bạn truyền vào có khớp với cấu trúc này không.

    • Kiểu trả về: Hàm được khai báo sẽ trả về một mảng các PageNode (PageNode[]).

    • childrenArray: PageNode[] = []: Mảng này được khai báo với kiểu PageNode[], đảm bảo rằng chỉ các đối tượng khớp với PageNode mới có thể được thêm vào.

    • Hàm traverseChildren(nodes: PageNode[] | undefined):

      • Đây là hàm đệ quy được sử dụng để duyệt qua các cấp độ con.

      • Tham số nodes có kiểu PageNode[] | undefined để xử lý trường hợp không có node nào.

      • Khi childrenArray.push(node) được gọi, TypeScript đảm bảo rằng node khớp với PageNode.

      • Logic kiểm tra node.children && node.children.nodes hoặc node.children && node.children.edges giúp hàm xử lý cả hai dạng trả về của children (trực tiếp nodes hoặc qua edges).

Bằng cách sử dụng các interface này, bạn sẽ nhận được sự hỗ trợ mạnh mẽ từ TypeScript, giúp phát hiện lỗi cú pháp, lỗi logic sớm hơn trong quá trình phát triển, và làm cho mã nguồn của bạn dễ đọc và bảo trì hơn.

Bạn muốn chuyển đổi cấu trúc dữ liệu GraphQL phức tạp thành một mảng phẳng các đối tượng Product đơn giản hơn, phù hợp với interface Product mà bạn đã định nghĩa.

Dưới đây là hàm TypeScript để thực hiện việc chuyển đổi này, bao gồm cả việc xử lý ảnh đại diện (featuredImage).

TypeScript

// 1. Định nghĩa các Interfaces cho dữ liệu GraphQL (giữ nguyên từ lần trước, đã được điều chỉnh)

interface MediaItemNode {
  __typename: "MediaItem";
  sourceUrl: string | null;
  title?: string;
}

interface NodeWithFeaturedImageConnectionEdge {
  __typename: "NodeWithFeaturedImageToMediaItemConnectionEdge";
  node: MediaItemNode;
}

interface FeaturedImageGraphQL { // Đổi tên để tránh xung đột với interface Product.img
  __typename: "NodeWithFeaturedImageToMediaItemConnectionEdge"; // Thêm typename nếu có
  node: MediaItemNode | null;
}


interface PageNode {
  __typename: "Page";
  id: string;
  excerpt: string;
  title: string;
  uri?: string;
  slug?: string;
  featuredImage: FeaturedImageGraphQL | null; // Sử dụng FeaturedImageGraphQL
  language?: { __typename: string; code: string; }; // Giữ nguyên nếu có
  translations?: { __typename: string; slug: string; language: { __typename: string; code: string; }; }[]; // Giữ nguyên nếu có
  children?: {
    __typename: "HierarchicalContentNodeToContentNodeChildrenConnection";
    edges?: {
      __typename: "HierarchicalContentNodeToContentNodeChildrenConnectionEdge";
      node: PageNode;
    }[];
    nodes?: PageNode[];
  };
}

interface GraphQLPageResult {
  data: {
    page: PageNode;
  };
}

// 2. Định nghĩa interface Product của bạn
interface Product {
  id: string;
  title: string;
  img: string; // URL của ảnh featured
  category: string; // Bạn cần xác định logic để gán category
}

// 3. Hàm chuyển đổi từ GraphQL sang mảng Product

/**
 * Chuyển đổi dữ liệu GraphQL phân cấp thành một mảng phẳng các đối tượng Product.
 *
 * @param graphQLResult Kết quả GraphQL trả về.
 * @returns Mảng phẳng các đối tượng Product.
 */
function convertGraphQLToProducts(graphQLResult: GraphQLPageResult): Product[] {
  const products: Product[] = [];

  // Hàm đệ quy để duyệt và chuyển đổi các page node thành product
  function processPageNode(pageNode: PageNode) {
    const imageUrl = pageNode.featuredImage?.node?.sourceUrl || ''; // Lấy sourceUrl hoặc chuỗi rỗng

    // Giả định cách bạn gán category.
    // Ví dụ: dựa vào một phần của title hoặc một logic phức tạp hơn.
    // Hiện tại, tôi sẽ dùng một logic đơn giản hoặc placeholder.
    let category: string = 'default';
    if (pageNode.title.includes('Test 1')) {
      category = 'category-A';
    } else if (pageNode.title.includes('Test 2.1') || pageNode.title.includes('Test 2.2')) {
      category = 'category-B';
    }
    // Bạn có thể mở rộng logic này để gán category phù hợp với yêu cầu của bạn

    // Chỉ thêm vào nếu có đủ thông tin cần thiết cho một Product
    products.push({
      id: pageNode.id,
      title: pageNode.title,
      img: imageUrl,
      category: category,
    });

    // Tiếp tục đệ quy cho các trang con
    if (pageNode.children) {
      if (pageNode.children.nodes) {
        pageNode.children.nodes.forEach(childNode => processPageNode(childNode));
      } else if (pageNode.children.edges) {
        pageNode.children.edges.forEach(edge => processPageNode(edge.node));
      }
    }
  }

  // Bắt đầu xử lý từ trang gốc
  // Lưu ý: Nếu bạn muốn trang gốc (ví dụ "Test") cũng là một "Product"
  // thì bạn sẽ gọi processPageNode(graphQLResult.data.page);
  // Nếu chỉ muốn các trang con, thì bạn sẽ làm như sau:

  const rootPage = graphQLResult.data.page;
  if (rootPage.children) {
    if (rootPage.children.nodes) {
      rootPage.children.nodes.forEach(childNode => processPageNode(childNode));
    } else if (rootPage.children.edges) {
      rootPage.children.edges.forEach(edge => processPageNode(edge.node));
    }
  }

  return products;
}

// --- Dữ liệu đầu vào bạn cung cấp ---
const graphQLDataInput = {
  "data": {
    "page": {
      "__typename": "Page",
      "id": "cG9zdDo1OA==",
      "uri": "/en/test/",
      "children": {
        "__typename": "HierarchicalContentNodeToContentNodeChildrenConnection",
        "edges": [
          {
            "__typename": "HierarchicalContentNodeToContentNodeChildrenConnectionEdge",
            "node": {
              "__typename": "Page",
              "id": "cG9zdDo4NQ==",
              "excerpt": "",
              "title": "Test 1",
              "featuredImage": {
                "__typename": "NodeWithFeaturedImageToMediaItemConnectionEdge",
                "node": {
                  "__typename": "MediaItem",
                  "sourceUrl": "https://test1.com/wp-content/uploads/2025/05/10.webp",
                  "title": "10"
                }
              },
              "children": {
                "__typename": "HierarchicalContentNodeToContentNodeChildrenConnection",
                "nodes": [
                  {
                    "__typename": "Page",
                    "id": "cG9zdDo5MA==",
                    "excerpt": "",
                    "featuredImage": null,
                    "title": "Test 2.2"
                  },
                  {
                    "__typename": "Page",
                    "id": "cG9zdDo4Nw==",
                    "excerpt": "",
                    "featuredImage": {
                      "__typename": "NodeWithFeaturedImageToMediaItemConnectionEdge",
                      "node": {
                        "__typename": "MediaItem",
                        "sourceUrl": "https://test1.com/wp-content/uploads/2025/05/4-scaled.jpg",
                        "title": "4"
                      }
                    },
                    "title": "Test 2.1"
                  }
                ]
              }
            }
          }
        ]
      }
    }
  }
};

// Chuyển đổi dữ liệu
const allProductsArray: Product[] = convertGraphQLToProducts(graphQLDataInput);
console.log(allProductsArray);

/*
Kết quả mong đợi:
[
  {
    id: "cG9zdDo4NQ==",
    title: "Test 1",
    img: "https://test1.com/wp-content/uploads/2025/05/10.webp",
    category: "category-A"
  },
  {
    id: "cG9zdDo5MA==",
    title: "Test 2.2",
    img: "", // featuredImage là null
    category: "category-B"
  },
  {
    id: "cG9zdDo4Nw==",
    title: "Test 2.1",
    img: "https://test1.com/wp-content/uploads/2025/05/4-scaled.jpg",
    category: "category-B"
  }
]
*/

Giải thích các thay đổi và logic:

  1. Cập nhật Interfaces GraphQL:

    • FeaturedImageGraphQL: Đã đổi tên để tránh nhầm lẫn với trường img trong Product.

    • Đảm bảo __typename được bao gồm ở tất cả các cấp nơi nó xuất hiện trong dữ liệu của bạn.

  2. Hàm convertGraphQLToProducts(graphQLResult: GraphQLPageResult): Product[]:

    • products: Product[] = []: Khởi tạo một mảng rỗng để lưu trữ các đối tượng Product đã chuyển đổi.

    • processPageNode(pageNode: PageNode): Đây là hàm đệ quy chính:

      • Nó nhận một PageNode làm đối số.

      • Lấy img (sourceUrl):TypeScript

        const imageUrl = pageNode.featuredImage?.node?.sourceUrl || '';

        Dòng này sử dụng optional chaining (?.) để truy cập an toàn vào featuredImage, nodesourceUrl. Nếu bất kỳ phần nào trên đường dẫn là null hoặc undefined, nó sẽ trả về undefined, và sau đó toán tử || '' sẽ gán một chuỗi rỗng.

      • Gán category:

        • Tôi đã thêm một logic giả định để gán category dựa trên title của trang (if (pageNode.title.includes('Test 1')) { category = 'category-A'; }).

        • Bạn cần thay đổi logic này để phù hợp với cách bạn muốn phân loại các sản phẩm của mình. Ví dụ, bạn có thể có một trường custom field trong WordPress lưu trữ category của sản phẩm, và bạn sẽ cần truy vấn trường đó qua GraphQL để lấy thông tin category.

      • Thêm vào products array: Một đối tượng Product mới được tạo với id, title (từ pageNode.title), img (từ imageUrl), và category và được push vào mảng products.

      • Đệ quy cho children: Hàm này sau đó kiểm tra pageNode.children và gọi đệ quy processPageNode cho tất cả các trang con (dù chúng nằm trong nodes hay edges).

    • Logic bắt đầu:

      • Hàm bắt đầu bằng cách lấy rootPage (graphQLResult.data.page).

      • Nó sau đó kiểm tra rootPage.children và bắt đầu quá trình đệ quy processPageNode cho tất cả các trang con trực tiếp của trang gốc.

      • Nếu bạn muốn bản thân trang gốc (ví dụ "Test") cũng được chuyển đổi thành một "Product" và thêm vào danh sách, bạn chỉ cần gọi processPageNode(rootPage); trước khi xử lý các con của nó. Hiện tại, nó chỉ xử lý các trang con của "Test".

Với hàm này, bạn có thể biến dữ liệu GraphQL phân cấp của mình thành một mảng phẳng các đối tượng Product dễ dàng quản lý trong ứng dụng Next.js của bạn.

Generate Audio Overview

src\graphql\queries.ts

import { gql } from '@apollo/client'
export const GET_HOMEPAGE = gql`
  query {
    page(id: "home", idType: URI) {
      title
      content
      translations {
        uri
        language {
          code
        }
      }
    }
  }
`
export const GET_POST = gql`
  query GetPost($slug: String!) {
    postBy(slug: $slug) {
      databaseId
      title
      content
      slug
      featuredImage {
        node {
          sourceUrl
          altText
          title
        }
      }
      categories {
        nodes {
          id
          name
          slug
        }
      }
      tags {
        nodes {
          id
          name
          slug
        }
      }
      translations {
        uri
        language {
          code
        }
      }
      language {
        code
      }
    }
  }
`
export const GET_RELATED_POSTS = gql`
query GetRelatedPosts($slug: ID!) {
  post(id: $slug,idType: SLUG) {
    categories {
      nodes {
        id
        posts(first: 4) {
          nodes {
            title
            slug
            uri
            featuredImage {
              node {
                sourceUrl
                altText
                title
              }
            }
          }
        }
      }
    }
    tags {
      nodes {
        id
        posts(first: 4) {
          nodes {
            title
            slug
            uri
          }
        }
      }
    }
  }
}`;
// GET_CHILD_POSTS
export const GET_CHILD_POSTS = gql`
query GetChildPosts($slug: String!) {
  page(id: $slug, idType: URI) {
    id
    uri
    children {
      edges {
        node {
          id
          ... on Page {
            id
            excerpt
            title
            featuredImage {
              node {
                sourceUrl
                title
              }
            }
            children {
              nodes {
                ... on Page {
                  id
                  excerpt
                  featuredImage {
                    node {
                      sourceUrl
                      title
                    }
                  }
                  title
                }
              }
            }
          }
        }
      }
    }
  }
}
`;
export const GET_PAGE = gql`
  query GetPage($slug: String!) {
    pageBy(uri: $slug) {
      title
      content
      featuredImage {
        node {
          sourceUrl
        }
      }
      translations {
        uri
        language {
          code
        }
      }
      language {
        code
      }
    }
  }
`;
// Query để lấy danh sách chuyên mục
export const GET_CATEGORIES = gql`
  query GetCategories {
    categories {
      nodes {
        slug
        name
        language {
          code
        }
        translations {
          slug
          language {
            code
          }
        }
      }
    }
  }
`;
// Query để lấy bài viết theo chuyên mục
export const GET_POSTS_BY_CATEGORY = gql`
  query GetPostsByCategory($slug: ID!) {
    category(id:$slug, idType: SLUG) {
      slug
      name
      language {
        code
      }
      translations {
        slug
        language {
          code
        }
      }
      posts {
        nodes {
          slug
          title
          content
          language {
            code
          }
          translations {
            slug
            language {
              code
            }
          }
        }
      }
    }
  }
`;
// Query để lấy bài viết mới nhất
export const GET_POSTS_NEW = gql`
  query GetPosts($language: LanguageCodeFilterEnum!) {
  posts(before: "10", where: {language: $language}) {
    nodes {
      title
      excerpt
      date
      uri
      slug
      featuredImage {
        node {
          sourceUrl
        }
      }
      language {
        code
      }
      translations {
        slug
        language {
          code
        }
      }
    }
  }
}
`;
export const GET_SINGLE_SEO_METADATA = gql`
  query GetPageSEOMetadata($uri: ID!) {
  page(id: $uri, idType: URI) {
    title
    seo {
      title
      description
      canonicalUrl
      breadcrumbTitle
      robots
      focusKeywords
      fullHead
      jsonLd {
        raw
      }
      breadcrumbs {
        text
        url
      }
    }
  }
}
`;
// Query để lấy bài tất cả bài viêt 
export const GET_ALL_POSTS = gql`
  query GetPosts {
    posts {
      nodes {
        title
        excerpt
        date
        uri
        slug
        featuredImage {
          node {
            sourceUrl
          }
        }
        language {
          code
        }
        translations {
          slug
          language {
            code
          }
        }
      }
    }
  }
`;

Last updated

Was this helpful?