So what's new in Orchard 1.3?
Orchard 1.3 was released yesterday night with some really neat features that I will outline in this post. I will come back in depth on some of those with full-length posts. Let's start with the simple but super-useful ones…
1. Draft Preview
Once you've created and saved a content item, there will now be a "Preview" link next to its summary:
Previously, it was impossible to view unpublished contents. This was one of the most requested missing features, and there it is.
2. Delete Content Types and Parts
Speaking about features high on the wish list, you can now delete the custom content types and parts that you built.
3. Markdown
Not everyone likes editing contents in Wysywyg editors, for various reasons. There has always been the possibility in Orchard of switching the flavor of the Body part, but the only available alternative to the default "html" so far has been "text", which was only giving you a plain text box. Now there is a new option, "markdown".
Markdown is a neat text syntax that has the advantage of being simple, rich and human-readable.
I especially like the code sample convention of starting a line with four spaces. Very handy for writing documentation. Oh, about that, did I mention that we are planning on switching the Orchard documentation from the current wiki to Markdown?
4. Title Part
Until now, the title of Orchard content items has been kept in the Route part. That was an inconvenience when you wanted to give a title to a content type that did not have a vocation to have its own URL, for example widgets.
Title is still there in the Route part, but what we did is introduce a new interface, ITitleAspect, that the Route part implements.
public interface ITitleAspect : IContent { string Title { get; } }
In all the places where we were using the old title, we are now using the interface instead. If you need to add a title, but not a URL to your own content types, you can either make one of your parts implements ITitleAspect, or you can add the new Title part, that already implements the interface in a ready to use form.
5. Rules
Rules are a truly wonderful feature that enables you to add event-driven behavior to your site from the admin UI. Let's create for example a new "Comment Notification" rule and add a "content created" event that we'll configure to be triggered on the Comment content type:
Once this is done, we can add an action to be triggered when that event fires. We'll choose "Send e-mail", which will raise the following form, where we can specify who will receive the e-mail, and what will be the subject and body:
The subject and body of the e-mail can use tokens, which are another new feature that I'll get to in a minute.
Here is how the content creation event was wired in a handler:
OnCreated<ContentPart>( (context, part) => rulesManager.TriggerEvent("Content", "Created", () => new Dictionary<string, object> { { "Content", context.ContentItem } }));
When a piece of content is created, an event is triggered on the rules manager, giving it the content item being created as the context. The event itself is implemented in a class that implements IEventProvider. I'll write more on creating your own events in a future post.
Actions are classes that implement IActionProvider. Both event and action providers can expose their own UI forms for their configuration, which brings us to the next feature…
6. Forms
So far, to expose admin UI, a module writer had to create controllers or drivers, view models and views. Starting with this release, they can use a much easier forms API. This is what rule events and actions are using to expose their UI. The forms API makes it possible to describe a form in a nice, compact and extensible form that is using, you guessed it, dynamic shapes.
Shape.Form( Id: "ActionEmail", _Type: Shape.SelectList( Id: "Recipient", Name: "Recipient", Title: T("Send to"), Description: T("Select who should be the recipient of this e-mail.")) .Add(new SelectListItem { Value = "owner", Text = T("Owner").Text }) .Add(new SelectListItem { Value = "author", Text = T("Author").Text }) .Add(new SelectListItem { Value = "admin", Text = T("Site Admin").Text }), _Subject: Shape.Textbox( Id: "Subject", Name: "Subject", Title: T("Subject"), Description: T("The subject of the e-mail."), Classes: new[] { "large", "text", "tokenized" }), _Message: Shape.Textarea( Id: "Body", Name: "Body", Title: T("Body"), Description: T("The body of the e-mail."), Classes: new[] { "tokenized" } ) );
What you see here is the form that is in the e-mail action picture above. Of course, each of the shapes in there will be rendered by a template that can be overridden (as usual). The advantage of such a description is that it can be enriched dynamically. A comments form for example could have a captcha inserted dynamically by another module, just by injecting a new shape in the form. I encourage you to dive into existing implementations to understand how you can use this new API, until we get the chance to write some good documentation.
7. Tokens
Tokens are system-wide variables whose values can vary depending on the context. They can be used in a variety of places, one of which is rules, as you can see from the example above (the subject of the e-mail that is sent when new comments are added uses a token to describe the name of the commenter). I've blogged about tokens before, so I encourage you to read these posts to know more:
http://weblogs.asp.net/bleroy/archive/2011/07/22/future-orchard-part-1-introducing-tokens.aspx
http://weblogs.asp.net/bleroy/archive/2011/07/27/future-orchard-part-2-more-tokens.aspx
8. New Content Manager Methods
Building contents by composing small parts is an extremely flexible approach, but it makes it more difficult to build efficient database queries. There is always caching, but we also needed to optimize things a bit. We did that by adding some new methods to the content manager, such as GetMany, which is taking multiple content ids in one query. We also added the Aggregate attribute that can be used to specify records that should be eagerly loaded. For example, the Tags property of the TagsPartRecord and the TagRecord property of ContentTagRecord are marked with the attribute, because when the tags are included with a content item, you don't want the act of actually getting the tags associated with the content item to be lazily executed (that is a SELECT N+1 condition). If you want the tag part, there is a very high chance that you'll want to actually access the tags themselves: the part in itself has nothing else of interest. With the attribute, the tags will be fetched at the same time and from the same query as the item itself.
9. The rest
There is a lot more in this release, such as RSS for lists (it's just there, not much to say about it), some localization improvements, the task lease API that enables better synchronization across web farms, and many, many bug fixes and performance improvements (in particular, if you use multi-tenancy, you should feel the difference). If you want to see everything that was fixed, take a look at the list on CodePlex:
What's next?
The current plan for the near future is to quickly release a 1.4 version with the focus on the new Projector feature that will enable you to query your contents in any way you want directly from the admin UI. This, I can assure you, is going to be a killer feature.