A Metalsmith.io plugin to pull in content from Prismic.io
$ npm install --save metalsmith-prismic
Install the node modules and add metalsmith-prismic
to your list of plugins in metalsmith.json
. Include the
url
(eg. https://lesbonneschoses.prismic.io/api) of your Prismic.io repository.accessToken
is optional, depending if your repository needs it or not.release
the name or raw reference of the release you want to generate; if none specified then master release will be generatedlinkResolver
an optional function to generate links or the path of a generated collection of files; if none specified then a default format of "/<document.type>/<document.id>/<document.slug>" will be usedhtmlSerializer
an optional function to format the resulting HTML. You don't have to write the HTML serialization for all the possible types, just the ones you want to override the default behavior
{
"plugins": {
"metalsmith-prismic": {
"url": "<your repository's API url>",
"accessToken": "<optional accessToken>",
"release": "<optional release name or raw reference value>",
}
}
}
Instead of using the CLI, you can configure your Metalsmith.io project to use the metalsmith-prismic plugin via Javascript.
var prismic = require('metalsmith-prismic');
// pull in content from Prismic
.use(prismic({
"url": "<your repository's API url>",
"accessToken": "<optional access token>",
"release": "<optional release name or raw reference value>",
"linkResolver": <optional linkResolver function>
"htmlSerializer": <optional htmlSerializer function>
}))
Pulling in content from the site's repository in Prismic.io for display is a two step process.
In your file's metadata add the Prismic queries and optional orderings, pageSize, arrayFragments, fetchLinks and htmlSerializer parameters
---
template: index_en.hbt
prismic:
page-header-footer:
query: '[[:d = at(document.type, "page-header-footer")]]'
hero-slide:
query: '[[:d = at(document.type, "hero-slide")]]'
orderings: '[my.hero-slide.seqNum]'
pageSize: 50
arrayFragments: true
output: html, text
blog:
query: '[[:d = at(document.type, "blog")]]'
allPages: true
formName: 'tech-related'
---
The required query
parameter specifies the query to run, following the Prismic's predicate-based query syntax.
The query
parameter may be replaced by a bookmark
parameter, which fetches a single document defined by a Prismic bookmark.
The optional orderings
parameter specifies how the results should be ordered, following the Prismic's ordering syntax.
The optional pageSize
parameter specifies the maximum number of results to retrieve for the query. The default is based on Prismic's own default of 20 items. Prismic also caps the maximum results for each query at 100. Any pageSize set above this number will be ignored by Prismic.
To get around this limitation and retrieve all results, use the optional allPages
parameter and set it to true. Doing so will force the plugin to override the pageSize
and get all results by repeatedly executing the query against Prismic, combining all paged results.
Prismic has an undocumented feature where fragments named like location[0], location[1] and so on, will be returned as an array in the request response. By default, only the first one will be returned. To get an array of all the fragments, use the optional arrayFragments
parameter and set to true.
By default the query runs against the everything Prismic form. To run against a different form (eg. a collection), provide the formName
(eg. collection name)
By default the plugin will generate the HTML output for each Prismic fragment. Use the output
parameter to control which outputs to generate from the fragments. Valid outputs are html
and text
, multiple options should be comma separated.
This pulls the Prismic response into the file's metadata.
---
template: "index_en.hbt"
prismic:
page-header-footer:
query: "[[:d = at(document.type, \"page-header-footer\")]]"
results:
-
id: <id>
type: "page-header-footer"
href: <url>
tags: []
slug: "home"
slugs:
- "home"
linkedDocuments: []
data:
homeLabel_en:
json:
value: "Home"
html: "<span>Home</span>"
videoLabel_en:
json:
value: "Video"
html: "<span>Video</span>"
prizesLabel_en:
json:
value: "Prizes"
html: "<span>Prizes</span>"
newsLabel_en:
json:
value: "News"
html: "<span>News</span>"
qcLabel_en:
json:
value: "Questions/Comments"
html: "<span>Questions/Comments</span>"
hero-slide:
query: "[[:d = at(document.type, \"hero-slide\")]]"
orderings: "[my.hero-slide.seqNum]"
results:
-
id: <id>
type: "hero-slide"
href: <url>
tags: []
slug: "welcome-to-our-website"
slugs:
- "welcome"
- "welcome-to-our-website"
linkedDocuments: []
data:
title_en:
json:
blocks:
-
type: "heading1"
text: "Introducing our new site!"
spans: []
html: "<h1>Introducing our new site!</h1>"
introduction_en:
json:
blocks:
-
type: "paragraph"
text: "Welcome to our new site, generated by Metalsmith.io with content from Prismic!"
spans: []
-
type: "paragraph"
text: "Why? Because the two combined is a sweet combo"
spans: []
html: "<p>Welcome to our new site, generated by Metalsmith.io with content from Prismic!</p><p>Why? Because the two combined is a sweet combo</p>"
contents: []
mode: "0644"
---
Prismic supports fetching data from nested documents through links using the Prismic fetchLinks
query parameter. You can use this specify the nested content to be retrieved with this plugin as well.
---
template: index.hbt
prismic:
jobOffers:
query: '[[:d = any(document.type, ["job-offer"])]]'
arrayFragments: true
fetchLinks: 'store.name,store.address,product.name'
---
If you choose to pass a custom htmlSerializer
function, it will alter the html
property of fragments with the applicable element types.
"htmlSerializer": function (elem, content) {
// Add a class to all <h1>:
if (elem.type == "heading1") {
return '<h1 class="test-h1-class">' + content + '</h1>';
}
}
You'll often need to generate a collection of files from a collection of documents, such as blog posts. This can be achieved with the collection
property designating that data binding to generate one file for every document in the query's result.
---
template: blog-post.hbt
prismic:
blog-post:
query: '[[:d = at(document.type, "blog-post")]]'
collection: true
page-header-footer:
query: '[[:d = at(document.type, "header")]]'
---
In the example above, the query for the blog-post returns a collection of results (ie. a collection of blog posts). Because it's been designated as the collection to generate, a file for each blog post will be created, with each file containing the metadata for a single blog post. The results for all other queries, such as for the page-header-footer in the example above, will also be available for each of these generated files. At most one data binding can be designated as the collection for each source file.
The location of these files will be determined by the linkResolver
function, which, as mentioned above, can be overridden with your own function to determine the path in which these files are created in. In addition, the filename of the source will be injected into the ctx.path
property so you can use it in your linkResolver
function.
"linkResolver": function (ctx, doc) {
if (doc.isBroken) return;
// create file based off of type, id and the filename (extracted from the full path)
return '/' + doc.type + '/' + doc.id + '/' + ctx.path.replace(/^.*(\\|\/|\:)/, '');
}
As mentioned above, if no linkResolver
function is provided the default one will be used, generating links with the default format of "/<document.type>/<document.id>/<document.slug>". This will generate files with no file extension. To specify one, the collection
can be further customized with the fileExtension
property.
---
template: blog-post.hbt
prismic:
blog-post:
query: '[[:d = at(document.type, "blog-post")]]'
collection:
fileExtension: 'html'
page-header-footer:
query: '[[:d = at(document.type, "header")]]'
---
The example above will append a .html file extension to each generated blog-post file.
Now that this content from Prismic is available in the file's metadata, you can display it by using the metalsmith-templates plugin. For example, here is how to do it with the plugin's Handlebars engine.
<div>
<ul>
<li><a href="#intro">{{{ prismic.page-header-footer.results.[0].data.homeLabel_en.html }}}</a></li>
<li><a href="#video">{{{ prismic.page-header-footer.results.[0].data.videoLabel_en.html }}}</a></li>
<li><a href="#prizes">{{{ prismic.page-header-footer.results.[0].data.prizesLabel_en.html }}}</a></li>
<li><a href="#news">{{{ prismic.page-header-footer.results.[0].data.newsLabel_en.html }}}</a></li>
<li><a href="#comments">{{{ prismic.page-header-footer.results.[0].data.qcLabel_en.html }}}</a></li>
</ul>
</div>
<div>
{{{prismic.blog-post.results.[0].data.title.html}}}
{{{prismic.blog-post.results.[0].data.author.html}}}
{{{prismic.blog-post.results.[0].data.post.html}}}
</div>
- This plugin is still early in development and has only been tested with a limited set of Prismic queries and predicates. If anything isn't working please let me know!
- Repo that this previously tested against (http://lesbonneschoses.prismic.io/api) is now gone. Need to update tests to point to new repo.
MIT