Skip to content

teemutammela/contentful-middleman-dynamic-pages

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Dynamic Pages with Contentful and Middleman

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

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.

Author

Teemu Tammela

Disclaimer

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.

Table of Contents

Requirements

Import Example Content

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

Ruby & RVM Setup

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

Middleman Setup

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

Contentful Setup

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

Dynamic Pages Setup

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

Deploy to Netlify

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 SitesImport 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 settingsBuild & deployEnvironmentEdit variables and set Contentful Delivery API key and Space ID as environmental variables CONTENTFUL_DELIVERY_API_KEY and CONTENTFUL_SPACE_ID.

Webhook Setup

1) On Netlify go to Site settingsBuild & deployBuild hooksAdd 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 SettingsWebhooks 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.