Blog System
Built-in blog with categories, SEO optimization, and markdown support for content marketing.
Overview
The blog system allows you to create and publish content to attract and engage users. It includes category organization, SEO features, and view tracking.
Features
- Create and publish blog posts
- Category organization (many-to-many)
- Draft and published states
- Cover images
- View counter
- Author attribution
- SEO-friendly URLs (slugs)
Database Schema
Blog Model
model Blog {
id String @id @default(cuid())
title String
slug String @unique
content String
excerpt String?
featuredImage String?
published Boolean @default(false)
views Int @default(0)
authorId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
author User @relation(fields: [authorId], references: [id])
categories BlogCategory[]
}Category Model
model Category {
id String @id @default(cuid())
name String @unique
slug String @unique
description String?
createdAt DateTime @default(now())
blogs BlogCategory[]
}Many-to-Many Relationship
model BlogCategory {
id String @id @default(cuid())
blogId String
categoryId String
createdAt DateTime @default(now())
blog Blog @relation(fields: [blogId], references: [id], onDelete: Cascade)
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
@@unique([blogId, categoryId])
}Creating Blog Posts
Admin Interface
At /admin/blog/new:
- Enter title (slug auto-generated)
- Write content
- Add excerpt for preview
- Upload cover image (optional)
- Select categories
- Choose publish or save as draft
Via API
POST /api/blogs
{
"title": "Getting Started with Next.js",
"slug": "getting-started-nextjs",
"content": "Full content here...",
"excerpt": "A beginner's guide",
"featuredImage": "https://example.com/image.jpg",
"published": true,
"categoryIds": ["clx123..."]
}Public Blog Views
Blog List
At /blog:
- Shows all published posts
- Grid layout with cover images
- Excerpt and metadata
- Category badges
- Read more links
Individual Post
At /blog/[slug]:
- Full post content
- Author information
- Publication date
- View counter
- Category tags
- Cover image
SEO Features
URL Slugs
- Human-readable URLs:
/blog/my-post-title - Unique slugs enforced at database level
- Auto-generated from title (can be customized)
Metadata
// src/app/blog/[slug]/page.tsx
export async function generateMetadata({ params }) {
const blog = await prisma.blog.findUnique({
where: { slug: params.slug },
});
return {
title: blog.title,
description: blog.excerpt,
openGraph: {
title: blog.title,
description: blog.excerpt,
images: [blog.featuredImage],
},
};
}Categories
Create Category
POST /api/categories
{
"name": "Technology",
"slug": "technology",
"description": "Tech news and tutorials"
}Assign to Post
A post can have multiple categories:
await prisma.blogCategory.createMany({
data: [
{ blogId: post.id, categoryId: "cat1" },
{ blogId: post.id, categoryId: "cat2" },
],
});View Tracking
View count increments automatically when post is viewed:
await prisma.blog.update({
where: { id: blog.id },
data: { views: { increment: 1 } },
});Content Formatting
Markdown Support
Content can be written in Markdown and rendered with proper styling:
<div className="prose prose-slate dark:prose-invert max-w-none">
{content}
</div>Best Practices
- Write compelling titles and excerpts
- Use high-quality cover images
- Organize with relevant categories
- Keep URLs short and descriptive
- Optimize images for web
- Publish consistently
- Enable comments (optional feature)
API Endpoints
GET /api/blogs- List blogs (published or all for admin)POST /api/blogs- Create blog (admin only)GET /api/blogs/:id- Get blog by ID or slugPUT /api/blogs/:id- Update blog (admin only)DELETE /api/blogs/:id- Delete blog (admin only)GET /api/categories- List categoriesPOST /api/categories- Create category (admin only)