Kiosk provides APIs for integrating WordPress content into a Rails application: a base REST model for retrieving content, a caching layer, and a rewriting engine for canonicalizing and contextualizing content elements.
This gem was initially developed by National Novel Writing Month for use in its event website. It has since been released under the MIT license.
gem install kiosk
CMS integration requires a WordPress installation that includes the JSON API Plugin.
Once the WP site is up and running, the site endpoint should be specified as
the origin
content server in config/kiosk.yml
of your Rails application.
Different configurations may be specified for each Rails environment, along
with a default.
origins:
default:
site: 'http://dev.cms.example/site_name'
production:
site: 'http://cms.example/site_name'
Localization of content resources depends further on the installation of the WPML Multilingual CMS (non-free) and WPML JSON API plugins.
Looking to serve up content on your Rails site at URLs like
/pages/example-page
? The process is just as simple as with any other type of
ActiveRecord, Mongoid or other model.
Define a model class to represent any of your WordPress pages
class Page < Kiosk::WordPress::Page
end
Set up a route to your pages at /pages/{id}
and allow the id to work with
WordPress page hierarchies (e.g. /pages/parent-page/child-page
).
Example::Application.routes.draw do
resources :pages, only: [:show], constraints: { id: /.+/ }
end
Define a controller that retrieves a given page.
class PagesController < ApplicationController
def show
@page = Page.find_by_slug(params[:id])
# authorization, etc.
end
end
Define a view that renders the page content. (Note that in this example we're trusting the CMS authors to not inject malicious content. You could easily pass the content through some sort of sanitizer if necessary.)
<h1><%= @page.title.html_safe %></h1>
<%= @page.content.html_safe %>
At this point, a request to your Rails application at /pages/example-page
will display your WordPress page! But what about all of those links pointing
back to your CMS in the body of the page? There's one final step you have to
take to that will integrate your own routes into the page content:
canonicalization.
Canonicalize your page content by defining a Kiosk rewrite in your controller. You could do this in the pages controller itself, but if you plan on exposing CMS resources anywhere else it's usually best to define rewrites in the application controller.
class ApplicationController
include Kiosk::Controller
before_filter do
Kiosk.rewriter.reset!
rewrite_paths_for(Page) { |page| page_path(page) }
end
end
That's it! Links in your page content should now point to your Rails page route and, barring images and other attachments, your CMS pages are fully embedded in your application. Now put those content editors to work!
One of the biggest challenges when implementing Kiosk was writing a canonicalization system that adheres to Rails MVC. This might sound strange until you consider some of the constraints that MVC imposes and the nature of our model data.
First, our content models are essentially ActiveResource classes that represent WordPress posts, both the metadata and the post body, the latter of which we want to re-frame such that it appears to live at the location of our Rails application, not WordPress.
Second, MVC constrains the model to know nothing about the context in which it may be requested or rendered. That knowledge is for the controller and view, respectively. In other words, to let our content models rewrite links and other elements within the post with our Rails application routes would have broken the MVC rules.
In order to play nice with the MVC constraint, Kiosk's canonicalization system works by a system of "claims" and rewrites of the HTML served up by WordPress. The model defines the claim, the controller the rewrite.
-
Content models claim to own certain DOM elements in the HTML of any WordPress resource. For example, a
Page
model could claim to own all<a>
elements with hrefs that match the WordPress URL for pages. -
Controllers define certain rewrite rules that transform DOM elements claimed by a given model. For example, a controller could transform the hrefs of the
<a>
elements claimed byPage
to point to the application's/pages/
route, the latter of which the controller has full knowledge of.
In fact, the above is exactly what we did in our example. If you were to look
at the implementation of Kiosk::WordPress::Page
, you would see something
similar to the following.
claims_path_content(selector: 'a', pattern: '/[^\?]+/')
For details on how to define more advanced claims, see Kiosk::Prospector
.
- Refactor off of ActiveResource to a lighter weight RESTful client
- Implement framework-agnostic caching adapter
- Generalize WordPress integration to pave the way for supporting other CMSs
- Factor WordPress specifics out to a separate adapter
- More test coverage!
Kiosk was developed in a pretty isolated environment for the use cases of National Novel Writing Month. For an open-source project to thrive, it needs contributors. So please, if you find this gem at all useful, please contribute!
- Fork the project and create a topic branch
- Write tests for your new feature or a test that reproduces a bug
- Implement your feature or make a bug fix
- Commit, push and make a pull request
Kiosk is licensed under the terms of the MIT License. See MIT-LICENSE
for
details.
Copyright (c) 2013 National Novel Writing Month