Oct 28, 2009
How to use Rails templates in WordPress themes

Man I love the cake
The Why
This last week I’ve been redesigning Missed Connections and today was time to bring the blog on board with the new design.
Under the hood Missed Connections is running Ruby on Rails, except for the site’s blog which is WordPress.
I wanted the blog to look like it belonged to the rest of the site so I decided to use the same design generated by the Rails layout template to create the WordPress theme. Now I have a WordPress theme that is generated by a Rails app. If I update my Rails layout, I only need to call ‘rake blog_theme:update’ and the WordPress theme gets updated too.
Below is how I did this and how you can too, simply and quickly. All we’ll need is some Rails knowledge, and no experience of WordPress or PHP to make this work.
The How
In brief, we’re going to create a controller action that generates a HTML response (that contains some PHP) and have rake package this generated code up as a WordPress theme.
- Create a BlogThemesController: script/generate controller BlogThemes
- Inside BlogThemesController write an empty show action method:
def show # do nothing or render :layout => 'my_custom_layout' # if you're not using the default layout end
- Add a route for the show action to config/routes.rb:
map.resource :blog_theme
- Create an empty template file for the show action at app/views/blog_themes/show.html.erb
- Copy and paste the following mix of ERB and PHP code into show.html.erb, and check that the angle brackets in the PHP code don’t get changed to entity codes or similar when pasting. Later we’ll call the show action and get a generated PHP file as the response.
<% # This assumes that in your layout, the title in the head is output like: # <title><%= @title %></title> # Change this line to how you set the title for your layout and remember # *not* to html escape this. @title = "<?php wp_title('«', true, 'right'); ?> <?php bloginfo('name'); ?>" %> <?php if ( have_posts() ) : ?> <?php while (have_posts()) : the_post(); ?> <h1><a href="<?php the_permalink() ?>"><?php the_title(); ?></a></h1> <?php the_content(); ?> <p> <a href="<?php the_permalink() ?>">Link to post</a> | Posted by <?php the_author(); ?> on <?php the_time('F jS, Y') ?> | Categorized as <?php the_category(', '); ?> <?php edit_post_link(); ?> </p> <?php comments_template(); ?> <?php endwhile; ?> <p> <?php posts_nav_link() ?> <?php previous_post_link(); ?><br /> <?php next_post_link(); ?><br /> </p> <?php else : ?> <p>Sorry, no posts matched your criteria</p> <?php endif; ?> <?php get_search_form(); ?> - Now we’re going to create a CSS file containing the comments required by all WordPress themes. Create an empty file in your Rails app at public/stylesheets/wordpress/style.css
- Copy and paste the following CSS comments into the empty file:
/* These comments must be in style.css and are used by wordpress Theme Name: Rails generated theme Theme URI: homepage Description: A rails generated theme Author: Eliot Sykes Author URI: http://blog.eliotsykes.com/ Version: 1.0 */
- Almost done, now we’re going to create a Rake task that will call the BlogThemesController#show action and package up the generated PHP code and the CSS file as a WordPress theme. In your Rails app, create an empty file at lib/tasks/blog-theme.rake. Copy and paste the following into this file, and edit the theme_home and blog_theme_url variables to the correct values for your production environment:
namespace :blog_theme do desc 'Update the wordpress blog theme' task :update => :environment do puts "Updating wordpress theme" require 'action_controller/integration' app = ActionController::Integration::Session.new; # Change this to the production url for your blog_theme blog_theme_url = "http://www.missedconnections.com/blog_theme" app.get(blog_theme_url) index_content = app.response.body # Change theme_home to the correct path for your # environment, leave the final directory as rails-generated theme_home = '/home/user/web/blog/wp-content/themes/rails-generated' mkdir theme_home unless File.exists? theme_home index_path = "#{theme_home}/index.php" puts "Writing index.php to '#{index_path}'" File.open(index_path, 'w') {|f| f.write(index_content) } puts "chmod index.php" File.chmod(0755, index_path) puts "Copying style.css to '#{theme_home}'" cp 'public/stylesheets/wordpress/style.css', "#{theme_home}/style.css", :verbose => true puts "Wordpress theme updated" end end - Run ‘rake blog_theme:update RAILS_ENV=production’ to create the WordPress theme in your WordPress installation.
- Log in to your WordPress admin go to Appearance > Themes and select/preview the “Rails Generated” theme.
Now anytime you want to update your blog layout to be in line with changes you’ve made to the Rails layout, simply call that rake task again.
After seeing how things turn out, you may want to play around with the CSS and show.html.erb to get things looking right. I edited the CSS in my Rails app’s existing CSS file at public/stylesheets/app.css. For the generated PHP template I gave it a body class of ‘blog’ and used this in app.css to make it obvious which CSS rules were WordPress specific.
You can see the final results at the Missed Connections site. See how the blog has a very similar layout to the info pages that are served by Rails like the About Us and Thank yous pages.
Important: if your WordPress blog is on another domain/subdomain
If your WordPress blog isn’t on the same domain as your Rails app use full URLs for all assets and links that are in your Rails layout, instead of absolute or relative paths. For assets (stylesheets, images, javascript files) use the AssetTagHelper to make sure the full URL is used. Create a asset_host.rb file in config/initializers and paste this into it:
ActionController::Base.asset_host = Proc.new { |source, request|
"#{request.protocol}#{request.host}"
}
All images in your layout should use the image_tag helper, and use the _url (i.e. not _path) helper methods for generating link URLs in your layout. Also use the javascript_include_tag and stylesheet_link_tag helper methods to generate full URLs for javascript and CSS files.
Summary
Using this method gives you many of the advantages of Rails layouts inside WordPress. It also makes maintenance of your blog and app a little easier and less repetitive.
P.S. If you’re reading this, then there’s a fair chance you run a few MySql databases and a few different web applications (e.g. a few Rails apps and a few PHP apps) on the same server. If you want a way to backup your database and your application directories securely my 6 minute backups project on github could help you out.