Adding a Blog Into an Existing Site

June 06, 201915 min read

Last reviewed June 06, 2019

This article was originally posted in the ButterCMS blog.

Consider the following scenario: you have a fully-functional website, and you want to add a blog to it. The problem: you haven’t previously accounted for this, and you start wondering what the best solution may be that won’t require a major rewrite of your working app.

Perhaps your website is instead still under development, but all solutions for adding blogging functionality seem difficult to fit in your current stack.

Sound familiar?

You may be a good candidate for CMS (Content Management System) integration for your app or website. CMS integration is simply taking your existing website/web app and integrating a Content Management System with it without having to resort to a complex monolithic solution like WordPress. It is the degree of freedom you are looking for in order to keep your tech stack of choice and still be able to enjoy the best of what a Content Management System can offer.

In other words, CMS integration is how to add CMS capabilities into an existing website. This article aims to explain more of it in practice, what the pain points are, how to solve them, and how you can efficiently add a CMS into your current project without needing to rewrite everything from scratch.

Challenges of CMS Integration

Traditional CMS solutions, like WordPress, have historically evolved into whole solutions controlling everything for your app or website. It means that your app will most likely live as a “monolith”, a single unit of technology that is supposed to control the entirety of your website.

This might be fine until it isn’t anymore. Suppose you grow tired of WordPress and want to change the CMS provider. Afterall, you are likely to encounter scalability issues with a monolithic solution as it grows. You now have a problem, as you will need to rebuild core parts of your app that might not even be related to the CMS. Or maybe you are an experienced developer who likes to write web apps using your preferred tech stack, but require an easy interface for non-technical content creators and editors to be able to add and edit content without needing you to update code.

Historically, CMS solutions are tightly coupled to the app. You can minimize the impact of an eventual change in the future by early planning, but the reality is that you won’t always be able to foresee the need for it - and even if you do, current approaches are just suboptimal, as we will see next.

The Subdomain Approach

A way to circumvent the constraints imposed by a monolith solution is to move your blog to a different subdomain, such as blog.example.com. By doing this you can set up your CMS and still keep your favorite tech stack. For example, you might have a website built with Angular + NodeJS and install a WordPress blog in another subdomain.

While this works there are some caveats with this approach:

  1. SEO. The main issue is that setting up your blog under a subdomain can negatively impact your SEO. For content that depends on organic searches, this is very undesirable.
  2. UI consistency. You will be tasked with the extra work of maintaining a consistent UI for two separate apps, so you don’t confuse your users. As naive as it is, consider the case where you have developed a layout for your web app and now need to find (or develop) a WordPress theme that resembles it.
  3. Multiple apps overhead. instead of one, you will have two applications to maintain. In the long run, this may cause a lot of headaches.

The Subdirectory Approach

An alternative to subdomains is to use subdirectories. In fact, subdirectories mitigate the major issues presented by subdomains. First, they are SEO friendly. Also, they are still part of the same app, just installed in a different directory. This structure softens the multi-app and multi-UI overhead.

The problem is that setting a CMS in a subdirectory can be technically challenging. It is definitely non-trivial to orchestrate everything together. A DevOps problem is something you certainly don’t want to foster.

What Then?

Both approaches have in common a considerable integration effort. Moreover, you don’t fully decouple your app from the CMS, meaning that they coexist in a clunky way. A truly good solution should neutralize integration risks and have minimal impact on the current architecture, especially from a DevOps perspective. This is something a headless CMS enables you to do.

A Conceptual Overview of CMS Integration

A headless CMS is a back-end content repository that makes content accessible via API. This approach allows you to treat content as you would treat any regular piece of data.

Content as Data

Suppose that you want to integrate your app with Google Maps. You do not want to make any styling changes, you should not set up any other servers, and you should keep everything in the same domain without creating a new directory. How is this possible?

This happens because you assume whatever geolocalization data you might need will be fetched in a predictable way from a 3rd-party application. Hence all you need to do is to prepare to receive that piece of information and display it accordingly. For instance, putting a marker in a map given a set of coordinates.

Traditional CMS solutions already perform these operations, but only for internal consumption. WordPress will save your content in the database and retrieve it when necessary, without exposing it to other applications. The way your layout or themes consume this data is different from what a regular API does, because you need to use framework-specific methods. These methods add one more layer of complexity, no matter how thorough you find their documentation.

This is precisely how a solution like Butter can help. ButterCMS, a headless CMS, allows you to create content normally in a separate environment, as it should be, and consume content directly in your app through an API. The end result is your content being managed as regular data, fetched from Butter’s servers and rendered as you wish, without changing the architecture of your app.

Headless CMS
Headless CMS diagram.

Using content as data means that you need to be language agnostic, i.e. you should be able to grab your content regardless of your tech stack. Butter currently supports all major languages, so you can throw it at your app today and start blogging at once.

In the next section, we will see how it works in practice by adding a blog into a regular website.

CMS Integration in Practice

Now that we understand what CMS integration means, let us see how one can do it. For the sake of this tutorial, I will be using React but as I mentioned earlier, you can work with your favorite stack. Go ahead and check all available APIs in the ButterCMS website if you haven’t done that before.

In our example, let us assume that we have an existing website and our goal is to add a blog into it. Here’s how it looks like before we add any Butter.

Simple app
Simple website with no blog content.

There is nothing fancy on the site right now. It’s just a regular website with some dummy content. You can follow along this tutorial by checking this GitHub repo. This project was bootstrapped with Create React App. For simplicity I’ll omit CSS changes but the main file can be inspected here.

Adding the Router

Let’s add a page that will hold our blog content and will work as a subdirectory. As explained before, this approach improves SEO. For this, we will need React Router. In your app directory open the terminal and type:

yarn react-router-dom 

Or alternatively:

npm i --save react-router-dom 

To simplify the code, I’ll break our home down into three different components. Here is how App.js looks like:

import React, { Component } from 'react';
import './App.css';
import Home from './Home';
import Header from './Header';
import Footer from './Footer';

class App extends Component {
  render() {
    return (
      <div className="container">
        <Header />
        <Home />
        <Footer />
      </div>
    );
  }
}

export default App;

Now, we want to be able to render either Home or the list of blog posts. We will then replace Home with the router and make sure that the main element is common to all routes:

import { 
  BrowserRouter as Router, 
  Route, 
  Switch 
} from 'react-router-dom';

class App extends Component {
  render() {
    return (
      <div className="container">
        <Router>
          <Header />
          <main>
            <Switch>
              <Route exact path="/" component={Home} />
            </Switch>
          </main> 
          <Footer />
        </Router>
      </div>
    );
  }
}

Save and check your progress by running npm start and going to http://localhost:3000. You will see that your app loads normally but if you change the URL to http://localhost:3000/blog an empty space will be rendered. Let’s fix that!

Adding the Blog Page

Once the router is all set, let us create a dummy page which we will use to hold the blog content in just a moment. Go ahead and create a file called Blog.js, adding this code:

import React from 'react';

const Blog = () => {
  return (
    <div>
      <h1>Blog</h1>
    </div>
  );
}

export default Blog;

Now it’s time to make our router aware of this new page. In App.js:

...
<main>
  <Switch>
    <Route exact path="/" component={Home} />
    <Route exact path="/blog" component={Blog} />
  </Switch>
</main>
...

We need a way to allow users to visit the blog page without needing to manually change the URL. Let’s fix that in Header.js:

import React from 'react';
import { Link } from 'react-router-dom';

const Header = () => (
  <header>
    <nav>
      <div className="logo">
        <Link to="/">
          Fine Coffee <span role="img" aria-label="Coffee"></span>
        </Link>
      </div>
      <ul className=