Add to the "require": { ... } section of your composer.json file:

"buttercms/buttercms-php": "~2.2.0"

Then run:

composer install

The source is available on Github.

Set your API token:

$apiToken = 'b60a008584313ed21803780bc9208557b3b49fbb';

Create an API client object:

use ButterCMS\ButterCMS;

// ...

$client = new ButterCMS($apiToken);

Run this:

var_dump($client->fetchPosts([
  'page' => $page,
  'page_size' => 10
]));

This API request fetches your blog posts. Your account comes with one example post which you'll see in the response.

Next, run:

var_dump($client->fetchContentFields(['homepage_headline']));

This API request fetches homepage headline content. 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 front-end of choice with our API. You can use ButterCMS for new projects as well as add it to existing codebases.

ButterCMS comes with a blogging interface and APIs for blog posts, categories, authors, and XML feeds. For other use cases you can setup custom content fields based on your needs.

For example, if you wanted to enable a non-technical person to edit some copy on your homepage, you might create two custom content fields called "Homepage Headline" and "Homepage Main Paragraph". The non-technical person would be able to edit the values of the fields and the JSON API output would look something like this:

{
  "homepage_headline": "OMG I can edit this!",
  "homepage_paragraph": "I love ButterCMS"
}

Custom content fields can be used for more complex cases like creating dynamic pages and managing knowledgebases, which we will cover in this guide.

Table of Contents

Introduction

Learn how to quickly build a custom CMS-powered blog with great SEO using Laravel. Butter also works with any other kind of PHP application like CodeIgniter, Symfony, or raw PHP. Full working example code is available on Github.

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.

routes/web.php:

Route::get('/blog', 'BlogController@listAllPosts');
Route::get('/blog/p/{page}', 'BlogController@listAllPosts');

app/Http/Controllers/BlogController.php:

namespace App\Http\Controllers;

use Illuminate\Routing\Controller as BaseController;
use ButterCMS\ButterCMS;

class BlogController extends BaseController {

  private static $apiToken = 'b60a008584313ed21803780bc9208557b3b49fbb';
  private $client;

  public function __construct() {
    $this->client = new ButterCMS(BlogController::$apiToken);
  }

  public function listAllPosts(int $page = 1) {
    $response = $this->client->fetchPosts([ 
      'page' => $page,
      'page_size' => 10
    ]);
    return view('posts', [
      'posts' => $response->getPosts(),
      'nextPage' => $response->getMeta()['next_page'],
      'previousPage' => $response->getMeta()['previous_page']
    ]);
  }
}

Next we'll create a simple view at resources/views/posts.blade.php that displays our posts and pagination links:

@extends('master')

@section('pageTitle', 'Blog')

@section('content')
  <h2>Blog</h2>

  @foreach ($posts as $post)
    <a href="/blog/{{urlencode($post->getSlug())}}">{{$post->getTitle()}}</a> 
    by 
    <a href="/author/{{urlencode($post->getAuthor()->getSlug())}}">
      {{$post->getAuthor()->getFirstName()}} {{$post->getAuthor()->getLastName()}}
    </a>
    <br>
  @endforeach

  @if (!is_null($previousPage))
    <a href="/blog/p/{{$previousPage}}">Prev</a>
  @endif
  @if (!is_null($nextPage))
    <a href="/blog/p/{{$nextPage}}">Next</a>
  @endif
@stop

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

Route::get('/blog/{slug}', 'BlogController@showPost')
public function showPost(string $slug) {
  $response = $this->client->fetchPost($slug);
  $post = $response->getPost();
  return view('post', [
    'post' => $post,
    'published' => date('j/n/Y', strtotime($post->getPublished())),
  ]);
}

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 @section Laravel helper for setting the HTML title and meta description in the <head> tag of the page.

@extends('master')

@section('pageTitle', $post->getSeoTitle())
@section('metaDescription', $post->getMetaDescription())

@section('content')

  <!-- Post title -->
  <h2>{{$post->getTitle()}}</h2>

  <!-- Publish date -->
  Published {{$published}} 

  @if (count($post->getCategories()) > 0)  
    in
  @endif

  <!-- Post categories -->
  @foreach ($post->getCategories() as $category)
    <a href="/category/{{urlencode($category->getSlug())}}">{{$category->getName()}}</a>
  @endforeach

  <br />

  <!-- Post author -->
  <a href="/author/{{urlencode($post->getAuthor()->getSlug())}}">
    {{$post->getAuthor()->getFirstName()}} {{$post->getAuthor()->getLastName()}}
  </a>

  <br />

  <div>
    {!! $post->getBody() !!}
  </div>
@stop

Categories, Tags, and Authors

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

Route::get('/authors', 'BlogController@listAllAuthors');
Route::get('/author/{slug}', 'BlogController@showAuthor');
Route::get('/author/{slug}/p/{page}', 'BlogController@showAuthor');

Route::get('/categories', 'BlogController@listAllCategories');
Route::get('/category/{slug}', 'BlogController@showCategory');
Route::get('/category/{slug}/p/{page}', 'BlogController@showCategory');

Route::get('/tags', 'BlogController@listAllTags');
Route::get('/tag/{slug}', 'BlogController@showTag');
Route::get('/tag/{slug}/p/{page}', 'BlogController@showTag');
<?php

namespace App\Http\Controllers;

use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Response as Response;
use ButterCMS\ButterCMS;

class BlogController extends BaseController {

  private static $apiToken = 'b60a008584313ed21803780bc9208557b3b49fbb';
  private $client;

  public function __construct() {
    $this->client = new ButterCMS(BlogController::$apiToken);
  }

  public function listAllAuthors() {
    $response = $this->client->fetchAuthors();
    return view('authors', [
      'authors' => $response,
    ]);
  }

  public function showAuthor(string $slug, int $page = 1) {
    $authorResponse = $this->client->fetchAuthor($slug);
    $postsResponse = $this->client->fetchPosts([ 
      'author_slug' => $slug,
      'page' => $page,
      'page_size' => 10
    ]);
    return view('author', [
      'posts' => $postsResponse->getPosts(),
      'author' => $authorResponse,
      'nextPage' => $postsResponse->getMeta()['next_page'],
      'previousPage' => $postsResponse->getMeta()['previous_page']
    ]);
  }

  public function listAllCategories() {
    $response = $this->client->fetchCategories();
    return view('categories', [
      'categories' => $response,
    ]);
  }

  public function showCategory(string $slug, int $page = 1) {
    $categoryResponse = $this->client->fetchCategory($slug);
    $postsResponse = $this->client->fetchPosts([ 
      'category_slug' => $slug,
      'page' => $page,
      'page_size' => 10
    ]);
    return view('category', [
      'posts' => $postsResponse->getPosts(),
      'category' => $categoryResponse,
      'nextPage' => $postsResponse->getMeta()['next_page'],
      'previousPage' => $postsResponse->getMeta()['previous_page']
    ]);
  }

  public function listAllTags() {
    $response = $this->client->fetchTags();
    return view('tags', [
      'tags' => $response,
    ]);
  }

  public function showTag(string $slug, int $page = 1) {
    $tagResponse = $this->client->fetchTag($slug);
    $postsResponse = $this->client->fetchPosts([ 
      'tag_slug' => $slug,
      'page' => $page,
      'page_size' => 10
    ]);
    return view('tag', [
      'posts' => $postsResponse->getPosts(),
      'tag' => $tagResponse,
      'nextPage' => $postsResponse->getMeta()['next_page'],
      'previousPage' => $postsResponse->getMeta()['previous_page']
    ]);
  }

}

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::get('/feeds/rss', 'BlogController@showRSS');
Route::get('/feeds/atom', 'BlogController@showAtom');
Route::get('/sitemap', 'BlogController@showSitemap');
public function showRSS() {
  return Response::make(
    $this->client->fetchFeed('rss')->asXML(),
    200, 
    ['Content-Type' => 'text/xml']
  );
}

public function showAtom() {
  return Response::make(
    $this->client->fetchFeed('atom')->asXML(),
    200, 
    ['Content-Type' => 'text/xml']
  );
}

public function showSitemap() {
  return Response::make(
    $this->client->fetchFeed('sitemap')->asXML(),
    200, 
    ['Content-Type' => 'text/xml']
  );
}

Comments

Butter doesn't provide an API for comments due to the excellent existing options that integrate easily. Two popular servies 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.

Table of Contents

Introduction

Learn how to make content on a static page editable using Butter and Laravel.

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

This guide uses the Laravel web framework but Butter integrates with any PHP web 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.

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:

routes/web.php:

Route::get('/faq', 'BlogController@showFaq');

app/Http/Controllers/BlogController.php:

public function showFaq() {
  return view('faq');
}

resources/views/faq.blade.php:

<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:

app/Http/Controllers/BlogController.php:

<?php

namespace App\Http\Controllers;

use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Response as Response;
use ButterCMS\ButterCMS;

class BlogController extends BaseController {

  private static $apiToken = 'b60a008584313ed21803780bc9208557b3b49fbb';
  private $client;

  public function __construct() {
    $this->client = new ButterCMS(BlogController::$apiToken);
  }

  public function showFaq() {
    $response = $this->client->fetchContentFields([
      'faq_headline',
      'faq_items'
    ]);
    return view('faq', [
      'faqHeadline' => $response['faq_headline'],
      'faqItems' => $response['faq_items']
    ]);
  }

}

resources/views/faq.blade.php:

@extends('master')

@section('pageTitle', $faqHeadline)

@section('content')
  <h2>{{$faqHeadline}}</h2>

  @foreach ($faqItems as $item)
    <h4>{{$item['question']}}</h4>
    <p>{!! $item['answer'] !!}</p>
  @endforeach
@stop

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 create dynamic pages using Butter and Laravel.

Creating dynamic pages with Butter is a two-step process:

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

This guide uses the Laravel web framework but Butter integrates with any PHP web 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.

Setup content fields

Let's suppose we want to be able to create pages for retail-chain locations using ButterCMS and we're starting out with a basic static page template for a single location:

routes/web.php:

Route::get('/locations/chicago', 'BlogController@showLocation');

app/Http/Controllers/BlogController.php:

<?php

namespace App\Http\Controllers;

use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Response as Response;
use ButterCMS\ButterCMS;

class BlogController extends BaseController {

  private static $apiToken = 'b60a008584313ed21803780bc9208557b3b49fbb';
  private $client;

  public function __construct() {
    $this->client = new ButterCMS(BlogController::$apiToken);
  }

  public function showLocation() {
    return view('location');
  }

}

resources/views/location.blade.php:

<h1>Widget Store - Chicago</h1>
<img src="/images/chicago.jpg">
<p>Our Chicago location is located at 566 Wacker Drive.</p>

Enabling new pages to be created 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 "Collection" type and name the field "Location Pages":

On the next screen, we’ll setup the properties for each page in the collection.

Now go back to the work space and create a location:

Integrating your app

To create these pages in our app, we create a dynamic route that fetches content for the page by using a URL parameter. Here's what the code looks like:

routes/web.php:

Route::get('/locations/{slug}', 'BlogController@showLocation');

app/Http/Controllers/BlogController.php:

<?php

namespace App\Http\Controllers;

use Illuminate\Routing\Controller as BaseController;
use Illuminate\Support\Facades\Response as Response;
use ButterCMS\ButterCMS;

class BlogController extends BaseController {

  private static $apiToken = 'b60a008584313ed21803780bc9208557b3b49fbb';
  private $client;

  public function __construct() {
    $this->client = new ButterCMS(BlogController::$apiToken);
  }

  public function showLocation(string $slug) {
    $response = $this->client->fetchContentFields(["location_pages[slug=${slug}]"]);
    $page = $response['location_pages'][0];
    return view('location', [
      'featureImage' => $page['feature_image'],
      'name' => $page['name'],
      'description' => $page['description'],
    ]);
  }

}

resources/views/location.blade.php:

@extends('master')

@section('pageTitle', $name)

@section('content')
  <h2>Widget Store - {{$name}}</h2>

  <img src="{{$featureImage}}" />
  <br />

  {!! $description !!}

@stop

That's it! If you browse to /locations/chicago, you'll see the content we just entered into 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.

Get started now

Sign up with Google Sign up with Github
or