Guide for creating dynamic pages with the Contentful content management platform and the Middleman static site generator. Prior methods of combining Contentful and Middleman, such as the contentful_middleman gem, involved exporting Contentful entries as a JSON file. The dynamic page approach, however, streamlines the development by querying content in real time via the Contentful Delivery API without the need for exporting files.
In addition, this tutorial describes how to deploy the application to Netlify and how to setup a Contentful webhook to rebuild the site whenever entries are published. This tutorial is written with Unix-like operating systems such as macOS or Linux in mind.
NOTE! The source code found in this repository is the end result of this tutorial. Both cloning the repository and carrying out the tutorial is not necessary. Furthermore, this example is boilerplate code and not by any means a comprehensive guide to Contentful and Middleman.
Contentful provides a content infrastructure for digital teams to power content in websites, apps, and devices. Unlike a CMS, Contentful was built to integrate with the modern software stack. It offers a central hub for structured content, powerful management and delivery APIs, and a customizable web app that enable developers and content creators to ship digital products faster.
Contentful is registered trademark of Contentful GmbH.
Teemu Tammela
- [email protected]
- www.auralcandy.net
- github.com/teemutammela
- www.linkedin.com/in/teemutammela
- t.me/teemutammela
This source code is distributed under Unlicense and comes with absolutely no warranty. The author assumes no responsibility for data loss or any other unintended side-effects.
- Requirements
- Import Example Content
- Ruby & RVM Setup
- Middleman Setup
- Contentful Setup
- Dynamic Pages Setup
- Deploy to Netlify
- Webhook Setup
- Contentful CLI
- Ruby (3.1.2)
- RVM
- Bundler
- Git (optional)
- GitHub, GitLab or Bitbucket account (optional)
- Netlify account (optional)
1) Login to Contentful CLI and select the target space.
$ contentful login
$ contentful space use
2) Import content model Page
and example entries to target space.
$ contentful space import --content-file setup/example_content.json
1) It's highly recommended to have RVM (Ruby Version Manager) installed. RVM makes installing and managing various Ruby versions a breeze. Once you have RVM installed, install Ruby 3.1.2
and set it as the default version in your project directory.
$ rvm install 3.1.2
$ rvm use 3.1.2 --default
2) Make sure you have the Ruby version 3.1.2
installed and set as the active Ruby version.
$ ruby -v
3) Install Bundler if not already installed.
$ gem install bundler
1) Install the Middleman gem.
$ gem install middleman
2) Create a project directory and set up the default Middleman installation.
$ mkdir my_project_dir
$ cd my_project_dir/
$ middleman init
NOTE! If you encounter an error while executing middleman init
or middleman server
, you may have to create Gemfile
in advance and/or define strict version number for the haml
gem.
gem 'haml', '~> 5.0'
3) Modify the Gemfile
by adding the Ruby version as well as the contentful
and rich_text_renderer
gems. Using exact gem version numbers is not absolutely necessary, simply a precaution to ensure this tutorial works as intended.
# frozen_string_literal: true
source 'https://rubygems.org'
ruby '3.1.2'
gem 'contentful', '2.16.3'
gem 'middleman', '4.4.2'
gem 'middleman-autoprefixer', '3.0.0'
gem 'redcarpet', '3.5.1'
gem 'rich_text_renderer', '0.3.0'
gem 'rubocop', '1.36.0'
gem 'tzinfo-data', platforms: %i[mswin mingw jruby x64_mingw]
gem 'wdm', '~> 0.1', platforms: %i[mswin mingw x64_mingw]
4) Finish the installation by executing Bundler once again.
$ bundle install
5) Start the Middleman server. You should now see Middleman's default page at http://localhost:4567. By default Middleman runs at port 4567
. Change the default parameter using the -p
parameter (e.g. middleman server -p 9292
).
$ middleman server
1) Add .evn
to .gitignore
file. It should look like this.
.env
.bundle
.cache
.DS_Store
.sass-cache
build/
2) Create a copy of the .env.example
file and insert the Delivery API key and Space ID. See Contentful's authentication documentation for instructions how to set up API keys.
$ cp .env.example .env
CONTENTFUL_DELIVERY_API_KEY=xyz123
CONTENTFUL_SPACE_ID=xyz123
3) Add Contentful Delivery API client, Rich Text renderer and Redcarpet gems to config.rb
. Redcarpet is a library for converting Markdown into HTML.
require 'contentful'
require 'rich_text_renderer'
require 'redcarpet'
require 'redcarpet/render_strip'
4) Add the Contentful Delivery API client to config.rb
. Delivery API key and Space ID will be loaded from .env
file.
client = Contentful::Client.new(
access_token: ENV['CONTENTFUL_DELIVERY_API_KEY'],
space: ENV['CONTENTFUL_SPACE_ID']
)
5) Add custom helpers to config.rb
. These helpers are used for converting Rich Text and Markdown into HTML. This example uses the Rich Text renderer library's default settings. See Rich Text renderer documentation for more details how to create custom renderers for various embedded entry types, or see Redcarpet's documentation for more details about rendering options.
helpers do
# Custom helper for converting Rich Text to HTML
def rich_text_to_html(value)
renderer = RichTextRenderer::Renderer.new
renderer.render(value)
end
# Custom helper for convert Markdown to HTML
def markdown_to_html(value)
renderer = Redcarpet::Markdown.new(
Redcarpet::Render::HTML,
autolink: false,
tables: true,
escape_html: false
)
renderer.render(value)
end
end
1) Create an ERB template file for the Page
content type.
$ mkdir source/pages
$ touch source/pages/page.html.erb
2) Insert the following lines of code to source/pages/page.html.erb
. Notice how we are displaying values from both the fields
and sys
properties of the entry. On the last two lines we are using our custom helpers to convert Markdown and Rich Text into HTML.
---
title: Example Page
---
<h1><%= page.fields[:title] %></h1>
<p><%= page.sys[:updated_at] %></p>
<p><%= markdown_to_html(page.fields[:lead]) %></p>
<p><%= rich_text_to_html(page.fields[:body]) %></p>
Mixing raw HTML tags and Ruby syntax doesn’t yield the cleanest template code, so alternatively you can take advantage of Padrino's tag helpers.
<%= content_tag :h1, page.fields[:title] %>
<%= content_tag :p, page.sys[:updated_at] %>
<%= content_tag :p, markdown_to_html(page.fields[:lead]) %>
<%= content_tag :p, rich_text_to_html(page.fields[:body]) %>
3) Add the following code block to config.rb
. Query the Slug
field of every Page
entry, map the Slug
field values into a flat array, query the corresponding Page
entry and set a proxy. See Middleman's dynamic pages documentation for more details about proxies.
# Query entries that match the content type 'Page'.
# Parameter `include` is set to 0, since we don't need related entries.
# Parameter `limit` value set as 10 for development, 1000 for build.
pages = client.entries(
content_type: 'page',
include: 0,
select: 'fields.slug',
limit: build? ? 1000 : 10
)
# Map the 'Slug' field values of 'Page' entries into a flat array.
page_slugs = pages.map do |page|
page.fields[:slug]
end
# Query 'Pages' entry and set corresponding proxy.
page_slugs.each do |page_slug|
# Query 'Page' entry by 'Slug' field value.
page = client.entries(
content_type: 'page',
include: 2,
"fields.slug": page_slug
).first
# Set proxy for 'Slug' field value and pass 'Page' entry's data to template.
proxy "/pages/#{page_slug}/index.html", '/pages/page.html', locals: {
page:
}
end
4) Add an ignore command to config.rb
. This will prevent Middleman from trying to build the Page
template into a HTML page. We're already creating paths for the HTML pages via the proxy.
ignore '/pages/page.html'
5) Test the proxy at http://localhost:4567/pages/example-page-1.
6) Test building the site.
$ middleman build
1) Create a .ruby-version
file.
$ echo "ruby-3.1.2" > .ruby-version
2) Push your Middleman app into a GitHub, GitLab or Bitbucket repository.
3) Log into Netflify. Sign up to a new account if you don't already have one.
4) Select Sites → Import an existing project on the Netlify dashboard. Select your preferred Git service provider under Connect to Git provider and insert your credentials.
5) Set middleman build
as the Build command and build/
as the Publish directory. You can configure Netlify to use any branch in your repository as the build source. By default, Netlify launches a new build whenever new commits are pushed to the main
branch.
6)
Go to Site settings → Build & deploy → Environment → Edit variables and set Contentful Delivery API key and Space ID as environmental variables CONTENTFUL_DELIVERY_API_KEY
and CONTENTFUL_SPACE_ID
.
1) On Netlify go to Site settings → Build & deploy → Build hooks → Add build hook and create a new build hook. Name the new build hook as Contentful. By default, Branch to build is set to main
. Your new build hook URL should look like this.
https://api.netlify.com/build_hooks/<WEBHOOK_ID>
2) On Contentful go to Settings → Webhooks and select Netlify - Deploy a site from the Webhook templates list. Insert the URL to Netlify build hook URL field and select Create webhook. By default the webhook is set to trigger whenever entries are published or unpublished. You can change this behavior from Webhook settings.