Metaprogramming with RadiantCMS

My short stint with Radiant in the near past was actually quite interesting ! — No I did not design websites or webpages. What I am talking about is the internals – making radiant plugins and creating radius tags, the overwhelming use of meta-programing and the ease of overriding and extending the base or extensions functionality.

First-up, Radiant is NOT for newbies. If you are looking to design some static webpages or basic content, I would probably not recommend radiant – there are other tools for this. Radiant however is very exciting if you are planning on things which are more complicated than static web-pages, like authorization based views, galleries, custom website configuration, etc. etc. If you are well versed and aware of page-parts, snippets, layouts and how they all interact with each other, then you can look at Radiant

Though radiant supports ALL basic HTML tags, it also supports radius tags — loaded via extensions. The excellent open source contributions as radiant extensions leaves very little to do on your own ;) but then again – there is nothing called a free lunch.

Its easy to override any existing functionality in core radiant or its extensions by some simple meta-programing. Some good insight here

module MyExtension
module SiteControllerExt
def self.included(base)
base.class_eval {
def new_method
... # whatever new functionality you want to add to the site controller
end
}
end
end
end

You can then activate the SiteController by adding these additional methods in the meta-class.

The alias chain method ensures that we can write some code before or after the core method. Similarly you can override the views. More details here The above are some very simple basic rules of meta-programing.

base.class_eval {

This line of code is actually accessing the meta-class and changing it. In other words, we evaluate the Class object and update the methods in it! This helps us add or modify the functionality of the class.

Radiant Multihosting

Radius and multisite hosting is cool — but you should know how it works to reap the benefits. The following extensions help out: multi_site, scoped_admin.

Both these ensure that all pages are site_scoped. Using some basic meta-programing, each site now has its own ‘scope’. Remember the all important Page.current_site !! Sandip and I busted our heads trying to figure out why the following was ‘wierd’. On the console

This implies that the data is there in the database BUT not available from the associations! So frigging wierd. Then we got into the details of multi_site plugin and realized the ‘error in our ways’. Radiant is by default single site scoped. When we work with multi_site, we need to fool Radiant and tell it which site we are working with! The following works:

So, it extremely important to ensure that the Page.current_site is set when working with multi-hosting. So, why did this happen or how is it so, you ask? The multi_site extension, uses some pretty cool metaprograming to override (using alias_method_chain) find, count, max, min, and other ActiveRecord methods. It defaults to ‘default_site’ if the current_site is not set !

Extension Loading and Configurations

Using Radiant extensions is what makes Radiant radiant! :) There are plenty of extensions that can be easily installed in the radiant setup. However, its important to remember the following:

environment.rb config.extensions is the file to ensure ‘extension load ordering’. This is very important especially if you want to override some extension functionality.

The :all symbol in config.extensions implies the remaining extensions. BUT remember that these extension are then loaded in ALPHABETICAL order! So, be careful to either ensure your call your extension ‘zzz_myextension’ (LoL) or ensure that any extensions you override load before you load your own extension.

The ‘settings’ extension is pretty cool for managing configurations. To add a configuration, you can simply do this:

Radiant::Config["key"] = value

Recommended way of adding default configurations is the have yml file use YAML::load_file in the extension activate function.

Remember, the configuration is saved in the database — so if you override the value from the GUI, the database gets updated — NOT the yml file. So you have to be careful.

Radius tags

Radius tags look something like this:

<r:content />
<r:gallery id="id> ... </r:gallery>

Radius tags help in managing the programing part of dynamic pages. You can add your own radius tags to ease the effort of inserting HTML code. Some cool examples are:

<r:gallery:lightbox_stuff />

This generates the HTML for loading JS and CSS for lightbox — simple. To create a lightbox:

<r:gallery id="3">
<r:gallery:lighbox />
</r:gallery>

To add your own radius tags, you need to do the following in a module.