Run this in your commandline:

npm install buttercms --save

Butter can also be loaded using a CDN:

<script src="https://cdnjs.buttercms.com/buttercms-1.1.4.min.js"></script>

The source code to our JavaScript SDK is available on Github.

If you'd like a full example project, check out our Gatsby.js CMS Starter Project on Github.

Create a new Gatsby site with the default starter

Run this in your terminal:

gatsby new butter-site

Install the source plugin

npm install gatsby-source-buttercms

Configure the source plugin

Here you'll specify the config that will be needed to pull down data from butter. make sure to add your api_token from your dashboard, in this guide we will be add CMS capability to a Gatsby for blogging, marketing pages, and more. Below is an example gatsby-config.js file that you'll want to configure for your app. We dive into more detail on the config file in the sections below. For now just be aware you'll need to add this type of config file to your project.

// Example gatsby-config.js file
module.exports = {
{
      resolve: `gatsby-source-buttercms`,
      options: {
        authToken: `your_api_token`,
        // Optional. Returns values for the supplied content field keys.
        contentFields: {
          keys: [`faq_items`, `faq_headline`],
          // Optional. Set to 1 to enable test mode for viewing draft content.
          test: 0,
        },
        // Optional. Array of page slugs.
        pages: [`homepage`],
        // Optional. Array of page types.
        pageTypes: [`customer_case_study`],
      },
    },
}

Test calling the API

Verify you are able to call the ButterCMS API using the JS SDK and your own api_token

Using ES6:

import Butter from 'buttercms';
export const butter = Butter('your_api_token');

Using CDN:

<script src="https://cdnjs.buttercms.com/buttercms-1.1.3.min.js"></script>

<script>
  var butter = Butter('your_api_token');
</script>

Import this file into any component you want to use ButterCMS. Then from the console run:

butter.post.list({page: 1, page_size: 10}).then(function(response) {
  console.log(response)
})

This API request fetches our blog posts. Your account comes with one example post which you'll see in the response. If you get a response it means you're now able to connect to our API.

Contents

Headless CMS

ButterCMS is a headless CMS that lets you manage content using our dashboard and integrate it into your tech stack of choice with our content APIs. You can use ButterCMS for new projects as well as add it to existing codebases.

If you're familiar with Wordpress, see how ButterCMS compares to WordPress.

ButterCMS provides a user-friendly UI for managing marketing sites, blogging, and custom content scenarios. We can be used for SEO landing pages, customer case studies, company news & updates, events + webinar pages, education center, location pages, knowledgebases, and more.

We are different from a traditional CMS like Drupal or Wordpress in that we're not a large piece of software you need to download, host, customize, and maintain. Instead we provide easy to consume, performant content API's that you add to your application.

For example, if you wanted to enable a non-technical person to be able to add customer case study pages to your marketing site, you might create a Case Study Page Type to represent these pages. The non-technical person would be able to manage these pages from our dashboard and the JSON API output would look something like this:

{  
  "data": {
    "slug": "acme-co-case-study",
    "fields": {
      "seo_title": "Acme Co Customer Case Study",
      "seo_description": "Acme Co saved 200% on Anvil costs with ButterCMS",
      "title": "Acme Co loves ButterCMS",
      "body": "<p>We've been able to make anvils faster than ever before! - Chief Anvil Maker</p>"
    }
  }
}

Use Postman to experiement

Postman is a great tool for experiementing with our API. We wrote a post about it here. Once you've installed Postman, click this button to quickly add our end point Collection to your Postman.

Run in Postman

Webhooks

Webhooks are a powerful feature that allow you to notify your internal systems whenever content in ButterCMS has changed. You can learn more about Webhooks in this blog post.

Reloading the Gatsby app on adding a new page

We can make use of the ButterCMS webhooks to notify our application everytime a new page is added or modified, and reload the Gatsby application.

You can add a new webhook by going to the https://buttercms.com/webhooks/ page. There, you can provide the URL of your deployed application:

Suppose your server is deployed with the address http://abc.def/, we can create a /webhook-receiver route, so that the resulting webhook URL configured on ButterCMS would be http://abc.def/webhook-receiver. We will get a POST request everytime there is a change, so you will want to implement a route which executes code that rebuilds your Gatsby application.

Image Transformation

ButterCMS has integrated with a rich image transformation API called Filestack. This allows you to modify your uploaded images in dozens of ways. Everything from resizing, cropping, effects, filters, applying watermarks and more. Check out Filestack full documentation for more detail.

After you upload an image to ButterCMS, it's stored on our CDN. To create a thumbnail, here's an example:

Original URL = https://cdn.buttercms.com/zjypya5tRny63LqhHQrv

Thumbnail URL = https://fs.buttercms.com/resize=width:200,height:200/zjypya5tRny63LqhHQrv

Resizing is just one of the many different transformations you can do to your images. Refer to the Filestack docs for full details.

Localization

ButterCMS has full support for localization of your content. Locale names and keys are completely customizable and there's no limit to the number of locales you can have. View our API Reference to learn how to query by locale.

Table of Contents

Introduction

Quickly launch a new marketing site or add CMS-powered pages to your existing site using our Pages.

Create a Single Page

Adding a CMS-powered page to your app involves three easy steps:

  1. Create the Page structure
  2. Populate the content
  3. Integrate into your application

If you need help after reading this, contact us via email or livechat.

Create the Page Structure

Create a new Page and define it's structure using our Page Builder. Let's create an example homepage.

PagesNewSinglePage

Populate the Content

Then populate our new page with content. In the next step, we'll call the ButterCMS API to retrieve this content from our app.

PagesNewSinglePageContent

Integrate into your application

With your homepage defined, the ButterCMS Pages API will return it in JSON format like this:

{
  "data": {
    "slug": "homepage",
    "fields": {
      "seo_title": "Anvils and Dynamite | Acme Co",
      "headline": "Acme Co provides supplies to your favorite cartoon heroes.",
      "hero_image": "https://cdn.buttercms.com/c8oSTGcwQDC5I58km5WV",
      "call_to_action": "Buy Now",
      "customer_logos": [
        {
          "logo_image": "https://cdn.buttercms.com/c8oSTGcwQDC5I58km5WV"
        },
        {
          "logo_image": "https://cdn.buttercms.com/c8oSTGcwQDC5I58km5WV"
        }
      ]
    }
  }
}

Now lets create the home page src/pages/index.js

import React from 'react'
import { graphql, Link } from 'gatsby'
import Layout from '../components/layout'
import SEO from '../components/seo'

const IndexPage = ({ data }) => {
  const home = data.home.edges[0].node

  return (
    <Layout>
      <SEO
        title={home.seo_title}
      />
      <div>
        <h1>{home.headline}</h1>
        <img src={home.hero_image} >
        <button>{home.call_to_action}</button>
      </div>

      <h1>Our Customers</h1>
      <div>
        {home.customer_logos.map(({ logo_image }) => (
          <img
            key={logo_image}
            src={logo_image}
          />
        ))}
      </div>
    </Layout>
  )
}

//GraphQl query to fetch homepage data
export const query = graphql`
  {
    home: allButterPage(filter: { slug: { eq: "homepage" } }) {
      edges {
        node {
          slug
          headline
          seo_title
          customer_logos {
            logo_image
          }
          hero_image
          call_to_action
        }
      }
    }
  }
`

export default IndexPage

That's it! Now run gatsby develop in your terminal and open localhost:8000/home to see the home page populated with the content you created on butter.

Create multiple pages using Page Types

Overview Video

Let's say you want to add a set of customer case study pages to your marketing site. They all have the same structure but the content is different. Page Types are perfect for this scenario and involves three easy steps:

  1. Create the Page Type structure
  2. Populate the content
  3. Integrate into your application

If you need help after reading this, contact us via email or livechat.

Create the Page Type structure

Create a Page Type to represent your Customer Case Study pages:

PagesNewPageType1

After saving, return to the configuration page by clicking the gear icon:

PagesNewPageType2

Then click on Create Page Type and name it "Customer Case Study". This will allow us to reuse this field configuration across multiple customer case study pages:

PagesNewPageType3

Populate the Content

Then populate our new page with content. In the next step, we'll call the ButterCMS API to retrieve this content from our app.

PagesNewSinglePageContent

Integrate into your application

With a case study defined, the ButterCMS Pages API will return it in JSON format like this:

{
    "data": {
        "slug": "acme-co",
        "fields": {
            "facebook_open_graph_title": "Acme Co loves ButterCMS",
            "seo_title": "Acme Co Customer Case Study",
            "headline": "Acme Co saved 200% on Anvil costs with ButterCMS",
            "testimonial": "<p>We've been able to make anvils faster than ever before! - <em>Chief Anvil Maker</em></p>\r\n<p><img src=\"https://cdn.buttercms.com/NiA3IIP3Ssurz5eNJ15a\" alt=\"\" caption=\"false\" width=\"249\" height=\"249\" /></p>",
            "customer_logo": "https://cdn.buttercms.com/c8oSTGcwQDC5I58km5WV",
        }
    }
}

Testing with GrapiQL

You can test out your Graphql queries with GrahiQl( A graphql debugger) fire up Graphiql on http://localhost:8000/___graphql

Once graphiql is opened paste the query below:

{
  allButterPage(filter: {page_type: {eq: "customer_case_study"}}) {
    edges {
      node {
        id
        facebook_open_graph_title
        seo_title
        headline
        customer_logo
        testimonial
      }
    }
  }
}

Integrate into your application

Now lets refactor our home page to display link(s) to each customer case study page

src/pages/index.js

import React from 'react'
import { graphql, Link } from 'gatsby'
import Layout from '../components/layout'
import SEO from '../components/seo'

const IndexPage = ({ data }) => {
  console.log(data)
  const home = data.home.edges[0].node
  const case_studies = data.case_studies.edges

  return (
    <Layout>
      <SEO
        title={home.seo_title}
      />
      <div>
        <h1>{home.headline}</h1>
        <button>{home.call_to_action}</button>
      </div>

      <h1>Our Customers</h1>
      <div>
        {home.customer_logos.map(({ logo_image }) => (
          <img
            key={logo_image}
            src={logo_image}
          />
        ))}

        <h1>Case Studies</h1>
        {case_studies.map(({ node: { id, slug, headline } }) => (
          <div key={id}>
            <Link to={`case-study/${slug}`}>{headline}</Link>
          </div>
        ))}
      </div>
    </Layout>
  )
}

export const query = graphql`
  {
    home: allButterPage(filter: { slug: { eq: "homepage" } }) {
      edges {
        node {
          slug
          headline
          seo_title
          customer_logos {
            logo_image
          }
          hero_image
          call_to_action
        }
      }
    }
    case_studies: allButterPage(
      filter: { page_type: { eq: "customer_case_study" } }
    ) {
      edges {
        node {
          id
          slug
          facebook_open_graph_title
          seo_title
          headline
          testimony
          customer_logo
        }
      }
    }
  }
`

export default IndexPage

Next we'll refactor gatsby-node-js to programatically create customer case study pages with gatsby create pages API. First we need to define a customer case study template

src/templates/customer-case-study.js

import React from 'react'
import { graphql } from 'gatsby'
import Layout from '../components/layout'
import SEO from '../components/seo'


function CustomerCaseStudy({ data }) {
  const page = data.allButterPage.edges[0].node

  return (
    <Layout>
      <SEO
        title={page.facebook_open_graph_title}
        description={page.headline}
      />
      <div>
        <h1>{page.seo_title}</h1>
        <p>{page.headline}</p>
        <img alt="customer_logo" src={page.customer_logo} />
        <p>{page.testimonial}</p> 
      </div>
    </Layout>
  )
}

export const pageQuery = graphql`
  query CaseStudyPageBySlug($slug: String!) {
    allButterPage(filter: { slug: { eq: $slug } }) {
      edges {
        node {
          id
          slug
          facebook_open_graph_title
          seo_title
          headline
          testimony
          customer_logo
        }
      }
    }
  }
`

export default CustomerCaseStudy

Now Let's programatically Create customer case study pages based on the template we defined in src/template/customer-case-study.js

In gatsby-node.js:

const path = require(`path`)

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions
  
 // Blog post template 
  const blogPost = path.resolve(`./src/templates/blog-post.js`)
  
  //customer case study template 
  const customerCaseStudy = path.resolve(
    `./src/templates/customer-case-study.js`
  )

  let posts
  try {
    posts = await graphql(`
      {
        allButterPost {
          edges {
            node {
              id
              seo_title
              slug
              categories {
                name
                slug
              }
              author {
                first_name
                last_name
                email
                slug
                profile_image
              }
              body
            }
          }
        }
      }
    `)
  } catch (error) {
    console.log(`Error Running Querying Posts`, error)
  }
    
  posts = posts.data.allButterPost.edges;

  posts.forEach((post, index) => {
    const previous = index === posts.length - 1 ? null : posts[index + 1].node
    const next = index === 0 ? null : posts[index - 1].node

    // Create blog posts pages.
    createPage({
      path: `/blog/${post.node.slug}`,
      component: blogPost,
      context: {
        slug: post.node.slug,
        previous,
        next,
      },
    })
  })

  // Fetch Customer Case study pages
  let pages
  try {
    pages = await graphql(`
      {
        allButterPage(filter: { page_type: { eq: "customer_case_study" } }) {
          edges {
            node {
              id
              slug
              facebook_open_graph_title
              seo_title
              headline
              testimony
              customer_logo
            }
          }
        }
      }
    `)
  } catch (error) {
    console.log(`Error Running Querying Pages`, error)
  }

  //Create Customer Case study pages
  pages.data.allButterPage.edges.forEach(page => {
    createPage({
      path: `/case-study/${page.node.slug}`,
      component: customerCaseStudy,
      context: {
        slug: page.node.slug,
      },
    })
  })
}

That's it! now stop the server and run:

> gatsby develop

Now the home page should contain links to customer case study pages, Click around you'll notice that the template we defined in src/template/customer_case_study.js is used by Gatsby to create each case study page.

If you need help after reading this, contact us via email or livechat.

Table of Contents

Introduction

This guide uses Gatsby but Butter works with any client-side JavaScript framework including Angular and React.js. For a sample project, checkout this Gatsby Starter Project Github Repo.

Content Fields are global pieces of content that can be managed by your team. They can be used for content that spans multiple pages (header, footer) or platforms (desktop, mobile). Each content field has unique ID for querying via our API. Let's see how you can use them to power a knowledge base. Again Content Fields are great for content that can appear in multiple places so this knowledge base could appear on your website and mobile app. This example will focus on your website.

If you need help after reading this, contact us via email or livechat.

Setup content fields

Let's suppose we want to add a CMS to a static FAQ page with a title and a list of questions with answers.

Making your content dynamic with Butter is a two-step process:

  1. Setup custom content fields in Butter
  2. Integrate the fields into your application

To setup custom content fields, first sign in to the Butter dashboard.

Create a new workspace or click on an existing one. Workspaces let you organize content fields in a friendly way for content editors and have no effect on development or the API. For example, a real-estate website might have a workspace called "Properties" and another called "About Page".

Once you're in a workspace click the button to create a new content field. Choose the "Object" type and name the field "FAQ Headline":

After saving, add another field but this time choose the "Collection" type and name the field FAQ Items:

On the next screen setup two properties for items in the collection:

Now go back to your workspace and update your heading and FAQ items.

Integrate your app

To display this dynamic content in our app we create a new file.

In /src/pages/faq.js

import React from 'react'
import { graphql } from 'gatsby'

import Layout from '../components/layout'
import SEO from '../components/seo'

const Faq = ({ data }) => {
  const FAQs = data.allButterCollection.edges[0].node.value
  const headline = data.allButterContentField.edges[0].node.value

  return (
    <Layout>
      <SEO title="FAQ - Frequently Asked Questions" />
      <h1>{headline}</h1>
      <div>
        {FAQs.map(faq => (
          <div<
            <h2>{faq.question}</h2>
            <p>{faq.answer}</p>
          </div>
        ))}
      </div>
    </Layout>
  )
}

export const query = graphql`
  {
    allButterCollection(filter: { id: { eq: "faq_items" } }) {
      edges {
        node {
          id
          value {
            question
            answer
          }
        }
      }
    }

    allButterContentField(filter: { id: { eq: "faq_headline" } }) {
      edges {
        node {
          id
          value
        }
      }
    }
  }
`
export default Faq

If you need help after reading this, contact us via email or livechat.

Table of Contents

Introduction

Learn how to quickly build a CMS-powered blog with Gatsby. Note Butter works with any client-side JavaScript framework including Angular, Vue.js and React.js. For a sample project, check out out this Gatsby Starter Project Github Repo. To get started even quicker, here's a set of sample blog templates you can use.

If you need help after reading this, contact us via email or livechat.

Displaying Posts

In src/pages/blog.js

import React from 'react'
import { Link, graphql } from 'gatsby'
import Layout from '../components/Layout'
import SEO from '../components/seo'

class BlogIndex extends React.Component {
  render() {
    const { data } = this.props
    const siteTitle = data.site.siteMetadata.title
    const posts = data.allButterPost.edges

    return (
      <Layout location={this.props.location} title={siteTitle}>
        <SEO title="Blog Home" />

        <div>
          {posts.map(({ node }) => {
            const title = node.seo_title || node.slug
            return (
              <div
                key={node.slug}>
                <h3>
                  <Link to={`/blog/${node.slug}`}>
                    {title}
                  </Link>
                </h3>
                <small>{node.date}</small>
                <p>{node.summary}<p>
              </div>
            )
          })}
        </div>
      </Layout>
    )
  }
}

export default BlogIndex

export const pageQuery = graphql`
  query {
    site {
      siteMetadata {
        title
      }
    }
    allButterPost {
      edges {
        node {
          id
          seo_title
          meta_description
          slug
          categories {
            name
            slug
          }
          author {
            first_name
            last_name
            email
            slug
            bio
            title
            linkedin_url
            facebook_url
            instagram_url
            pinterest_url
            twitter_handle
            profile_image
          }
          body
        }
      }
    }
  }
`

Creating a blog template

Now we've listed our blog posts in src/pages/blog.js, using Gatsby createpages API we'll generate blog post pages using a template:

In src/pages/template/blog-post.js:

import React from 'react'
import { Link, graphql } from 'gatsby'

import Bio from '../components/Bio'
import Layout from '../components/Layout'
import SEO from '../components/seo'

class BlogPostTemplate extends React.Component {
  render() {
    const post = this.props.data.allButterPost.edges[0].node
    const siteTitle = this.props.data.site.siteMetadata.title
    const { previous, next } = this.props.pageContext

    return (
      <Layout location={this.props.location} title={siteTitle}>
        <SEO title={post.seo_title} description={post.description} />
        <div>
          <div>
            <h1>{post.seo_title}</h1> <span>{post.date}</span> •
            {post.categories.map(category => (
              <span>{category.name}</span>
            ))}
            <hr />
            <div
              dangerouslySetInnerHTML={{ __html: post.body }}
            />
            <Bio />
            <ul>
              <li>
                {previous && (
                  <Link to={`/blog/${previous.slug}`} rel="prev">
                    ← {previous.seo_title}
                  </Link>
                )}
              </li>
              <li>
                {next && (
                  <Link to={`/blog/${next.slug}`} rel="next">
                    {next.seo_title} →
                  </Link>
                )}
              </li>
            </ul>
          </div>
        </div>
      </Layout>
    )
  }
}

export default BlogPostTemplate

export const pageQuery = graphql`
  query BlogPostBySlug($slug: String!) {
    site {
      siteMetadata {
        title
        author
      }
    }
    allButterPost(filter: { slug: { eq: $slug } }) {
      edges {
        node {
          id
          body
          seo_title
          date
          categories {
            name
          }
        }
      }
    }
  }
`

Generate Blog Pages

Now we'll use the blog template defined in src/templates/blog-post.js to generate blog pages.

In gatsby-node.js:

const path = require(`path`)

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions

  const blogPost = path.resolve(`./src/templates/blog-post.js`)

  let posts
  try {
    posts = await graphql(`
      {
        allButterPost {
          edges {
            node {
              id
              seo_title
              slug
              categories {
                name
                slug
              }
              author {
                first_name
                last_name
                email
                slug
                profile_image
              }
              body
            }
          }
        }
      }
    `)
  } catch (error) {
    console.log(`Error Running Querying Posts`, error)
  }
    
  posts = posts.data.allButterPost.edges;

  posts.forEach((post, index) => {
    const previous = index === posts.length - 1 ? null : posts[index + 1].node
    const next = index === 0 ? null : posts[index - 1].node
}

Now our app has a working blog that can be updated easily in the ButterCMS dashboard.

Categories, Tags, and Authors

Use Butter's APIs for categories, tags, and authors to feature and filter content on your blog.

See our API reference for more information about these objects:

RSS, Atom, and Sitemap

Butter generates RSS, Atom, and sitemap XML markup. To use these on your blog, return the generated XML from the Butter API with the proper content type headers.

Comments

Butter doesn't provide an API for comments due to the excellent existing options that integrate easily. Two popular services we recommend are:

Both products are free, include moderation capabilities, and give your audience a familiar commenting experience. They can also provide some additional distribution for your content since users in their networks can see when people comment on your posts. For a minimalist alternative to Disqus, check out RemarkBox or for an open-source option, Isso.

Social Sharing

To maximize sharing of your content, we recommend using a free tool called AddThis.

They provide an attractive and easy to integrate social sharing widget that you can add to your website.

Social Share Buttons

CSS

Butter integrates into your front-end so you have complete control over the design of your blog. Use the following CSS as boilerplate for post content styling.

.post-container {
  h1, h2, h3, h4, h5 {
    font-weight: 600;
    margin-bottom: 1em;
    margin-top: 1.5em;
  }

  ul, ol {
    margin-bottom: 1.25em;

    li {
      margin-bottom: 0.25em;
    }
  }

  p {
    font-family: Georgia, Cambria, "Times New Roman", Times, serif;
    font-size: 1.25em;
    line-height: 1.58;
    margin-bottom: 1.25em;
    font-weight: 400;
    letter-spacing: -.003em;
  }

  /* Responsive default image width */
  img {
    max-width: 100%;
    height: auto;
  }

  /* Responsive floating */
  @media only screen and (min-width: 720px)  {
    .butter-float-left {
      float: left;
      margin: 0px 10px 10px 0px;
    }

    .butter-float-right {
      float: right;
      margin: 0px 0px 10px 10px;
    }
  }

  /* Image caption */
  figcaption {
    font-style: italic;
    text-align: center;
    color: #ccc;
  }

  p code {
    padding: 2px 4px;
    font-size: 90%;
    color: #c7254e;
    background-color: #f9f2f4;
    border-radius: 4px;
    font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
  }

  pre {
    display: block;
    padding: 1em;
    margin: 0 0 2em;
    font-size: 1em;
    line-height: 1.4;
    word-break: break-all;
    word-wrap: break-word;
    color: #333333;
    background-color: #f5f5f5;
    font-family: Menlo, Monaco,Consolas, "Courier New", monospace;
  }
}

Migration

To import content from another platform like WordPress or Medium, send us an email.

Get started now

Sign up with Google Sign up with Github
or