Pages

Top 5 posts

Wednesday, February 09, 2011

To upgrade or not to upgrade * updated


Greetings!

One of our partners asked me yesterday about my thoughts on upgrading. Whether Sitecore recommends upgrading to 6.4 as of now or not. Also, just stumbled upon this great discussion here on Kim Hornung’s blog!

This is quite an interesting and thought provoking question, and I don’t think there could be a single answer to that and I also think that Sitecore has been doing a great job not forcing customer’s to upgrade. At the end of the day, it is your customer’s requirements and expectations that should drive the decision. With Sitecore’s successful hotfix process, if you have an issue that is a showstopper, you can request a quick hotfix from the Customer Service rather than upgrading your whole infrastructure!

upgrade decision treeHere is a decision tree that encompass everything that I generally suggest to customers and partners.

Click on the image to expand.

Please note that this is not an official recommendation from Sitecore. Rather, these are my personal thoughts on the subject.

With 6.3.1 being recommended, I’ve updated the image.

Friday, February 04, 2011

New Year, New Sitecore Blog


I have been thinking about this for a while, and finally decided to create another Sitecore blog on our Community area dedicated to sharing my experiences in the field working closely with implementation partners:

http://www.sitecore.net/AlexShyba

My ambitious plan is too continue sharing anything deeply technical here while the new blog would be a place where technical meets business half way.

Hope you enjoy it!

Thursday, February 03, 2011

Sitecore User Group in San Francisco / Bay Area


I would like to announce the formation of the first and only Sitecore User Group in the Bay Area.

My vision is to create a dedicated community for passionate Sitecore developers and end users devoted to learning new things and sharing experience about everything related to Sitecore CMS. Anybody can join. You can be either a beginner or experienced Sitecore developer, or end user.

Since Sitecore USA is headquartered in San Francisco, you have an amazing opportunity to get new information about the product directly from the vendor and get to meet the Sitecore folks!

The user group’s home is here. Join us!

Wednesday, February 02, 2011

8 Reasons to Use New Search in Sitecore


Greetings,

Back in 2010 at the first Dreamcore conference, I was honored to present on two topics: ”Data Retrieval Techniques with Sitecore” and “Using Lucene.NET with Sitecore”.
If you have not seen any of those, download the slides and check them out. I consider myself being a data guy, so that’s why I really enjoyed presenting on these topics. Not sure why, but I love everything about data access, and absolutely adore what Microsoft did with Entity Framework 4, especially the oData stuff. There is something truly exciting in seeing your data flow and materialize in one shape or another.

Anyways, back to the topic. During my presentation on Lucene/Sitecore marriage, I was showing that Sitecore actually has two (!!!) implementation of Lucene.NET. One is a legacy, what we call “old” search. Everything within Sitecore.Data.Indexing namespace is considered to be “old” search. It is configured and implemented differently, though it uses the same Lucene.NET dll. There is also the “new” search which is represented by a few classes within Sitecore.Search namespace.

The main point of the presentation was to show that you should not really use the “old” search if you develop on Sitecore 6.

Here are some extracts from the presentation explaining why:

1. Much richer out of the box:

a. one can specify locations, templates, etc.
b. indexes all fields
c. supports tagging
d. automatic prioritization

2. More extensible, more flexible and “overridable”

a. Configuration is separated from database

3. Better API

a. enforcing programming best practices

b. friendlier and easier to work with

c. external integration is possible

d. supports of “context of search operation“

4. Faster and more dependable.

Convinced yet?

Both “old” and “new” search index are being maintained by Sitecore in a similar fashion. However, they present different APIs to interact with them.

There is got to be a reason, but I frequently witness Sitecore implementers favor “old” over the “new” one. My only explanation is that we did not fully document the “new” search with the release of Sitecore 6, and that SDN was not steering developers in the right direction.

My humble hope is to address this shortcoming.

Here are 8 reasons why I should consider using “new” search.

1. All the good stuff about the “new” search listed above.

2. There is already a very comprehensive document on the “new” search on SDN. It should explain most of what the “new” search is about.

3. There is a shared source project called “Advanced Database Crawler” which leverages the “new” search and pushes its limits further introducing such things as field filters, dynamically computed fields, extended field crawler factory, plus includes an easy to use Searcher APIs that should abstract complexities of building search queries.

4. I have also blogged about it and recorded a very long and boring screencast showcasing this component.

5. Ivan blogged about it for quite a bit here and showed a few code snippets and workarounds.

6. The “new” Sitecore.Search namespace has a high chance of being the data access technique of choice, since that’s all you need to effectively query Sitecore data repository.

7. The “old” implementation may be deprecated in next major release, so it is important not to miss the early opportunity and migrate as soon as you can.

8. It is tried out in production by many already.
Just recently I actually was able to help a partner who decided to completely revamp their Sitecore Query based data access implementation with the “new” search. The results were reportedly dramatic and are already paying off.

One important note: please make sure to use either of the following Sitecore CMS versions if you go with it:
- 6.4.1 rev.101221
- 6.3.1 rev.110112
- 6.2.0 rev.101105 (Update-5)

They all contain some critical enhancements that will make your experience with the “new” search much smoother.

Enjoy it!

Tuesday, February 01, 2011

Sitecore Product URLs Amazon Style


If you are a Sitecore CMS developer and you love shopping on Amazon, you probably had the same thought: what would it take to re-create Amazon.com in Sitecore? Completely from scratch. Ok, maybe it’s just me.
So you will need to think about how to architect your content tree properly. Luckily, Derek has a blog dedicated solely to content tree architecture so I don’t need to go into much detail here.
Let’s say you have your content tree already designed. We are going to take Nicam demo site as an example:image
So all the camera products are structured in categories, that’s nice.
Since we talk about URLs in this post, everything is set there too. Each product has a content path which more or less serves as product URL on the public facing side.
In other words, I would be able to access my D3X camera using the following URL:
http://localhost/en/Products/Digital_SLR/Full_featured/D3X.aspx

One of the things you need to know is that Sitecore is constructing those URLs on the fly based on LinkManager configuration in web.config. And it is actually doing a pretty great job out of the box by giving you a number of options when it comes to URL construction. You can prepend language ISO code in URL, use display name instead of item name, etc. You can learn more about it here.

But what if we want to have fluid URLs that are constructed based on product attributes, meta data or some other criteria? Just as on Amazon.com, where the product URL is clearly driven by product attributes:

SNAGHTMLaa324b6For example, for all of our SLR cameras, use the following URL pattern: http://localhost/{SLR}/{Name}/{SKU}, where SKU is an attribute on the product itself:

imageWell, as it turns out, it is quite straightforward to do.
When it comes to handling any custom URL handling requirements, there are mainly two components you have to deal with.
1. Custom Item Resolver.
The custom logic here will attempt to resolve a valid item in the content tree by the custom URL.
2. Custom Link Provider.
This is the flip side of the solution. We need to teach Sitecore to generate product URLs based on our custom rules.
In addition, you would generally need a component to process such custom URL rules. In my example I would simply use IDTable, which allows to store any mapping to an item in a flat table. For the sake of simplicity I will be updating my IDTable based mapping table every time an item is saved via a handler.
The result will look something like this:
image
So here are all the pieces:
1. Custom Item Resolver:

public class ProductUrlResolver : HttpRequestProcessor
{
   public override void Process(HttpRequestArgs args)
   {
      Assert.ArgumentNotNull(args, "args");
      if (Context.Item != null || Context.Database == null || args.Url.ItemPath.Length == 0) return;
      Context.Item = ProductUrlManager.GetProductItemByFilePath(args.Url.FilePath);
   }
}

<processor type="Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel"/>
<!-- the proper order is important -->
<processor type="Custom.ProductUrlResolver, ProductUrlResolver"/>
<processor type="Sitecore.Pipelines.HttpRequest.LayoutResolver, Sitecore.Kernel"/>

2. Custom Link Provider:
public class ProductLinkProvider : LinkProvider
{
   public override string GetItemUrl(Item item, UrlOptions options)
   {
     Assert.ArgumentNotNull(item, "item");
     Assert.ArgumentNotNull(options, "options");
     return item.IsProduct() ? item.ProductUrl() : base.GetItemUrl(item, options);
   }
}

<linkManager defaultProvider="sitecore">
      <providers>
        <clear/>
         <add name="sitecore"
              type="Custom.ProductLinkProvider, ProductUrlResolver"
              .../>
      </providers>
</linkManager>

3. ItemSaved event handler:
public class ProductHandler
{
      protected void OnItemSaved(object sender, EventArgs args)
      {
         if (args == null) return;

         var item = Event.ExtractParameter(args, 0) as Item;

         if (item == null) return;

         if (item.IsProduct())
         {
            item.RegisterMapping();
         }
      }
}

<event name="item:saved">
    ...
   <handler type="Custom.ProductHandler,ProductUrlResolver" method="OnItemSaved"/>
</event>

4. Utility Manager where all the logic is handled:
public static class ProductUrlManager
   {
      public static string IdTableKey
      {
         get { return "ProductResolver"; }
      }

      public static bool IsProduct(this Item item)
      {
         var template = TemplateManager.GetTemplate(item);
         return template != null &&
template.DescendsFromOrEquals(ID.Parse("{B87EFAE7-D3D5-4E07-A6FC-012AAA13A6CF}"));
      }

      public static string ProductUrl(this Item item)
      {
         return "/{0}/{1}/{2}".FormatWith(item.TemplateName.ToLowerInvariant(), 
item.Name.ToLowerInvariant(),
item["SKU"]);
      }

      public static Item GetProductItemByFilePath(string filePath)
      {
         var id = IDTable.GetID(ProductUrlManager.IdTableKey, filePath);

         if (id != null && !ID.IsNullOrEmpty(id.ID))
         {
            return Context.Database.GetItem(id.ID);
         }

         return null;
      }

      public static void RegisterMapping(this Item item)
      {
         IDTable.RemoveID(ProductUrlManager.IdTableKey, item.ID);
         IDTable.Add(ProductUrlManager.IdTableKey, item.ProductUrl(), item.ID);
      }
   }

Conceptually, what do you think about this?
Note that this is a pretty hardcoded way of implementing such requirement. Please consider this as a prototype rather than a solution ready for production.