Experience Sitecore ! | More than 200 articles about the best DXP by Martin Miles

Experience Sitecore !

More than 200 articles about the best DXP by Martin Miles

Best way to master Rocks - use it with Sitecore Rocks Cheat Sheet!


Recently, I came across a question on StackOverflow where a guy asked how he could edit Standard Values for a certain template using Sitecore Rocks (here is the original question with my answer). Rocks has so many features, that it is not as trivial to keep them all in one's mind. So how do I challenge that?

The document I have found (and even printed out) could not be over exaggerated and lists most of the features grouped by the way you access them just in one two-sided A4 paper.

You may download it by this link.

One more point to mention: in case you have some decent experience with Sitecore already but never used Rocks, please do give it a try. For the first moment you will not find it as convenient and the more you got used to classical Sitecore web interface - the harder you may find it to start using Rocks. But please, don't give up with that, just give Rock a bit more time and as soon as you start getting used to it - you'll start wondering how did you manage to work without it previously and why didn't you try it earlier!

StackOverflow: How to edit template content properties via sitecore rocks?

I have recently came across a question on StackOverflow I couldn't pass by. Here's original question:

Is it possible to edit content property via sitecore rocks plugin for VS ? for example Item Buckets section?


I knew that is not quite obvious so would want to share the answer:

Sure, that is possible. As I understood you right, you have an item with its fields loaded right hand side in Sitecore Rocks, you you do see custom fields but do not see fields coming from Standard Template, including Bucketable.

In that case just do right mouse click somewhere on the right hand side part, where your fields are and select Standard Fields from context menu. This will show those fields.



Hope someone might find that helpful!

original question on StackOverflow

StackOverflow: Adding route in Application_Start

One more question I could not pass by on StackOverflow (link to original question):

I am using sitecore 7.5 and I need to add new route in application_start in order to use it in ajax call but when I run the application it seems that sitecore deals with the route as content item any help please.

Below in my answer:

Here is the code that creates a route for you. In global.asax.cs you will call RegisterRoutes from App_Start event handler:

    protected void Application_Start()
    {
        RouteConfig.RegisterRoutes(RouteTable.Routes);
    }

And there you specify your route as:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.MapRoute(
             name: "test",
             url: "mvc/Forms/{action}/{id}",
             defaults: new { controller = "Forms", action = "Test", id = UrlParameter.Optional }
           );
    }

You will have /mvc/ prefix in this case that will handle your route to specifies controller, so you will call it as:

/mvc/Forms/Test/{you_may_pass_some_optional_GUID_here}

This will route to FormsController class action method Test(string id) but you may omit id parameter

A bit of attention: Please note that setting route in Application_Start is not the best way of doing that; much better is to implement mapping routes at Initialize pipeline, as it fits Sitecore architecture:

public class Initialize
{
    public void Process(PipelineArgs args)
    {
        MapRoutes();
    }

    private void MapRoutes()
    {
        RouteTable.Routes.MapRoute(
                "Forms.Test", 
                "forms/test", 
                new
                {
                    controller = "FormsController",
                    action = "Test"
                },
                new[] { "Forms.Controller.Namespace" });
     }
}

The rest of implementation: Also I have previously wrote an article in my blog about how to implement ajax call to a route, that will guide you through the rest of the implementation process:

https://blog.martinmiles.net/post/editing-content-on-a-cd-server

Update: Please also make sure your config has a handler to handle your prefix, see below:

<customHandlers>
    <handler trigger="~/mvc/" handler="sitecore_mvc.ashx" />
Hope someone finds this helpful!


PowerShell Module issue - got a NullReferenceException when trying to open PowerShell ISE

Today I downloaded the latest (v.3.1 for Sitecore 8_001) PowerShell module and decided to play around one concept I hoped to push forward. But unfortunately, as soon as I opened ISE window, I got a NullReferenceException.


I thought that could possibly be related to my Sitecore instance. Thus I have installed a new copy of Sitecore 8.0.4 using Sitecore Instance Manager. Then tried to install package at that instance and magically worked there. So, two instances with the same Sitecore version, same PowerShell module, but different results... hm-m...

Then I assumed that ISE is trying to run some default script and probably that fact for some reason causes the exception. So, what are difference between two instances? I thought that initial ISE script might be rely on home item, and the one may be hardcoded, while my first sitecore instance has several website roots, but none of them is called Home. Worth of checking that idea. Just as the quickest, I have duplicated one of my webroots within /sitecore/content node and set a copy with the name Home. And voila - it magically worked for me!



Understanding Buckets: adding new items to buckets correctly

I just came across a question on StackOverflow about Buckets, so I decided to highlight in my blog, as it it is based on very common misunderstanding of Buckets and their functioning principles. Here's the link to original SO question.

If briefly, a guy asked why having a bucket folder with several items in it, when he tries to add a new item, the one appears in a folder as normal item, not hidden. So every time he adds new item he has to perform Sync on that. So let's go and reproduce the situation by steps.

Prerequisites: I have a folder with some items that I am turning into a bucket (at that stage we assume those Articles 1 - 5 have Bucketable checkbox being set on individual level; if you don't know how to update a checkbox for multiple already existing items - here is the great blog post about mass update field values I wrote about):


At this stage my folder is a bucket, items are not displayed, but are searchable, everything functions as normal.



The issue: Then I try to add a new item called Article 6 into my bucket folder. That item is being created as normal, is diaplyed within a folder, and there is also a notification panel warning about storing unbucketable item within a bucket folder. I believe - that is an issue of person asking a question on StackOverflow (see image below). That new item has normal path as an immediate child of bucket folder (not date-specific as defaults for bucket items path) and looking into Item Buckets sections reveals that Bucketable checkbox is not set. To add this Article 6 item into bucket, one needs to check its Bucketable field and then perform Sync from the Ribbon above.


But why that behavior happens?


Solution: Well, this checkbox isn't set but should be on items creation. How do we get that behavior? Just checking that checkbox in corresponding template's Standard Values. Screenshot below shows Article template that is a data template for all Article items. Standard Values for template are always called as __Standard Values so fields set in that item (with static values or tokens) will be auto pre-set each time and item of that template is being created:



So, as soon we have updated Standard Values with Bucketable checked, we try to create another article (of the same template, for sure), we logically call it Article 7. Once created, Article 7 is already bucketable by its Standard Values and is immediately stored in the bucket. There's no need to perform Sync! It also preloads content area right hand side (or you may search for it from Search tab) and if you pay attention to an Item path field - it is being located exactly as specified in (default in our example) bucketing configuration:



Hope this post helps you to understand a concept that is hidden behind the buckets!

Mass update of field value for all existing items of certain template - two ways of achieving result

Given: I have multiple already existing items of a specific template across my content tree. Template has some field that I want to update with a new value for all existing items, within some node I can specify.

Use cases for that scenario are really universal - you may use that for various purposes. What comes into my head, at a first glance, is the situation when you would like to assign some template to a workflow but already have multiple existing items of that template (just to remind - setting a field value at Standard Values will apply for all new, but not existing items of that particular template). In that case you need assign a workflow to each existing item individually.

Another good example is when you have a folder with multiple items, growing in amount with time flow. Then you may decide to make a folder bucketable, but those existing items require to set a Bucketable checkbox for each existing item individually. I have described that case in one of my previous blog posts - "Understanding Buckets: adding new items to buckets correctly". So let's pick up second case and try to solve it.

Solution: So, what are possible ways of achieving that goal? Not so much of them, there are just two options.

1. Straightforward option - use C# code. With C# task may be achieved by a recursive method, that accepts an item, verifies if the one is of desired template and if yes - updates the field and does the same for all item's children if any. Here is an example of such method and example of call :

private void UpdateAllFieldsRecursively(Item parentItem, string templateName, string fieldName, string newValue)
{
    if (parentItem != null)
    {
        using (new SecurityDisabler())
        {
            foreach (Item childItem in parentItem.Children)
            {
                if (childItem.Fields[fieldName] != null && childItem.TemplateName == templateName)
                {
                    using (new EditContext(childItem))
                    {
                        childItem[fieldName] = newValue;
                    }
                }

                if (childItem.HasChildren)
                {
                    UpdateAllFieldsRecursively(childItem, templateName, fieldName, newValue);
                }
            }
        }
    }
}

// and below there is the call to recursive mehod
const string parentNode = "/sitecore/content";
var database = Sitecore.Context.Database;
var parentItem = database.GetItem(parentNode);

UpdateAllFieldsRecursively(parentItem, "Article", "Bucketable", "1");

The code above works out perfectly and does exactly what we want from it, however there are certain disadvantages: first of all you need to run the code in some context - call if from some existing class, for example. Second - as that is C# code - it must be re-compiled and re-deployed. And if you may need to amend small change into the code - will have to re-compile and re-deploy again. But, luckily, there is a much better and faster alternative:

2. PowerShell Module. That module integrates into the platform and offers unprecedentedly ultimate possibilities and power over Sitecore instance and databases. After installation there is PowerShell console and more advanced PowerShell ISE, where you may create and test scripts. They are executed immediately without any of prerequisites like rebuilt DLL with a code at your bin folder. So, here is a script that does exactly the same as previous C# code:

cd 'master:/sitecore/content'
Get-ChildItem -Recurse . | Where-Object { $_.TemplateName -match "Article" -and $_.Fields["Bucketable"] -ne $null } | ForEach-Object {
   
    $_.Editing.BeginEdit()
    $_.Fields["Bucketable"].Value = "1";
    $_.Editing.EndEdit()
    ""
}

PowerShell script above does exactly the same - iterates Sitecore tree for "Article" templates, starting recursively from /sitecore/content node and if anything found - updates the filed value.

Hope this code helps!

How to host several sites within the same Sitecore instance without specifying a hostname, just on different ports

Challenge: I have got a test server running, where I usually deploy early builds and proofs of concept for business users to acknowledge. Since recent solution has grown to several websites, so I want users to be able to access all of them. The problem occurs from that users do not have administrative permissions to their PCs and are not able to edit hosts file in order to set multiple host names for my server IP (most of them also are not aware how to do that). The good news is that despite being geographically distributed and being in different virtual networks, they do have access to the server IP address.

Unfortunately, I was not able to specify multiple host names (or IP addresses) to the server as a part of infrastructure configuration, so it became obvious that users should access those websites by IP address, moreover the same IP address to all sites. So what came first into my mind was to distinguish websites by ports within same IIS. Sounds good, but how to do that? I definitely knew that the it resolves website by the host name, not the port, as set within <sites> node of config file. I tried googling a solution but did not find anything...


Investigation: Thus, armed with Reflector and dotPeek tools I started investigating and debugging original code from Sitecore.Kernel.dll. Since a while I came across SiteResolver class, that serves a processor for httpRequestBegin pipeline:


    ...

    ...

So far, so good. The method doing resolving job is called ResolveSiteContext, so I already morally prepared to inherit from SiteResolver class and override that method, implementing site resolution by port.

But what was my excitement, when I notices that it calls SiteContextFactory.GetSiteContext passing hostname, file path and port! So it already supposes port coming from config file, doesn't it? Let's go and inspect this method:

    public static SiteContext GetSiteContext(string hostName, string fullPath, int portNumber)
    {
      fullPath = fullPath.ToLowerInvariant();
      foreach (SiteInfo info in SiteContextFactory.Sites)
      {
        if (info.Matches(hostName, fullPath, portNumber))
          return new SiteContext(info);
      }
      return (SiteContext) null;
    }

and Matches() method follows as:

    public bool Matches(string host, string folder, int portNumber)
    {
      return this.MatchesHost(host) && this.MatchesPort(portNumber) && this.MatchesFolder(folder);
    }

After looking at MatchesPort(portNumber) I chased portNumber and where it comes from. It occurred that parser expects attribute with name "port" and takes the value out of it, or sets default value(0).

Right, so in fact that proves that port number can be solely used for resolving site within same Sitecore instance. But why there is lack of references or documentation about that? In any case this blog post fills the gap, I hope.


Testing: Now it's time to test my assumption. I have created two bindings for my sitecore instance, for 80 and 8080 ports. Notice that there's no hostnames assigned:

Challenge: I have got a test server running, where I usually deploy early builds and proofs of concept for business users to acknowledge. Since recent solution has grown to several websites, so I want users to be able to access all of them. The problem occurs from that users do not have administrative permissions to their PCs and are not able to edit hosts file in order to set multiple host names for my server IP (most of them also are not aware how to do that). The good news is that despite being geographically distributed and being in different virtual networks, they do have access to the server IP address.

Unfortunately, I was not able to specify multiple host names (or IP addresses) to the server as a part of infrastructure configuration, so it became obvious that users should access those websites by IP address, moreover the same IP address to all sites. So what came first into my mind was to distinguish websites by ports within same IIS. Sounds good, but how to do that? I definitely knew that the it resolves website by the host name, not the port, as set within <sites> node of config file. I tried googling a solution but did not find anything...


Investigation: Thus, armed with Reflector and dotPeek tools I started investigating and debugging original code from Sitecore.Kernel.dll. Since a while I came across SiteResolver class, that serves a processor for httpRequestBegin pipeline:


    ...

    ...

So far, so good. The method doing resolving job is called ResolveSiteContext, so I already morally prepared to inherit from SiteResolver class and override that method, implementing site resolution by port.

But what was my excitement, when I notices that it calls SiteContextFactory.GetSiteContext passing hostname, file path and port! So it already supposes port coming from config file, doesn't it? Let's go and inspect this method:

    public static SiteContext GetSiteContext(string hostName, string fullPath, int portNumber)
    {
      fullPath = fullPath.ToLowerInvariant();
      foreach (SiteInfo info in SiteContextFactory.Sites)
      {
        if (info.Matches(hostName, fullPath, portNumber))
          return new SiteContext(info);
      }
      return (SiteContext) null;
    }

and Matches() method follows as:

    public bool Matches(string host, string folder, int portNumber)
    {
      return this.MatchesHost(host) && this.MatchesPort(portNumber) && this.MatchesFolder(folder);
    }

After looking at MatchesPort(portNumber) I chased portNumber and where it comes from. It occurred that parser expects attribute with name "port" and takes the value out of it, or sets default value(0).

Right, so in fact that proves that port number can be solely used for resolving site within same Sitecore instance. But why there is lack of references or documentation about that? In any case this blog post fills the gap, I hope.


Testing: Now it's time to test my assumption. I have created two bindings for my sitecore instance, for 80 and 8080 ports. Notice that there's no hostnames assigned:



Voila! Hope this hapens to be helpful and may save some efforts for you in future!

Within Sitecore Desktop I created two website landing pages for each of sites.
Here is te content for Primary website sitting on default 80 port:

and below is the same for Secondary website on 8080:


Finally, assign them in the config file. Notice, there is no hostname defined again. Only start item and port number:


Ok, now publish both sites to web database and try accessing them. The first one (primary) opens on default port 80 by simply entering IP address. Expected behavior! It shows content exactly as configured earlier:


Just aplyint port number (8080) to the same IP address we got routed to secondary website. As expected, again:


Voila! Hope this hapens to be helpful and may save some efforts for you in future!

Web Forms for Marketers 8.0 - missing Save to Database action and making it work with SQL database again

As we know, Sitecore version 8.0 incorporated popular the module called Web Forms for Marketers (WFFM), and it became an integral part of Sitecore. WFFM is still shipped as a package, however now through Sitecore SDN portal, rather than via Marketplace as before.

So, let's assume you have a brand clean install of Sitecore (I have 8.0 Update 4 for this example). In order to download WFFM for 8.0 Update 4 please follow to https://dev.sitecore.net/Downloads/Sitecore_Experience_Platform/8_0/Sitecore_Experience_Platform_80_Update4.aspx and find download link below in the module section.

Remark 1: zip archive you download is not a package - it is normal archive containing 2 child packages - first is package for CM instance and additionally contains all dialogs etc. while another is just CD installation package. For our demonstration, unpack Web Forms for Marketers 8.0 rev. 150625.zip into /Data/Packages directory and use Development Tools - Installation Wizard, as you normally install packages.

Remark 2: ensure you have Mongo up and running, otherwise it will come to "package never installs" issue (more details about that bug here). it is required just for installation, after you have it installed you it is safe to turn off Mongo - WFFM will save data to database without any problems.

Remark 3: it may take up to 5 minutes to install the package, so please do not panic, as soon as you got Mongo running - you'll reach the point when it prompts you for setting Placeholder settings.


After WFFM installation is complete, you may configure a form. By default WFFM contains several pre-created forms as an example for people to play with it and get acknowledges with the module. For those who are new to WFFM here is a screenshot below displaying how to locate Form Designer:


Selecting Form Designer above loads a screen with the list of existing forms. Let's pick Get Our Newsletter form and click OK. Form Designer will load form configuration screen with fields and Subscribe button at the bottom. A click to that button opens Submit panel left hand side with several settings for pre-save (validation), save and post-save (success page / success message).


Remark 4: Those who used to work with previous versions of WFFM will be frustrated by missing Save to Database action from save actions menu. These are save actions that come out of box:


There is nothing to worry about, Save to Database action is still there but is not displayed only because as it always happens. However:

Remark 5: SQL database itself is not coming with the package, so you need to pick database backup from one of previous versions - its schema remains the same. To make you life easier, I have attached forms empty database backup so you may download it by this link. In WFFM 8.0 there is the setting that references connection string name (in you ConnectionStrings.config file) that is used by WFFM.

<!-- CONNECTION STRING - Sets the name of the connection string -->
<setting name="WFM.ConnectionString" value="wfm" />
<add name="wfm" connectionString="Data Source=.;Initial Catalog=test2_Forms;Integrated Security=False;User ID=sa;Password=your_password" />

To make Get Our Newsletter form work, we need to assign it to some page. Default landing page called Home will work well for our purpose. This is how you set a form to a placeholder:


Image above displays webform, because we use default layout that comes with webforms aspx page. For MVC there is rendering called Form MVC. With next step below (as clicking Edit button) you need to specify which exact form should be served by this sublayout (or rendering for MVC):



Now you may verify /Home page in Publish - Preview screen or publish web site and then load the page normally (http://your.site.name/) so you end up with something like on a screenshot below:


After you fill in valid email and click Subscribe button, you'll get "Thank you for filling in the form" message, that's in case database was references correctly. if not - there will be message abut unexpected error and corresponding exception details will appear in log file.

Let's get physically into database to verify the data has been stored correctly. In successful case you'll see one record in Form table and few records in Field table, one record per each form field.


That's all!

Following blog post will demonstrate how to make WFFM result screen display forms records from SQL database.


Sitecore Boilerplate - the repository of best practices all at the same place

I decided to create an ultimate "boilerplate" solution for Sitecore, implementing all the best Sitecore practices in one place, well documented and cross-linked with the support on this blog.

As a multi-language website with Experience Editor (ex. Page Editor) support utilizing with Glass Mapper, Lucene indexes and test-driven codebase and much more working well all together - it will be a perfect place for newbies to familiarize themselves with Sitecore platform. It aims also to simplify work of more senior Sitecore developers in terms of quickly searching for desired features and grabbing them into their working solutions.

The project originated out of my R&D activities as I decided it would be beneficial to share my workouts with Sitecore community. Any suggestions, comments and criticism are highly welcome!

List of the features I desire to supply into Sitecore boilerplate:

  • Support for Page Editor
  • Usage of Glass Mapper for ORM purposes
  • Unit testable code
  • Synchronization of user-editable content from CD environment to CM and further re-publish to the rest of CDs
  • Support for multi-language environment
  • Custom Lucene indexes
  • Custom personalisation of components and data
  • Workflows based on user permissions
  • Make all mentioned above working together as a solid and stable website
  • Implement new Sitecore 8 marketing features on top of that

.. for the moment I have planned and implemented several of mentioned features as a starting point, so it is coming soon on GitHub and further blog posts here.

Sitecore MVC areas as pluggable separate DLL - making areas further more independent!

I want to share my experience of implementing MVC Areas as an individually pluggable (into the host website) DLL, that contains the code of specific area: controllers, models / view models, some area-specific DLL. The proof of concept was created by my great colleague Chandra Prakash, I decided to pick it after him and implemented in our product, so now it is 8 month as it works in production without any issues at all.


We are working in a big enterprise Sitecore-hosted project with more than hundred of developers, so each deployment process may bring a pain. Pluggable areas implementation has proven its concept and helped us to keep updating only those parts of entire multisite Sitecore solution that have been updated, without any risk of affecting the rest!


Features:

  • no need to code anything in a host website, thus:
  • no need to rebuild whole big outer solution - just rebuild (and replace) DLL
  • no more need to struggle with complex dependencies
  • simplified update: drop DLL into host website bin folder, and copy some static files referenced by this DLL - js, css, cshtml, img.

In day-to-day usage you will have the only one minor overhead of that implementation: 2 extra fields in controller rendering. In fact, instead of standard Controller Rendering we are using Area Controller Rendering that is derived from Controller Rendering just with addition of 2 extra fields required to resolve the area on a fly:



Sound attractive, isn't it? Then look how it is implemented - I address to the original article with more detailed explanations.