Integrating Rails and WordPress

I do most of my development in Rails, but many sites need a tab that contains a blog, so I’d like to install WordPress in my Rails app. Here’s how I do it.
(I’m using Passenger for deployment.) We first need to create a space for the blog, and we do that by creating a symbolic link in the Rails’ app’s public folder:

cd path/to/rails/app/public
ln -s /path/to/wordpress/installation news

This separates the WordPress from the Rails app physically, so it makes deployment easier. With the symbolic link, when we go to http:/mydomain.com/news, it should go to the blog.
However, Passenger is going to grab that URL and print out a Rails error message. This needs to be put in the Apache config file to get Passenger to ignore the blog:

<Directory "/path/to/rails/app/public/news">

    PassengerEnabled off
    AllowOverride all
</Directory>

Now, theoretically, that’s all you’d need to do, but the theme for the blog should be the same as the theme for your app. To do that, we need to get WordPress to use our stylesheets, and the code for our header and footer. That means that we should put most of the code in the layout file in partials, and create routes for them. After doing that, my layout file looks like this:

<!DOCTYPE html>

<html>

<head>

    <%= render :partial => '/layouts/dependencies' %>

    <title>Site Title</title>

</head>

<body>

    <%= render :partial => '/layouts/header' %>

    <%= yield %>
    
<%= render :partial => '/layouts/footer' %>

</body>
</html>

and my routes.rb file contains:

get "/styles" => "home#styles"

get "/header" => "home#header"

get "/footer" => "home#footer"

and my home_controller.rb file contains:

def styles
    render :partial => "/layouts/dependencies"

end


def header

    render :partial => "/layouts/header"
end


def footer

    render :partial => "/layouts/footer"

end



And, to use it, I created a little plugin for WordPress. I haven’t packaged it up, but here is the entire code for it. Just put this in the plugins folder, then activate it and look under “settings” for “Rails Theme”.  Put in the URL of the Rails app, and it should use your theme.
Note that because html ids and classes are global, it is easy to have a conflict, so you will probably need to be careful in the names of the css selectors you use. I use the Hybrid WordPress Theme, which doesn’t impose much and has lots of functionality. I had to rename a class that was named “content” because it conflicted. I also needed to add these two styles to override Hybrid styles:

/* for wordpress */
#body-container {
margin: 0;
}
#header-container {
display:none;
}

Here is the entire code of the plugin:

<?php
/*
Plugin Name: Rails Theme
Plugin URI: http://paulrosen.net
Description: This plugin causes WP to call into a Rails app to get stylesheets, javascripts, header, and footer info. This allows WP to seamlessly be integrated into a rails app.
Version: 1.0
Author: Paul Rosen
Author URI: http://paulrosen.net
License: Private
*/

/////////////////////////////////////////////////////
// options in the admin section
////////////////////////////////////////////////////

//------------- Add the admin menu -------------
function rails_admin_options() {
if (!current_user_can('manage_options'))  {
wp_die( __('You do not have sufficient permissions to access this page.') );
}
echo '<div>';
echo '<h2>Rails Theme Options</h2>';
echo 'Options for the Rails Theme Plugin';
echo '<form action="options.php" method="post">';
echo settings_fields("rails_theme_options");
echo do_settings_sections("rails_theme");
echo '<input name="Submit" type="submit" value="Save Changes" />';
echo '</form></div>';
}

function rails_modify_menu() {
add_options_page('Rails Theme', 'Rails Theme', 'manage_options', __FILE__, 'rails_admin_options');
}

add_action('admin_menu', 'rails_modify_menu');

//----------------- Add the settings for this plugin ---------------------
function rails_theme_admin_init(){
register_setting( 'rails_theme_options', 'rails_theme_options', 'rails_theme_options_validate' );
add_settings_section('rails_theme_main', 'Settings', 'rails_theme_section_text', 'rails_theme');
add_settings_field('rails_theme_text_string', 'Base URL (e.g. http://example.com)', 'rails_theme_setting_string', 'rails_theme', 'rails_theme_main');
}

add_action('admin_init', 'rails_theme_admin_init');

function rails_theme_section_text() {
echo '<p>Set the location of the rails web service that will respond to the urls: /styles, /header, and /footer.</p>';
}

function rails_theme_setting_string() {
$options = get_option('rails_theme_options');
echo "<input id='rails_theme_text_string' name='rails_theme_options[url]' size='40' type='text' value='" . $options['url'] . "' />";
}

function rails_theme_options_validate($input) {
$newinput['url'] = trim($input['url']);
return $newinput;
}

/////////////////////////////////////////////////////
// Calling rails app
/////////////////////////////////////////////////////

add_action ( 'wp_head', 'load_stylesheets');

function load_stylesheets() {
$options = get_option('rails_theme_options');
$base_url = $options['url'];

$style = file_get_contents($base_url . "/styles");
$style = str_replace("/stylesheets", $base_url . "/stylesheets", $style);
$style = str_replace("/javascripts", $base_url . "/javascripts", $style);
echo $style;
}

add_action ( 'hybrid_before_html', 'load_header');

function load_header() {
$options = get_option('rails_theme_options');
$base_url = $options['url'];

$contents = file_get_contents($base_url . "/header");
$contents = str_replace("href='/", "href='" . $base_url . "/", $contents);
echo $contents;
}

add_action( 'wp_footer', 'load_footer' );

function load_footer() {
$options = get_option('rails_theme_options');
$base_url = $options['url'];

echo file_get_contents($base_url . "/footer");
}

?>