Radiant replace Pages with Abstract Content Model

Hi all:

The following might violate the “no-fluff” mentality of Radiant, but I
will give it a shot anyway. Chances are that somebody else has already
worked on something similar.

Something I have missed in Radiant, since I have first used it
(pre-0.5), is a uniform representation of content. I personally find the
Page model clever, but rather strict as online content is rarely limited
to pages, page parts and layouts. A content management system should be
able to handle all kinds of content, not just pages. Various attempts
have been made to “hack” support for other content types into Radiant
and we ended up with assets management, strange page behaviours (e.g.
search_behaviour) and still no commenting system.

While for many the page model is perfectly fine and Extensions will
solve all the other problems, I was dreaming of a uniform representation
of all content independent of its type. So I hacked together a slightly
modified version of Radiant (mental branch) which replaces the Page
model with an abstract content model at the root and derives all other
content types from this abstract model.

For now, I have modified the previous Page model to be a derived content
class and added a very simple content class called Binary. Those two
content classes alone already provide me with a very rudimentary assets
management as their content is uniformly represented in Radiant using
uniform URLs and the familiar tree based administration interface.
Additional content classes can be easily added through extensions and
integrate seamlessly with the existing administration interface avoiding
extra tabs, proxy pages and non-uniform URLs.

At the moment the modifications are not ready for release, but if you
want you can play with the online demo. The site contains further
information on how the abstract content model works and provides some
examples as well as demonstrates the admin interface:

Live Site
URL: http://init.ca:3000/

Administration Interface
URL: http://init.ca:3000/admin/
Username: admin
Password: admin

I will actively maintain and further develop this approach and hopefully
release some code and patches against stock Radiant soon. On the top of
my list for content classes is also a Comment content class, which
essentially will store comments as children of a page.

Comments, ideas and flames – all are welcome.

Cheers,
Oliver

search_behaviour) and still no commenting system.
I had a similar play when I first started messing around with radiant -
I think it’s something that makes some sense from a model
point of view - a lot of the behaviour of page is really specific to
creating a general page, whereas specialized page behaviours
(such as redirection) don’t need breadcrumbs (not that I’ve really ever
gotten the point of those) and page parts.

In terms of interface, however I think creating dedicated interfaces for
asset and comment management is a better way to go.

I do like the way that you’ve put the ‘add…’ combo box on the page
tree - we definitely need something that lets you specify the
page type before you start editing it so that you can get the interface
appropriate for your specific page type rather than just the
generic page editing interface. Not sure if yours is the way to go, but
I like the fact that it’s a one-click solution.

Dan.

Hi Dan:

Daniel S. wrote:

In terms of interface, however I think creating dedicated interfaces
for asset and comment management is a better way to go.

My plan for that is to provide content class filters for the tree, such
that only objects of the specific class are displayed. This idea can
also be extended to provide stored tree views that can be accessed. For
example a view that only shows comments or assets. Another potential
extension is to provide the option to limit the display to a specific
subtree, e.g. “Show me all comments that are below this page.”

I do like the way that you’ve put the ‘add…’ combo box on the page
tree - we definitely need something that lets you specify the page
type before you start editing it so that you can get the interface
appropriate for your specific page type rather than just the generic
page editing interface. Not sure if yours is the way to go, but I
like the fact that it’s a one-click solution.

I find it looks quite crowded as it is right now, though I currently
can’t think of an alternative. Maybe some fancy Javascript with hovering
pop-ups or so will do.

Thanks for the feedback.

Cheers,
Oliver

Oliver, I like your thought process.

What you are running up against is the fact that the core of radiant
does not model the true problem domain. And I continually read here
were developers hit this wall.

One of the things that I love about radiant (and rails too, really) is
that it focuses on the user. In my mind, the goal should always be to
make the user’s life simpler - even if this means making the developer’s
work more difficult.

So I agree with John’s and Dan’s objective to keep the interface simple
and intuitive. Let’s not over-complicate the thing. No fluff.

But does the radiant back-end have to match the UI?

No matter what the radiant interface design, HTML and HTTP are what they
are. The web specifies HTML pages, images, stylesheets, and more - all
organized within directories. Yet the core of radiant, really, only
addresses the page (or at least text) part of this spec.

The (wise) simplification of UI has lead to a over-simplification of the
data model - to the point where the model doesn’t match enough of web
reality.

So newcomers to radiant keep stubbing their toes when they try to use
radiant in legitimate but unforeseen ways. Yes, sometimes this is
genuine over-complication on the developer’s part but many problems
would be trivial with a more consistent model. And radiant would grow
more gracefully.

As I see it, radiant, should model, track and store all the key web
elements (in a db or otherwise is only a technical issue) because they
are needed to make a site (they are all part of the content being
managed).

Once the true objects exist within radiant, nothing says that you then
can’t adjust how and which elements are exposed (like showing only HTML
pages in the admin interface) or to add metaphors that make our user’s
jobs simpler (like page parts).

So, Oliver I like your thinking because you see the benefit to making
radiant “aware” of all the fundamental web pieces.

Now, whether the UI should expose the creation of page types with a
combo-box or how simple the admin page should look… that’s is a wholly
separate issue.

As I read through my original reply, it sounds a bit soap-boxy now. I
apologize if it came across that way - it was getting late.

My concern with Oliver’s patch is that it over complicates the
model. I’m a little leary of creating a complex inheritance
heirarchy for Radiant.

My thoughts are not so much tied to whether the model should be
abstracted to the point of “generic HTML element” from which everything
inherits (though that could prove smart). Instead, my view is that in a
content management system, the goal should be to manage content. This
means managing pages, but also pictures, video, etc.

Yes pages and images and redirects have URLs, but beyond that
they have very little in common. Sometimes things that look similar
are not similar at all.

A small business user or any user with basic needs still requires
method(s) to manage all the parts. It seems counter productive to the
simplicity of Radiant to say, “We’ll help you store and manage your
pages. Oh, you need pictures too? Here’s an FTP client” It seems that
even a no frills CMS tool should address all the content.

This isn’t to say it has to be live in v0.6 but is it even a future
goal? Having extension developers slog through various ways to
implement these ideas may be a great development plan but eventually, I
think that Radiant should own this domain.

Even if it’s just to offer a basic storage architecture and give an API
to developers to customize the UI so that they can match their special
use cases (like store an image with each page vs. some centralized
administration UI).

I’m not ruling out what Oliver is suggesting, but I am having
difficulty seeing the true value.

Would it not strengthen the platform to tackle the storage and
management issue for all content? I think that many of the
extensions/customizations out there are continually reinventing these
wheels because it is a core need of any CMS system.

Other values come to play where you can treat these different elements
commonly:

  • CRUD operations
  • User permissions and levels
  • Caching
  • Rules for handling simultaneous edits

I can give technical arguments like this all day long but, really though

  • when it comes down to it - I keep seeing extensions and developer
    requests for the same recurring needs. It just smells like there is a
    simpler, more developer friendly, DRY-er solution. And my mind keeps
    refactoring this problem space back into Radiant.

Chris P. wrote:

What you are running up against is the fact that the core of radiant
does not model the true problem domain. And I continually read here
were developers hit this wall.

The (wise) simplification of UI has lead to a over-simplification of the
data model - to the point where the model doesn’t match enough of web
reality.

I’m not sure that I agree. My concern with Oliver’s patch (which has
been suggested at least once before) is that it over complicates the
model. I’m a little leary of creating a complex inheritance heirarchy
for Radiant. Yes pages and images and redirects have URLs, but beyond
that they have very little in common. Sometimes things that look similar
are not similar at all. I’m not ruling out what Oliver is suggesting,
but I am having difficulty seeing the true value.


John L.
http://wiseheartdesign.com

What about also unifying Snippets and Layouts under a single abstract
model?

In which case this is no longer true:

Actually the commonality is:

  • available through a url
  • updates the response

The commonality is simply “user editable content”

If Pages, Snippets, and Layouts all made use of the same underlying
“content” model, then this would give additional flexibility to
extension authors to write other kinds of “content” also using this
model.

For example: “Spotlights”. I can imagine an extension for managing a
collection of spotlights and setting up rotating spotlights, (And it
could even do things like manage banner ads) But underneaeth it should
use the same Model and the same R:tags that Sinppets, Layouts and Pages
use. And that model should be called Content.

Jacob

John W. Long wrote:

Chris P. wrote:

What you are running up against is the fact that the core of radiant
does not model the true problem domain. And I continually read here
were developers hit this wall.

The (wise) simplification of UI has lead to a over-simplification of the
data model - to the point where the model doesn’t match enough of web
reality.

This is exactly what I am trying to address. The data model does not
have to reflect the simplicity of the UI, as long as it does not
affect the UI. Especially not, when it could make the software
developer’s job easier.

I’m not sure that I agree. My concern with Oliver’s patch (which has
been suggested at least once before) is that it over complicates the
model. I’m a little leary of creating a complex inheritance heirarchy
for Radiant.

I, as a software developer, personally find dealing with many
different non-related classes more complicated than with an
inheritance hierarchy that provides abstraction. Very much like I
prefer using a uniform set of file manipulation tools to move, copy,
rename, archive, find, categorize, etc. files on my file system,
independent of what content they represent.

Yes pages and images and redirects have URLs, but beyond
that they have very little in common.

While I would not throw redirects together with pages and images, as
they do not really represent content, I think pages and images and
other content types have a lot in common. They can be published,
searched, tagged (as in labeled), commented, viewed, have authors and
licenses. If I think harder I might come up with some more.

Cheers,
Oliver

Daniel S. wrote:

Maybe that ‘separate url lookup’ table that has been rattling round a little could come into play here. Pages and Assets and
Redirects are all ‘mappable’ things - they can handle a url.

class UrlMapping
belongs_to :handler, :polymorphic => true
end

module UrlHandler
def self.included(base)
[…]
#do whatever
end
end

This would perfectly address the problem of unifying URLs for all
content, but an abstract content model can go even further and provide
standard interfaces for searching/indexing, backup, tagging,
commenting etc. Maybe the OO thinking of mine is old-fashioned and
acts_as_searchable, acts_as_backupable, acts_as_taggable and
acts_as_commentable are the hip things to these days.

Oliver

Jacob B. wrote:

What about also unifying Snippets and Layouts under a single abstract
model?

In which case this is no longer true:

Actually the commonality is:

  • available through a url
  • updates the response

The commonality is simply “user editable content”

Hmm, I do not really see snippets and layouts as content, but they
certainly could be and you could even give them a URL. I mean you
would give a CSS file a URL or images that are embedded in an article.
Why not do the same for layouts and snippets. In fact when using
server-side includes, that is exactly how you include layouts and
snippets, via URLs.

For example: “Spotlights”. I can imagine an extension for managing a
collection of spotlights and setting up rotating spotlights, (And it
could even do things like manage banner ads) But underneaeth it should
use the same Model and the same R:tags that Sinppets, Layouts and Pages
use. And that model should be called Content.

Spotlights? I assume you are not talking about the ones used in stage
performance :wink:

Cheers,
Oliver

I’m not sure that I agree. My concern with Oliver’s patch (which has
been suggested at least once before) is that it over complicates the
model. I’m a little leary of creating a complex inheritance heirarchy
for Radiant. Yes pages and images and redirects have URLs, but beyond
that they have very little in common. Sometimes things that
look similar
are not similar at all. I’m not ruling out what Oliver is suggesting,
but I am having difficulty seeing the true value.

Actually the commonality is:

  • available through a url
  • updates the response

There’d be a couple of advantages of unifying pages/images/redirects
into the one model - most notably the fact that the
SiteController could remain untouched when you add another of these ‘url
handling’ objects (I pretty much had to do a copy/paste
duplicate to serve up images in my asset extension). I definitely think
they should be viewed differently in the admin interface,
but I could be sold on unifying the model.

The Page object adds really only one extra thing to that mix:

  • has many page parts

I’m not sure if those advantages are worth it, but the point that I do
see is that we currently have the view that Pages must be
made up of parts - I don’t think that’s necessarily true… but until
the work in facets for changing the way that you can interact
with a page through the editing interface is worked out properly, I
don’t think it’s easy to see the need. Perhaps if there was a
SimplePage above page that didn’t have page parts, that’d by all the
seperation I would need.

Maybe that ‘separate url lookup’ table that has been rattling round a
little could come into play here. Pages and Assets and
Redirects are all ‘mappable’ things - they can handle a url.

class UrlMapping
belongs_to :handler, :polymorphic => true
end

module UrlHandler
def self.included(base)
base.class_eval {
has_one :url_mapping
before_save :update_mapping
}
end

def update_mapping
url_mapping = UrlMapping.new(:path => url)
end
end

class Page
include UrlHandler
def handle(request, response)
#do whatever
end
end

class Attachment
include UrlHandler
def update_mapping
#url can have a transform part (the %) (ie /page/thumbnail/slug)
url_mapping = UrlMapping.new(:path => “#{page.url}%#{slug}”
end
def handles_url?(url)
/#{Regexp.escape(page.url)}([^/]/)?#{Regexp.escape(slug)}"
end
def handle(request, response)
#do whatever
end
end

(Not sure if that should be has_one or has_many, I’ll go with has_one
for now)

If the sitecontroller looked up pages using a reverse like lookup (not
sure about the database compatability of that):

mappings = UrlMapping.find(:all, :conditions => [’? like path’,url])
if(mapping = mappings.find {|m| m.handler.handles_url?(url)})
handler = mapping.handler
handler.handle(request, response)
end

Pages that would need to handle multiple url paths that are unknown at
publish time could override the update_mapping method to set
a mapping like “/search/%” and would be able to handle
“/search/monkeys/blah” or “/search/things/bump/night”.

Dan.

Oliver B. wrote:

Hmm, I do not really see snippets and layouts as content, but they
certainly could be and you could even give them a URL.

Snippets, layouts, and things like radiant tags are not true web
elements. Instead they are abstract concepts that correspond to how
users go about building sites. Concepts like these should guide the user
to work more effectively.

Frankly, it’s one of the things I like most about Radiant.

We need to be able to reference them somehow to build pages but I like
the delineation to the user that “these are pages” and “these are only
parts of pages.” Once you get outside developers, you can easily get
into too much abstraction.

While I favor Radiant owning all content and, possibly, abstracting it
(I’m from that same old OO school), I agree wholeheartedly that users
fundamentally approach the different content types differently.

For instance the benefit of page parts is lost on me if the content type
is an image. Of course an edit image page… hmmm that might be cool.

-Chris

Oliver,

Might I suggest you write up a proposal of sorts on wiki. We can all
help you refine it, but let’s propose something concrete about the
strucutre of the “abstract models” from which Pages, Layouts, Snippets,
and “future content types” should be based.

Hi,

I’ve read with interest all above messages as I have the same concern
about how a model should manage contents.

Simplicity is a key of Radiant, and should remains as this. Now,
extensions open the way to many new features. Even keeping the interface
user centric, it’s important to deal with the need of extending content
types. The interface doesn’t need to relate the content abstraction, but
it should exists to allow extensions to easily integrate new content
types and, more important, to globally manage contents (as for a
search).

It s a good practice to think the interface for users, as it’s a good
practice to think the model for contents.

Why not making everything a content (pages, assets, snippets,…) but
keeping the model simple? Is a wiki already exists about an Abstract
Content Model ?


Stephane

PS: looking further with the example on init.ca, I don’t think Content
should replace Page, and the interface should keep it’s way to manage
‘separately’ objects (contents)