Sitemap navigator
Populating the sitemap navigator allows you to use it for navigating website pages. The sitemap navigator provides a single point from which to access all editable pages on a website.
# Navigate the sitemap
The sitemap provides two ways to navigate:
# Tree view
The sitemap is built in a hierarchical way using the urlPath
from page documents. (More on this below.)
It is collapsed by default, so that only top-level pages are visible. Each page can be expanded and collapsed as needed.
# Search pages
On larger sites, it's usually easier to search for a page. The search field is automatically focused when opening the sitemap. Search values query a page document's title
and urlPath
properties.
# Populate the sitemap
The sitemap will be populated by default, according to your content schema. If the slug of the page is not part of the content schema, you need to override the default sitemap behavior.
# Default sitemap from pages
By default, the sitemap is populated by retrieving the urlPath
value from all documents of models with the type
property set to page
.
If your content source uses inferred schemas (most headless CMSs) or does not have the concept of pages, you need to extend the models that represent pages.
Make sure the name
of the page model object corresponds to the name in the json schema that appears in the headless CMS.
// stackbit.config.ts
import { defineStackbitConfig } from "@stackbit/types";
export default defineStackbitConfig({
contentSources: [
// ...
],
modelExtensions: [
{ name: "page", type: "page", urlPath: "/{slug}" },
{ name: "post", type: "page", urlPath: "/blog/{slug}" }
]
});
In this case, all pages and posts will show up in the sitemap.
# Custom sitemap
To override default behavior, use the siteMap
property.
The siteMap
property provides an array of SiteMapEntry
objects. These objects can specify URL paths or be tied directly to a document. We suggest using TypeScript to introspect the expected properties.
Here’s an example that implements a similar approach to the default sitemap behavior. To ensure stableId
is set to a value that will not change, the example includes logic to set a unique pageId
for each page, if one doesn’t exist already. The pageId
is then used for the stableId
when generating the siteMap
.
// stackbit.config.ts
import {
defineStackbitConfig,
getLocalizedFieldForLocale,
SiteMapEntry
} from "@stackbit/types";
export default defineStackbitConfig({
stackbitVersion: "~0.6.0",
contentSources: [
// ...
],
// 1: add the `pageId` field here
modelExtensions: [
{
name: "page",
type: "page",
urlPath: "/{slug}",
fields: [{ name: "pageId", type: "string", hidden: true }]
}
],
// 2: add this method to create the ID when creating a page
async onContentCreate({ object, model }) {
if (model.type !== "page") {
return object;
}
// for pages that already have a pageId field, use that value; if not, generate one
const hasPageIdField = !!model.fields?.find(
field => field.name === "pageId"
);
if (hasPageIdField && !object.pageId) {
object.pageId = Date.now().toString();
}
return object;
},
siteMap: ({ documents, models }) => {
const pageModels = models.filter(m => m.type === "page").map(m => m.name);
return documents
.filter(d => pageModels.includes(d.modelName))
.map(document => {
// 3: use the pageId value for the stableId
const slugField =
document.fields.slug.type === "slug"
? document.fields.slug
: undefined;
const pageIdField =
document.fields.pageId.type === "string"
? document.fields.pageId
: undefined;
const slug = getLocalizedFieldForLocale(slugField);
const pageId = getLocalizedFieldForLocale(pageIdField);
if (!slug.value || !pageId.value) return null;
const urlPath = "/" + slug.value.replace(/^\/+/, "");
return {
stableId: pageId.value,
urlPath,
document,
isHomePage: urlPath === "/"
};
})
.filter(Boolean) as SiteMapEntry[];
}
});
Did you find this doc useful?
Your feedback helps us improve our docs.