donderdag 8 december 2011

E-Commerce Services - Storing the configuration settings outside home node

Sitecore has a great E-Commerce module (They just released their latest version that runs under Sitecore 6.5 called E-Commerce Services). When running multiple sites you probably want each site to have it's own configuration items. The default setup isn't ideal for this situation as it forces you to store the configuration item under the /home node of your website. If you're not going to setup any presentation details for these items it makes no sense to store them under the /home node.

How does it work?
Well, first of all E-Commerce Services is configured using "site" settings and "business" settings. Site settings are general settings for your site like: links to item locations, design, defaults, formats etc. Whilst business settings define things like VAT regions, Currencies, Order statusses etc. Business settings can be placed anywhere you like because they are linked under site settings. The site settings itself however are resolved through a pipeline called "getConfiguration"

The getConfiguration pipeline
The configuration pipeline is configured in the Sitecore.Ecommerce.config file and looks like this:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
      <getConfiguration>
        <processor type="Sitecore.Ecommerce.Pipelines.GetConfiguration.GetFromContextSite, Sitecore.Ecommerce.Kernel" />
        <processor type="Sitecore.Ecommerce.Pipelines.GetConfiguration.GetFromWebSite, Sitecore.Ecommerce.Kernel" />
        <processor type="Sitecore.Ecommerce.Pipelines.GetConfiguration.GetFromLinkManager, Sitecore.Ecommerce.Kernel" />
        <processor type="Sitecore.Ecommerce.Pipelines.GetConfiguration.GetFromResolver, Sitecore.Ecommerce.Kernel" />
      </getConfiguration>
  </sitecore>
</configuration>


The problem lies in the fact that the GetFromContextSite processor gets the Site settings item based on the StartPath property of the site. This points to the /sitecore/content/Sitename/home item of the website and not the /sitecore/content/Sitename item. The module allows for the <site /> definition to contain a EcommerceSiteSettings attribute to be specified which defaults to "/Site Settings" in the processor. But as said this is relative to the StartPath property and not the ContentStartPath property.

The solution
The solution to the problem is very simple. I created a custom processor that retrieves the Site Settings relative to the ContentStartPath property of the website. Just insert this processor at the first position in the pipeline and you're good to go!

Good luck!


namespace Sitecore.SharedSource.Pipelines.GetConfiguration  
 {  
   class GetFromContextSiteOutsideRoot : GetConfigurationProcessor  
   {  
     private static readonly string SettingsRootTemplateId = Settings.GetSetting("Ecommerce.Settings.SettingsRootTemplateId");  
     private const string EcommerceSiteSettingsAttribute = "EcommerceSiteSettings";  
     private const string EcommerceSiteSettingsDefaultValue = "/Home/Site settings";  
     public GetFromContextSiteOutsideRoot()  
     {  
     }  
     public override void Process(ConfigurationPipelineArgs args)  
     {  
       object obj1 = IoCContainerExtensions.Resolve(Sitecore.Ecommerce.Context.Entity, args.ConfigurationItemType, new ResolverOverride[0]);  
       if (!(obj1 is IEntity) || Sitecore.Context.Site == null || Sitecore.Context.Database == null)  
         return;  
       string part2 = Sitecore.Context.Site.Properties[GetFromContextSiteOutsideRoot.EcommerceSiteSettingsAttribute];  
       if (string.IsNullOrEmpty(part2))  
         part2 = GetFromContextSiteOutsideRoot.EcommerceSiteSettingsDefaultValue;  
       Item obj2 = Sitecore.Context.Database.GetItem(FileUtil.MakePath(Sitecore.Context.Site.ContentStartPath, part2));  
       if (obj2 == null || obj2.Template.ID.ToString() != GetFromContextSiteOutsideRoot.SettingsRootTemplateId && Enumerable.FirstOrDefault<TemplateItem>(Enumerable.Where<TemplateItem>((IEnumerable<TemplateItem>)obj2.Template.BaseTemplates, (Func<TemplateItem, bool>)(x => x.ID.ToString() == GetFromContextSiteOutsideRoot.SettingsRootTemplateId))) == null)  
         return;  
       IEntity entity = (IEntity)obj1;  
       Item source = obj2.Axes.SelectSingleItem(string.Format(".//*[@@name='{0}']", (object)entity.Alias));  
       this.RegisterInstance(args, (IEntity)obj1, source);  
       args.AbortPipeline();  
     }  
   }  
 }  

Geen opmerkingen:

Een reactie posten