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