mirror of
https://github.com/UiO-Gaming/uiogaming.no.git
synced 2026-11-05 13:56:47 +01:00
Add sitemap.xml and robots.txt
List the home page, blog posts and events in both languages with hreflang alternates, and point crawlers to the sitemap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2e54e32ea6
commit
b60f8a92e1
4 files changed
+90
-5
No files matched your search
@@ -0,0 +1,14 @@
|
||||
import { SITE_URL } from "@/components/seo"
|
||||
|
||||
import type { MetadataRoute } from "next"
|
||||
|
||||
export default function robots(): MetadataRoute.Robots {
|
||||
return {
|
||||
rules: {
|
||||
userAgent: "*",
|
||||
allow: "/",
|
||||
disallow: "/api/",
|
||||
},
|
||||
sitemap: `${SITE_URL}/sitemap.xml`,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import { getLocalizedPath, SITE_URL } from "@/components/seo"
|
||||
import { routing } from "@/i18n/routing"
|
||||
import { getSitemapDocuments } from "@/lib/sanity"
|
||||
|
||||
import type { MetadataRoute } from "next"
|
||||
|
||||
export const revalidate = 3600 // 1 hour
|
||||
|
||||
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||
const { posts, events } = await getSitemapDocuments()
|
||||
|
||||
const pages: { path: string; lastModified?: string }[] = [
|
||||
{ path: "/" },
|
||||
...posts.map(post => ({
|
||||
path: `/blog/${post.slug}`,
|
||||
lastModified: post._updatedAt,
|
||||
})),
|
||||
...events.map(event => ({
|
||||
path: `/event/${event.slug}`,
|
||||
lastModified: event._updatedAt,
|
||||
})),
|
||||
]
|
||||
|
||||
// One entry per language version, each linking to the other versions
|
||||
return pages.flatMap(({ path, lastModified }) => {
|
||||
const languages = Object.fromEntries(
|
||||
routing.locales.map(locale => [
|
||||
locale,
|
||||
`${SITE_URL}${getLocalizedPath(locale, path)}`,
|
||||
])
|
||||
)
|
||||
|
||||
return routing.locales.map(locale => ({
|
||||
url: languages[locale],
|
||||
lastModified,
|
||||
alternates: { languages },
|
||||
}))
|
||||
})
|
||||
}
|
||||
@@ -7,6 +7,10 @@ import { routing } from "@/i18n/routing"
|
||||
export const SITE_URL = "https://uiogaming.no"
|
||||
export const THEME_COLOR = "#7d36e7"
|
||||
|
||||
/** Adds the locale prefix to a path, e.g. ("en", "/event/x") -> "/en/event/x" */
|
||||
export const getLocalizedPath = (locale: Locale, path: string) =>
|
||||
path === "/" ? `/${locale}` : `/${locale}${path}`
|
||||
|
||||
type SeoProps = {
|
||||
locale: Locale
|
||||
/** Path without the locale prefix, e.g. "/" or "/event/some-slug" */
|
||||
@@ -32,8 +36,6 @@ export async function generateSeoMetadata({
|
||||
|
||||
const defaultTitle = "UiO Gaming"
|
||||
const metaDescription = description || t("description")
|
||||
const localizedPath = (pageLocale: Locale) =>
|
||||
path === "/" ? `/${pageLocale}` : `/${pageLocale}${path}`
|
||||
|
||||
return {
|
||||
title: title ? `${title} | ${defaultTitle}` : defaultTitle,
|
||||
@@ -42,12 +44,12 @@ export async function generateSeoMetadata({
|
||||
// Tells search engines that the Norwegian and English versions are the
|
||||
// same page. The unprefixed path redirects based on the browser language
|
||||
alternates: {
|
||||
canonical: localizedPath(locale),
|
||||
canonical: getLocalizedPath(locale, path),
|
||||
languages: {
|
||||
...Object.fromEntries(
|
||||
routing.locales.map(pageLocale => [
|
||||
pageLocale,
|
||||
localizedPath(pageLocale),
|
||||
getLocalizedPath(pageLocale, path),
|
||||
])
|
||||
),
|
||||
"x-default": path,
|
||||
@@ -60,7 +62,7 @@ export async function generateSeoMetadata({
|
||||
? { type: "article", publishedTime, authors: author && [author] }
|
||||
: { type: "website" }),
|
||||
locale: locale,
|
||||
url: localizedPath(locale),
|
||||
url: getLocalizedPath(locale, path),
|
||||
siteName: defaultTitle,
|
||||
images: imageURL
|
||||
? [
|
||||
|
||||
@@ -144,3 +144,33 @@ export async function getBoardMembers() {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export async function getSitemapDocuments(): Promise<{
|
||||
posts: { slug: string; _updatedAt: string }[]
|
||||
events: { slug: string; _updatedAt: string }[]
|
||||
}> {
|
||||
const query = `
|
||||
{
|
||||
"posts": *[_type == "post" && defined(slug.current)] {
|
||||
"slug": slug.current,
|
||||
_updatedAt
|
||||
},
|
||||
"events": *[_type == "event" && defined(slug.current)] {
|
||||
"slug": slug.current,
|
||||
_updatedAt
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
return sanityClient.fetch(
|
||||
query,
|
||||
{},
|
||||
{
|
||||
cache: "force-cache",
|
||||
next: {
|
||||
tags: ["blog-posts", "events"],
|
||||
revalidate: 3600, // 1 hour
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user