Published by Dan Cunning on Jan 3, 2020
I've run this website for years via a custom Rails application (think Jekyll without hiding the Ruby), but over the past few years I haven't written anything about several projects, fixes, and ideas, mainly because writing was too much hassle.
This is exactly the problem Content Management Systems (CMS) are built to solve, but I choose not to use one back in 2012 because when you build on top of a CMS, you inherit all its dependencies, rules, and limitations. This website is my playground to try new things, and running my site on a CMS like WordPress seemed too restrictive:
WordPress plugins and custom theming could handle a lot of these, but the end result would be a disorganized site that I wouldn't enjoy maintaining. How can I use WordPress' world-class CMS without it restricting what my site can do?
WordPress would handle the creation of posts and pages, but another application will publish the content to https://dan.cunning.cc. The technical term for this approach is a Headless CMS because the "head" (the visitor facing site) is managed elsewhere.
I created a custom "publisher" application that performs the following workflow:
Rails' powerful routing engine allows the publisher to define my site's structure exactly how I want it:
Rails.application.routes.draw do
root to: "pages#show", slug: "home", as: :root
get "index.html", to: "pages#show", slug: "home"
get "sitemap.xml", to: "sitemap#show"
get "wp-content/uploads", to: "uploads#index", as: :uploads
get "wp-content/uploads/*path", to: "uploads#show", as: :upload
get ":category_slug/index", to: "categories#show", as: :category
get ":category_slug/:tag_slug", to: "tags#show", as: :category_tag, constraints: TagConstraint
get ":category_slug/:post_slug", to: "posts#show", as: :post
get ":category_slug/:post_slug/index", to: "posts#show", as: :parent_post
get ":category_slug/:parent_slug/:post_slug", to: "posts#show", as: :child_post
get "*slug", to: "pages#show", as: :page
end
Why the Thrashers left Atlanta is one of the most popular pages on this website, and it's 100% WordPress-driven content. Here's how it looks like inside WordPress' editor:
A more complicated page is the home page which organizes the WordPress categories and links to featured articles:
The Advanced Custom Fields allows me to choose the section order and what posts are featured, and the liquid code renders the HTML using a custom Ruby view component:
class Pages::SectionLinks
attr_reader :template
def initialize(template, page)
@template = template
@page = page
end
def render
sections = (1..6).collect { |i| read_section(i) }
template.render(
partial: "pages/components/section_links",
locals: {
groups: sections.in_groups_of(3),
},
)
end
private
def read_section(i)
acf = @page.data["acf"]
category_id = acf["section_#{i}"]
category_id = category_id.first if category_id.is_a?(Array)
return unless category_id
category = @page.wp.categories.find(category_id)
posts = %w[a b c d e f g h i j k l].collect do |c|
post = acf["link_#{i}#{c}"]
id = post["ID"] if post
@page.wp.posts.find(id) if id
end
OpenStruct.new(
category:,
posts: posts.compact,
)
end
end
<% groups.each do |group| %>
<div class="row section-group">
<% group.each do |section| %>
<div class="section">
<% if section %>
<h2>
<%= link_to section.category.name, category_path(section.category) %>
<span class="label label-default"><%= number_with_delimiter section.category.root_posts.length %></span>
</h2>
<% section.posts.each do |post| %>
<p><%= link_to post.title, page_path(post) %></p>
<% end %>
<% end %>
</div>
<% end %>
</div>
<% end %>
As evident in the Home Page example, a headless CMS requires coding to render the more complicated content, but I like that the code isn't bogged down in the WordPress platform. I think this solution balances the power of the CMS and the power of custom coding pretty well, but there are still some avenues I'd like to explore:
/wp-admin
to work without the MySQL/PHP backend?I'm a Ruby on Rails contractor from Atlanta GA, focusing on simplicity and usability through solid design. Read more »