Monday, March 29, 2010

Dreamcore is coming. Hope to see you in Boston!


If you read this, you may have already registered for Dreamcore or at least thought about it. For those who have not heard about it, this is the first Sitecore partner conference that offers huge opportunity to learn about cutting edge stuff we do with the products, do some networking, share experience and of course have fun!

I am proud to be presenting at developer tracks with the following topics. Here is the brief abstract of those:
- Data Retrieval Techniques with Sitecore
Everyone knows that Sitecore CMS gives you tons of options in every aspect of development. Knowing how to access Sitecore data is very important. Knowing what approach is more efficient for certain requirements is absolutely critical. In this session, I outline different use cases and covers multiple ways to address each of them using such methods as traditional data access API, Sitecore Query, Fast Query, Search Index, Database Crawler, Link Database, etc. After the session the attendee will be able to easily match a use case with the most appropriate and performing way to address it.
- Using Lucene.NET with Sitecore
This topic is related to “Data Retrieval Techniques with Sitecore” and goes deeper in exploration of Lucene.NET implementation in Sitecore. During this session the I will demonstrate the real world use case of this technology for the CMS reporting.

Our search analytics proved that Lucene is the most demanding topic on SDN, so hope it is appropriate.

Any feedback about the specifics of what you would like to see is appreciated!

Monday, March 15, 2010

Sitecore Friendly URLs and plus sign


One of the customers recently asked about using the plus sign in URLs, for example: http://localhost/news+events.aspx

There are at least two ways to accomplish this:
1. Allow “+” in item name via a configuration change
For this you will need to adjust the regular expression in the “ItemNameValidation” setting in web.config and make sure + sign is not  present in the “InvalidItemNameChars” setting.
2. Rely on the display name instead.

Thursday, March 11, 2010

Publish to pre-production web database


Update 3/11/2010: Correction » the last parameter of the ExtendedPublishOptions constructor should be “false”.  Please see below for details.

In my experience with enterprise level implementations, there is often a need for a separate “stage environment” for final content preview or a pre-production phase of workflow.

It is also often the case that the environmental limitations or restrictions make the content delivery part of the authoring environment suitable for such purpose. For example, your e-commerce infrastructure could not be available from the authoring instance. One of the possible ways to approach such a requirement is to configure a stand-alone staging instance of Sitecore which will be used for content delivery instance and is commonly configured exactly like one of the servers in the web farm. There is one exception though – the database that is used for content delivery is generally different from the one that is used in production content delivery.

With this approach, now the question is how to plug in workflow in a way that content could go via this “stage” environment and then only upon final approval will be able to get to “production”.

Now there is a problem that you cannot get get items published until they are in final workflow state. You could have two workflow states “Staged” and “Published”, both marked as final and with auto publish actions connected.
I don’t like this approach since it goes against the workflow nature – only one state should be marked as final.

Alternatively, you can plug in a “copy item” workflow action to the “Staged” workflow state where you can programmatically copy an item from master database to stage web.

While this approach does seem legitimate, it works around the need of publishing thus any additional processing you may be having in publish(item) pipeline would not work.

I looked into the option of having publishing process ignore workflow when publishing to stage. While this seemed like a dangerous path to go, I have soon discovered that the PublishHelper’s GetVersionToPublish method already accepts this notion of passing a “requireapproval” flag to the underlying publishing mechanism. Since it is always passes “true”, I started looking into ways to make this flag dynamic and figured that setting it on the level of PublishOptions could be a good idea. For example, from the code of my workflow action I would be able to define whether I want to have workflow respected or not.

Here is what you will need to do to make it work.

First, override the default PipelinePublishProvider and plug it into the web.config:

<publishManager defaultProvider="default" enabled="true">
    <providers>
        <clear />
         <!--<add name="default" type="Sitecore.Publishing.PipelinePublishProvider, Sitecore.Kernel" />-->
         <add name="default" type="SCUSAINC.Publishing.ExtendedPublishProvider, SCUSAINC.Publishing" />
     </providers>
</publishManager>

Secondly, you will need to override the CreatePublishHelper class:

public class ExtendedPublishProvider : PipelinePublishProvider
    {
        public override PublishHelper CreatePublishHelper(PublishOptions options)
        {
            Assert.ArgumentNotNull(options, "options");
            if (options is ExtendedPublishOptions)
                return new ExtendedPublishHelper(options as ExtendedPublishOptions);

            return new PublishHelper(options);
        }
    }

After that, introduce two more classes – ExtendedPublishHelper and ExtendedPublishOptions:

public class ExtendedPublishHelper : PublishHelper
    {
        private readonly ExtendedPublishOptions _options;

        public ExtendedPublishHelper(ExtendedPublishOptions options)
            : base(options)
        {
            _options = options;
        }

        public override Item GetVersionToPublish(Item sourceItem)
        {
            Assert.ArgumentNotNull(sourceItem, "sourceItem");
            if (Options is ExtendedPublishOptions)
            {
                return sourceItem.Publishing.GetValidVersion(Options.PublishDate, _options.RequireApproval);
            }

            return sourceItem.Publishing.GetValidVersion(Options.PublishDate, true);
        }
    }

public class ExtendedPublishOptions : PublishOptions
    {
        public ExtendedPublishOptions(Database sourceDatabase, Database targetDatabase, PublishMode mode, Language language, DateTime publishDate, bool requireApproval)
            : base(sourceDatabase, targetDatabase, mode, language, publishDate)
        {
            RequireApproval = requireApproval;
        }

        public bool RequireApproval { get; set; }
    }

Now you are ready to launch publishing with workflow settings completely ignored. For example, this is how you can do it from the workflow action:

var database = Factory.GetDatabase(databaseName);

var options = new ExtendedPublishOptions(dataItem.Database, database, PublishMode.SingleItem, dataItem.Language, DateTime.Now, false)
{
         RootItem = dataItem,
         Deep = true;
};

new Publisher(options).PublishAsync();

3/11/2010: Correction » the last parameter of the ExtendedPublishOptions constructor should be “false”.
Instead of hardcoding it, I’d suggest having a parameter on the level of a workflow action which you can read and pass on.

private static bool RequireApproval(string parameters)
{
         return WebUtil.ParseUrlParameters(parameters)["RequireApproval"] == "true";
 }
public void Process(WorkflowPipelineArgs args)
{
                ...
               var requireApproval = RequireApproval(innerItem["parameters"]);
               var options = new ExtendedPublishOptions(dataItem.Database, database, PublishMode.SingleItem, dataItem.Language, DateTime.Now, requireApproval)
              
                ...
           
 }

That’s it!

Tested on Sitecore 6.1. Expected to work with 6.2.

Sitecore startup time - something that could improve it


One of the things any Sitecore developer had to deal with is startup time. There are tons of reasons why an application pool may restart (file change notification, config change, etc.) so this generally happens pretty often, especially on a development machine.
So I decided to spend some time on the problem and engaged our brilliant technical support into this little project.

Wednesday, March 10, 2010

Things to consider when using Sitecore Packager


It is going to be a quick one. There is a simple checklist of things that you can use to help Packager be your friend.

1. Don’t include stuff you don’t need to. I see people including the whole folder with system templates instead of adding only custom templates or just changed fields on the system templates if there are any.

2. Use PChex component to verify package integrity.

3. Prefer dynamic sources over static sources. Kerry describes why here.

4. Disable search index to improve performance of package installation.

5. Get yourself familiar with the Installation Options. Use “Overwrite” very, very carefully as it may overwrite the branches.

6. Predefine those installation options. If somebody else is going to install your package, you don’t want them to choose for you.

7. Though readme gets ignored in most cases, do your best to supply the installation information or post-install directions with the package metadata.

8. Make sure to save the package project (xml file).

I realize that this may not be a complete list, so please feel free to share your experience and do comment.

Thanks!

Tuesday, March 09, 2010

Read only view of Rich Text field for Sitecore editor


Today I want to share an idea of a lightweight customization for Sitecore CMS that meant to increase usability of the rich text field for your editors. The idea is inspired by great feedback I received recently while being in the field.

The basic problem reported by one of the editors who uses Sitecore on the daily basis, is that when a content item is approved in workflow there is no way to see what’s inside of a rich text field easily. All field buttons are grayed out thus disabled:
disabled rich text field
…so the only way is to click “Lock and Edit” which creates a new version:
lock-and-edit

As you can imagine, this is not generally acceptable. If your non-admin editor user simply wants to see what’s in there, you don’t want a new version to be created.

Now it is worth mentioning that the item which is approved, unlocked is disabled for editing only if “RequireLockBeforeEditing” setting is set to true which is often the case, since you would want to have “Lock and Edit” in place so new version of the approved content is created.

Same goes along with the items that are locked. If there is a locked item, I would still want to see the content of the rich text field in read-only mode.

So one of the easiest ways I could think of to address this was enable “preview” of the rich text field in a modal dialog on double click.

Tech support provided the following solution which enabled the double click on disabled rich text field and showed the “preview” version of the field in a modal dialog:image

To make it work, follow these steps:
1. Open Preview.aspx under /sitecore/shell/Controls/Rich Text Editor.
2. Locate the scEdit() function and comment out the first IF statement:

function scEdit() {
        //if (scDisabled == "1") {
         // return;
       // }
        
var form = scGetForm();
...

3. Compile the following code:

namespace Company.Web.Fields
{
   using Sitecore.Diagnostics;
   using Sitecore.Shell.Applications.ContentEditor.RichTextEditor;
   using Sitecore.Web.UI.Sheer;

   public class RichText : Sitecore.Shell.Applications.ContentEditor.RichText
   {
      protected new void EditText(ClientPipelineArgs args)
      {
         Assert.ArgumentNotNull(args, "args");
         if (Disabled && !args.IsPostBack)
         {
            var url = new RichTextEditorUrl
                         {
                            Conversion = RichTextEditorUrl.HtmlConversion.Runtime,
                            Disabled = Disabled,
                            FieldID = FieldID,
                            ID = ID,
                            ItemID = ItemID,
                            Language = ItemLanguage,
                            Mode = string.Empty,
                            Source = Source,
                            Url = "/sitecore/shell/Controls/Rich Text Editor/Preview.aspx",
                            Value = Value,
                            Version = ItemVersion
                         };

            var str = url.GetUrl();
            SheerResponse.ShowModalDialog(str.ToString(), "800px", "500px", string.Empty, true);
            args.WaitForPostBack();
         }

         base.EditText(args);
      }
   }
}

4. In web.config, add your own controlSource reference to the namespace above:

<controlSources>
      <source mode="on" namespace="Sitecore.Web.UI.XmlControls" folder="/sitecore/shell/override" deep="true" />
...
       <source mode="on" namespace="Company.Web.Fields" assembly=" Company.Web" prefix="custom" />
</controlSources>

5. In the core database, locate the Rich Text field item (/sitecore/system/Field types/Simple Types/Rich Text) and adjust the value of the “control” field:
custom:RichText
Note that the prefix is used from the controlSource reference above.

Simple and lightweight customization that should bring some value. Sitecore rocks!

Tested on 6.1, expected to work on 6.0.x and 6.2.