Introduction

This article is about extending Orchard CMS. Orchard is a Content Management System that is built upon ASP.NET MVC and it's Open Source, community driven.

Orchard websites are composed using different types of content, where every content type can have one or more content parts or fields. There are predefined content types, like 'page', 'blog', 'comment', 'widget' etc. For instance, a 'blog post' is composed of multiple parts. You can also define custom content types within Orchard using the available parts and fields, without any coding. All the features are housed inside modules and with that, you can do anything.With Orchard, you can create content types that represent real-life objects, 'car', 'flower', 'stamp', 'dvd', etc. and show that (as collections) on your website.

This article shows how to create a module to extend existing content of an Orchard website. First a little background on which main problem Orchard solves for me. Then we start building a part.

Background

In the past, when I was working with content management systems (Which-Shall-Not-Be-Named), I used modules/features that came with the CMS and also modules/extensions created by others. And created modules myself of course. Mostly, these modules worked fine by them selves. Each module having it's own code, database table(s), scripts, stylesheets, etc. whatever was needed for the module.

But, there was no collaboration between modules of different companies/developers. As a simple example; suppose you use a module that enables you to have a list of products on your website. Each product having a title, description, picture, price, etc. The products are nicely shown and the user adds more products to it. Nice.Now later (the amount of products grew) the site owner wants the products to be categorized. What do you do? If you're the author of the products module, you could create a new version that supports categories. If you're not the author, you could ask the developer to make a new version. What else can you do. Wouldn't it be nice to leave the product module untouched and use a 'category module' to categorize the products? Then you don't have to alter existing code. What if the website owner wants to see something not so related to the products, for each product? Are you going to stuff that up in your product module?

Requirements change, always. With Orchard, you can 'weld' your additions to existing content. Of course, you can also grind parts off again. All this, without modifying existing (other ones) code!

Let's make a Module

There are a lot of modules and themes already created and are available in the gallery and can be used for your Orchard website. Sure, there can be modules that are not completely fulfilling your wishes. You could ask the module owner to make a new version or you can contribute code to that project. But anyone is free to make what he/she wants, so let's start building!

The module being made here contains a feature that enables you to weld an external photo album to your content type. In this case, a Picasa web photo album. To access a Picasa web album, we need a reference (id) to the user, the album and optional, an authorization key. You can get the id's from the album url (via RSS link or Google+ link). The authorization key is used for non-public albums, so called 'anyone with the link' protection.

Architecture

Now how do we build a module. It should be clear that this is an MVC pattern, of course. Because every module is implemented as an ASP.NET MVC area. But Orchard poors a little bit more juice to it, to enable a lot more functionality. Basically, the ContentPart is the model, the driver is partly a (simplified) controller, and the View receives the stuff to display through a shape, whether it's the ContentPart or something composed by the driver.

Setup development environment

Just to show (again and again) how easy it is to setup your development environment.

Start downloading code

The Orchard code is on CodePlex and you can download the latest release here.Go for the ´Orchard.Source.x.x.x.zip´ file. Currently 1.5.1 is the latest.

Load it up in Visual Studio

Unzip the file to a local drive and double click the .sln file, assuming you have Visual Studio installed.

Build and run, setup website

Hit Control-F5 and you'll see the 'Get Started' page. Give your site a name and make up some credentials. Remember them of course.

Setup the database. You can use SQL Server Compact but for speed use SQL Server.New up the database inside SQL Server Management Studio.

Then you will need a connection string. Since I have a history screwing this up, here is the connection string based on my local SQL Server database called 'OrchardModuleDev'.

As I know up front I will need the jQuery module, I put that as our single module dependency.

Add web.config (copy that from the source)

Now we have an empty module. Go to your site and look at the installed modules at /admin/modules. Type 'external' in the search box and hit search. The module shows up as 'installed'. Orchard recognized the module just by placing a file called module.txt.

Enable module

Now the module shows installed but it´s not yet enabled. Go to /admin/modules/features type 'external' in the filter box and enable it.

Add a migrations class

Add a migrations class to specify the database table and columns. Also define the content part and make it attachable.

using Orchard.Data.Migration;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents.Extensions;
namespace Orchard.ExternalAlbum
{
publicclass Migrations : DataMigrationImpl
{
publicint Create()
{
SchemaBuilder.CreateTable("PicasaAlbumPartRecord", table => table
// The following method will create an "Id" column for us and set it is the primary key for the table
.ContentPartRecord()
.Column<string>("UserID", column => column.WithLength(255))
.Column<string>("AlbumID", column => column.WithLength(255))
.Column<string>("AuthKey", column => column.WithLength(255))
);
// Create (or alter) a part called "PicasaAlbumPart" and configure it to be "attachable".
ContentDefinitionManager.AlterPartDefinition("PicasaAlbumPart", part => part
.Attachable());
// Return the version that this feature will be after this method completesreturn1;
}
}
}

Build the project and our part will now be visible /Admin/ContentTypes/ListParts

Add a driver class

Add a driver class for the content part. By overriding Editor and Display, the driver determines what to do when the album is edited or being displayed.

At this stage, you could create a custom content type, hook up the PicasaAlbumPart, create a content item of that and edit the fields. Since that would be a newly created object, there has not been any interaction to the storage layer for the album part. We need to let Orchard know that we want to persist the part. This is done through a handler.

As you can see, the file starts with adding stylesheets and javascript files. If you need to see more of that, download te code.

Now, you might think "but I want to visualize the album different way". That's possible in your theme. If adding css to your theme is not enough, you can override the view by adding an alternate.

Take it for a spin

First we're setting up a situation without the Picasa album. Then we add the part, fill it in and show you the end result.

Setup a demo scenario

Suppose you have a DVD collection and want to show/sell them on your website. In Orchard you can create a content type for that. To keep it simple, we create a DVD type and add a title, some text and a price. For the demo, we create the content type manually, but keep in mind that it can also be a module developed by someone else.

The CommonPart is added automatically to each content type.

Go to /admin and create a new type called DVD.

The type has been created, choose the parts you want to add. We choose a title and a body and hit save.

We're adding the price as a field.

Click on 'Add Field' and choose the field type.

After saving that, open up the 'price' field and set some properties and hit save again.

We're done specifying our content type. Let's add a DVD. On the left side, under 'New', click 'DVD' and fill it in. You can then save it and publish it later, or hit 'Publish Now' to do it directly.

On the left side, choose 'Content' and your DVD will show up. Choose 'View' to take a look.

This is how it looks with the default theme.

Add the album part

Now we have a situation with existing content. We're going to add the Picasa album now, so that every DVD on the site can have a Picasa album attached.

Conclusion

While reading this article, you might have noticed that Orchard can already do a lot by it self. That's true, this article shows only some basics, just to make my point. And of course it shows you how to extend it with your own parts. Take a look at the gallery too, to see the available modules.

The nice thing is, that we can 'weld' the picasa album to any content type now. Think about that for a while. What if you were building and maintaining a website like that. That's one big reason to go for Orchard!

What do you think? Express your opinion by a vote or comment. Any feedback is welcome.

Bonus

I went ahead and added something nice to the code. With a few lines of code, you can make any content part a widget. So you don´t have to attach the album part to something. Now you can place a Picasa album anywhere on your website as a widget.

What's next

I'm planning to add support for importing & exporting, so your album information is not lost when moving content to another website.

Support for 'Projections' is just an idea, don't know if it can be useful. With that you can make a view (a projection) of all content types that have the album part attached and make an album overview/index.

I will give this project to the community by putting it on codeplex. Anyone can make contributions to the module there.

There are other web albums available, for example a SkyDrive part could be added to the project. Vote for it

Comments and Discussions

After adding my migrations class and rebuild, nothing appends ! No new database class created and I cant see my part from /Admin/ContentTypes/ListParts !
I knew i am repeating the query again as posted by 'Nico' but as i dont found any suitable reply from the author, i was forced to repost so that Author can focus on that.
"
I dont understand why the function Create in Migration.cs is never called so the table cant be created in base !
Is someone got the same problem ? I tried to put the UpdateFrom... function but no success at all Frown | perhaps i dont put the right number of version...

Brand new to Orchard but a veteran web developer. I loved how you hooked all the parts together in the context of the MVC pattern right in the beginning. Example: "Every module is implemented as an ASP.NET MVC area", and the model/view/ comparisons to the ContentPart and driver. Even better, you attacked this from the Visual Studio angle rather than the Web Matrix approach that seems to be the norm in the others articles I've read (briefly). Thanks much!

After adding my migrations class and rebuild, nothing appends ! No new database class created and I cant see my part from /Admin/ContentTypes/ListParts !

I dont understand why the function Create in Migration.cs is never called so the table cant be created in base !
Is someone got the same problem ? I tried to put the UpdateFrom... function but no success at all perhaps i dont put the right number of version...

Timing of your article couldn't have been better, as I had to do some CMS work. Orchard seems to be the most 'developer friendly' CMS that I have tried so far.
Your excellent and detailed article helped me very much!