Back to notes
mastery-seo
Featured

Next.js Metadata Mastery: เสกเว็บให้ติด Search และหล่อเท่บน Social

เจาะลึก Metadata API ของ Next.js วิธีทำ Dynamic Title, Description และ Open Graph Image ให้เว็บของคุณดูโปรฯ ทุกแพลตฟอร์ม

February 2, 20263 min read readNNexis by Seereen

🎭 1. First Impression is Everything

คุณเคยแชร์ลิงก์เว็บให้เพื่อนใน Line หรือ Facebook แล้วมันขึ้นแค่ URL โล้นๆ ไหมครับ? ดูไม่น่ากดเลยใช่ไหม? ในทางกลับกัน ลิงก์ที่ขึ้นภาพพรีวิวสวยๆ มีหัวข้อชัดเจน ย่อมดึงดูดนิ้วโป้งคนได้มากกว่า

นั่นคือพลังของ Metadata และ Open Graph (OG Tags) ครับ

ใน Next.js (App Router) การจัดการเรื่องนี้ง่ายจนน่าตกใจ ด้วย Metadata API ใหม่ที่ไม่ต้องไปแก้ HTML Head เองให้วุ่นวายครับ


🛠 2. Static Metadata: พื้นฐานที่ต้องมี

สำหรับหน้า Static ทั่วไป (เช่น Home, About) เราสามารถ export const metadata ได้เลยครับ

HLJS TYPESCRIPT/app/page.tsx
import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'My Awesome Blog',
  description: 'เรียนรู้ Programming ฉบับ Senior Developer',
  keywords: ['Next.js', 'React', 'Coding Tutorial'],
  openGraph: {
    title: 'My Awesome Blog',
    description: 'เรียนรู้ Programming ฉบับ Senior Developer',
    images: ['/og-image.png'], // รูปต้องอยู่ใน public folder
  },
}

export default function Page() {}

🚀 3. Dynamic Metadata: ไฮไลท์ของจริง

จุดพีคคือหน้าบทความ ([slug]) ครับ เพราะแต่ละหน้า Title และ Description ต้องเปลี่ยนไปตามเนื้อหา Next.js ให้ฟังก์ชัน generateMetadata มาเพื่อการนี้โดยเฉพาะ

HLJS TYPESCRIPT/app/[category]/[slug]/page.tsx
import type { Metadata } from 'next'
import { getPostBySlug } from '@/lib/markdown'

interface Props {
  params: { slug: string; category: string }
}

// 🪄 Magic Function: ทำงานที่ฝั่ง Server เท่านั้น
export async function generateMetadata(
  { params }: Props
): Promise<Metadata> {
  // 1. ดึงข้อมูลบทความ
  const post = await getPostBySlug(params.slug)

  if (!post) {
    return { title: 'Post Not Found' }
  }

  // 2. Return Metadata ที่สอดคล้องกับบทความ
  return {
    title: {
        absolute: post.metadata.title, // ใช้ Absolute เพื่อไม่ให้มี Template มาต่อท้าย
    },
    description: post.metadata.description,
    openGraph: {
      title: post.metadata.title,
      description: post.metadata.description,
      type: 'article',
      publishedTime: post.metadata.date,
      authors: [post.metadata.author || 'Nexis Team'],
      images: [
        {
          url: `/api/og?title=${encodeURIComponent(post.metadata.title)}`, // 🖼️ Dynamic Image!
          width: 1200,
          height: 630,
        }
      ],
    },
    twitter: {
      card: 'summary_large_image',
      title: post.metadata.title,
      description: post.metadata.description,
    },
  }
}

export default function Page({ params }: Props) {
    // ... render page content
}

Senior Tip: สังเกตตรง images ไหมครับ? เราสามารถสร้าง API Route เพื่อ Generate รูปภาพหน้าปกบทความแบบอัตโนมัติ (Image Generation) ได้ด้วย! ไม่ต้องมานั่งทำ Photoshop ทีละรูปครับ


🎨 4. Open Graph Image Generation (แถม!)

Next.js มี ImageResponse ให้ใช้สร้างรูปจาก Code ได้เลย (ใช้ library satori เบื้องหลัง)

HLJS TYPESCRIPT/app/api/og/route.tsx
import { ImageResponse } from 'next/og'

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url)
  const title = searchParams.get('title') || 'My Blog'

  return new ImageResponse(
    (
      <div
        style={{
          fontSize: 60,
          background: 'white',
          width: '100%',
          height: '100%',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        👋 {title}
      </div>
    ),
    { width: 1200, height: 630 }
  )
}

🏆 5. Check List ก่อน Deploy

  1. Title: ต้องไม่เกิน 60 ตัวอักษร
  2. Description: ต้องไม่เกิน 160 ตัวอักษร (ถ้าเกินจะถูกตัด)
  3. Canonical URL: เพื่อบอก Google ว่าหน้านี้คือต้นฉบับ (Next.js ใส่ให้ Auto ถ้าตั้ง metadataBase)
  4. OG Image: ต้องมีขนาด 1200x630px และไฟล์ไม่ควรใหญ่เกิน 300KB

การใส่ใจ Metadata คือการ "ให้เกียรติคนแชร์" ครับ ยิ่งเราทำ Link Preview สวย เพื่อนๆ ก็ยิ่งอยากแชร์เว็บเราต่อครับ!

Share this note

© 2026 My Notes by Seereen