diff --git a/source/Constants.cs b/source/Constants.cs
new file mode 100644
index 0000000..7689975
--- /dev/null
+++ b/source/Constants.cs
@@ -0,0 +1,39 @@
+using System.ComponentModel;
+
+namespace SharedSource.RedirectModule
+{
+ public static class Constants
+ {
+ public static class Paths
+ {
+ public static string VisitorIdentification = "/layouts/system/visitoridentification";
+ public static string MediaLibrary = "/sitecore/media library/";
+ }
+
+ public static class Settings
+ {
+ public static string RedirExactMatch = "SharedSource.RedirectModule.RedirectionType.ExactMatch";
+ public static string RedirPatternMatch = "SharedSource.RedirectModule.RedirectionType.Pattern";
+ public static string QueryExactMatch = "SharedSource.RedirectModule.QueryType.ExactMatch";
+ public static string QueryPatternMatch = "SharedSource.RedirectModule.QueryType.PatternMatch";
+ public static string RedirectRootNode = "SharedSource.RedirectModule.RedirectRootNode";
+
+ }
+ public static class Templates
+ {
+ public static string RedirectUrl = "Redirect Url";
+ public static string VersionedRedirectUrl = "Versioned Redirect Url";
+ public static string RedirectPattern = "Redirect Pattern";
+ public static string VersionedRedirectPattern = "Versioned Redirect Pattern";
+ }
+ public static class Fields
+ {
+ public static string RequestedUrl = "Requested Url";
+ public static string RedirectTo = "redirect to";
+ public static string RequestedExpression = "requested expression";
+ public static string SourceItem = "source item";
+ public static string ItemProcessRedirects = "Items Which Always Process Redirects";
+ }
+
+ }
+}
diff --git a/source/RedirectModule.csproj b/source/RedirectModule.csproj
index 3946eff..40cdad9 100644
--- a/source/RedirectModule.csproj
+++ b/source/RedirectModule.csproj
@@ -46,6 +46,7 @@
+
diff --git a/source/Redirects.cs b/source/Redirects.cs
index aca9a86..af0aef6 100644
--- a/source/Redirects.cs
+++ b/source/Redirects.cs
@@ -13,146 +13,163 @@
namespace SharedSource.RedirectModule
{
- ///
- /// Redirection Module which handles 301 redirects. Both exact matches and regular expression pattern matches are supported.
- ///
- public class Redirects : HttpRequestProcessor
- {
- ///
- /// The main method for the processor. It simply overrides the Process method.
- ///
- public override void Process(HttpRequestArgs args)
- {
- // This processer is added to the pipeline after the Sitecore Item Resolver. We want to skip everything if the item resolved successfully.
- // Also, skip processing for the visitor identification items related to DMS.
- Assert.ArgumentNotNull(args, "args");
- if ((Context.Item == null || AllowRedirectsOnFoundItem(Context.Database)) && args.LocalPath != "/layouts/system/visitoridentification" && Context.Database != null)
- {
- // Grab the actual requested path for use in both the item and pattern match sections.
- var requestedUrl = HttpContext.Current.Request.Url.ToString();
- var requestedPath = HttpContext.Current.Request.Url.AbsolutePath;
- var requestedPathAndQuery = HttpContext.Current.Request.Url.PathAndQuery;
- var db = Context.Database;
+ ///
+ /// Redirection Module which handles 301 redirects. Both exact matches and regular expression pattern matches are supported.
+ ///
+ public class Redirects : HttpRequestProcessor
+ {
+ ///
+ /// The main method for the processor. It simply overrides the Process method.
+ ///
+ public override void Process(HttpRequestArgs args)
+ {
+ // This processer is added to the pipeline after the Sitecore Item Resolver. We want to skip everything if the item resolved successfully.
+ // Also, skip processing for the visitor identification items related to DMS.
+ Assert.ArgumentNotNull(args, "args");
+ if ((Context.Item == null || AllowRedirectsOnFoundItem(Context.Database)) && args.LocalPath != Constants.Paths.VisitorIdentification && Context.Database != null)
+ {
+ // Grab the actual requested path for use in both the item and pattern match sections.
+ var requestedUrl = HttpContext.Current.Request.Url.ToString();
+ var requestedPath = HttpContext.Current.Request.Url.AbsolutePath;
+ var requestedPathAndQuery = HttpContext.Current.Request.Url.PathAndQuery;
+ var db = Context.Database;
- // First, we check for exact matches because those take priority over pattern matches.
- if (Sitecore.Configuration.Settings.GetBoolSetting("SharedSource.RedirectModule.RedirectionType.ExactMatch", true))
- {
- // Loop through the exact match entries to look for a match.
- foreach (Item possibleRedirect in GetRedirects(db, "Redirect Url", Sitecore.Configuration.Settings.GetSetting("SharedSource.RedirectModule.QueryType.ExactMatch")))
- {
- if (requestedUrl.Equals(possibleRedirect["Requested Url"], StringComparison.OrdinalIgnoreCase) ||
- requestedPath.Equals(possibleRedirect["Requested Url"], StringComparison.OrdinalIgnoreCase))
- {
- var redirectToItem = db.GetItem(ID.Parse(possibleRedirect.Fields["redirect to"]));
- if (redirectToItem != null)
- {
- SendResponse(redirectToItem, HttpContext.Current.Request.Url.Query, args);
- }
- }
- }
- }
+ // First, we check for exact matches because those take priority over pattern matches.
+ if (Sitecore.Configuration.Settings.GetBoolSetting(Constants.Settings.RedirExactMatch, true))
+ {
+ // Loop through the exact match entries to look for a match.
+ foreach (Item possibleRedirect in GetRedirects(db, Constants.Templates.RedirectUrl, Constants.Templates.VersionedRedirectUrl, Sitecore.Configuration.Settings.GetSetting(Constants.Settings.QueryExactMatch)))
+ {
+ if (requestedUrl.Equals(possibleRedirect[Constants.Fields.RequestedUrl], StringComparison.OrdinalIgnoreCase) ||
+ requestedPath.Equals(possibleRedirect[Constants.Fields.RequestedUrl], StringComparison.OrdinalIgnoreCase))
+ {
+ var redirectToItem = db.GetItem(ID.Parse(possibleRedirect.Fields[Constants.Fields.RedirectTo]));
+ if (redirectToItem != null)
+ {
+ SendResponse(redirectToItem, HttpContext.Current.Request.Url.Query, args);
+ }
+ }
+ }
+ }
- // Second, we check for pattern matches because we didn't hit on an exact match.
- if (Sitecore.Configuration.Settings.GetBoolSetting("SharedSource.RedirectModule.RedirectionType.Pattern", true))
- {
- // Loop through the pattern match items to find a match
- foreach (Item possibleRedirectPattern in GetRedirects(db, "Redirect Pattern", Sitecore.Configuration.Settings.GetSetting("SharedSource.RedirectModule.QueryType.ExactMatch")))
- {
- var redirectPath = string.Empty;
- if (Regex.IsMatch(requestedUrl, possibleRedirectPattern["requested expression"], RegexOptions.IgnoreCase))
- {
- redirectPath = Regex.Replace(requestedUrl, possibleRedirectPattern["requested expression"],
- possibleRedirectPattern["source item"], RegexOptions.IgnoreCase);
- }
- else if (Regex.IsMatch(requestedPathAndQuery, possibleRedirectPattern["requested expression"], RegexOptions.IgnoreCase))
- {
- redirectPath = Regex.Replace(requestedPathAndQuery,
- possibleRedirectPattern["requested expression"],
- possibleRedirectPattern["source item"], RegexOptions.IgnoreCase);
- }
- if (string.IsNullOrEmpty(redirectPath)) continue;
+ // Second, we check for pattern matches because we didn't hit on an exact match.
+ if (Sitecore.Configuration.Settings.GetBoolSetting(Constants.Settings.RedirPatternMatch, true))
+ {
+ // Loop through the pattern match items to find a match
+ foreach (Item possibleRedirectPattern in GetRedirects(db, Constants.Templates.RedirectPattern, Constants.Templates.VersionedRedirectPattern, Sitecore.Configuration.Settings.GetSetting(Constants.Settings.QueryExactMatch)))
+ {
+ var redirectPath = string.Empty;
+ if (Regex.IsMatch(requestedUrl, possibleRedirectPattern[Constants.Fields.RequestedExpression], RegexOptions.IgnoreCase))
+ {
+ redirectPath = Regex.Replace(requestedUrl, possibleRedirectPattern[Constants.Fields.RequestedExpression],
+ possibleRedirectPattern[Constants.Fields.SourceItem], RegexOptions.IgnoreCase);
+ }
+ else if (Regex.IsMatch(requestedPathAndQuery, possibleRedirectPattern[Constants.Fields.RequestedExpression], RegexOptions.IgnoreCase))
+ {
+ redirectPath = Regex.Replace(requestedPathAndQuery,
+ possibleRedirectPattern[Constants.Fields.RequestedExpression],
+ possibleRedirectPattern[Constants.Fields.SourceItem], RegexOptions.IgnoreCase);
+ }
+ if (string.IsNullOrEmpty(redirectPath)) continue;
- // Query portion gets in the way of getting the sitecore item.
- var pathAndQuery = redirectPath.Split('?');
- var path = pathAndQuery[0];
- if (LinkManager.Provider != null &&
- LinkManager.Provider.GetDefaultUrlOptions() != null &&
- LinkManager.Provider.GetDefaultUrlOptions().EncodeNames)
- {
- path = MainUtil.DecodeName(path);
- }
- var redirectToItem = db.GetItem(path);
- if (redirectToItem != null)
- {
- var query = pathAndQuery.Length > 1 ? "?" + pathAndQuery[1] : "";
- SendResponse(redirectToItem, query, args);
- }
- }
- }
- }
- }
+ // Query portion gets in the way of getting the sitecore item.
+ var pathAndQuery = redirectPath.Split('?');
+ var path = pathAndQuery[0];
+ if (LinkManager.Provider != null &&
+ LinkManager.Provider.GetDefaultUrlOptions() != null &&
+ LinkManager.Provider.GetDefaultUrlOptions().EncodeNames)
+ {
+ path = MainUtil.DecodeName(path);
+ }
+ var redirectToItem = db.GetItem(path);
+ if (redirectToItem != null)
+ {
+ var query = pathAndQuery.Length > 1 ? "?" + pathAndQuery[1] : "";
+ SendResponse(redirectToItem, query, args);
+ }
+ }
+ }
+ }
+ }
- private static bool AllowRedirectsOnFoundItem(Database db)
- {
- if (db == null)
- return false;
- var redirectRoot = Sitecore.Configuration.Settings.GetSetting("SharedSource.RedirectModule.RedirectRootNode");
- var redirectFolderRoot = db.SelectSingleItem(redirectRoot);
- if (redirectFolderRoot == null)
- return false;
- var allowRedirectsOnItemIDs = redirectFolderRoot["Items Which Always Process Redirects"];
- return allowRedirectsOnItemIDs != null &&
- allowRedirectsOnItemIDs.Contains(Context.Item.ID.ToString());
- }
+ private static bool AllowRedirectsOnFoundItem(Database db)
+ {
+ if (db == null)
+ return false;
+ var redirectRoot = Sitecore.Configuration.Settings.GetSetting(Constants.Settings.RedirectRootNode);
+ var redirectFolderRoot = db.SelectSingleItem(redirectRoot);
+ if (redirectFolderRoot == null)
+ return false;
+ var allowRedirectsOnItemIDs = redirectFolderRoot[Constants.Fields.ItemProcessRedirects];
+ return allowRedirectsOnItemIDs != null &&
+ allowRedirectsOnItemIDs.Contains(Context.Item.ID.ToString());
+ }
- ///
- /// This method return all of the possible matches for either the exact matches or the pattern matches
- ///
- private static IEnumerable- GetRedirects(Database db, string templateName, string queryType)
- {
- // Based off the config file, we can run different types of queries.
- IEnumerable
- ret = null;
- var redirectRoot = Sitecore.Configuration.Settings.GetSetting("SharedSource.RedirectModule.RedirectRootNode");
- switch (queryType)
- {
- case "fast": // fast query
- {
- ret = db.SelectItems(String.Format("fast:{0}//*[@@templatename='{1}']", redirectRoot, templateName));
- break;
- }
- case "query": // Sitecore query
- {
- ret = db.SelectItems(String.Format("{0}//*[@@templatename='{1}']", redirectRoot, templateName));
- break;
- }
- default: // API LINQ
- {
- Item redirectFolderRoot = db.SelectSingleItem(redirectRoot);
- if (redirectFolderRoot != null)
- ret = redirectFolderRoot.Axes.GetDescendants().Where(i => i.TemplateName == templateName);
- break;
- }
- }
+ ///
+ /// This method return all of the possible matches for either the exact matches or the pattern matches
+ /// Note: Because Fast Query does not guarantee to return items in the current language context
+ /// (e.g. while in US/English, results may include other language items as well, even if the
+ /// US/EN language has no active versions), an additional LINQ query has to be run to filter for language.
+ /// Choose your query type appropriately.
+ ///
+ private static IEnumerable
- GetRedirects(Database db, string templateName, string versionedTemplateName, string queryType)
+ {
+ // Based off the config file, we can run different types of queries.
+ IEnumerable
- ret = null;
+ var redirectRoot = Sitecore.Configuration.Settings.GetSetting(Constants.Settings.RedirectRootNode);
+ switch (queryType)
+ {
+ case "fast": // fast query
+ {
+ //process shared template items
+ ret = db.SelectItems(String.Format("fast:{0}//*[@@templatename='{1}']", redirectRoot, templateName));
- // make sure to return an empty list instead of null
- return ret ?? new Item[0];
- }
+ //because fast query requires to check for active versions in the current language
+ //run a separate query for versioned items to see if this is even necessary.
+ //if only shared templates exist in System/Modules, this step is extraneous and unnecessary.
+ IEnumerable
- versionedItems = db.SelectItems(String.Format("fast:{0}//*[@@templatename='{1}']", redirectRoot, versionedTemplateName));
- ///
- /// Once a match is found and we have a Sitecore Item, we can send the 301 response.
- ///
- private static void SendResponse(Item redirectToItem, string queryString, HttpRequestArgs args)
- {
- var redirectToUrl = GetRedirectToUrl(redirectToItem);
- args.Context.Response.Status = "301 Moved Permanently";
- args.Context.Response.StatusCode = 301;
- args.Context.Response.AddHeader("Location", redirectToUrl + queryString);
- args.Context.Response.End();
- }
+ //if active versions of items in the current context exist, union the two IEnumerable lists together.
+ ret = versionedItems.Any(i => i.Versions.Count > 0)
+ ? ret.Union(versionedItems.Where(i => i.Versions.Count > 0))
+ : ret;
+
+
+ break;
+ }
+ case "query": // Sitecore query
+ {
+ ret = db.SelectItems(String.Format("{0}//*[@@templatename='{1}' or @@templatename='{2}']", redirectRoot, templateName, versionedTemplateName));
+ break;
+ }
+ default: // API LINQ
+ {
+ Item redirectFolderRoot = db.SelectSingleItem(redirectRoot);
+ if (redirectFolderRoot != null)
+ ret = redirectFolderRoot.Axes.GetDescendants().Where(i => i.TemplateName == templateName || i.TemplateName == versionedTemplateName);
+ break;
+ }
+ }
+
+ // make sure to return an empty list instead of null
+ return ret ?? new Item[0];
+ }
+
+ ///
+ /// Once a match is found and we have a Sitecore Item, we can send the 301 response.
+ ///
+ private static void SendResponse(Item redirectToItem, string queryString, HttpRequestArgs args)
+ {
+ var redirectToUrl = GetRedirectToUrl(redirectToItem);
+ args.Context.Response.Status = "301 Moved Permanently";
+ args.Context.Response.StatusCode = 301;
+ args.Context.Response.AddHeader("Location", redirectToUrl + queryString);
+ args.Context.Response.End();
+ }
private static string GetRedirectToUrl(Item redirectToItem)
{
- if (redirectToItem.Paths.Path.StartsWith("/sitecore/media library/"))
+ if (redirectToItem.Paths.Path.StartsWith(Constants.Paths.MediaLibrary))
{
var mediaItem = (MediaItem)redirectToItem;
var mediaUrl = MediaManager.GetMediaUrl(mediaItem);
@@ -162,6 +179,6 @@ private static string GetRedirectToUrl(Item redirectToItem)
return LinkManager.GetItemUrl(redirectToItem);
}
- }
+ }
}