ButterCMS is a headless CMS that lets you manage content using the dashboard and integrate it into your tech stack of choice with the available content APIs. In this tutorial, we are going to go through the process of building a Gridsome Source Plugin for ButterCMS from scratch.

What is Gridsome?

Gridsome homepage

Gridsome is a Vue-powered static site generator that enables you to build blazing fast web applications and websites. Gridsome has a central data layer that uses GraphQL to plug in data from different sources i.e. Headless CMS, Local Files, and Traditional API’s. Gridsome is the direct equivalent of Gatsby, which is used in React applications.

Gridsome allows us to fetch data from local files or external APIs and headless CMS and store the data in a GraphQL layer that lets us extract only the data we need and use it in our Vue.js components.

Creating Gridsome Source Plugin

Now we know what Gridsome entails and what we need it for, we can go ahead and create our source plugin, and for this, we’ll be creating a source plugin for ButterCMS. The reason behind creating this plugin is to manage the content used in Gridsome website or web application with ButterCMS this way we’ll be handling all our content on ButterCMS and using the butter source- plugin to consume the data in our Gridsome website through the GraphQL layer. Gridsome Data Store API lets you insert your data into the GraphQL data layer. You will then be able to access it through GraphQL in your components. That is the idea we want to be able to achieve, and by the end of this tutorial, we’ll have a source plugin ready for use. To get more information on how to create Gridsome plugins the documentation covers it.

Setting Up The Plugin Environment

The first step to take when building a plugin with Gridsome is to set up the environment and to do this we’ll need to set up our project by first creating a folder for this project called gridsome-source-buttercms and then running the npm init command to initialize a new project. This will create a package.json file in our root directory.

{ "name": "gridsome-source-buttercms", "version": "1.0.0", "description": "Source plugin for pulling blog posts, authors, categories, tags, and content fields into Gridsome from ButterCMS.", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "git+https://github.com/lauragift21/gridsome-source-buttercms.git" }, "author": "Gift Egwuenu <laurandidi21@gmail.com>", "license": "MIT", "keywords": [ "gridsome", "gridsome-plugin", "buttercms", "vuejs", "gridsome-source-plugin" ], "bugs": { "url": "https://github.com/lauragift21/gridsome-source-buttercms/issues" }, "homepage": "https://github.com/lauragift21/gridsome-source-buttercms#readme", "dependencies": { } } Note that for your plugin to get picked by Gridsome Plugins you need to add the gridsome-plugin keyword to your package.json . Right after creating our package.json file, we will need to add the project directory to GitHub so we can easily sync and track changes. Go ahead and create a new repository for this project with the latest changes added and push to Github. Add ButterCMS to your Gridsome app in minutes. Plugging In ButterCMS Now we have that setup, the next step is to start building the plugin, we’ll be required to install the buttercms npm package with the command:

npm install buttercms

Right after installing ButterCMS, create an index.js file this is where all the functionality for the plugin will be located. Note that you can also create a source plugin within a gridsome.server.js file, but for the sake of this tutorial I’ll be sticking to the index.js . Now within the index.js file, import buttercms package.

const buttercms = require('buttercms')

When creating a source plugin it is required that we use the Data Store API from Gridsome that allows us plug our own external data into GraphQL data layer. We will be working with the following APIs from ButterCMS: Pages, Collections and Blog Engine. Let’s go ahead and add the following to our index.js as a base for the plugin functionality we are going to create.

const ButterCMS = require('buttercms'); class ButterSource { static defaultOptions() { return { authToken: process.env.GRIDSOME_BUTTER_AUTHTOKEN || process.env.BUTTER_AUTHTOKEN, collections: [''], pages: '', pageTypes: '', typeName: 'Butter' }; } constructor(api, options = ButterSource.defaultOptions()) { this.api = api; this.options = options; this.client = ButterCMS(options.authToken, false, 20000); if (!options.authToken) throw new Error('ButterSource: Missing API Key'); api.loadSource(async actions => { console.log('Processing data...'); await this.allButterPosts(actions); await this.allButterCollections(actions); await this.allButterPages(actions); }); } }

I understand a lot is going on in the code block above, but I will go ahead and explain what’s happening to help understand where we are.

First, install buttercms and import it within the index.js file. Next, create a Class method called ButterSource where we’ll be defining all the functionality for this plugin. In order to gain access to ButterCMS API we need an API key that can be found in your ButterCMS Dashboard. Store the API key in a .env file with BUTTER_AUTHTOKEN variable. Gridsome suggests we keep variables prefixed with GRIDSOME_ so they are available in the browser for security reasons. Create a method called defaultOptions which we use to configure the plugin. We define a function and pass api and defaultOptions as parameters and then initialize ButterCMS and also include a check to make sure the API key is present. Then we map our data from the API to GraphQL we need to use the api.loadSource() hook Finally, we have three methods allButterPost() , allButterCollections , and allButterPages . These methods will be the source where we’ll be adding functionality from ButterCMS API.

Add Butter Posts

Here what we are trying to achieve is to create a query where we can view a full list of all posts created using ButterCMS. The first step is to query the REST API and return the posts, then call the actions.addCollection method which is used to add a collection to the GraphQL schema. In this case, allButterPosts and butterPosts respectively.

async allButterPosts(actions) { const post = await this.client.post.list() const { data } = post.data; const contentType = actions.addCollection({ typeName: this.createTypeName("posts") }); for (const item of data) { contentType.addNode({ ...item }); } }

Adding Butter Collections

Collections are tables of data to be referenced by Pages. We use allButterCollections to retrieve collections.

async allButterCollections(actions) { const collection = await this.client.content.retrieve(this.options.collections) const { data } = collection.data; const contentType = actions.addCollection({ typeName: this.createTypeName('collection') }); contentType.addNode({ data }) }

Adding Butter Pages

ButterCMS allows you to create pages. The fields of a page are defined by you, they are customizable. We can retrieve a single page or multiple pages using Page Types depending on how it is setup. Here allButterPages is configured in a way that you can retrieve either single or multiple pages by checking the options provided in the config.

async allButterPages(actions) { if (this.options.pages || this.options.pageTypes) { if (this.options.pages) { const page = await this.client.page.retrieve('*', this.options.pages) const { data } = page.data; const contentType = actions.addCollection({ typeName: this.createTypeName('pages') }); contentType.addNode({ slug: data.slug, page_type: data.page_type, data: data.fields }) } if (this.options.pageTypes) { const page = await this.client.page.list(this.options.pageTypes) const { data } = page.data; const pageTypeName = data.map(pages => { return pages.page_type }) const contentType = actions.addCollection({ typeName: this.createTypeName(pageTypeName[0]) }); for (const item of data) { contentType.addNode({ slug: item.slug, page_type: item.page_type, data: item.fields }) } } } }

Publishing ButterCMS Plugin

Now that we have successfully built the plugin, it’s time to publish to npm. Remember the first step we took in building out this plugin was to initialize a new project using npm init . Right, so now that we have to publish this package we need to run through the following to make sure everything looks great and is available as a public npm package. If you have never used npm CLI before you can run the npm adduser command to add a registry user account. But if you already completed that step, you can move to the next, which is to ensure you are logged in using this command.

npm login

You will be prompted to enter your username, password and email address. Once you are logged in you can confirm using the command npm whoami . The last step is to publish the plugin using the command:

npm publish

This command publishes the buttercms package to the registry and it can be installed by the package used gridsome-source-buttercms .

npm install gridsome-source-buttercms

Using the ButterCMS Plugin in a Gridsome App

We now have a published plugin we can use within our Gridsome app, let’s take a look at how to go about setting it up when we need to use it. First, we need to install the plugin with the command:

npm install gridsome-source-buttercms

or

yarn add gridsome-source-buttercms

After installing the plugin, we can go ahead and configure it within the gridsome.config.js file.

module.exports = { siteName: 'Gridsome', plugins: [ { use: "gridsome-source-buttercms", options: { authToken: process.env.GRIDSOME_BUTTER_AUTHTOKEN || process.env.BUTTER_AUTHTOKEN, collections: [''], pages: '', page_type: '' } } ] }

With that configured, we can now have our content from buttercms in our GraphQL layer. Go ahead and run gridsome develop to start the server and navigate to GraphQL playground. You should be able to run queries from buttercms in the documentation section.

Preview of example query on GraphQL sandbox

Wrapping Up

In this article, we walked through how to create a source plugin for Gridsome and outlined steps to take when we want to publish the plugin for final use. The benefits of using a modern, headless CMS over having our website content within the main application is vital and in general, it improves the workflow and performance of the application.