Merging categories and articles

When I first started writing Nesta I wanted a CMS that would allow me to:

  1. Write articles that would be published in an XML feed, and
  2. Collect my articles on topic specific category pages that would introduce each topic and link to relevant articles (see my Ruby on Rails page for an example).

Articles and categories are a great way to organise a blog; they're user friendly and search engines love them. So nothing's changed there; I still want articles and categories. However, I've been using Nesta on e-commerce sites recently and have been finding that Nesta, as a general purpose CMS, didn't quite cut it.

Update: The work described below was originally carried out on a separate unification branch. As of 7 October 2009 the changes described below have been merged into the main code base.

The problem

I made a list of the things that I thought were holding Nesta back:

  • To make a simple web page (e.g. a /contact page) I had to put a contact.mdown file in the categories folder. It's not a category page, so this didn't feel quite right.
  • You couldn't host a page at an arbitrary URL; /foo and /articles/foo were supported, while /foo/bar or /foo/bar/baz weren't.
  • A category page could collect links to articles, but not to other category pages. This prevented me from building up a hierarchy of topics and limited Nesta's flexibility.
  • There was no way to control which category pages appeared in the menu. It hadn't been a problem on my blog (I don't have many categories), but for larger sites it doesn't scale. You need to be able to choose what goes in the menu.
  • There shouldn't be any need to specify the "Parent" metadata (it's used to setup the navigation links at the top of each page). If we're going to choose our own URLs then we can work out the parent automatically (e.g. /blog is clearly the parent of /blog/stuff).

The solution

After mulling it over for a while I concluded that the only thing that makes articles different from any other page is that I want them to appear in my atom feed. I've also noticed that only the pages that appear in the feed need a date.

  • Assumption 1: Articles are just web pages that are published on a specific date.

If articles are just pages, what's the difference between a category page and a generic web page? A page only becomes a category page when you've got other pages with related content, and declare them to belong to that category.

  • Assumption 2: Any web page can become a category page.

If you've ever browsed the Nesta code you might have noticed that an Article and a Category were slightly different beasts, and yet we've just concluded that they're both just web pages with different metadata. Whoops -- that's a design flaw.

I've refactored Nesta, merging the Article and Category model classes into a new Page class.

A typical content folder might now look like this:

menu.txt
pages/
  |
  +---- articles/
  |       |
  |       +---- things.mdown
  |       +---- more-things.mdown
  +---- topic.mdown
  +---- topic/
  |       |
  |       +---- stuff.mdown
  |       +---- more-stuff.mdown
  +---- about.mdown
  +---- contact.mdown
attachments/
  |
  +---- foo.png
  +---- bar.png

Note that categories/ and articles/ have been replaced with pages/, and that there's nothing special about the new pages/articles/ directory; I just want to serve some pages with /articles in the URL. You could serve things.mdown from /cabbages/things if you like; just rename the directory. You can create URLs like /foo/bar/baz simply by nesting directories.

This seems like the way forward to me. I'm planning on waiting a couple of weeks to give people a chance to try it out and give me some feedback, before merging the unification branch into master.

As an added bonus the code is now simpler, runs faster, and uses fewer resources.

Trying it out

Update (11 Jan 2011): Since this article was written Nesta has evolved significantly, and the instructions in this section are no longer valid.

If you'd like to try Nesta, see the quick start instructions.

Published on