Skip to content

Commit

Permalink
add category/tag archive support
Browse files Browse the repository at this point in the history
  • Loading branch information
gregrickaby committed Dec 19, 2023
1 parent 68e9245 commit fda0984
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Please consider it a starting point for your next headless WordPress project.
- Previews
- Static Site Generation (SSG)
- On-demand Revalidation
- Category and Tag Archives
- Custom Post Types
- Custom Fields
- Comments
Expand Down
7 changes: 5 additions & 2 deletions app/blog/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import getAllPosts from '@/lib/queries/getAllPosts'
import getPostBySlug from '@/lib/queries/getPostBySlug'
import {Metadata} from 'next'
import Image from 'next/image'
import Link from 'next/link'
import {notFound} from 'next/navigation'

/**
Expand Down Expand Up @@ -78,7 +79,9 @@ export default async function Post({params}: {params: {slug: string}}) {
<ul className="m-0 flex list-none gap-2 p-0">
{post.categories.nodes.map((category) => (
<li className="m-0 p-0" key={category.databaseId}>
{category.name}
<Link href={`/blog/category/${category.name}`}>
{category.name}
</Link>
</li>
))}
</ul>
Expand All @@ -89,7 +92,7 @@ export default async function Post({params}: {params: {slug: string}}) {
<ul className="m-0 flex list-none gap-2 p-0">
{post.tags.nodes.map((tag) => (
<li className="m-0 p-0" key={tag.databaseId}>
{tag.name}
<Link href={`/blog/tag/${tag.name}`}>{tag.name}</Link>
</li>
))}
</ul>
Expand Down
72 changes: 72 additions & 0 deletions app/blog/category/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import config from '@/lib/config'
import getCategoryBySlug from '@/lib/queries/getCategoryBySlug'
import {Metadata} from 'next'
import Image from 'next/image'
import Link from 'next/link'
import {notFound} from 'next/navigation'

/**
* Generate the metadata for each static route at build time.
*
* @see https://nextjs.org/docs/app/api-reference/functions/generate-metadata#generatemetadata-function
*/
export async function generateMetadata({
params
}: {
params: {slug: string}
}): Promise<Metadata | null> {
const slug = params.slug

return {
title: `${slug} Archives - ${config.siteName}`,
description: `The post archive for ${slug}`
}
}

/**
* The category archive route.
*
* @see https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#pages
*/
export default async function CategoryArchive({
params
}: {
params: {slug: string}
}) {
// Fetch posts from WordPress.
const posts = await getCategoryBySlug(params.slug)

// No posts? Bail...
if (!posts) {
notFound()
}

return (
<main className="flex flex-col gap-8">
<h1 className="capitalize">Post Category: {params.slug}</h1>
<div className="flex flex-wrap gap-8">
{posts.map((post) => (
<article className="w-72" key={post.databaseId}>
<Image
alt={post.featuredImage.node.altText}
height={post.featuredImage.node.mediaDetails.height}
src={post.featuredImage.node.sourceUrl}
width={post.featuredImage.node.mediaDetails.width}
priority={true}
/>
<Link href={`/blog/${post.slug}`}>
<h2 dangerouslySetInnerHTML={{__html: post.title}} />
</Link>
<p className="text-sm text-gray-500">
{post.commentCount} Comments
</p>
<div dangerouslySetInnerHTML={{__html: post.excerpt}} />
<Link className="button" href={`/blog/${post.slug}`}>
View Post
</Link>
</article>
))}
</div>
</main>
)
}
68 changes: 68 additions & 0 deletions app/blog/tag/[slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import config from '@/lib/config'
import getTagBySlug from '@/lib/queries/getTagBySlug'
import {Metadata} from 'next'
import Image from 'next/image'
import Link from 'next/link'
import {notFound} from 'next/navigation'

/**
* Generate the metadata for each static route at build time.
*
* @see https://nextjs.org/docs/app/api-reference/functions/generate-metadata#generatemetadata-function
*/
export async function generateMetadata({
params
}: {
params: {slug: string}
}): Promise<Metadata | null> {
const slug = params.slug

return {
title: `${slug} Archives - ${config.siteName}`,
description: `The post archive for ${slug}`
}
}

/**
* The tag archive route.
*
* @see https://nextjs.org/docs/app/building-your-application/routing/pages-and-layouts#pages
*/
export default async function TagArchive({params}: {params: {slug: string}}) {
// Fetch posts from WordPress.
const posts = await getTagBySlug(params.slug)

// No posts? Bail...
if (!posts) {
notFound()
}

return (
<main className="flex flex-col gap-8">
<h1 className="capitalize">Post Category: {params.slug}</h1>
<div className="flex flex-wrap gap-8">
{posts.map((post) => (
<article className="w-72" key={post.databaseId}>
<Image
alt={post.featuredImage.node.altText}
height={post.featuredImage.node.mediaDetails.height}
src={post.featuredImage.node.sourceUrl}
width={post.featuredImage.node.mediaDetails.width}
priority={true}
/>
<Link href={`/blog/${post.slug}`}>
<h2 dangerouslySetInnerHTML={{__html: post.title}} />
</Link>
<p className="text-sm text-gray-500">
{post.commentCount} Comments
</p>
<div dangerouslySetInnerHTML={{__html: post.excerpt}} />
<Link className="button" href={`/blog/${post.slug}`}>
View Post
</Link>
</article>
))}
</div>
</main>
)
}
46 changes: 46 additions & 0 deletions lib/queries/getCategoryBySlug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {fetchGraphQL} from '@/lib/functions'
import {Post} from '@/lib/types'

/**
* Fetch a category archive by slug.
*/
export default async function getCategoryBySlug(
slug: string,
limit: number = 10
) {
const query = `
query GetCategoryBySlug($slug: String!) {
posts(where: {categoryName: $slug, status: PUBLISH}, first: ${limit}) {
nodes {
databaseId
date
excerpt(format: RENDERED)
title(format: RENDERED)
featuredImage {
node {
altText
sourceUrl
mediaDetails {
height
width
}
}
}
seo {
metaDesc
title
}
slug
}
}
}
`

const variables = {
slug: slug
}

const response = await fetchGraphQL(query, variables)

return response.data.posts.nodes as Post[]
}
43 changes: 43 additions & 0 deletions lib/queries/getTagBySlug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {fetchGraphQL} from '@/lib/functions'
import {Post} from '@/lib/types'

/**
* Fetch a tag archive by slug.
*/
export default async function getTagBySlug(slug: string, limit: number = 10) {
const query = `
query GetTagBySlug($slug: String!) {
posts(where: {tag: $slug, status: PUBLISH}, first: ${limit}) {
nodes {
databaseId
date
excerpt(format: RENDERED)
title(format: RENDERED)
featuredImage {
node {
altText
sourceUrl
mediaDetails {
height
width
}
}
}
seo {
metaDesc
title
}
slug
}
}
}
`

const variables = {
slug: slug
}

const response = await fetchGraphQL(query, variables)

return response.data.posts.nodes as Post[]
}

1 comment on commit fda0984

@vercel
Copy link

@vercel vercel bot commented on fda0984 Dec 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.