/metalsmith-prismic

A Metalsmith.io plugin to pull in content from Prismic.io

Primary LanguageJavaScriptMIT LicenseMIT

metalsmith-prismic Build Status

A Metalsmith.io plugin to pull in content from Prismic.io

Installation

$ npm install --save metalsmith-prismic

Configuration

CLI Usage

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 generated
  • linkResolver 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 used
  • htmlSerializer 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>",
    }
  }
}

Javascript Usage

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>
}))

Usage

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'
---
query

The required query parameter specifies the query to run, following the Prismic's predicate-based query syntax.

bookmark

The query parameter may be replaced by a bookmark parameter, which fetches a single document defined by a Prismic bookmark.

orderings

The optional orderings parameter specifies how the results should be ordered, following the Prismic's ordering syntax.

pageSize & allPages

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.

arrayFragments

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.

formName

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)

output

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"

---
fetchLinks

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'
---
htmlSerializer

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>';
    }
}
Generating a Collection of Files

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.

Displaying Content

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>

To Do

  • 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.

License

MIT