One of my clients recently had a somewhat unusual requirement when working with Sitecore. Due to some business rules, they are forced to input their Production content into Sitecore at their Development Environment and push it from Development all the way up to Production. Their Sitecore website has links to other of their in-house systems that are external to Sitecore. When you add those two up, you get the requirement that you are going to need “Environment Specific Links”. In other words, if I’m in the QA Environment of my Sitecore site and I have a link to another system, I need to make sure I’m linking to the QA Environment link for that system. As I move “up” in environment, then my links should dynamically adjust as well. My colleague, and recent author, Kyle Burns came up with a creative solution that was easy to implement in Sitecore and handles links done through any field (including the dreaded RTE Fields!).
Kyle’s solution was to create an “Environment Sensitive Link” data template in Sitecore. The data template would have one field, “URL”, of General Link type. The insert options on the link would allow instances to create children of the same template. Content Authors would create instances of this template for any link that requires adjustment per environment. (It should be noted here that for this client we were talking about 20 environment specific links – not hundreds or thousands.) The Content Authors would name the first instance of this template with a context specific link so that they could easily identify what system it was going to link to. In the URL field of this instance, they would put the link to the Production Environment URL of the system they were linking to. For any existing environments that require a differing URL from the production URL, the Content Authors would create children instances of the same template. These children would get named with the host name of the environment for their Sitecore site (up to the first “.”). The URL field would be set to the address that should be used for a given environment.
The resulting Sitecore content tree of an example Environment Sensitive Link would look something like this :
ExternalSystemA [URL field: http://www.externalsystema.com]
qaMySite [URL field: http://qa.externalsystema]
testMySite [URL field: http://test.externalsystema]
In that example, “qaMySite” would be the hostname of the Sitecore QA Environment, and “testMySite” is the hostname of the Sitecore Test Environment – both up to the first period in the hostname. (Therefore, the QA Environment URL for the Sitecore site might be “http://qamysite.mySitecoreSite”].)
Once each of the Environment Sensitive Links was set up (in a central location within the Sitecore Content Tree), then the content authors set all links to these systems to point to the Parent Instance of that environment. Furthering with the above example, that means that if a Content Author needed to link to “http://www.externalsystema.com”, instead of using an external link to link directly to that URL, they would instead link to the parent item defined above (name “ExternalSystemA”). After that was done, the Content Authors work regarding Environment Sensitive Links was also complete.
So what makes the above data templates work? We went through two iterations of code solutions that both worked. The first solution that we implemented involved creating a Controller Rendering and attaching it to the Presentation Details of our data template. (My client is using Sitecore 6.6 and their code is using MVC rather than web forms. In the web forms world, we would’ve simply created a Sublayout and assigned that to our data template.) Our Controller Rendering code looked like the following:
public ActionResult EnvironmentSpecificLink()
{
Item myContextItem = Sitecore.Context.Item;
Sitecore.Links.UrlOptions urlOptions = new Sitecore.Links.UrlOptions();
urlOptions.AlwaysIncludeServerUrl = true;
string myURL = Sitecore.Links.LinkManager.GetItemUrl(myContextItem, urlOptions);
string HostName = myURL.Replace("http://", string.Empty).Replace("https://", string.Empty);
if (HostName.Contains('.'))
{
HostName = HostName.Substring(0, HostName.IndexOf('.'));
}
if (HostName.Contains('/'))
{
HostName = HostName.Substring(0, HostName.IndexOf('/'));
}
ChildList myChildren = myContextItem.GetChildren();
foreach (Item myChild in myChildren)
{
if (myChild.Name.ToLower() == HostName.ToLower())
{
myContextItem = myChild;
break;
}
}
string RedirectTo = ((LinkField)myContextItem.Fields["URL"]).Url;
return Redirect(RedirectTo);
}
You can see from that code that when a link to an instance of our Environment Sensitive Link template is triggered, the controller looks to determine if the item being linked to has a child that’s name matches the current environment host name. If a match is found, the child is set to the variable “myContextItem”. If no match is found, then the parent instance remains as “myContextItem”. At the end, we pull the URL field value from myContextItem and immediately redirect the browser to that new address.
The above code worked perfectly, but it’s of course requiring two round trips because of the redirect. This isn’t an ideal situation if it can be avoided, which is why we went from that solution to the next. My client has already created a custom class that they’re using as the default Sitecore Link Provider. In this class, they were already overriding the GetItemURL method. We simply took the above code and put it inside this overridden GetItemURL method. We had to make some slight modifications to check if the item that was being linked to was of the EnvironmentSensitiveLink template, rather than using the Sitecore.Context.Item, but otherwise the concept was the same. Instead of redirecting though, we simply adjusted the method to return the proper Environment URL. Now we have a solution that works without any extra server trips!
Again, this scenario is a bit rare, because most companies will only put Production level content into their Authoring environment, but I thought it was a creative utilization of a data template, so I wanted to share it with anyone who may have a similar problem.