content management that won't rot your brain
DESCRIPTION
TRANSCRIPT
![Page 1: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/1.jpg)
Content Management That Won’t Rot
Your BrainSean Cribbs
![Page 2: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/2.jpg)
complicated
http://flickr.com/photos/koolgary/2460635163/Content management on the web can be pretty complicated.
![Page 3: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/3.jpg)
hundreds
http://flickr.com/photos/carowallis1/485124848/There are hundreds of open-source content management systems to choose from,
![Page 4: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/4.jpg)
in-completion
http://flickr.com/photos/yakobusan/2436481628/all in various states of completion.
![Page 5: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/5.jpg)
un-intuitive
http://flickr.com/photos/mashed_potatoe/65823367/Most of them have unintuitive user interfaces,
![Page 6: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/6.jpg)
tangled
http://flickr.com/photos/randomurl/440190706/tangled content models,
![Page 7: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/7.jpg)
ugly code
http://flickr.com/photos/flickerbulb/187044366/
and opaque, poorly-architected and undocumented code that refuses to yield to customization attempts.
![Page 8: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/8.jpg)
content model
These include abominations like ezPublish, which is so in love with its content model
![Page 9: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/9.jpg)
content model
that it seems they implemented the editing interface in the content model.
![Page 10: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/10.jpg)
huh?
http://flickr.com/photos/fdecomite/402499198/Good luck figuring that one out.
![Page 11: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/11.jpg)
pluggable
http://flickr.com/photos/studiosmith/2085278030/Or Xaraya, that despite its ultra-pluggable code modules with proscribed interfaces
![Page 12: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/12.jpg)
bridge to nowhere
http://flickr.com/photos/garlandcannon/3048731338/doesn't seem to do anything it advertises.
![Page 13: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/13.jpg)
template surgery
http://flickr.com/photos/soldiersmediacenter/1148977208/Or Joomla & Mambo, which require template surgery to create a custom look and feel
![Page 14: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/14.jpg)
everything to everyone
http://flickr.com/photos/twose/887903401/while trying to be everything to everyone.
![Page 15: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/15.jpg)
FTP is so 1971
http://flickr.com/photos/daveseven/167903362/Why is it so hard to publish a web page that I don't have to use FTP to edit?
![Page 16: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/16.jpg)
webstandards
Why can't I use HTML, CSS and the other web standards I know and love?
![Page 17: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/17.jpg)
ideal CMS
So what would I want in my ideal CMS?
![Page 18: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/18.jpg)
#1 : simple
First, it would be simple to use and understand.
![Page 19: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/19.jpg)
meta is overrated
I'm not impressed with hyper-abstract meta-content models, just make it work.
![Page 20: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/20.jpg)
#2 : standards markup
Second, it would let me write markup and presentation in any format and structure I like,
![Page 21: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/21.jpg)
design freedom
giving me the freedom to design my site the way I want.
![Page 22: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/22.jpg)
#3 : powerful tools
Third, it would have simple and powerful tools built-in to make most content-generation tasks a breeze,
![Page 23: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/23.jpg)
PHP not required
without needing plugin modules.
![Page 24: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/24.jpg)
#4 :clear code
Fourth, it would have a well-architected code design
![Page 25: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/25.jpg)
easy customization
so I could understand and customize it easily.
![Page 26: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/26.jpg)
drum roll please
Fortunately, there's a CMS that lets me do all these things.
![Page 27: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/27.jpg)
It’s Radiant!
It's called Radiant, and it's written in our favorite language, Ruby.
![Page 28: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/28.jpg)
DHHAPPROVED
And yes, even David likes it.
![Page 29: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/29.jpg)
#1 :simple content
model
So how does Radiant meet my expectations? First, Radiant's content model is easy to understand.
![Page 30: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/30.jpg)
Pages
Every Radiant site is made up primarily of Pages,
![Page 31: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/31.jpg)
acts_as_tree
which are arranged in a tree, much like a directory/file structure.
![Page 32: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/32.jpg)
has_many :parts
Pages have many content pieces called parts,
![Page 33: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/33.jpg)
logical pieces
which let you break your pages into logical sections
![Page 34: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/34.jpg)
content_for
think "content_for" blocks in Rails views.
![Page 35: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/35.jpg)
Page-Types(STI)
Any page can have a special type, essentially a subclass of the Page model,
![Page 36: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/36.jpg)
page-level plugins
that acts as a localized plugin, modifying the front-end behavior of that page.
![Page 37: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/37.jpg)
Layouts
Pages also have layouts,
![Page 38: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/38.jpg)
design details
which let you abstract common design details, just like Rails layouts,
![Page 39: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/39.jpg)
Content-Type: text/html
and also let you specify the content type - be it HTML
![Page 40: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/40.jpg)
Content-Type: text/xml
XML
![Page 41: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/41.jpg)
Content-Type: text/css
CSS, or whatever.
![Page 42: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/42.jpg)
Snippets
To round out the system are Snippets,
![Page 43: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/43.jpg)
render :partial
which are kind of like Rails partials
![Page 44: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/44.jpg)
repetitive
small pieces of common or repetitive content
![Page 45: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/45.jpg)
contextual
that can be rendered in the context of many pages.
![Page 46: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/46.jpg)
Filters
Pages and snippets can use text filters
![Page 47: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/47.jpg)
TextileMarkdown
etc.
that let you write content in shortcut languages like Textile or Markdown.
![Page 48: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/48.jpg)
template language
This is all tied together with a template language
![Page 49: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/49.jpg)
Radius
called Radius
![Page 50: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/50.jpg)
non-evaluating
that keeps code well-separated from your content.
![Page 51: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/51.jpg)
#2 : complete design
control
Second, Radiant lets you design your site the way you want.
![Page 52: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/52.jpg)
any text
It doesn't care whether you're publishing HTML, CSS, Javascript, plain text or whatever.
![Page 53: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/53.jpg)
(no binary)
You probably don't want to put binary data in a page, but any kind of text is OK.
![Page 54: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/54.jpg)
tags expose functionality
Most built-in and plugin functionality is exposed through template tags, so you don't have to worry that some feature will produce bad markup;
![Page 55: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/55.jpg)
write your own markup
you can write the markup yourself.
![Page 56: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/56.jpg)
#3 : powerful tools
Third, Radiant has powerful tools
![Page 57: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/57.jpg)
over 50 tags
about 50 built-in template tags to help you accomplish many content-generation tasks.
![Page 58: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/58.jpg)
navigation, sucker
You can use tags to generate navigation
![Page 59: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/59.jpg)
row-striping
stripe table rows
![Page 60: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/60.jpg)
feed me, Seymor
collate content into a feed
![Page 61: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/61.jpg)
no logo for you!
http://flickr.com/photos/rafastarix/2729553586/
or display the big company logo only on the homepage.
![Page 62: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/62.jpg)
#4 : clean code
Last but not least, our reason for being here
![Page 63: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/63.jpg)
well-architected
Radiant is well-architected
![Page 64: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/64.jpg)
developer goodies
and has plenty of goodies for developers.
![Page 65: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/65.jpg)
show me the code
Since this is a technical talk, I'm going to gloss over the details of using Radiant to create a site and focus on how we can customize Radiant to our own needs.
![Page 66: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/66.jpg)
Extensions
To this end, Radiant has a souped-up plugin system called "extensions"
![Page 67: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/67.jpg)
plugins + awesome
which picks up where Rails plugins leave off.
![Page 68: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/68.jpg)
merb-slices
Extensions are more like `merb-slices`
![Page 69: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/69.jpg)
Rails Engines
or Rails Engines than plugins.
![Page 70: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/70.jpg)
app/controllersapp/helpersapp/modelsapp/views
An extension can have its own "app" folder with controllers, helpers, models and views.
![Page 71: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/71.jpg)
db/migrate
An extension can define database migrations
![Page 72: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/72.jpg)
public
public files
![Page 73: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/73.jpg)
vendor/plugins
and even its own plugins.
![Page 74: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/74.jpg)
TATFT
Most importantly, you can "test all the time" in your extensions
![Page 75: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/75.jpg)
RSpec
because Radiant provides a full RSpec harness
![Page 76: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/76.jpg)
dataset :pages
a bunch of test datasets
![Page 77: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/77.jpg)
@page.should render(“foo”)
and some nifty matchers to help out with Radiant-specific stuff.
![Page 78: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/78.jpg)
class FooExtension < Radiant::Extension
In addition to the directory and file structure, every extension is expressed as a singleton class
![Page 79: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/79.jpg)
def activate
that can provide some startup code in the "activate" method
![Page 80: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/80.jpg)
define_routes do |map| map.resources :fuzzy_bearsend
route definitions
![Page 81: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/81.jpg)
description “My first extension.”url “http://foo.com”
and some metadata that is displayed in the user-interface.
![Page 82: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/82.jpg)
TIMTOWTDI
Depending on the scenario, there are a number of different ways we can customize Radiant to accomplish our goals, all of which can be nicely packaged up in extensions.
![Page 83: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/83.jpg)
I could easily fill many hours talking about all the ways to tweak Radiant with extensions, so I'm going to give you the 10,000-foot view of the primary techniques.
![Page 84: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/84.jpg)
#1 :new tags
The first and simplest way to add functionality is to define new Radius tags. As I said before, Radius is the template language used to expose dynamic functionality to the designer and content editor,
![Page 85: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/85.jpg)
<r:awesome />
through the use of these 'r'-prefixed XML-like tags.
![Page 86: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/86.jpg)
(not) XML
The tags seem to imply an XML-structure, but I assure you they are strictly not XML and are really just interpolated in-place.
![Page 87: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/87.jpg)
<r:
Radius tags are composed of four parts - the 'r' prefix;
![Page 88: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/88.jpg)
<r:children:each
the tag name, which may be colon separated;
![Page 89: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/89.jpg)
<r:children:each order=“desc”>
the attributes;
![Page 90: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/90.jpg)
<r:children:each order=“desc”> foo</r:children:each>
any nested contents, and a closing tag. A few notes on these tag names: Radius will execute the definition of each of those colon separated names in order and determine which definitions to use based on context.
![Page 91: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/91.jpg)
<r:children><r:each order=“desc”> foo</r:each></r:children>
The colon-separated version is just a shortcut for nesting them, so this snippet is logically equivalent to the last one we saw.
![Page 92: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/92.jpg)
<r:children><r:each order=“desc”> foo</r:each></r:children>
Also, the last named tag in the colon-separated list gets the attributes passed to its definition.
![Page 93: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/93.jpg)
<r:stylesheet url=“/mine.css” />
So let's make a tag that generates some content - say a stylesheet link, and we'll make the tag look like this.
![Page 94: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/94.jpg)
module LazyTags
First, we'll make a module in our extension to hold the tag definition.
![Page 95: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/95.jpg)
include Radiant::Taggable
Include "Radiant::Taggable" and we're ready to start defining tags.
![Page 96: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/96.jpg)
tag ‘stylesheet’ do |tag|
Next we'll start our tag definition with the `tag` keyword, the tag name, and a block yielding one parameter.
![Page 97: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/97.jpg)
url = tag.attr[‘url’]
Inside our tag definition block, we'll grab the 'url' attribute off the tag,
![Page 98: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/98.jpg)
%Q[<link rel=”Stylesheet” type=”text/css” href=”#{url}” />]
and interpolate that into the proper place in the HTML `link` tag.
![Page 99: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/99.jpg)
end
The return value of the tag-definition block is what is rendered, so we're done.
![Page 100: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/100.jpg)
def activate Page.send :include, LazyTagsend
Last, we mix the module into the Page model in the 'activate' method of our extension, and we have access to our new tag definition.
![Page 101: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/101.jpg)
|tag|
The yielded 'tag' object inside a definition is very powerful.
![Page 102: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/102.jpg)
TagBinding === tag
It's your access to the contextual parsing environment, including what page is being rendered, the request and response objects, and any variables set by surrounding tags.
![Page 103: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/103.jpg)
tag.globalseverywhere
Its primary properties are 'globals', which gives you access to the global environment, including the current page being rendered;
![Page 104: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/104.jpg)
tag.localscascading, contextual
‘locals' which is a cascading symbol-table of sorts, contextual to the current parsing environment;
![Page 105: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/105.jpg)
tag.attrHash
'attr', a hash of attributes placed on the current tag;
![Page 106: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/106.jpg)
tag.double?<r:foo>text</r:foo>
'double?', which is true when the tag contains other tags or text,
![Page 107: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/107.jpg)
tag.single?<r:bar />
and 'single?' which is true when the tag is self-closing.
![Page 108: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/108.jpg)
be kind, I’m sensitive
Because many tags are sensitive to their surrounding environment, you can easily do things like iteration, changing some locals property on each step of the iteration, and causing contained tags to use that property.
![Page 109: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/109.jpg)
children.map do |child| tag.locals.page = child tag.expandend.join
This is essentially what the `r:children:each` tag does - iterate on each of the children, changing `tag.locals.page` on each iteration, then joining the output. To trigger rendering of a tag's contents, we just call `tag.expand`.
![Page 110: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/110.jpg)
tag.render(“title”)
You can also directly invoke the rendering of another tag using `tag.render`. The result will be returned to you as a string.
![Page 111: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/111.jpg)
tag.block
One neat trick is capture the contents of a container tag and reuse it in multiple places with `tag.block`.
![Page 112: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/112.jpg)
<r:navigation urls=”Foo:/foo |Bar: /bar”>...</r:navigation>
The built-in `r:navigation` tag uses this to render navigation links depending on whether the current page matches the URL being output.
![Page 113: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/113.jpg)
tag.locals.hash = {}tag.expand# ...
First, it sets up a hash that can be used inside nested tags, then renders its contents.
![Page 114: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/114.jpg)
tag ‘navigation:here’ do |tag| tag.locals.hash[:here] = tag.blockend
The contained "navigation:here" tag assigns its block into the created hash.
![Page 115: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/115.jpg)
# for each link...if url == page.url tag.locals.hash[:here].callend
Then the "navigation" tag calls the "here" block when the passed URL exactly matches the current page's URL. It uses the same technique to render prefix-matching and non-matching links by capturing blocks.
![Page 116: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/116.jpg)
#2:Admin UI
So now that we can customize page output with tag definitions, let's look at the next big area of customization -- the admin UI.
![Page 117: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/117.jpg)
class Widget < ActiveRecord::Base
Let's say you've built a model for widgets
![Page 118: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/118.jpg)
<r:widgets />
and some Radius tags to display them in a page,
![Page 119: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/119.jpg)
CRUD
and now you need to create an interface for CRUDing them.
![Page 120: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/120.jpg)
map.resources :widgets
The first thing you might want to do, after creating your controller,
![Page 121: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/121.jpg)
Add “Widgets” Tab
is to add a tab to the interface so your widgets are navigable.
![Page 122: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/122.jpg)
Extension.admin
Radiant exposes an "admin" object to every extension that lets you tweak the interface
![Page 123: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/123.jpg)
admin.tabs.add “Widgets”, “/admin/widgets”
and easily add tabs. As well as letting you simply add tabs,
![Page 124: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/124.jpg)
:before => “Layouts”
you can also specify where they occur in the tab order
![Page 125: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/125.jpg)
:visibility => [:admin]
and who can see them. But that's just a simple case of how to customize the UI.
![Page 126: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/126.jpg)
a dash of spice
Often what you want to do is just add a little piece to one view or another.
![Page 127: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/127.jpg)
widget list
Say you need to be able to see your widget list while editing a page.
![Page 128: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/128.jpg)
fine-grained regions
Luckily, you can inject a view partial into any number of defined "regions" in the view template you want to modify, without overwriting the whole thing. This is enabled again through the admin object.
![Page 129: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/129.jpg)
app/views/admin/pages/_widget_list.erb
To add our widget list, we just put it in the app/views/admin/pages directory,
![Page 130: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/130.jpg)
admin.pages.edit.add :form_top, ‘widget_list’
and add it to the proper region like so. In this case, we’re adding it to the form_top region of the edit view for the pages controller.
![Page 131: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/131.jpg)
include_stylesheet “widgets”include_javascript “widgets”
Inside your partial, in addition to simply rendering, you can add stylesheets and javascript files to the head block in the layout so you can make your widget list look awesome.
![Page 132: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/132.jpg)
brute-force override
If you don't like the finessed approach, you can brute-force override any view template,
![Page 133: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/133.jpg)
application.html.haml
including the default layout,
![Page 134: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/134.jpg)
extensionsbefore core
by putting one of the same name in your extension, since extension view paths are searched before Radiant's built-in paths.
![Page 135: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/135.jpg)
#3:front-end
So now you've got your admin interface doing cool things, but you want to provide a little more functionality on the front-end.
![Page 136: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/136.jpg)
page rendering
Let's take a look at the process of how a page is rendered.
![Page 137: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/137.jpg)
map.connect “*url”
First, any request URL that doesn't match an admin or extension controller gets sent to the splatted route
![Page 138: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/138.jpg)
SiteController#show_page
assigned to SiteController.
![Page 139: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/139.jpg)
request.get? orrequest.head?# read cache
If the request method is GET or HEAD, the controller checks whether the requested URL is cached, populating the response if it is.
![Page 140: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/140.jpg)
show_uncached_page(url)
Otherwise, it tries to show an uncached version of the page.
![Page 141: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/141.jpg)
@page = find_page(url)
The controller tries to find the page by the given URL,
![Page 142: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/142.jpg)
process_page(@page)
and then processes it if found
![Page 143: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/143.jpg)
@page.process(request, response)
calling page.process with the request and response
![Page 144: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/144.jpg)
@cache.cache_response(url, response)
caching the response where appropriate.
![Page 145: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/145.jpg)
render :template => “site/not_found”,:status => 404
If it's not found, you get the default 404 page,
![Page 146: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/146.jpg)
redirect_to welcome_path
and if there's no pages at all in the database, you get redirected to the login screen.
![Page 147: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/147.jpg)
SiteController#find_page
So within this process are a number of extension points to play with - `find_page`,
![Page 148: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/148.jpg)
SiteController#process_page
`process_page`,
![Page 149: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/149.jpg)
Page#process(req, resp)
and `Page#process`.
![Page 150: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/150.jpg)
conversion SEO
Let's say that we have an old site that has some existing URLs that we want to preserve for a bit for SEO purposes.
![Page 151: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/151.jpg)
choose a Page class
Since when we create a new page in the interface, Radiant lets us choose the page class we want,
![Page 152: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/152.jpg)
redirect oldies
let's create a new Page class that performs a redirect from the old URL to our new location.
![Page 153: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/153.jpg)
class RedirectPage < Page
So we'll choose to override the `process` method in our new subclass that we'll call `RedirectPage`.
![Page 154: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/154.jpg)
page.part(:body).content == “/old/url”
We'll assume that we put the new URL in the 'body' part of the page,
![Page 155: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/155.jpg)
301 Moved Permanently
and we'll want to consider this a permanent redirection.
![Page 156: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/156.jpg)
def process(req, res) url = parse_object part(:body)
To accomplish this, inside we'll just render the body part to get our URL,
![Page 157: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/157.jpg)
res.redirect url, “301 Moved Permanently”end
then cause the response to redirect.
![Page 158: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/158.jpg)
def cache?; true; end
Believe it or not, a redirect can be cached!
![Page 159: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/159.jpg)
5-minute cachewith headers
Radiant nicely captures the response headers and status when caching pages so, if we want to cache this, it won't have to call our process method again for 5 minutes after the first render.
![Page 160: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/160.jpg)
GET HEAD cache
Now you may have noticed that when I walked through the SiteController workflow, it only checks for cached versions of a page on GET or HEAD requests.
![Page 161: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/161.jpg)
POST PUT DELETEdon’t cache
This means that when a page receives POST, PUT, or DELETE, you can do cool stuff with the data in the request.
![Page 162: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/162.jpg)
mailerdatabase_form
For example, the mailer and database_form extensions respectively process email forms and store data to the database on POST requests,
![Page 163: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/163.jpg)
seamless experience
allowing a seamless front-end experience.
![Page 164: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/164.jpg)
#4:I want my MVC
This is great and all, but sometimes you'd just rather use a controller and views instead of a page.
![Page 165: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/165.jpg)
share_layouts
That's ok too, because there's a very popular extension called `share_layouts`.
![Page 166: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/166.jpg)
ERb, Haml -> Radiant Layout
share_layouts lets you set a Layout, as in a Radiant Layout, within which your regular ERb or Haml view will render.
![Page 167: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/167.jpg)
content_for :side
part(:side)
Captured content blocks - using `content_for` - become page-parts,
![Page 168: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/168.jpg)
@content_for_layout
part(:body)
and the default content becomes the body part, all of which are rendered in your Radiant Layout via `r:content` tags.
![Page 169: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/169.jpg)
@breadcrumbs@title
You can also set the breadcrumbs and title that will be rendered inside our phantom page.
![Page 170: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/170.jpg)
MOAR contexthttp://icanhascheezburger.com/2007/02/23/moar/
And should that not be good enough, and you need even better context, say, for rendering localized navigation or an inherited sidebar,
![Page 171: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/171.jpg)
endpoints
you can reify these phantom pages as "endpoints" in the page-tree,
![Page 172: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/172.jpg)
“Application”page-type
placing an "Application" page at the root of your controller route.
![Page 173: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/173.jpg)
/widgets
That is, if your controller sits at '/widgets',
![Page 174: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/174.jpg)
“widgets” slug
you'd make a page as a child of the root page with the slug 'widgets'.
![Page 175: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/175.jpg)
just a spoonful of sugar
And that's just a smidgen of how you can customize Radiant.
![Page 176: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/176.jpg)
RadiantRailsRuby
Because it's built on Rails, nearly anything you can do with Ruby and Rails can be done inside Radiant extensions.
![Page 177: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/177.jpg)
workflowlifecycle
You could play with the model workflow and lifecycle,
![Page 178: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/178.jpg)
concurrent_draft(working copies)
like the `concurrent_draft` extension that enables working copies,
![Page 179: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/179.jpg)
scheduler(timed publish)
or the `scheduler` extension that lets you specify dates for your pages to appear and disappear from the site.
![Page 180: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/180.jpg)
multi_site(virtual hosts)
Or you could modify built-in models and controllers, like the `multi_site` extension that creates virtual hosts as multiple page-trees inside the same Radiant instance.
![Page 181: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/181.jpg)
twitterthirty_boxes
You could integrate with a third-party web-service, like the `twitter` and `thirty-boxes` extensions.
![Page 182: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/182.jpg)
file_systemDB <-> files
Or you could make design, development, and maintenance easier like the `file_system` extension, which serializes models into text files,
![Page 183: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/183.jpg)
import_export(big YAML file)
or the `import_export` extension that dumps the whole database to a YAML file.
![Page 184: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/184.jpg)
ext.radiantcms.orgAnd once you've completed your masterpiece, you can share it on the extension registry,
![Page 185: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/185.jpg)
script/extension install
thereby enabling automatic installation scripts for your users.
![Page 186: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/186.jpg)
The world is your oyster.
![Page 187: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/187.jpg)
fin
I hope this has whet your appetite to use Radiant
![Page 188: Content Management That Won't Rot Your Brain](https://reader034.vdocuments.us/reader034/viewer/2022051609/5478eb91b379597b2b8b45fa/html5/thumbnails/188.jpg)
<r:questions:ask />
do you have any questions?