Install Angular cli

npm install -g @angular/cli

Setup a new Angular project using Angular cli

ng new hello-buttercms-project
cd hello-buttercms-project

Install Angular Material and Angular Material related package

npm install --save @angular/material @angular/cdk
npm install --save @angular/animations

Install ButterCMS. 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 is available on Github.

If you'd like a full example project, check out our Angular project on Github.

Open the project in your code editor of choice.

Under src/app create a directory called _services

We create a file called butterCMS.service.js. This allows us to have our API Token in one place and not accidentally alter it.

import * as Butter from 'buttercms';

export const butterService = Butter('your_api_token');

We'll import this file into any component we want to use ButterCMS.

For a Quickstart go to src/app/hello-you/hello-you.component.ts and import butterService

import {butterService} from '../_services';

Inside HelloYouComponent create methods:

fetchPosts() {
  butter.post.list({
    page: 1,
    page_size: 10
  })
  .then((res) => {
    console.log('Content from ButterCMS')
    console.log(res)
  })
}

Now call this method when the component is loaded by adding it to the OnInit lifecycle hook:

ngOnInit() {
  this.fetchPosts();
}

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.

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"
        }
      ]
    }
  }
}

This guide uses the Angular framework and Angular cli to generate all our components and package our application. We are using Angular Material for our look and feel, but feel free to use any other.

Let's get to the code.

Create new project

ng new buttercms-project
cd buttercms-project
npm install --save @angular/material @angular/cdk
npm install --save @angular/animations
npm install -S buttercms
ng serve

Your localhost:4200 should be ready to serve your Angular page.

Create typescript to export ButterCMS service

Under src/app create a directory called _services. Create a file called butterCMS.service.js.

import * as Butter from 'buttercms';
export const butterService = Butter('your_api_token');

Update the component routes

These components are generated by angular cli using ng g component <my-new-component>

Under src/app create a file called app-routing.module.ts

import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {HomeComponent} from './home/home.component';

const appRoutes: Routes = [
    {path: 'home', component: HomeComponent},
    {path: '**', redirectTo: 'home'}
];

@NgModule({
    imports: [RouterModule.forRoot(appRoutes)],
    exports: [RouterModule]
})
export class AppRoutingModule {
}

Under apps/home type ng g component home

apps/home/home/home.component.ts

  1. Import butterService
  2. In OnInit hook, use butterService to get the homepage given the page slug
import {Component, OnInit} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {ActivatedRoute} from '@angular/router';
import {butterService} from '../../_services';
import {map, take} from 'rxjs/operators';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})

export class HomeComponent implements OnInit {
  constructor(protected route: ActivatedRoute) { }

  public page: any;

  ngOnInit() {
    butterService.page.retrieve('*', 'homepage')
      .then((res) => {
        this.page = res.data.data;
      }).catch((res) => {
      console.log(res);
    });
  }
}

Display the results in home.component.html

<mat-card>
  <div class="container">
    <div fxLayout="column" class="details">
      <div class="blocks">
        <img src="{{page.fields.hero_image}}" "/>
      </div>

      <h1 class="blocks">
        {{page.fields.headline}}
      </h1>

      <button>{{page.fields.call_to_action}}</button>

      <h3>Customers Love Us!</h3>
      <!-- Loop over customer logos -->
      {{page.fields.customer_logos}}
    </div>
  </div>
</mat-card>

That's it! If you browse to your homepage you'll see your homepage populated with the content you created in 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",
        }
    }
}

This guide uses the Angular framework and Angular cli to generate all our components and package our application. We are using Angular Material for our look and feel, but feel free to use any other.

Let's get to the code.

Create new project

ng new buttercms-project
cd buttercms-project
npm install --save @angular/material @angular/cdk
npm install --save @angular/animations
npm install -S buttercms
ng serve

Your localhost:4200 should be ready to serve your Angular page.

Create typescript to export ButterCMS service

Under src/app create a directory called _services. Create a file called butterCMS.service.js.

import * as Butter from 'buttercms';
export const butterService = Butter('your_api_token');

Update the component routes

These components are generated by angular cli using ng g component <my-new-component>

Under src/app create a file called app-routing.module.ts

import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {CustomerComponent} from './customer/listing/customer.listing.component';
import {FaqComponent} from './faq/faq.component';
import {BlogPostComponent} from './blog-post/listing/blog-post.component';
import {HomeComponent} from './home/home.component';
import {CustomerDetailsComponent} from './customer/details/customer.details.component';
import {BlogPostDetailsComponent} from './blog-post/details/blog-post.details.component';
import {FeedComponent} from './feed/feed.component';

const appRoutes: Routes = [
    {path: 'customer', component: CustomerComponent},
    {path: 'customer/:slug', component: CustomerDetailsComponent},
    {path: 'faq', component: FaqComponent},
    {path: 'blog', component: BlogPostComponent},
    {path: 'blog/:slug', component: BlogPostDetailsComponent},
    {path: 'rss', component: FeedComponent},
    {path: 'home', component: HomeComponent},
    {path: '**', redirectTo: 'home'}
];

@NgModule({
    imports: [RouterModule.forRoot(appRoutes)],
    exports: [RouterModule]
})
export class AppRoutingModule {
}

Setup the Customers List Page

Under apps/customer type ng g component listing

apps/customer/listing/customer.listing.component.ts

In that file

  1. Import butterService
  2. In OnInit hook, use butterService to get the list of customers
  3. Store results in pages variable and markup (html) will be updated with the data
import {Component, OnInit} from '@angular/core';
import {butterService} from '../../_services';

@Component({
    selector: 'app-customer',
    templateUrl: './customer.listing.component.html',
    styleUrls: ['./customer.listing.component.scss']
})

export class CustomerComponent implements OnInit {
  public pages: any[];
  constructor() { }

  ngOnInit() {
    butterService.page.list('customer_case_study')
      .then((res) => {
        this.pages = res.data.data;
      });
  }
}

Display the results in customer.listing.component.html

<mat-card>
  <mat-card-title class="page-title">Customers</mat-card-title>
  <mat-divider></mat-divider>
  <mat-card-content class="page-body">
      <mat-card *ngFor="let page of pages">
          <mat-card-title>
              <div class="container">
                  <a [routerLink]="[page.slug]">
                      <div fxLayout="row" fxLayout.xs="column"
                           fxFlex class="content">
                          <div class="blocks">
                              <img src="{{page.fields.customer_logo}}" alt="{{page.fields.seotitle}}" height="64"
                                   width="64"/>
                          </div>
                          <div class="blocks">
                              {{page.fields.headline}}
                          </div>
                      </div>
                  </a>
              </div>
          </mat-card-title>
      </mat-card>
  </mat-card-content>
  <mat-divider></mat-divider>
  <mat-card-footer>
      <div class="page-footer">
          <mat-icon>whatshot</mat-icon>
      </div>
  </mat-card-footer>
</mat-card>

Setup the Customer Detail Page

Under apps/customer type ng g component details

apps/customer/details/customer.details.component.ts

Create customer page

  1. Import butterService
  2. In OnInit hook, use butterService to get the customer page given the slug in the URL path
  3. Store results in page variable and markup (html) will be updated with the customer data
import {Component, OnInit} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {ActivatedRoute} from '@angular/router';
import {butterService} from '../../_services';
import {map, take} from 'rxjs/operators';

@Component({
  selector: 'app-customer-details',
  templateUrl: './customer.details.component.html',
  styleUrls: ['./customer.details.component.scss']
})

export class CustomerDetailsComponent implements OnInit {
  constructor(protected route: ActivatedRoute) { }

  protected slug$: Observable<string>;
  public page: any;

  ngOnInit() {
    this.slug$ = this.route.paramMap
      .pipe(
        map(params => (params.get('slug')))
      );

    this.slug$.pipe(
      take(1))
      .subscribe(slug => {
        butterService.page.retrieve('customer_case_study', slug)
          .then((res) => {
            this.page = res.data.data;
          }).catch((res) => {
          console.log(res);
        });
      });
  }
}

Display the results in customer.details.component.html

<mat-card>
  <div class="container">
    <div fxLayout="column" class="details">
      <div class="blocks">
        <img src="{{page.fields.customer_logo}}" alt="" height="124" width="124"/>
      </div>

      <h1 class="blocks">
        {{page.fields.headline}}
      </h1>
      <h3 class="is-size-3">Testimonials</h3>
      <div [innerHTML]="page.fields.testimonial"></div>
      <div [innerHTML]="page.fields.body"></div>
    </div>
  </div>
</mat-card>

We can now navigate to the Customer Page via the list of all Customer Pages or directly via url.

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

Introduction

Collections are tables of data to be referenced by Pages, extending the use cases that you can achieve with ButterCMS. Collections can also be queried from the API directly. We'll cover example use cases of both.

Several of these use cases involve References. References are a powerful field type you can add to Pages and Collections that allow you to create links between your content.

Use Cases

Page Facets to Group/Filter By

You can use Collections as Facets (filterable properties) for your Pages. The simpliest example would be to add Categories to your Pages. Let's say you have a recipe website for different cocktails and you want to add categories to better organize these cocktail pages for your customers.

Each cocktail Page has a name, image, and ingredients:

Sample Cocktail Page

Here's what the API JSON response looks like for your cocktail pages. You're going to enhance this by adding a Reference to a Category Collection.

GET https://api.buttercms.com/v2/pages/cocktails/

{
    "data": [
        {
            "slug": "old-fashioned",
            "fields": {
                "name": "Old Fashioned",
                "image": "https://cdn.buttercms.com/k4UHbZOuRhOMKw3Gys8s",
                "ingredients": "<p>1/2 tsp Sugar<br />3 dashes Angostura bitters<br />1 tsp Water<br />2 oz Bourbon</p>"
            }
        },
        {
            "slug": "martini",
            "fields": {
                "name": "Martini",
                "image": "https://cdn.buttercms.com/UKVn6r1RQSVyKoZIVeHU",
                "ingredients": "<p>2 oz. vodka</p>\n<p>1/2 oz. dry vermouth</p>\n<p>Shake ingredients with ice. Strain into a martini glass. Popular garnishes include a lemon twist and olives.</p>"
             }
        }
    ],
    meta": {
        "count": 2,
        "previous_page": null,
        "next_page": null
    }
}

To add a Category to your cocktail pages, first create a Category Collection and then configure your Collection data structure by adding Name and Slug properties to it.

Create Category Collection
Name Slug Properties To Collection

Now you can add some cocktail categories to it like Martini, Old Fashioned, etc...

Adding Items To Collection

With your Collection in place, go back to your Cocktail Page Type and add a Reference field called "Category" to the Category Collection

Adding Reference Field To Collection

Now when editing your cocktail pages, you can now categorize your cocktails.

Select a Category

These categories of course also show up in your API response your cocktails:

GET https://api.buttercms.com/v2/pages/cocktails/

{
    "data": [
        {
            "slug": "old-fashioned",
            "fields": {
                "name": "Old Fashioned",
                "image": "https://cdn.buttercms.com/k4UHbZOuRhOMKw3Gys8s",
                "ingredients": "<p>1/2 tsp Sugar<br />3 dashes Angostura bitters<br />1 tsp Water<br />2 oz Bourbon</p>",
                "category": {
                    "name": "Old Fashioned",
                    "slug": "old-fashioned"
                }
            }
        },
        {
            "slug": "martini",
            "fields": {
                "name": "Martini",
                "image": "https://cdn.buttercms.com/UKVn6r1RQSVyKoZIVeHU",
                "ingredients": "<p>2 oz. vodka</p>\n<p>1/2 oz. dry vermouth</p>\n<p>Shake ingredients with ice. Strain into a martini glass. Popular garnishes include a lemon twist and olives.</p>",
                "category": {
                    "name": "Martini",
                    "slug": "martini"
                }
             }
        }
    ],
    meta": {
        "count": 2,
        "previous_page": null,
        "next_page": null
    }
}

Naturally, now that your pages have categories, you'll want to filter your pages by category. To do this just add fields.category.slug=martini to your API query.

GET https://api.buttercms.com/v2/pages/cocktails/?&fields.category.slug=martini

{
    "data": [
        {
            "slug": "martini",
            "fields": {
                "name": "Martini",
                "image": "https://cdn.buttercms.com/UKVn6r1RQSVyKoZIVeHU",
                "ingredients": "<p>2 oz. vodka</p>\n<p>1/2 oz. dry vermouth</p>\n<p>Shake ingredients with ice. Strain into a martini glass. Popular garnishes include a lemon twist and olives.</p>",
                "category": {
                    "name": "Martini",
                    "slug": "martini"
                }
             }
        }
    ],
    meta": {
        "count": 1,
        "previous_page": null,
        "next_page": null
    }
}

To take this example further, let's say you wanted multiple Facets to organize your cocktails by. You could set up multiple Collections such as:

  • Drink Types: Cider, Colada, Cosmo, ...
  • Spirits: Bourbon, Whiskey, Gin
  • Color: Brown, Yellow, Orange

Then you would add a corresponding Reference field to link each Collection to your cocktail Pages.

This use case demonstrates is how you can use Collections to add filterable Facets to your Pages.

Reusable Promotional Page Content

There are many use cases for Collections. Another is using Collections to store reusable promotional content that can be Referenced by multiple pages. A common example is customer testimonials. You can store all of your testimonials in a Collection, then Reference those testimonials from your Pages. Here's how you'd do that:

First let's assume your marketing site has some features Pages, each focusing on a particular feature of your product or service.

ButterCMS Feature Page

Here's what the API JSON response looks like for your feature page. You're going to enhance this by adding a Reference to a Testimonials Collection.

GET https://api.buttercms.com/v2/pages/*/full-cms-feature-page

{
    "data": {
        "slug": "full-cms-feature-page",
        "fields": {
            "headline": "Powerful CMS. Zero headache.",
            "hero_image": "https://cdn.buttercms.com/RB2R32WbSxqcanOXiHYA",
            "benefits": [
                {
                    "benefit": "SEO Landing Pages"
                },
                {
                    "benefit": "Customer Case Studies"
                },
                {
                    "benefit": "Company News & Updates"
                }
            ]
        }
    }
}

Create a Collection for testimonials, each having the name of the person, their quote, a headshot, and their title + company.

Testimonials Collection

Then add your customer testimonials to your Collection.

Add Testimonials To Collection

Then add a Reference field from your feature Pages to your Testimonials Collection.

Reference to Testimonials Collection

Now you can easily add multiple testimonials to display on your marketing Pages

Selecting Testimonials From Reference

The API JSON response for your feature page now includes the testimonials you just linked.

GET https://api.buttercms.com/v2/pages/*/full-cms-feature-page

{
    "data": {
        "slug": "full-cms-feature-page",
        "fields": {
            "headline": "Powerful CMS. Zero headache.",
            "hero_image": "https://cdn.buttercms.com/RB2R32WbSxqcanOXiHYA",
            "benefits": [
                {
                    "benefit": "SEO Landing Pages"
                },
                {
                    "benefit": "Customer Case Studies"
                },
                {
                    "benefit": "Company News & Updates"
                }
            ],
            "testimonials": [
                {
                    "name": "Maggie Summers",
                    "headshot": "https://cdn.buttercms.com/iAvdwmxmSjKVfpuqPjWJ",
                    "title_company": "Sasquatch",
                    "quote": "After several attempts at implementing an open source CMS into my app, I found Butter. It’s the best!"
                },
                {
                    "name": "Drew Johnson",
                    "headshot": "https://cdn.buttercms.com/q3z0MfVTJWso2JM5IXvg",
                    "title_company": "App Partner",
                    "quote": "Wordpress was too slow and impacting our business. Butter is more performant and a faster alternative. A no brainer."
                },
                {
                    "name": "BEAU O'HARA",
                    "headshot": "https://cdn.buttercms.com/vOWy5G1LRzm60NyRd3P0",
                    "title_company": "Anstar Products",
                    "quote": "I've tried other API-first CMS'. I liked their programs, but I got yours up and running the fastest"
                }
            ]
        }
    }
}

This use case demonstrates is how you can use Collections to store reusable promotional content that can be Referenced by multiple pages.

Tables of Related Content

There are many use cases for Collections. Another is using Collections as tables of related data which you can query directly. For example let's say you want to create a music site for musicians and you want to store data like Albums and Artists. Here's how you'd model that out using Collections in Butter and then query your content.

For code examples of making API calls to query a Collection directly, check out our Collections API Reference.

First create a Collection for Arists and configure it's properties to be Name, Headshot, and Genre.

Arists Collection

Then add a few Arists to the Collection.

Add Arists To Collection

You can query Collections directly via our API. Here's what the API JSON response looks like for your Artists Collection.

GET https://api.buttercms.com/v2/content/?keys=artists

{
    "data": {
        "artists": [
            {
                "genre": "Rap",
                "name": "Drake",
                "headshot": "https://cdn.buttercms.com/V0mLWb47TaI9qmrRkzAC"
            },
            {
                "genre": "Country",
                "name": "Carrie Underwood",
                "headshot": "https://cdn.buttercms.com/FRToQffDSK2IE1O3fUuq"
            },
            {
                "genre": "Rock",
                "name": "Young the Giant",
                "headshot": "https://cdn.buttercms.com/jqVWtHf6T6acW8APrh3g"
            }
        ]
    }
}

With your Artists Collection created, you can now create a Collection for Albums which will include a Reference to our Artist Collection (every Album belongs to an Artist).

Albums Collection

Then add a few Albums.

Add Ablums To Collection

Here's what the API JSON response looks like for your Albums Collection. Note artist is a Reference the Arists Collection above.

GET https://api.buttercms.com/v2/content/?keys=albums

{
    "data": {
        "albums": [
            {
                "release_date": "2018-06-29T00:00:00",
                "artist": {
                    "genre": "Rap",
                    "name": "Drake",
                    "headshot": "https://cdn.buttercms.com/V0mLWb47TaI9qmrRkzAC"
                },
                "cover_art": "https://cdn.buttercms.com/uorkxsTQfit8N8uW6Im4",
                "album_name": "Scorpion"
            },
            {
                "release_date": "2018-09-14T00:00:00",
                "artist": {
                    "genre": "Country",
                    "name": "Carrie Underwood",
                    "headshot": "https://cdn.buttercms.com/FRToQffDSK2IE1O3fUuq"
                },
                "cover_art": "https://cdn.buttercms.com/3m0oGGyXQNCUnQke4Ps5",
                "album_name": "Cry Pretty"
            },
            {
                "release_date": "2018-10-12T00:00:00",
                "artist": {
                    "genre": "Rock",
                    "name": "Young the Giant",
                    "headshot": "https://cdn.buttercms.com/jqVWtHf6T6acW8APrh3g"
                },
                "cover_art": "https://cdn.buttercms.com/ThLT87lBSzyCkhivr64l",
                "album_name": "Mirror Master"
            }
        ]
    }
}

This use case demonstrates is how you can use Collections to create tables of data that Reference each other for complex content structures.

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 Angular. Note Butter works with any client-side JavaScript framework including Angular and React.js. For a sample project, check out out this Angular + ButterCMS 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.

Display posts

To display posts we create a simple /blog route in our app and fetch blog posts from the Butter API, as well as a /blog/:slug route to handle individual posts.

See our API reference for additional options such as filtering by category or author. The response also includes some metadata we'll use for pagination.

Setup Blog Home Page

Under apps/blog-post type ng g component listing

apps/blog-post/listing/blog-post.listing.component.ts

Update component to get all posts

  1. import butterService
  2. Get all post onInit
import {Component, OnInit} from '@angular/core';
import {butterService} from '../../_services';

@Component({
  selector: 'app-blog-post',
  templateUrl: './blog-post.component.html',
  styleUrls: ['./blog-post.component.scss']
})
export class BlogPostComponent implements OnInit {
  public posts: any[];

  constructor() { }

  ngOnInit() {
    butterService.post.list({
      page: 1,
      page_size: 10
    }).then((res) => {
      console.log(res.data)
      this.posts = res.data.data;
    });
  }
}

Display the result

<mat-card>
  <mat-card-title class="page-title">Blog Posts</mat-card-title>
  <mat-divider></mat-divider>
  <mat-card-content class="page-body">
    <mat-card *ngFor="let post of posts">
      <mat-card-title>

        <a [routerLink]="[post.slug]">
          <div class="container">
            <div fxLayout="row" fxLayout.xs="column"
               fxFlex class="content">
              <div class="blocks">
                <img *ngIf="post.featured_image" src="{{post.featured_image}}" height="64" width="64"/>
              </div>
              <div class="blocks">
                {{post.title}}
              </div>
            </div>
          </div>
          <div class="container">
            <div fxLayout="column" class="summary">
              <div [innerHTML]="post.summary"></div>
            </div>
          </div>
        </a>
      </mat-card-title>
    </mat-card>
  </mat-card-content>
  <mat-divider></mat-divider>

  <mat-card-footer>
    <div class="page-footer">
      <mat-icon>whatshot</mat-icon>
    </div>
  </mat-card-footer>
</mat-card>

Setup Blog Post Page

Under apps/blog-post type ng g component details

apps/blog-post/details/blog-post.details.component.ts

To show to the single post

  1. Import butterService
  2. In OnInit hook, use butterService to get the blog-post post given the slug in the URL path
  3. Store results in post variable and markup (html) will be updated with the customer data
import {Component, OnInit, ViewEncapsulation} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import {ActivatedRoute} from '@angular/router';
import {butterService} from '../../_services';
import {map, take} from 'rxjs/operators';


@Component({
    selector: 'app-blog-post-details',
    templateUrl: './blog-post.details.component.html',
    styleUrls: ['./blog-post.details.component.scss'],
    encapsulation: ViewEncapsulation.None
})
export class BlogPostDetailsComponent implements OnInit {

    constructor(protected route: ActivatedRoute) {
    }

    protected slug$: Observable<string>;
    public post = {
        meta: null,
        data: null
    };

    ngOnInit() {
        this.slug$ = this.route.paramMap
            .pipe(
                map(params => (params.get('slug')))
            );

        this.slug$.pipe(
            take(1))
            .subscribe(slug => {
                butterService.post.retrieve(slug)
                    .then((res) => {
                        this.post = res.data;
                    }).catch((res) => {
                    console.log(res);
                });
            });
    }
}

Display the result

<mat-card>
  <div class="container">
    <div fxLayout="column" class="blog-details">
      <div class="container">
        <div fxLayout="row">
          <h1 class="blocks">
            {{post.data.title}}
          </h1>
          <div *ngIf="post.meta.previous_post"><a [routerLink]="post.meta.previous_post"><</a></div>
          <div *ngIf="post.meta.next_post"><a [routerLink]="post.meta.next_post">></a></div>
        </div>
        <h4>
          {{post.data.author.first_name}} {{post.data.author.last_name}}
        </h4>
        <div class="post-body" [innerHTML]="post.data.body"></div>
      </div>
    </div>
  </div>
</mat-card>

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:

List all categories and get posts by category

Call these methods on the onInit() lifecycle hook

methods: {
  ...
  getCategories() {
    butter.category.list()
      .then((res) => {
        console.log('List of Categories:')
        console.log(res.data.data)
      })
  },
  getPostsByCategory() {
    butter.category.retrieve('example-category', {
        include: 'recent_posts'
      })
      .then((res) => {
        console.log('Posts with specific category:')
        console.log(res)
      })
  }
},
created() {
  ...
  this.getCategories()
  this.getPostsByCategory()
}

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.

Create a file to see an example of what we get back from the API.

app/feed/feed.component.ts

import {Component, OnInit} from '@angular/core';
import {butterService} from '../_services';

@Component({
  selector: 'app-misc',
  templateUrl: './feed.component.html',
  styleUrls: ['./feed.component.scss']
})

export class FeedComponent implements OnInit {
  protected rss;
  protected atom;
  protected sitemap;

  constructor() { }

  ngOnInit() {
    butterService.feed.retrieve('rss').then((res) => {
      console.log(res.data.data);
      this.rss = res.data.data;
    });

    butterService.feed.retrieve('atom').then((res) => {
      console.log(res.data.data);
      this.atom = res.data.data;
    });

    butterService.feed.retrieve('sitemap').then((res) => {
      console.log(res.data.data);
      this.sitemap = res.data.data;
    });
  }
}

Display the result

<mat-card>
  <mat-card-title class="page-title">RSS, Atom & Sitemap</mat-card-title>
  <mat-divider></mat-divider>
  <div class="feeds">
    <mat-card>
      <mat-card-title>RSS</mat-card-title>
      <mat-card-content></mat-card-content>
    </mat-card>
    <mat-card>
      <mat-card-title>Atom</mat-card-title>
      <mat-card-content></mat-card-content>
    </mat-card>
    <mat-card>
      <mat-card-title>Sitemap</mat-card-title>
      <mat-card-content></mat-card-content>
    </mat-card>
  </div>
  <mat-divider></mat-divider>
  <mat-card-footer>
    <div class="page-footer">
      <mat-icon>whatshot</mat-icon>
    </div>
  </mat-card-footer>
</mat-card>

Navigate to localhost:4200/rss

We can see ButterCMS passes back the entire xml need to create a feed or sitemap.

Setup to create feeds and sitemap

If you want to statically generate these xml files you can use our Webhooks which will POST change notifications to your app.

Setup up a listener webhook on your hosting that will trigger a rebuild or redeploy of your static site when it receives a POST request.

Setup a POST Webhook in the ButterCMS dashboard with the Event "Blog Post Create, Update, or Delete" and paste the listener url into Target URL field.

ButterCMS Webhooks

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