Basics
Features
Best Practices
Addon Development
Related Docs
Dark Mode

#Pages and Layouts

Unlike Assets, Media, Components, and other things your Addon provides, you generally should not directly create Pages and Layouts. Instead, you should create Repository Pages and Repository Layouts (RepoPages and RepoLayouts for short). These are Page and Layout definitions that are added to the Page Library and Layout Library that act as examples the user can import and modify to suit their Site.

There are certain, rare instances where you will need to directly create Pages and Layouts. For these use-cases see Pages and Layouts Direct Access.

#RepoPage Schema

{

  // uneditable properties
  _id: '63a0db9dd37c3735b468e1f8',
  managedByAddonId: '639b8f837f5fb8a39404280a',
  updatedAt: 1671486365027,
  createdAt: 1671486531695,

  // basic properties
  title: '',
  type: '',
  path: '',
  description: '',
  layoutName: '',
  isEnabled: true,

  // body properties
  lang: 'pug',
  body: '',

  // style properties
  styleLang: 'stylus',
  style: '',

  // tags
  tags: [],

  // scripts
  script: '',
  usesDataScript: false,
  dataScript: '',

  // seo
  favicon: '',
  noindex: false,
  nofollow: false,
  canonicalUrl: '',
  ogType: '',
  ogTitle: '',
  ogImages: '',
  ogDescription: '',
  ogArticleAuthors: '',
  ogArticlePublishedTime: '',
  ogArticleModifiedTime: '',
  ogArticleExpirationTime: '',
  ogArticleSection: '',
  ogArticleTags: '',
  schemas: [],

}

#Uneditable Properties

NameDescription
_idAssigned by MercuryCMS when the RepoPage is created
managedByAddonIdAll of your created RepoPages have this automatically added so they can be removed when the Addon is uninstalled
createdAtJavaScript Date the RepoPage was created
updatedAtJavaScript Date the RepoPage was last modified

#Basic Properties

NameDescription
titleThe RepoPage's Title used in the <title> tag in the generated page's <head>
typeThe RepoPage's Type. This can be '' for normal Pages, '404' for 404s, or '500' for 500 pages. Default is ''
pathThe path of the RepoPage. The user will likely change this path. Example: /path/to/page. For 404 and 500 pages, this will be a regex to match against the path
descriptionOptional, but you should always provide a description of what the RepoPage does
layoutNameIf provided, the created Page will use the RepoLayout provided by your Addon with this name
isEnabledSet to false to disable the Page

#Body Properties

NameDescription
langLanguage to use for the body. Either "html" or "pug". Default is "pug"
bodyBody HTML/Pug. This is meant to be further edited by the user after they create a Page from this RepoPage, so don't use minification

#Style Properties

NameDescription
styleLangLanguage to use for the style. Either "css" or "stylus". Default is "stylus"
styleStyle CSS/Stylus. This is meant to be further edited by the user after they create a Page from this RepoPage, so don't use minification

#Tags

This is a list of Tags in the order they should be added to the Page. See Tags for more information.

NameDescription
nameThe name of the Tag. For example: "Google Analytics"
locationOne of "head", "bodyStart", or "bodyEnd". Default is "head"
langThe language of the tag body. Either "pug" or "html". Default is "html"
bodyThe HTML/Pug body of the Tag

#Scripts

NameDescription
scriptThe script to be used on the Page
usesDataScriptWhen true, the Build system will use the RepoPage's dataScript to determine dynamic data and paths. Otherwise dataScript is ignored
dataScriptThe script used to create determine the data for use in the Page's markup

#SEO Properties

Many of a RepoPage's SEO properties relate to Open Graph.

NameDescription
faviconA Media ID to use for the Page's favicon
noindexWhen true, tell robots not to index the Page
nofollowWhen true, tell robots not to follow links on the Page
canonicalUrlThe RepoPage's canonical URL
ogTypeThe RepoPage's Open Graph type. Either article, book, music.album, music.playlist, profile, music.radio_station, music.song, video.episode, video.movie, video.other, video.tv_show, or website. Default is website
ogTitleThe RepoPage's Open Graph title
ogImagesA list of paths or URLs for the RepoPage's Open Graph images as a comma-separated string
ogDescriptionThe RepoPage's Open Graph description
ogArticleAuthorsThe RepoPage's Open Graph authors. Only applies if ogType is article
ogArticlePublishedTimeThe RepoPage's Open Graph published time. This will generally be a generated value using Templating. Only applies if ogType is article
ogArticleModifiedTimeThe RepoPage's Open Graph modified time. This will generally be a generated value using Templating. Only applies if ogType is article
ogArticleExpirationTimeThe RepoPage's Open Graph expiration time. This will generally be a generated value using Templating. Only applies if ogType is article
ogArticleSectionThe RepoPage's Open Graph article section (article category like "Technology"). Only applies if ogType is article
ogArticleTagsThe RepoPage's Open Graph tags (keywords) as a comma-separated string. Only applies if ogType is article
schemasAn array of Rich Snippets to add to the page. See Rich Snippets

#Authoring Addon RepoPages

Trying to write body, style, and script within your code is very difficult. It is recommended you first write and test the Page in MercuryCMS, then export it as a zip. You can then include the exported page.zip file in your Addon Package as a RepoPage.

#Creating RepoPages

You can create RepoPages using cms.upsertRepoPage().

let repoPageDef = {
  title: 'My Page',
  path: '/my-page',
  description: 'A Demo Page',
  layoutName: 'My Layout',
  body: '.my-page\n  This is my demo page!',
  style: ".my-page\n  color {{ addons['demo-addon'].mainColor }}",
}

// use static-cms-addon
import cms from 'static-cms-addon'

let repoPage = await cms.upsertRepoPage({title: 'My Page'}, repoPageDef)
console.log(repoPage._id) // "63a0db9dd37c3735b468e1f8"

// use axios
let response = await axios.post(`http://localhost:${cmsPort}/api/addon/${addonId}/repopage`, {match: {title: 'My Page'}, repoPage: repoPageDef})
console.log(response.data.repoPage._id) // "63a0db9dd37c3735b468e1f8"

You can also load the RepoPage from a zip using cms.loadRepoPagePackage().

let repoPageDef = cms.loadRepoPagePackage('repoPages/myPage.page.zip').page
let repoPage = await cms.upsertRepoPage({title: repoPageDef.title}, repoPageDef)

#Listing RepoPages

You can use cms.getRepoPages() to get a list of the RepoPages your Addon has created.

// use static-cms-addon
import cms from 'static-cms-addon'

let repoPages = await cms.getRepoPages()
console.log(repoPages.map(repoPage => repoPage.title)) // ['My Page', 'Another Page']

// use axios
let response = await axios.get(`http://localhost:${cmsPort}/api/addon/${addonId}/repopage`)
console.log(response.data.repoPages.map(repoPage => repoPage.title)) // ['My Page', 'Another Page']

#Deleting RepoPages

You can use cms.deleteRepoPages() to delete RepoPages your Addon has created.

// use static-cms-addon
import cms from 'static-cms-addon'

let repoPages = await cms.getRepoPages()
let repoPage = repoPages.find(repoPage => repoPage.title == 'My Page')
await cms.deleteRepoPages([repoPage._id])

// use axios
let response = await axios.get(`http://localhost:${cmsPort}/api/addon/${addonId}/repopage`)
let repoPage = response.data.repoPages.find(repoPage => repoPage.title == 'My Page')
await axios.post(`http://localhost:${cmsPort}/api/addon/${addonId}/repopage/delete`, {repoPageIds: [repoPage._id]})

#RepoLayout Schema

{

  // uneditable properties
  _id: '63a0db9dd37c3735b468e1f8',
  managedByAddonId: '639b8f837f5fb8a39404280a',
  updatedAt: 1671486365027,
  createdAt: 1671486531695,

  // basic properties
  name: '',
  description: '',

  // body properties
  lang: 'pug',
  body: '',

  // style properties
  styleLang: 'stylus',
  style: '',

  // tags
  tags: [],

  // scripts
  script: '',

  // seo
  favicon: '',
  schemas: [],

}

#Uneditable Properties

NameDescription
_idAssigned by MercuryCMS when the RepoLayout is created
managedByAddonIdAll of your created RepoLayouts have this automatically added so they can be removed when the Addon is uninstalled
createdAtJavaScript Date the RepoLayout was created
updatedAtJavaScript Date the RepoLayout was last modified

#Basic Properties

NameDescription
nameThe RepoLayout's name
descriptionOptional, but you should always provide a description of what the RepoLayout does

#Body Properties

NameDescription
langLanguage to use for the body. Either "html" or "pug". Default is "pug"
bodyBody HTML/Pug. This is meant to be further edited by the user after they create a Layout from this RepoLayout, so don't use minification

#Style Properties

NameDescription
styleLangLanguage to use for the style. Either "css" or "stylus". Default is "stylus"
styleStyle CSS/Stylus. This is meant to be further edited by the user after they create a Layout from this RepoLayout, so don't use minification

#Tags

This is a list of Tags in the order they should be added to any Page that uses this RepoLayout. See Tags for more information.

NameDescription
nameThe name of the Tag. For example: "Google Analytics"
locationOne of "head", "bodyStart", or "bodyEnd". Default is "head"
langThe language of the tag body. Either "pug" or "html". Default is "html"
bodyThe HTML/Pug body of the Tag

#Scripts

NameDescription
scriptThe script to be used on any Page that uses this RepoLayout

#SEO

NameDescription
faviconA Media ID to use as a favicon for any Page that uses this Layout
schemasAn array of Rich Snippets to add to Pages that use this Layout. See Rich Snippets

#Authoring Addon RepoLayouts

Trying to write body, style, and script within your code is very difficult. It is recommended you first write and test the Layout in MercuryCMS, then export it as a zip. You can then include the exported layout.zip file in your Addon Package as a RepoLayout.

#Creating RepoLayouts

You can create RepoLayouts using cms.upsertRepoLayout().

let repoLayoutDef = {
  name: 'My Layout',
  description: 'A Demo Layout',
  body: 'doctype html\nhtml\n  head\n    meta(charset="utf-8")\n    title #{ page.title }\n  body\n    .my-layout !{ page.body }',
  style: ".my-layout\n  color {{ addons['demo-addon'].mainColor }}",
}

// use static-cms-addon
import cms from 'static-cms-addon'

let repoLayout = await cms.upsertRepoLayout({name: 'My Layout'}, repoLayoutDef)
console.log(repoLayout._id) // "63a0db9dd37c3735b468e1f8"

// use axios
let response = await axios.post(`http://localhost:${cmsPort}/api/addon/${addonId}/repolayout`, {match: {name: 'My Layout'}, repoLayout: repoLayoutDef})
console.log(response.data.repoLayout._id) // "63a0db9dd37c3735b468e1f8"

You can also load the RepoLayout from a zip using cms.loadRepoLayoutPackage().

let repoLayoutDef = cms.loadRepoLayoutPackage('repoPages/myLayout.layout.zip').layout
let repoLayout = await cms.createRepoLayout({name: repoLayoutDef.name}, repoLayoutDef)

#Listing RepoLayouts

You can use cms.getRepoLayouts() to get a list of the RepoLayouts your Addon has created.

// use static-cms-addon
import cms from 'static-cms-addon'

let repoLayouts = await cms.getRepoLayouts()
console.log(repoLayouts.map(repoLayout => repoLayout.name)) // ['My Layout', 'Another Layout']

// use axios
let response = await axios.get(`http://localhost:${cmsPort}/api/addon/${addonId}/repolayout`)
console.log(response.data.repoLayouts.map(repoLayout => repoLayout.name)) // ['My Layout', 'Another Layout']

#Deleting RepoLayouts

You can use cms.deleteRepoLayouts() to delete RepoLayouts your Addon has created.

// use static-cms-addon
import cms from 'static-cms-addon'

let repoLayouts = await cms.getRepoLayouts()
let repoLayout = repoLayouts.find(repoLayout => repoLayout.name == 'My Layout')
await cms.deleteRepoLayouts([repoLayout._id])

// use axios
let response = await axios.get(`http://localhost:${cmsPort}/api/addon/${addonId}/repolayout`)
let repoLayout = response.data.repoLayouts.find(repoLayout => repoLayout.name == 'My Layout')
await axios.post(`http://localhost:${cmsPort}/api/addon/${addonId}/repolayout/delete`, {repoLayoutIds: [repoLayout._id]})

#User Modification

Unlike Components and other things your Addon manages. With RepoPages and RepoLayouts, you are not managing Pages and Layouts. You are managing RepoPages and RepoLayouts, which the user may or may not choose to use as examples to build their own Pages and Layouts.

The user may choose not to use your RepoPages and RepoLayouts at all, or they may decide to use some of your RepoPages as starting points for building their own Pages. Many times, they will incorporate your RepoPages into their own Layouts to match the rest of their Site. Because of this, it's important not to design RepoPages that are dependent on specific Layouts.

#Rich Snippets

For details about adding Rich Snippets to Pages and Layouts, see Rich Snippets.