Next.js support for Agility CMS.
This package makes it easy to get started with Agility CMS and Next.js. Also includes support Nextjs Image using the AgilityImage component.
The agility object that is passed around is the api object of the Fetch SDK.
@agility/nextjs/geo turns a page's seo and geo properties from the Fetch API into Next.js metadata and one schema.org JSON-LD <script>. It needs @agility/geo installed alongside this package:
npm install @agility/geo// app/[...slug]/page.tsx
import { AgilityJsonLd, generateAgilityMetadata, resolveAgilityAlternates } from "@agility/nextjs/geo"
const SITE = "https://www.example.com"
const LOCALES = ["en-us", "fr-ca"]
const DEFAULT_LOCALE = "en-us"
export async function generateMetadata({ params }) {
const { page, sitemapNode, dynamicPageItem, languageCode } = await getAgilityPage({ params })
// Each locale's flat sitemap, keyed by locale code (`agility` is the Fetch SDK's api object).
const sitemaps = Object.fromEntries(
await Promise.all(LOCALES.map(async (languageCode) => [languageCode, await agility.getSitemapFlat({ channelName: "website", languageCode })])),
)
return generateAgilityMetadata({
page,
item: dynamicPageItem, // on a dynamic page
url: `${SITE}${sitemapNode.path}`,
title: sitemapNode.title, // used when the page (or item) has no SEO title
titleTemplate: "%s | Example", // applied to that fallback only
alternates: resolveAgilityAlternates({
sitemaps,
pageID: sitemapNode.pageID,
contentID: sitemapNode.contentID,
toUrl: (locale, path) => (locale === DEFAULT_LOCALE ? `${SITE}${path}` : `${SITE}/${locale}${path}`),
}),
defaultLocale: DEFAULT_LOCALE, // also emitted as x-default
})
}
export default async function Page({ params }) {
const { page, sitemapNode, dynamicPageItem, languageCode } = await getAgilityPage({ params })
const sitemap = await agility.getSitemapFlat({ channelName: "website", languageCode })
return (
<>
<AgilityJsonLd
page={page}
item={dynamicPageItem}
url={`${SITE}${sitemapNode.path}`}
locale={languageCode}
sitemap={sitemap} // breadcrumb, and a dynamic item's name
/>
{/* … */}
</>
)
}generateAgilityMetadata()returns only what the page sets:title(an editor's SEO title is used as-is, without the template),description(falls back togeo.summary),keywords, the canonical URL (seo.canonicalUrl, otherwiseurlwithout its query string and fragment),robots, the share image (seo.ogImage) andhreflangalternates (fromalternates, withx-defaultfordefaultLocale). A site-relative canonical or share image (/blog,/og.png) is resolved againsturl. Merge it over your own defaults.<AgilityJsonLd />renders a WebPage typed bygeo.schemaType, a BreadcrumbList when you pass a flatsitemap(on a dynamic page the sitemap also names the item's WebPage), and the editor'sgeo.structuredDatamerged in by@id, as one escaped@graph. It's rendered on the server, so crawlers that don't run JavaScript see it.resolveAgilityAlternates()finds each locale's URL for a page from each locale's flat sitemap, for thealternatesoption.- Dynamic pages: pass the item (
dynamicPageItem, with its ownseoandgeo). Itsgeo.schemaType,seo.robotsand eachgeo.aiproperty are its own, else the dynamic page's (the dynamic page's values are the defaults for all its items). Its title (passtitleandsitemap; the dynamic page's title is never used), canonical URL, share image, description,geo.summaryandgeo.structuredDataare its own only: the dynamic page's describe the listing page, so they aren't applied to its items. An item with no summary is described by itsseo.metaDescription. The rule is implemented once, in@agility/geo.
Publishing runs in GitHub Actions (.github/workflows/npm-publish.yml) with npm Trusted Publishing, so no npm token is stored anywhere:
- In a PR, bump
versioninpackage.jsonand move the## [Unreleased]notes inCHANGELOG.mdunder a new## [<version>] - <date>heading. Merge it. - Push a matching tag:
git tag v<version> && git push origin v<version>. - The workflow checks the tag matches
package.jsonand thatCHANGELOG.mdhas a section for it, then builds, typechecks, tests, publishes to thebetadist-tag with provenance, and creates a GitHub pre-release with that section as its notes. - Once verified, promote it:
npm dist-tag add @agility/nextjs@<version> latest.