SEO GRAPHQL theo type page, post, product (ok)

ưới đây là các truy vấn GraphQL đã viết sẵn để lấy metadata SEO từ Rank Math SEO cho từng loại: page, post, và product (giả sử WooCommerce đang dùng WPGraphQL for WooCommerce).


✅ Truy vấn SEO cho Page

graphqlCopyEditquery GetPageSEOMetadata($uri: ID!) {
  page(id: $uri, idType: URI) {
    title
    seo {
      title
      description
      canonicalUrl
      breadcrumbTitle
      robots
      focusKeywords
      fullHead
      jsonLd {
        raw
      }
      breadcrumbs {
        text
        url
      }
    }
  }
}

✅ Truy vấn SEO cho Post

graphqlCopyEditquery GetPostSEOMetadata($uri: ID!) {
  post(id: $uri, idType: URI) {
    title
    seo {
      title
      description
      canonicalUrl
      breadcrumbTitle
      robots
      focusKeywords
      fullHead
      jsonLd {
        raw
      }
      breadcrumbs {
        text
        url
      }
    }
  }
}

✅ Truy vấn SEO cho Product (WooCommerce)

graphqlCopyEditquery GetProductSEOMetadata($uri: ID!) {
  product(id: $uri, idType: URI) {
    name
    seo {
      title
      description
      canonicalUrl
      breadcrumbTitle
      robots
      focusKeywords
      fullHead
      jsonLd {
        raw
      }
      breadcrumbs {
        text
        url
      }
    }
  }
}

🔁 Tuỳ biến dùng chung (optionally)

Bạn cũng có thể viết 1 query "union" tùy biến nếu bạn dùng nodeByUri (áp dụng nếu site bạn bật tính năng này):

graphqlCopyEditquery GetSEOMetadata($uri: String!) {
  nodeByUri(uri: $uri) {
    ... on Page {
      id
      title
      seo { ...SeoFields }
    }
    ... on Post {
      id
      title
      seo { ...SeoFields }
    }
    ... on Product {
      id
      ... on Node {
        id
      }
      name
      seo { ...SeoFields }
    }
  }
}

fragment SeoFields on SEO {
  title
  description
  canonicalUrl
  breadcrumbTitle
  robots
  focusKeywords
  fullHead
  jsonLd {
    raw
  }
  breadcrumbs {
    text
    url
  }
}

Nếu bạn đang dùng Next.js với Apollo Client, mình có thể giúp bạn viết sẵn hook hoặc getStaticProps / getServerSideProps để gọi mấy cái này cho chuẩn. Muốn không?

Tuyệt! Dưới đây là cách bạn có thể tích hợp lấy SEO metadata từ Rank Math SEO vào dự án Next.js sử dụng Apollo Client, với cả getStaticProps, getServerSideProps, và React hook nếu dùng Client-side.


🔧 1. Cấu hình Apollo Client

Nếu bạn chưa có sẵn Apollo Client, bạn cần khởi tạo:

tsCopyEdit// lib/apollo-client.ts
import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
  uri: 'https://your-wordpress-site.com/graphql', // thay bằng URL của bạn
  cache: new InMemoryCache(),
});

export default client;

📦 2. Tạo GraphQL Query (dùng nodeByUri)

tsCopyEdit// graphql/seo.ts
import { gql } from '@apollo/client';

export const GET_SEO_METADATA = gql`
  query GetSEOMetadata($uri: String!) {
    nodeByUri(uri: $uri) {
      __typename
      ... on Page {
        id
        title
        seo { ...SeoFields }
      }
      ... on Post {
        id
        title
        seo { ...SeoFields }
      }
      ... on Product {
        id
        name
        seo { ...SeoFields }
      }
    }
  }

  fragment SeoFields on SEO {
    title
    description
    canonicalUrl
    breadcrumbTitle
    robots
    focusKeywords
    fullHead
    jsonLd {
      raw
    }
    breadcrumbs {
      text
      url
    }
  }
`;

🧠 3. getStaticProps (Static Page với SEO)

tsCopyEdit// pages/[slug].tsx
import { GetStaticProps } from 'next';
import client from '@/lib/apollo-client';
import { GET_SEO_METADATA } from '@/graphql/seo';

export const getStaticProps: GetStaticProps = async ({ params }) => {
  const uri = `/${params?.slug || ''}`;

  const { data } = await client.query({
    query: GET_SEO_METADATA,
    variables: { uri },
  });

  return {
    props: {
      seo: data?.nodeByUri?.seo ?? null,
    },
    revalidate: 60,
  };
};

✅ Tương ứng với slug: /about, /contact, /products/abc


🕸 4. getServerSideProps (SEO cập nhật real-time)

tsCopyEditexport const getServerSideProps = async ({ params }) => {
  const uri = `/${params.slug || ''}`;

  const { data } = await client.query({
    query: GET_SEO_METADATA,
    variables: { uri },
  });

  return {
    props: {
      seo: data?.nodeByUri?.seo ?? null,
    },
  };
};

🪝 5. Custom Hook (Client-side fetching)

tsCopyEdit// hooks/useSEOMetadata.ts
import { useQuery } from '@apollo/client';
import { GET_SEO_METADATA } from '@/graphql/seo';

export function useSEOMetadata(uri: string) {
  const { data, loading, error } = useQuery(GET_SEO_METADATA, {
    variables: { uri },
  });

  return {
    seo: data?.nodeByUri?.seo ?? null,
    loading,
    error,
  };
}

🧠 6. Hiển thị SEO data trong <Head>

tsxCopyEdit// components/SEO.tsx
import Head from 'next/head';

export default function SEO({ seo }) {
  if (!seo) return null;

  return (
    <Head>
      <title>{seo.title}</title>
      <meta name="description" content={seo.description} />
      <link rel="canonical" href={seo.canonicalUrl} />
      {seo.robots && <meta name="robots" content={seo.robots} />}
      {/* Inject full head HTML if you want */}
      <div dangerouslySetInnerHTML={{ __html: seo.fullHead }} />
    </Head>
  );
}

Nếu bạn cho mình biết:

  • Bạn dùng App Router hay Pages Router?

  • Bạn có cần multi-language (i18n)?

  • Bạn dùng client-side hay server-side rendering?

Mình có thể tinh chỉnh đoạn code này phù hợp hơn 💡

Hoàn hảo! Vì bạn dùng:

  • Next.js Pages Router

  • i18n (đa ngôn ngữ) – ví dụ /en/about, /vi/about

  • Server-side Rendering (SSR)

Mình sẽ giúp bạn tối ưu toàn bộ flow lấy Rank Math SEO metadata theo đúng chuẩn, có thể xài cho bất kỳ trang nào (post, page, product,...).


🧩 1. Cấu trúc URL hỗ trợ i18n

Trong Next.js pages với i18n, bạn thường có:

tsCopyEdit// next.config.js
i18n: {
  locales: ['en', 'vi'],
  defaultLocale: 'en',
}

Nghĩa là:

  • /en/about ⇒ uri là /about

  • /vi/gioi-thieu ⇒ uri là /gioi-thieu

➡️ Ta cần tách locale ra khỏi resolvedUrl để lấy uri.


🧠 2. Viết getServerSideProps với i18n và Rank Math SEO

tsxCopyEdit// pages/[...slug].tsx
import { GetServerSideProps } from 'next';
import client from '@/lib/apollo-client';
import { GET_SEO_METADATA } from '@/graphql/seo';
import SEO from '@/components/SEO';

export const getServerSideProps: GetServerSideProps = async ({ locale, resolvedUrl }) => {
  // Remove locale prefix (e.g., "/vi/about" => "/about")
  const uri = resolvedUrl.replace(/^\/[a-z]{2}(\/|$)/, '/');

  const { data } = await client.query({
    query: GET_SEO_METADATA,
    variables: { uri },
  });

  return {
    props: {
      seo: data?.nodeByUri?.seo ?? null,
    },
  };
};

export default function Page({ seo }) {
  return (
    <>
      <SEO seo={seo} />
      <main>
        {/* Nội dung trang ở đây */}
        <h1>Hello Page</h1>
      </main>
    </>
  );
}

🔁 3. File query GraphQL

tsCopyEdit// graphql/seo.ts
import { gql } from '@apollo/client';

export const GET_SEO_METADATA = gql`
  query GetSEOMetadata($uri: String!) {
    nodeByUri(uri: $uri) {
      __typename
      ... on Page {
        title
        seo { ...SeoFields }
      }
      ... on Post {
        title
        seo { ...SeoFields }
      }
      ... on Product {
        name
        seo { ...SeoFields }
      }
    }
  }

  fragment SeoFields on SEO {
    title
    description
    canonicalUrl
    breadcrumbTitle
    robots
    focusKeywords
    fullHead
    jsonLd {
      raw
    }
    breadcrumbs {
      text
      url
    }
  }
`;

🧱 4. Component SEO (inject vào <Head>)

tsxCopyEdit// components/SEO.tsx
import Head from 'next/head';

export default function SEO({ seo }) {
  if (!seo) return null;

  return (
    <Head>
      <title>{seo.title}</title>
      <meta name="description" content={seo.description || ''} />
      <link rel="canonical" href={seo.canonicalUrl || ''} />
      {seo.robots && <meta name="robots" content={seo.robots} />}
      {seo.fullHead && (
        <div dangerouslySetInnerHTML={{ __html: seo.fullHead }} />
      )}
    </Head>
  );
}

✅ Kết quả:

  • Bạn có thể thêm SEO tự động cho mọi trang /en/* hoặc /vi/*

  • Sử dụng SSR để lấy đúng dữ liệu từ Rank Math

  • i18n xử lý chuẩn vì mình bóc locale khỏi resolvedUrl


Bạn có muốn mình giúp bạn xử lý luôn cả breadcrumbs hoặc tạo sitemap XML tự động từ Rank Math không?

Last updated

Was this helpful?