So, you want to build something using Sitecore Habitat, part 2

Posted 02/11/2016 by Ed Kapuscinski

In part one of this post, I discussed the planning for creating a new Sitecore Habitat feature. If you're unfamiliar with where we left off, now would be a great time to catch up! In this post we're going to get into the details of what we did to create our feature for the 2016 Sitecore Hackathon.

Creating the Project

The place to start with Habitat development is in creating a new project inside the solution.

Habitat arranges things using solution folders, and this convention should be followed. In our case, we created a solution folder inside the “Feature” folder inside the Habitat solution. We called out folder simply “Redirects”.

Inside that folder, we created our Sitecore.Feature.Redirects project. I would like to say I did this from scratch, but I believe in expediency, so I simply copied it from an existing project. I then opened the project file up in Notepad++ and made the various namespaces and paths appropriate for our project. Once it was cleaned up, I added it to the solution in Visual Studio.

I then went and cleaned up the files that were actually in the project, keeping the following:

The “App_Config” folder and its “Include” and “Feature” subfolders. Inside the Feature folder, I renamed the existing configs to properly represent their new project.

The Habitat.Redirects.config contains settings for and from the future that get patched into the main web.config using Sitecore’s usual patching methodology.  This config is where I later patched our created pipeline processor into the httpRequestBegin pipeline.

The Habitat.Redirects.Serialization.config gets used by Unicorn to determine what items should be serialized. I’ll discuss that configuration file in more detail when we talk about data templates.

I also created a Views folder, and renamed its subfolder to “Redirects” from the original one I copied over. You could create this from scratch, if you don’t copy a project. The important thing is that any views that you create live inside a folder that belongs to your feature. I would do the same thing with the Models folder if I needed one, but our feature uses a viewrendering, which does not require a specific model.

I also cleaned up references and other files that came over from the duplicated project.

One last step is making sure that your project deploys when you do a build. Because of the great number of projects in a Habitat solution, I’ve found it helpful to use Visual Studio’s “Publish” functionality directly on the project itself when I need to just build and deploy the changes in a single project.

Creating and serializing data templates

The first step when building most Sitecore solutions is creating data templates.

In a Habitat solution you’ll end up creating two sets of data templates. The first is for going to be for individual features (like our redirects). The second is going to be for the specific project that you’re using the feature in. The feature level templates are where you create the fields required for the feature to work, while the project specific templates are where you set project specific settings like workflows, insert options and presentation details. The project level templates then inherit the feature data template to enable the desired functionality.

In our case, we created a “Redirects” template folder for our feature templates under /sitecore/templates/Feature/. This is an important Habitat convention.

We then created a _Redirect template that contains the fields for our feature: “Incoming URL” and “Redirect Target”. The underscore is another important Habitat convention: data templates created for features should always begin with an underscore.

After creating our data templates for the feature, we created ones for the project level under /sitecore/templates/Project/Habitat/Content Types, again, creating a folder and our own templates under that: a “Redirect” item and a “Redirect Folder” item to hold them. We then set the insert options on the folder to allow users to create items of the Redirect type under it.

We set our “Redirect” data template to inherit from the “_Redirect” data template that we created as part of the feature. This exposes the feature functionality in the project layer data template.

Now that we’ve created our data templates, we need to get them serialized for inclusion in the Git repository. How do we do this? With Unicorn, it’s simple. We define a pattern in the Habitat.Redirects.Serialization.config file that tells Unicorn to monitor items that match that pattern, and serialize them when they are changed. These settings are called “predicates”.

In order to serialize our data templates, I added the following setting inside the config file’s <predicate> node:

<include name="Feature.Redirects.Templates" database="master" path="/sitecore/templates/Feature/Redirects" />

This configuration tells Unicorn to watch the master database for item changes at or under /Sitecore/templates/Feature/Redirect, and to serialize those items.

Once you’ve made that config change, you’ll need to publish the project to see it take effect, but once that’s done, when you go to an item that matches the pattern, you will see a notice in Sitecore to indicate that it’s working:

Successful Unicorn Message

Since we did this after creating the templates, we’ll need to tell Sitecore that these items must be serialized. That’s done by enabling the Developer ribbon, and then using the “Serialize item” button to do a single item, or the “Serialize Tree” button if you want to do the item and all of its children.

When you look at Git, you’ll see that files will have been created for those items, and can now be included in the source code repository.

The data templates that got created as part of the project layer (“Redirect” and “Redirect Folder”) already fell under the Unicorn “Project.Habitat.Website” configuration that handles items that live in the project domain. This is because there is a unicorn configuration with a pattern that these items match.

With our templates created, serialized and committed, we’re now ready to start doing some development work.

Building the pipeline processor

Building the actual logic of our feature was relatively straight forward, and was done as it would be done in most Sitecore architectures.

The one thing to be aware of, though, is the convention of calling templates and field names out into their own class. In our case, this was in the Templates.cs file, and contains the names of the fields that we’re going to be using from out data templates.

public struct Fields
        public static string RedirectIncomingURL_FieldName = "Incoming URL";
        public static string RedirectTargetURL_FieldName = "Redirect Target";

You can see examples of this in existing features.

We coded up our pipeline processor, and made sure the references to it were correct in the Habitat.Redirects.config file. Make sure to specify the proper assembly name in the “type” parameter. In our case it was Sitecore.Feature.Redirects, which is the name of the DLL.

Building some presentation components

Because we wanted to optimize our content for experience editor, and we like treating our content editors nicely, we wanted to create some presentation components for our redirects so that they could be viewed and edited when in experience editor or preview mode.

We did this by creating a simple View rendering. First, following the Habitat convention, we created a rendering folder named “Redirects” under /sitecore/layout/Renderings/Feature/. Then we created our view rendering.

Because Habitat uses Bootstrap, we used some Bootstrap friendly markup that we sourced from a similar module. We put the cshtml file in a Views/Redirects/ folder in our solution.

It’s got very simple markup, a div with a class of “article body” with an h1 inside it and a paragraph inside it that describes what will happen: “In production [incoming url] will perform a 302 redirect to [redirect target].

However, because Habitat solutions should support all languages, we made the static text rendered by using the dictionary. This was actually incredibly easy, consisting of two simple steps.

First, creating the actual dictionary items under /sitecore/content/Habitat/Global/Dictionary. First, following the Habitat convention, we created a Dictionary folder called redirects. Then, under that, we created another dictionary folder for the actual “use”, called “Redirect Preview”. Then, finally, under that, we created individual dictionary entries for each bit of text “In production”, “preview for”, and “will perform”. For each entry, the “Key” is what’s used to refer to it, and the “Phrase” it what’s output on the page.

Second, use a Habitat helper, that we got access to via a using statement (@using Sitecore.Foundation.SitecoreExtensions.Repositories) in our view, do render the dictionary content:

@DictionaryRepository.Get("/Redirects/RedirectPreview/Will perform", " will perform a 302 redirect to ")

The first string is the path under the dictionary about where to find the dictionary item. The second is the default text to use if the dictionary item is not there.

The last part of adding this in was binding the rendering to a data template’s standard values. This was done in the project level data templates (in our case, /sitecore/templates/Project/Habitat/Content Types/Redirects/Redirect/__Standard Values). Because there are a bunch of presentation components that are needed to make the page display correctly, I copied the presentation settings from another type of page, and swapped out the body content rendering.

When I previewed an example, I was presented with a yellow screen of death error though, and resolving it was worth mentioning. There were a number of components being used on the page that depended on other features. In this case, the Metadata feature. In order to clear our error, I had to make the project level’s “Redirect” item inherit the “_PageMetadata” data template from the Metadata feature. Adding that in cleared up the error, and we were then able to preview our redirects.

That concluded our actual development of our basic feature. There wasn’t much actual development, but it provided a great way to learn about the Habitat architecture, and the things you need to do to use it.