Build Phases
Phase 8 — SEO & Metadata
Dynamic per-page metadata and auto-generated sitemaps.
Yoast SEO Integration
Yoast exposes its SEO data via yoast_head_json in the REST API response. Extend your WPPost type to include it:
// Extended type for posts with Yoast data
export interface WPPostWithYoast extends WPPost {
yoast_head_json: {
title: string;
description: string;
og_image?: Array<{ url: string; width: number; height: number }>;
canonical: string;
};
}
// In your [slug]/page.tsx generateMetadata:
export async function generateMetadata({ params }: { params: { slug: string } }) {
const post = await getPostBySlug(params.slug) as WPPostWithYoast;
if (!post) return {};
const y = post.yoast_head_json;
return {
title: y?.title ?? post.title.rendered,
description: y?.description ?? "",
openGraph: {
images: y?.og_image?.map(img => ({
url: img.url,
width: img.width,
height: img.height
})),
},
alternates: { canonical: y?.canonical },
};
}Auto-generated Sitemap
// src/app/sitemap.ts
import { getAllPosts, getAllProjects } from "@/lib/wordpress";
import { MetadataRoute } from "next";
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await getAllPosts(100);
const projects = await getAllProjects();
const base = "https://yourdomain.com";
return [
{ url: base, changeFrequency: "daily", priority: 1 },
{ url: `${base}/blog`, changeFrequency: "daily", priority: 0.9 },
{ url: `${base}/projects`, changeFrequency: "weekly", priority: 0.9 },
...posts.map(p => ({
url: `${base}/blog/${p.slug}`,
lastModified: new Date(p.modified),
changeFrequency: "weekly" as const,
priority: 0.8,
})),
...projects.map(p => ({
url: `${base}/projects/${p.slug}`,
lastModified: new Date(p.modified),
changeFrequency: "monthly" as const,
priority: 0.7,
})),
];
}Robots.txt
// src/app/robots.ts
import { MetadataRoute } from "next";
export default function robots(): MetadataRoute.Robots {
return {
rules: { userAgent: "*", allow: "/" },
sitemap: "https://yourdomain.com/sitemap.xml",
};
}SEO Checklist
| Item | How |
|---|---|
| Page title | generateMetadata per route |
| Meta description | Yoast yoast_head_json.description |
| Open Graph image | Yoast og_image or featured image URL |
| Canonical URL | Yoast canonical field |
| Sitemap | src/app/sitemap.ts — auto-submits to Google |
| Robots.txt | src/app/robots.ts |
| Structured data | Add JSON-LD in page components for articles |
After deploying, submit your sitemap to Google Search Console at yourdomain.com/sitemap.xml. This speeds up indexing significantly.