Monthly Archives: May 2013

Building News Module with Umbraco v6

This is a small tutorial describing the process of building news module and recycling content in Umbraco v6. I go through the entire process of building a simple Umbraco website that includes a calendar with events, news page with news articles, home page that displays a selection of news and a calendar module that can be rendered on any page within the website.


Update: thanks to a hint from Jeroen Breuer I improved this tutorial a bit. You can do this tutorial as it is or have a look at the end of this post for an update and explanation.

Inaboxdesign.dk: Home screenshot

I am using Umbraco 6.0.3 with Razor and Twitter Bootstrap so that I don’t have to think much about the presentation. I hope you will find it useful and well described but as always with this blog, any and all feedback is very much welcome.

Set up

Start by creating an empty MVC project in Visual Studio. Go to Tools -> library package manager -> Manage NuGet Packages and install Umbraco CMS. You can also use WebMatrix instead. Once Umbraco is installed, go to config folder -> umbracoSettings.config in your solution explorer and find this snippet:

<!-- To switch the default rendering engine to MVC, change this value from WebForms to Mvc -->
<!-- Do not set useAspNetMasterPages to false, it is not relevant to MVC usage -->
WebForms

Replace it “WebForms” with “Mvc”. This will make sure that we are using MVC architecture and Razor engine in our templates and macros.

Run the solution and complete the installation with the database options of your choice. In the next step choose an empty installation

DocTypes

Any good Umbraco website starts with planning – so plan your docTypes carefully.In our case we will have the following docTypes and properties

  • FrontPage (properties: title – textstring)
  • NewsContainer (properties: title – textstring)
  • Article (properties: title – textstring, img – mediaUploader, snippet – RTE, showSnippet – true/false, content -RTE)
  • Calendar (properties: title – textstring)
  • Event (properties: title – textstring, date – Date Picker, img – mediaUploader, snippet – RTE, showSnippet – - true/false, content -RTE)
  • FrontPage doctype will be used to create the Home page at the top of the content tree. The editors will only create the title for this page. The rest of content will be pulled in from the Article and Event docType pages.
  • NewsContainer is not necessary but will make the content tree look much cleaner. It will also help to guide the editors when they create new items on the content tree. Same function is fulfilled by the Calendar.

The properties and docTypes should be fairly self-explanatory so let me just explain that the snippet property will serve to give the user control over what should be displayed on the Home page. If the showSnippet checkbox is checked the snippet will also show as the first paragraph of the Event or Article page.

You might have also noticed that Event and Article are almost identical when it comes to properties. The only difference is that Event docType includes date property. This means that we can have Event docType inherit from Article docType instead of creating all the properties twice.

InaBoxDesign.dk: docType tree

Next step is to actually create the docTypes. Start by creating all the docTypes and their properties. Make sure you create tabs to organize properties into groups. All docTypes should have matching templates.

Once all the docTypes are created and have their properties, you can build the structure of your website. In our small website the structure is fairly simple:

  • FrontPage is allowed at the root and has only two types of allowed children nodes: NewsContainer and Calendar
  • NewsContainer allows Article children
  • Calendar allows Event children

Now you can go ahead and create your basic content. Hint: install FamFamFam Icon package to make it easier for your future editors to discern between docTypes.

Content Tree

Templates

Next step is to present the content. I will use Twitter Bootstrap to make my site shiny but it is up to you if you want to do the same or build your own CSS.

To present the content we need to build templates. I start with Master, to make my life easier. All the other templates will be partials under Master and they will inherit the basic structure of the website. This way I don’t need to repeat the same markup.

Master

All the Master really does is to establish html structure of our website, load scripts and stylesheets and render the content of templates that inherit from it (@RenderBody()). It also renders the navigation macro (@Umbraco.RenderMacro(“Navigation”)) so that navigation will appear on all pages without the need to repeat the code. Isn’t this just neat?

@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = null;
}
<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>@Umbraco.Field("pageName")</title>
    	<meta name="viewport" content="width=device-width, initial-scale=1.0">
    	<meta name="description" content="">

	<link href="/css/bootstrap.css" rel="stylesheet"/>
    	<link href="/css/bootstrap-responsive.css" rel="stylesheet"/>
	<link href="/css/style.css" rel="stylesheet"/>

	<script src="/scripts/jquery.js"></script>
	<script src="/scripts/bootstrap.js"></script>
</head>
<body>
    @Umbraco.RenderMacro("Navigation")
    <div class="container">
        <div class="hero-unit">
            <h1>Hello, world!</h1>
            <p>This is a community website with news and calendar modules</p>
        </div>
	    @RenderBody()
    	 </div>
    <footer>
        <p>&copy; InaBox 2013</p>
    </footer>
</body>
</html>

Article

This template simply presents the content of any node with docType Article. It renders 3 macros: Image, Snippet and SideCalendar. They will be described further down in this post.

@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = "Master.cshtml";
}
    <div class="row">
    <div class="span8">
        <h2>@Umbraco.Field("title")</h2>
        @Umbraco.RenderMacro("Image")
	 @Umbraco.RenderMacro("Snippet")
        @Umbraco.Field("content")
    </div>
    <div class="span4">
        <h2>Upcoming Events</h2>
        @Umbraco.RenderMacro("SideCalendar")
    </div>
    </div>

InaBoxDesign.dk:Article Page

Event

This template presents the content of any node with docType Event. It renders 4 macros: Date, Image, Snippet and SideCalendar. And again, keep reading to find more about them.

@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = "Master.cshtml";
}

  <div class="row">
    <div class="span8">
        <h2>@Umbraco.Field("title")</h2>
	 <h4>@Umbraco.RenderMacro("Date")</h4>
        @Umbraco.RenderMacro("Image")
	 @Umbraco.RenderMacro("Snippet")
        @Umbraco.Field("content")
    </div>
	<div class="span4">
		<h2>Upcoming Events</h2>
		@Umbraco.RenderMacro("SideCalendar")
    	</div>
    </div>

InaBoxDesign.dk: Event page, Umbraco News Module

FrontPage

This template presents the content of the FrontPage node, our Home page. It renders only 2 macros: NewsModule and SideCalendar. These two macros provide most of the functionality in our website and they will be explained in detail.

	@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = "Master.cshtml";
}
    <div class="row">
    <div class="span8">
        <h2>@Umbraco.Field("title")</h2>
        @Umbraco.RenderMacro("NewsModule")
    </div>
    <div class="span4">
        <h2>Upcoming Events</h2>
        @Umbraco.RenderMacro("SideCalendar")
    </div>
    </div>

NewsContainer

This template is used by…surprise, surprise…NewsContainer docType. All it does, is to render NewsPage and SideCalendar macros. The first one pulls the content from child nodes of the the node (events under calendar page), the latter displays the next 3 upcoming events.

	@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = "Master.cshtml";
}

   <div class="row">
		<div class="span8">
			<h2>@Umbraco.Field("title")</h2>
			@Umbraco.RenderMacro("NewsPage")
			<p><a class="btn" href="#">View details &raquo;</a></p>
		</div>
		<div class="span4">
        	<h2>Upcoming Events</h2>
        	@Umbraco.RenderMacro("SideCalendar")
    	</div>
    </div>

InaBoxDesign: Umbraco screenshot: NewsContainer

Calendar

And lastly, the very succinct Calendar template renders the tilte of the page and CalendarPage macro. Most of the content on this page will be pulled in from its children – the events.

@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
@{
    Layout = "Master.cshtml";
}
<h2>@Umbraco.Field("title")</h2>
	@Umbraco.RenderMacro("CalendarPage")

InaBoxDesign.dk:Umbraco Screenshot Calendar

Macros

Now comes the lifeblood of the website and the best part: functionality. It will be handled with macro scripts written with Razor.

I’ll start with the three simplest scripts: Date, Image and Snippet. Then I’ll move on to navigation and lastly, I’ll pull the content from Article and Event docTypes to display it wherever I want.

Date

The only reason to have this macro instead of a regular umbraco field is so that we will be able to convert Date property from Event docType into a string and display it in a format that makes us happy campers. In my case the format will be 07/05/2013. If you want to choose another way of displaying your date, have a look at this string format codes.

@inherits umbraco.MacroEngines.DynamicNodeContext

@Model.Date.ToString("dd/MM/yyyy")

Image

Again, this macro is not really necessary but it opens up future possibilities for manipulating the content. I find it most intuitive to only use templates for displaying the most basic umbraco fields and render everything else through macros.

@inherits umbraco.MacroEngines.DynamicNodeContext

<img alt="" src="@Model.Image" />

Snippet

This is another simple macro. You might remember that we gave our editor the option to choose whether they want to display the snippet on the article and event pages or if it should be hidden and only used on the front page as a teaser. In the Snippet macro we simply check if the ShowSnippet checkbox was checked. If yes, then we should display the snippet, if no…well, nothing to see here, move on.

@inherits umbraco.MacroEngines.DynamicNodeContext
@{
	if(@Model.ShowSnippet)
	{
		<div class="snippet">@Model.Snippet</div>
	}
}

Navigation

As the name suggests, this script renders the navigation by iterating through child nodes of the Home page. First we define the root node (var root = Model.AncestorsOrSelf(1)) and then we iterate through its children nodes (@foreach…) and wrap it all up in html markup from Bootstrap – no magic included.

@inherits umbraco.MacroEngines.DynamicNodeContext
@{ 
    var root = Model.AncestorOrSelf(1);
}

<div class="navbar navbar-inverse navbar-fixed-top">
    <div class="navbar-inner">
        <div class="container">
            <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="brand" href="#">Our Community Website</a>
            <div class="nav-collapse collapse">
                <ul class="nav">
                    <li><a href="@root.Url">@root.Name</a></li>
                    @foreach (var page in root.Children.Where("Visible"))
                        { 
                            <li class="@page.IsAncestorOrSelf(Model, "active", "")">
                                <a href="@page.Url">@page.Name</a>
                            </li>
                        }
                </ul>
            </div>
        </div>
    </div>
</div>

CalendarPage

Similarly to NewsPage, the CalendarPage is a macro that pulls in the content from child pages to display it on Calendar (and Community News). To do this, it starts by checking if the current node has any children and then iterates through them with foreach statement, displaying its properties.

@inherits umbraco.MacroEngines.DynamicNodeContext

@if (Model.Children.Any())
{            
	foreach (var childPage in Model.Children)
	{
		<div class="row">
		    <div class="span12">
				<h4><a href="@childPage.Url">@childPage.Title</a></h4>
					@childPage.Snippet
			</div>	
		</div>
	}
}

NewsPage

This macro does exactly the same as CalendarPage but for NewsContainer docType.

@inherits umbraco.MacroEngines.DynamicNodeContext

@if (Model.Children.Any())
{            
	foreach (var childPage in Model.Children)
	{
		<div class="row">
		    <div class="span8">
				<h4><a href="@childPage.Url">@childPage.Title</a></h4>
				@childPage.Snippet
			</div>	
		</div>
	}
}

NewsModule

News Module is the juicy bit in our website (and the whole reason for this entire article). It is rendered on the front page and it pulls in the content from the 3 topmost Article docType nodes under the Community News node. It simply displays the community news on the Home page.

In the case of this macro we know that our Model (so our current page) refers to Home page. This is because of the structure we’ve established with docTypes. NewsContainer simply cannot be created anywhere else in the node tree.

Therefore we can start by checking if our Model has descendants of type NewsContainer and if NewsContainer has any children. If both of the conditions are satisfied we move on to…yup, you guessed it, iterating through NewsContainer’s children (a.k.a Articles) and display their title and snippet. Notice that we don’t want all the articles so we .Take(3) from the collection.

@inherits umbraco.MacroEngines.DynamicNodeContext
@if (Model.Descendants("NewsContainer").Any())
{   
	if(Model.Descendants("NewsContainer").First().Children.Any())
	{

		foreach (var item in Model.Descendants("NewsContainer").First().Children.Take(3))
		{
			<div class="row">
				<div class="span8">
					<h4>@item.Title</h4>
					@item.Snippet
					<p><a class="btn" href="@item.Url">View details &raquo;</a></p>
				</div>	
			</div>
		}
	}
}	

SideCalendar

This is a bit more complicated version of the previous macro that built news module. It also pulls in the content of 3 nodes of a certain type, events from under the Calendar page. However there are 2 major differences here. The first one is that the 3 nodes are ordered according to the date property.

The second difference stems from the fact that the macro will be rendered on multiple nodes of different types. We want to have the side calendar on the FrontPage, NewsContainer, Article and Event docTypes. This means that we don’t know what will be the exact relation of the node that renders the macro and the nodes that should provide the content (events). To deal with this problem is dealt with by defining the root node and finding Event nodes by crawling down from it.

The first thing we need to do is define the root node as the ultimate ancestor of Model. No matter where in the structure you are, the root is always either your model (if you are on the Home page) or an ancestor of your model (since all pages are created under the Home page).

The second step is to check if root has any children of the type Calendar. If it does, we create a variable that stores the first calendar node (we only have one so this simply means that its not a collection but rather a single node). Then we move on to checking if this calendar has any children (Have we created any events yet?). If it does, we organize them by date (OrderBy(“Date”) ), take the 3 topmost and store them in events variable.

And I think at this point we can all guess what happens next. Yup, it seems like Umbraco is all about iterating.

@inherits umbraco.MacroEngines.DynamicNodeContext

@{
    var root = Model.AncestorOrSelf();
	
	if(root.Descendants("Calendar").Any())
	{
		var calendar = root.Descendants("Calendar").First();
		
		if(calendar.Children.Any())
		{
			var events = calendar.Children.OrderBy("Date").Take(3);
		
			foreach(var item in events)
			{
				 <div class="row">
						<div class="span4">
							<h4>@item.Title</h4>
							<span>@item.Date.ToString("dd/MM/yyyy")</span>
							@item.Snippet
							<p><a class="btn" href="@item.Url">View details &raquo;</a></p>
						</div>	
					</div>
			   
			}
		}
	}
   
}

Update

So as mentioned at the beginning of the post, Jeroen asked the very good question of why using macros for date and image when it can be done in templates instead and he pointed me in the right direction for solutions.

It turns out the the syntax one uses in the macros is not exactly the same as in templates. It seems it has to do with different versions of Razor but let us not get into the topic right now

The point is that you can delete Date and Image macros and enter the following lines of code instead of the respective references to macros in your templates

  • Replace @Umbraco.RenderMacro(“Date”) with
@Umbraco.Field("date", formatAsDate:true)
  • Replace @Umbraco.RenderMacro(“Image”) with
<img src="@Model.Content.GetPropertyValue("Image")" alt=""/>

Summary

This write up should have taken you through all the necessary steps of creating a website that recycles its content with news module and calendar module. Hopefully, the explanations were clear and you will now be able to take this general tool and use it on your various projects.

I am looking forward to hearing about your experiences!