AgentSkillsCN

seo-system

使用 Vitest 编写快速而高效的测试。在为新功能添加测试、调试失败的测试,或决定哪些内容需要测试、哪些可以跳过时使用。

SKILL.md
--- frontmatter
name: seo-system
description: Add page metadata, JSON-LD structured data, and OG images. Use when adding SEO to pages, implementing schema.org markup, configuring Open Graph/Twitter cards, or using dynamic OG image generation.

SEO System

Sources:

When to Use

Use this skill when:

  • Adding metadata to pages
  • Implementing JSON-LD structured data
  • Configuring Open Graph / Twitter cards
  • Working with dynamic OG images

Instructions

Configuration

All SEO settings are in src/lib/seo/config.ts:

typescript
export const seoConfig = {
	siteName: "Saleor Store",
	description: "...",
	twitterHandle: null, // Set to enable Twitter cards
	enableJsonLd: true,
	enableOpenGraph: true,
	enableTwitterCards: true,
	noIndexPaths: ["/checkout"], // Excluded from crawlers
};

File Structure

code
src/lib/seo/
├── index.ts      # Public exports
├── config.ts     # Configuration
├── metadata.ts   # Page metadata helpers
└── json-ld.ts    # Structured data helpers

Root Layout Metadata

typescript
// src/app/layout.tsx
import { rootMetadata } from "@/lib/seo";
export const metadata = rootMetadata;

Page Metadata

typescript
import { buildPageMetadata } from "@/lib/seo";

export async function generateMetadata() {
	return buildPageMetadata({
		title: "Page Title",
		description: "Page description",
		image: "/og-image.jpg",
		url: "/page-path",
	});
}

Product JSON-LD

typescript
import { buildProductJsonLd } from "@/lib/seo";

const jsonLd = buildProductJsonLd({
  name: product.name,
  description: product.description,
  price: { amount: 29.99, currency: "USD" },
  inStock: true,
  images: [product.thumbnail?.url],
});

// In JSX:
{jsonLd && (
  <script
    type="application/ld+json"
    dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
  />
)}

Dynamic OG Images

The /api/og route generates branded images:

code
/api/og?title=Product%20Name&price=€29.99

Use in metadata:

typescript
buildPageMetadata({
	title: product.name,
	image: `/api/og?title=${encodeURIComponent(product.name)}`,
});

Examples

Complete Product Page SEO

typescript
// src/app/[channel]/(main)/products/[slug]/page.tsx

export async function generateMetadata({ params }) {
  const product = await fetchProduct(params.slug);

  return buildPageMetadata({
    title: product.name,
    description: product.seoDescription || product.description,
    image: product.thumbnail?.url,
    url: `/${params.channel}/products/${params.slug}`,
  });
}

export default async function ProductPage({ params }) {
  const product = await fetchProduct(params.slug);

  const jsonLd = buildProductJsonLd({
    name: product.name,
    price: product.pricing?.priceRange?.start?.gross,
    inStock: product.isAvailable,
  });

  return (
    <>
      {jsonLd && (
        <script type="application/ld+json"
          dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
        />
      )}
      <ProductContent product={product} />
    </>
  );
}

Disabling SEO

To remove SEO features entirely:

  1. Delete src/lib/seo/ folder
  2. Remove rootMetadata import from layout
  3. Remove buildPageMetadata/buildProductJsonLd from pages
  4. Delete src/app/api/og/

Anti-patterns

Don't hardcode metadata - Use the helpers
Don't skip JSON-LD on product pages - Important for search
Don't forget noIndexPaths - Exclude checkout, cart