Here's the problem: You have a Ruby on Rails application and its Wordpress blog. For the sake of consistency and branding, you'd like to use the same layout in your Wordpress blog as you do for your Rails app. Perhaps your blog is one of the main links or tabs in your application's header.
And then there's the impossible stuff... if anything in your Rails app layout loads information from the database in your Rails app, then you cannot have those elements in your Wordpress layout, unless you do something like create an XML or JSON feed in your Rails app and then import it in your Wordpress layout. But this is quite tedious still if you want to change any of it!
There's an easier way.
The solution I found turns out to be quite simple. The basic idea is to create a `:partial` in your Rails app layout, make it publicly accessible via your `config/routes.rb`, have it generate and simply return the appropriate html using your controller method, and then import that html (and CSS) in your Wordpress layout.
For this to really work well, you'll want to make sure that you make your Rails app cache the partials to be imported into your Wordpress layout, so that a lot of traffic on your blog doesn't cause your Rails app server to explode.
The first step is to break as much of your
app/views/layouts/application.html.erb into partials as possible/desired. At the very least, this means a header and a footer partial. Typically, you would not include the stuff in the
A simple Rails layout using this method would look something like this:
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'> <html> <head> ... </head> <body> <%= render :partial => 'static/header' %> <div id="content"> <%= yield %> </div> <%= render :partial => 'static/footer'%> <%= render :partial => 'static/widgets' %> </body> </html>
Note that your layout and partials can have any and all Ruby/Rails code in them that you want. Since your Wordpress theme is importing this stuff from your Rails application, the Rails app will run as usual and just return the end result, which is HTML, so your Wordpress will have no problem interpreting it.
app/views/static/_header.html.erb partial may look something like this:
<div id="header"> <%= link_to image_tag("layout/my_logo.png"), root_path, :alt => "My Rails App", :id => "banner_logo" %> <div id="menu"> <ul> <li> <%= link_to "Products", products_path, :class => ('active' if request.path == products_path) %> </li> <li> <%= link_to "Blog", blog_path, :class => ('active' if @blog) %> </li> <li> <%= link_to "Contact", contact_path, :class => ('active' if request.path == contact_path) %> </li> </ul> </div> </div>
Notice that the normal links in the header are "active" simply if the current URL matches the link path, but the "Blog" link is active if the
@blog variable is set and true. This is because, as you will see in the next section, the URL for the header when it is called from your blog won't be the blog URL.
The next step is to make your layout partials publicly accessible. I.e. make it so that you can access your layout partials from the browser using a direct URL, like http://mysite.com/static/header. The actual URL you use doesn't really matter, because users won't ever need to see or use it.
The way we do this is to explicitly set a path for each layout partial in our
config/routes.rb and then create a controller method for each that renders the HTML generated by the partial.
A path in your routes for your header partial might look like this:
ActionController::Routing::Routes.draw do |map| ... map.header_partial 'static/my_blog_header', :controller => 'static', :action => 'blog_header_partial' ... end
Then in the
app/controllers/static_controller.rb, your corresponding action would look like this:
def blog_header_partial @blog = true render :partial => 'static/header' end
Now, hopefully you see why, in the header partial, we couldn't just say that the blog menu item is
:class => ('active' if request.path == blog_path). The path that the header partial will be seeing when the Wordpress layout requests it will be the path you defined in your
routes.rb, in this case
"static/header". This is why we instead say
:class => ('active' if @blog) and then set
@blog = true in the controller action.
Here's the real trick. In order to include the Rails partials in your Wordpress layout, you might be inclined to use on of these PHP functions:
require(). This won't work though for two reasons.
2) By default, neither method allows absolute URLs due to security precautions. You can change your PHP setup to allow this, but again, this is a security issue. Not to mention, for our purposes, you still would have to deal with reason 1 above.
Instead, we can use PHP's function to retreive HTML code,
In your wp-content/themes/my_theme/header.php file, you would then include this line:
... <body> <?php $a = file_get_contents("http://myrailsapp.com/static/my_blog_header"); echo $a; ?> ...
Of course, you'll also want to import the base stylesheet that styles your layout HTML for your Wordpress theme. You can do this a few different ways. The easiest is to just include it in your
header.php file in the
<head> area like any other stylesheet, just using the absolute URL to the CSS file.
... <link rel="stylesheet" href="http://myrailsapp.com/stylesheets/style.css" type="text/css" media="screen" /> <link rel="stylesheet" href="<?php bloginfo('stylesheet_url'); ?>" type="text/css" media="screen" /> ...
Notice that we include the Rails app stylesheet before the blog stylesheet. This is so that it's easy to override any of the styles we need to specifically in the blog stylesheet.
An alternative way we can do this is using the CSS
Luckily this is easy to fix with Rails's built-in page-caching.
app/controllers/static_controller.rb file, include the following.
class StaticController < ApplicationController caches_page :index, :blog_header_partial, :blog_header_footer, :blog_widgets ... end
And make sure that caching is turned on in your production app, in
... config.action_controller.perform_caching = true config.action_view.cache_template_loading = true ...
Of course, if you install and setup caching in your Wordpress installation (highly recommended), then the complete layout files will be cached and never even need to make calls to your Rails application after the cached pages are generated the first time. This is even faster for your Wordpress blog, because it'll load faster now that it doesn't have to import portions of the layout from an external URL every time a page is loaded.
Note that when you do this, you'll need to expire/delete the cached Wordpress files anytime you update the layout in your Rails app.
Now you have a great looking Wordpress blog that looks like you're never leaving your Rails application. And best of all, you don't have to tediously duplicate efforts every time you update your Rails app layout! How's that for DRY design?