In Visual Studio, open the Package Manager Console and run:

Install-Package ButterCMS

The source is available on Github.

Set your API token:

var apiToken = "b60a008584313ed21803780bc9208557b3b49fbb";

Create an API client object:

using ButterCMS;

// ...

var client = new ButterCMSClient(apiToken);

Run this:

var response = client.ListPosts(1, 10);

You can inspect the response variable in the debugger to see the results. This API request fetches your blog posts. Your account comes with one example post which you'll see in the response.

Next, run:

Console.WriteLine(
  client.RetrieveContentFieldsJSON(new string[] { "homepage_headline" })
);

This API request fetches homepage headline content. You can use a JSON parser like Newtonsoft.Json to parse the response into an object. You can setup your own custom content fields to manage any content kind of content you need.

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

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>"
    }
  }
}
Table of Contents

Introduction

Setting up CMS-powered Pages is a simple three-step process:

1) Define the Page Type
2) Create a page
3) Integrate into your application

If you need help after reading this, contact us via email, livechat, or book a time with to pair with one of our developers.

Define Page Type

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

Define the fields you want for your customer case studies:

Create Page

With your Page Type defined, you can now create the first case study page. Specify the name and URL of the page...

...then populate the content of the page.

Integration

This guide uses C# with Microsoft's MVC web framework but Butter integrates with any .NET web app. With your page defined, the ButterCMS 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",
        }
    }
}

To create these pages in our app, we create a route that fetches content for the page by using a URL slug parameter:

Controllers/CaseStudyController.cs:

using System.Threading.Tasks;
using System.Web.Mvc;
using ButterCMS;
using Newtonsoft.Json;

namespace ButterCmsExample.Controllers 
{
    public class CaseStudyController : Controller
    {
        private ButterCMSClient Client;

        private static string _apiToken = "your_api_token";

        public CaseStudyController()
        {
            Client = new ButterCMSClient(_apiToken);
        }

        [Route("customers/{slug}")]
        public async Task<ActionResult> ShowCaseStudy(string slug)
        {
          butterClient.ListPageAsync()
            var json = await Client.ListPageAsync("customer_case_study", slug)
            dynamic page = ((dynamic)JsonConvert.DeserializeObject(json)).data.fields;
            ViewBag.SeoTitle = page.seo_title;
            ViewBag.FacebookTitle = page.facebook_open_graph_title;
            ViewBag.Headline = page.headline;
            ViewBag.CustomerLogo = page.customer_logo;
            ViewBag.Testimonial = page.testimonial;
            return View("Location");
        } 
    }
}

Views/CaseStudy.cshtml:


<html>
  <head>
    <title>@ViewBag.SeoTitle</title>
    <meta property="og:title" content="@ViewBag.FacebookTitle" /> 
  </head>
  <body>
    <h1>@ViewBag.Headline</h1>
    <img width="100%" src="@ViewBag.CustomerLogo">
    <p>@ViewBag.Testimonial</p>
  </body>
</html>

That's it! If you browse to /customers/acme-co, you'll see the Page you created in Butter.

If you need help after reading this, contact us via email, livechat, or book a time with to pair with one of our developers.

Table of Contents

Introduction

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.

Two-step process:

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

If you need help after reading this, contact us via email, livechat, or book a time with to pair with one of our developers.

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. Here's the initial code for the server and static page with the Butter API client installed:

Controllers/BlogController.cs:

[Route("tags")]
public async Task<ActionResult> ListAllTags()
{
    return View("Faq");
}

Views/Blog/Faq.cshtml:

<h1>FAQ</h1>

<ul>
  <li>
    <h4>When was this company started?</h4>
    <p>2014</p>
  </li>
  <li>
    <h4>What forms of payment do you accept?</h4>
    <p>Credit cards and checks.</p>
  </li>
</ul>

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 fetch the fields with an API call and then reference them in our view. Here's what the code looks like:

Controllers/BlogController.cs:

using System.Threading.Tasks;
using System.Web.Mvc;
using ButterCMS;
using Newtonsoft.Json;

namespace ButterCmsExample.Controllers 
{
    public class BlogController : Controller
    {
        private ButterCMSClient Client;

        private static string _apiToken = "b60a008584313ed21803780bc9208557b3b49fbb";

        public BlogController()
        {
            Client = new ButterCMSClient(_apiToken);
        }

        [Route("faq")]
        public async Task<ActionResult> ShowFaq()
        {
            var json = await Client.RetrieveContentFieldsJSONAsync(new[] {
                "faq_headline",
                "faq_items"
            });
            dynamic faq = JsonConvert.DeserializeObject(json);
            ViewBag.FaqHeadline = faq.data.faq_headline;
            ViewBag.FaqItems = faq.data.faq_items;
            return View("Faq");
        }

    }
}

Views/faq.cshtml:

@{
    Page.Title = "Frequently Asked Questions";
}

<h2>Frequently Asked Questions</h2>

@foreach (var item in ViewBag.FaqItems)
{
    <h4>@item.Question</h4>
    <p>@Html.Raw(item.Answer)</p>
}

That's it! The values entered in the Butter dashboard will immediately update the content in our app.

If you need help after reading this, contact us via email, livechat, or book a time with to pair with one of our developers.

Table of Contents

Introduction

Learn how to quickly build a custom blog with great SEO. This guide uses C# with Microsoft's MVC web framework but Butter integrates with any .NET web app. Full working example code is available on Github. 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, livechat, or book a time with to pair with one of our developers.

Display posts

To display posts we create a simple /blog route in our app and fetch blog posts from the Butter API. 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.

Controllers/BlogController.cs:

public class BlogController : Controller
{
    private ButterCMSClient Client;

    private static string _apiToken = "b60a008584313ed21803780bc9208557b3b49fbb";

    public BlogController()
    {
        Client = new ButterCMSClient(_apiToken);
    }

    [Route("")]
    [Route("blog")]
    [Route("blog/p/{page}")]
    public async Task<ActionResult> ListAllPosts(int page = 1)
    {
        var response = await Client.ListPostsAsync(page, 10);
        ViewBag.Posts = response.Data;
        ViewBag.NextPage = response.Meta.NextPage;
        ViewBag.PreviousPage = response.Meta.PreviousPage;
        return View("Posts");
    }
}

Next we'll create a simple view at Views/Blog/Posts.cshtml that displays our posts and pagination links:

@{ 
    Page.Title = "Blog";
}

<h2>Posts</h2>

@foreach(var post in ViewBag.Posts)
{
    <a href="/blog/@Uri.EscapeDataString(post.Slug)">@post.Title</a> 
    @Html.Raw("by")
    <a href="/author/@Uri.EscapeDataString(post.Author.Slug)">@post.Author.FirstName @post.Author.LastName</a>
    <br/>
}

@if(ViewBag.PreviousPage != null)
{
    <a href="/blog/p/@ViewBag.PreviousPage">Prev</a>
}

@if(ViewBag.NextPage != null)
{
    <a href="/blog/p/@ViewBag.NextPage">Next</a>
}

We'll also create an additional route and controller method for displaying individual posts:

[Route("blog/{slug}")]
public async Task<ActionResult> ShowPost(string slug)
{
    var response = await Client.RetrievePostAsync(slug);
    ViewBag.Post = response.Data;
    return View("Post");
}

The view for displaying a full post includes information such as author, publish date, and categories. See a full list of available post properties in our API reference. We use the Page object for setting the HTML title and meta description in the <head> tag of the page.

@{ 
    Page.Title = @ViewBag.Post.SeoTitle;
    Page.MetaDescription = @ViewBag.Post.MetaDescription;
}

<h2>@ViewBag.Post.Title</h2>

Published @ViewBag.Post.Published.ToString("d/M/yyyy")
@if (@ViewBag.Post.Categories.Count > 0)
{
    @Html.Raw("in")
}
@foreach (var category in @ViewBag.Post.Categories)
{
    <a href="/category/@Uri.EscapeDataString(category.Slug)">@category.Name</a>
}

<br/>

<a href="/author/@Uri.EscapeDataString(ViewBag.Post.Author.Slug)">
    @ViewBag.Post.Author.FirstName @ViewBag.Post.Author.LastName
</a>

<br/>

<div>
    @Html.Raw(ViewBag.Post.Body)
</div>

Categories, Tags, and Authors

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

[Route("authors")]
public async Task<ActionResult> ListAllAuthors()
{
    var response = await Client.ListAuthorsAsync(false);
    ViewBag.Authors = response;
    return View("Authors");
}

[Route("author/{slug}")]
[Route("author/{slug}/p/{page}")]
public async Task<ActionResult> ShowAuthor(string slug, int page = 1)
{
    var authorResponse = await Client.RetrieveAuthorAsync(slug, false);
    var postsResponse = await Client.ListPostsAsync(page, 10, true, slug);
    ViewBag.Posts = postsResponse.Data;
    ViewBag.Author = authorResponse;
    ViewBag.NextPage = postsResponse.Meta.NextPage;
    ViewBag.PreviousPage = postsResponse.Meta.PreviousPage;
    return View("Author");
}

[Route("categories")]
public async Task<ActionResult> ListAllCategories()
{
    var response = await Client.ListCategoriesAsync(false);
    ViewBag.Categories = response;
    return View("Categories");
}

[Route("category/{slug}")]
[Route("category/{slug}/p/{page}")]
public async Task<ActionResult> ShowCategory(string slug, int page = 1)
{
    var categoryResponse = await Client.RetrieveCategoryAsync(slug, false);
    var postsResponse = await Client.ListPostsAsync(page, 10, true, null, slug);
    ViewBag.Posts = postsResponse.Data;
    ViewBag.Category = categoryResponse;
    ViewBag.NextPage = postsResponse.Meta.NextPage;
    ViewBag.PreviousPage = postsResponse.Meta.PreviousPage;
    return View("Category");
}

[Route("tags")]
public async Task<ActionResult> ListAllTags()
{
    var response = await Client.ListTagsAsync(false);
    ViewBag.Tags = response;
    return View("Tags");
}

[Route("tag/{slug}")]
[Route("tag/{slug}/p/{page}")]
public async Task<ActionResult> ShowTag(string slug, int page = 1)
{
    var tagResponse = await Client.RetrieveTagAsync(slug, false);
    var postsResponse = await Client.ListPostsAsync(page, 10, true, null, null, slug);
    ViewBag.Posts = postsResponse.Data;
    ViewBag.Tag = tagResponse;
    ViewBag.NextPage = postsResponse.Meta.NextPage;
    ViewBag.PreviousPage = postsResponse.Meta.PreviousPage;
    return View("Tag");
}

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.

[Route("feeds/rss")]
public async Task<ActionResult> ShowRss()
{
    var xmlDoc = await Client.GetRSSFeedAsync();
    using (var sw = new StringWriter())
    {
        using (var xw = XmlWriter.Create(sw))
        {
            xmlDoc.WriteTo(xw);
            xw.Flush();
            return Content(sw.GetStringBuilder().ToString(), "text/xml");
        }
    }
}

[Route("feeds/atom")]
public async Task<ActionResult> ShowAtom()
{
    var xmlDoc = await Client.GetAtomFeedAsync();
    using (var sw = new StringWriter())
    {
        using (var xw = XmlWriter.Create(sw))
        {
            xmlDoc.WriteTo(xw);
            xw.Flush();
            return Content(sw.GetStringBuilder().ToString(), "text/xml");
        }
    }
}

[Route("sitemap")]
public async Task<ActionResult> ShowSitemap()
{
    var xmlDoc = await Client.GetSitemapAsync();
    using (var sw = new StringWriter())
    {
        using (var xw = XmlWriter.Create(sw))
        {
            xmlDoc.WriteTo(xw);
            xw.Flush();
            return Content(sw.GetStringBuilder().ToString(), "text/xml");
        }
    }
}

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.

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