Customization & Optimization
Customize metadata and optimize SEO for your specific needs.
This page shows how to customize Plainform's SEO features for your specific use cases.
Dynamic Metadata
Blog Posts
Generate metadata from blog post data:
import { blogSource } from '@/lib/source';
export async function generateMetadata({ params }: { params: { slug: string[] } }) {
const page = blogSource.getPage(params.slug);
if (!page) {
return { title: 'Post Not Found' };
}
return {
title: page.data.title,
description: page.data.description,
openGraph: {
title: page.data.title,
description: page.data.description,
type: 'article',
publishedTime: page.data.date,
images: [page.data.image],
},
};
}Product Pages
Generate metadata from database:
import { prisma } from '@/lib/prisma/prisma';
import { siteConfig } from '@/config/siteConfig';
export async function generateMetadata({ params }: { params: { id: string } }) {
const product = await prisma.product.findUnique({
where: { id: params.id },
});
if (!product) {
return { title: 'Product Not Found' };
}
return {
title: `${product.name} | ${siteConfig.siteName}`,
description: product.description,
openGraph: {
title: product.name,
description: product.description,
images: [product.imageUrl],
},
};
}Dynamic Sitemap
Add dynamic routes to your sitemap:
import { getServerSideSitemap } from 'next-sitemap';
import { blogSource } from '@/lib/source';
import { env } from '@/env';
export async function GET() {
const posts = blogSource.getPages();
const fields = posts.map((post) => ({
loc: `${env.SITE_URL}/blog/${post.slugs.join('/')}`,
lastmod: new Date(post.data.date).toISOString(),
changefreq: 'weekly',
priority: 0.7,
}));
return getServerSideSitemap(fields);
}Add to next-sitemap.config.js:
module.exports = {
siteUrl: process.env.SITE_URL,
exclude: ['/server-sitemap.xml'],
robotsTxtOptions: {
additionalSitemaps: [
`${process.env.SITE_URL}/server-sitemap.xml`,
],
},
};Structured Data (JSON-LD)
Article Schema
export default function BlogPost({ params }: { params: { slug: string[] } }) {
const page = blogSource.getPage(params.slug);
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: page.data.title,
description: page.data.description,
image: page.data.image,
datePublished: page.data.date,
author: {
'@type': 'Person',
name: page.data.author,
},
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<article>{/* Post content */}</article>
</>
);
}Organization Schema
import { siteConfig } from '@/config/siteConfig';
import { env } from '@/env';
export default function RootLayout({ children }) {
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: siteConfig.siteName,
url: env.NEXT_PUBLIC_SITE_URL,
logo: `${env.NEXT_PUBLIC_SITE_URL}/logo.png`,
sameAs: [
'https://twitter.com/yourhandle',
'https://github.com/yourorg',
],
};
return (
<html>
<body>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
{children}
</body>
</html>
);
}Canonical URLs
Prevent duplicate content:
export function generateMetadata() {
return {
alternates: {
canonical: 'https://yourdomain.com/page',
},
};
}Performance Optimization
Lazy Load Images
<Image
src="/image.jpg"
alt="Description"
width={800}
height={600}
loading="lazy" // Default behavior
/>Optimize Third-Party Scripts
import Script from 'next/script';
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Script
src="https://analytics.example.com/script.js"
strategy="lazyOnload"
/>
</body>
</html>
);
}Testing SEO
Local Testing
View page source (Ctrl+U) to verify:
<title>tag<meta name="description">tag- Open Graph tags
Production Testing
Use these tools after deployment:
- Google Rich Results Test: search.google.com/test/rich-results
- Facebook Sharing Debugger: developers.facebook.com/tools/debug
- Lighthouse: Chrome DevTools → Lighthouse tab
Common Customizations
Custom 404 Page
export const metadata = {
title: '404 - Page Not Found',
description: 'The page you are looking for does not exist.',
};
export default function NotFound() {
return (
<div>
<h1>404 - Page Not Found</h1>
</div>
);
}Exclude Pages from Indexing
export const metadata = {
robots: {
index: false,
follow: false,
},
};Next Steps
- Configuration & Best Practices - SEO configuration guide
- Next.js Metadata API - Complete API reference
- Schema.org - Structured data documentation
How is this guide ?
Last updated on