Sitecore CMS and everything related RSS 2.0
 Wednesday, August 20, 2008

Have you seen or used the Sitecore Poll module? Got any complaints, suggestions or feature requests? Mail ar at sitecore dot net or leave them here in comments. The feedback will be put to good use. Go.

Wednesday, August 20, 2008 10:56:18 AM (FLE Standard Time, UTC+02:00)  #    Comments [3]
Sitecore | Open Source
 Monday, August 18, 2008

A little known fact is that Sitecore 6 comes with Prototype and Firebug lite preinstalled. Prototype is a mind saving javascript library, and firebug lite is a helpful javascript instrumentation console replacing dozens of alert(“I’m here”) calls.

We’d do it for ourselves anyway, but what does it mean for you?

Prototype

Prototype javascript library is automatically included in Sitecore shell applications – both native, such as Content Editor, and the custom ones.

This means you can safely use prototype both in your Sitecore customizations, such as custom fields, and in your own applications. (If you look closely enough, you’ll see that custom FieldTypes I’ve made for Crestone shamelessly use prototype whenever possible).

Needless to say that prototype is great and saves a lot of brain cells if you do any javascript at all. Some great alternatives, such as jQuery, do exist – but if you don’t use anything at all, I really wonder why.

If you’re new to prototype and javascript frameworks in general – they have very solid documentation at http://prototypejs.org/.

Even more, prototype’s cousin – Scriptaculous, a javascript UI controls and effects library is also shipped with Sitecore, but is not included automatically. If you need it, it’s at /sitecore/shell/Controls/Lib/Scriptaculous.

Firebug Lite

Firebug lite is a cross browser javascript console – the fact that it works in Internet Explorer is of biggest interest to Sitecore developers. I’ve praised it before, but now it’s one key press away in Sitecore shell applications.

Press F12 and the firebug lite console will pop up from the top:

Firebug lite opened in Sitecore Content Editor

This means you can use console.log and other instrumentation methods to debug your javascript.

Sitecore UI has a lot of IFrames, so pay attention where you click before opening the console – each IFrame is a separate javascript realm, and therefore has its own firebug console.

The Website is Safe

I’d like to stress again that both Prototype and Firebug lite are only included in the Sitecore shell applications. Technically, if the sitecore.js javascript file is loaded, the prototype and firebug are also inlcuded.

We don’t add anything to the frontend sites – it’s your decision.

Monday, August 18, 2008 8:37:58 AM (FLE Standard Time, UTC+02:00)  #    Comments [4]
Sitecore | Crestone | Web development
 Thursday, August 14, 2008

And in case you haven’t seen this elsewhere: Do not install the .NET 3.5 Service Pack 1 on any servers running Sitecore. Service pack updates the LosFormatter class which is responsible for viewstate serialization/deserialization in the ASP.NET, and it looks like they’ve introduced a subtle bug that hit us.

 

An official release:

Dear Sitecore Enthusiast,

You are receiving this message because you are subscribed to the Sitecore Product Issues and Patches mailing list.

On Monday, August 4th, Microsoft released the following service packs: Visual Studio 2008 SP1 and .NET 3.5 SP1.

Sitecore has discovered that these service packs introduce a bug in the LosFormatter class (System.Web.UI.LosFormatter in System.Web.dll, used to serialize and deserialize an ASP.NET ViewState). This bug causes stability issues in Sitecore products. Sitecore has raised this as an urgent priority issue with Microsoft (case number : SRQ080813600454) and is working to help resolve this issue.

In the meantime, PLEASE DO NOT INSTALL .NET 3.5 SP1 and Visual Studio 2008 SP1 on any server running a Sitecore product (including Sitecore WCMS, Intranet Portal, and Foundry) until further notice!

Symptoms associated with installing either of these service packs:

  1. Memory consumption increases dramatically and single core CPU usage goes up to 100% when opening the Access Viewer or Media Library applications.
  2. OutOfMemoryExceptions thrown in the Desktop and Content Editor.
  3. The browser becomes unresponsive when accessing Sitecore.

Please be aware that Microsoft  may include this Service Pack as part of the monthly ‘Patch Tuesday’.  Please take steps to avoid the automatic installation of these service packs.

Please be aware that the final version of SQL Server 2008 will require .NET 3.5 SP1.

If you have any questions about this issue, please contact Sitecore support.

Best Regards,
Sitecore Support Team.

Thursday, August 14, 2008 9:05:40 AM (FLE Standard Time, UTC+02:00)  #    Comments [4]
ASP.NET | Sitecore

Sitecore 6 folder view renderItemTitle is another presentational pipeline introduced in Sitecore 6, allowing to modify the appearance of item blocks, or tiles, in the folder views. Folder view is what you see on the right: a default tab on folder items. You can also add it to any other item by adding it to the Editors list.

Hooking into the renderItemTile allows changing the appearance of individual item tiles. Most often, however, customization scenarios include adding a few bits of information, relevant to all items or to specific item types.

This is how the pipeline looks out of the box (simplified):

<renderItemTile>
  <processor type="RenderFolderTile" />
  <processor type="RenderTemplateTile" />
  <processor type="RenderDefaultTile" />
</renderItemTile>

The RenderFolderTile and RenderTemplateTile add information relevant to folders (a number of subitems) or templates (a number of usages).

In this example, I’ll be adding information about a number of validation errors of the item.

The processor has to inherit from Sitecore.Pipelines.RenderItemTile.RenderTileBase. This base class is already capable of rendering a default item tile, so I’m just slightly changing its behavior to also output a number of validation errors.

public class RenderItemTile : RenderTileBase {
  public override void Process(RenderItemTileArgs args) {
    if (args.View != TileView.Tiles) {
      return;
    }

    base.Process(args);

    args.AbortPipeline();
  }

  protected override void RenderTileDetails(HtmlTextWriter output, RenderItemTileArgs args) {
    base.RenderTileDetails(output, args);

    var errorCount = GetErrorCount(args.Item);
    if (errorCount == 0) {
      return;
    }

    var message = errorCount > 1 ? "{0} errors".FormatWith(errorCount) : "1 error";
    output.Write("<div class="\"scTileItemDetailsLine\"" style="color: red">");
    output.Write(message);
    output.Write("</div>");
  }

  int GetErrorCount(Item item) {
    var errorCount = 0;

    var validators = ValidatorManager.BuildValidators(ValidatorsMode.Gutter, item);
    ValidatorManager.Validate(validators, new ValidatorOptions(false));

    foreach(BaseValidator validator in validators) {
      if (validator.Result >= ValidatorResult.Warning) {
        errorCount++;
      }
    }

    return errorCount;
  }
}

A few pieces to notice:

  1. args.View defines the mode the pipeline runs in: Tiles, Large Icons, Small Icons, etc. Most of those are reserved for the future use and at the moment Sitecore only uses Tiles or IconOnly modes. In this customization, we’re after the Tiles mode.
  2. A relatively simple RenderTileDetails method is overriden. This method is only responsible only for the information to the right of the icon. The general shape and style of the tile, as well as the icon, are handled by other more complicated methods, which we’re not interested in.
  3. Note the usage of the new Validation API to validate the item: GetErrorCount method. Here I’m validating the item in the ‘Gutter’ (which is the old name for Quick Action Bar) mode. This means that the folder view will only run validators configured for the quick action bar (see the validation documentation on SDN and my post on validation for more)
  4. Once the tile is rendered, the pipeline must be aborted, or the RenderDefaultTile processor will kick in and do it’s job.

 

As with other pipelines, Sitecore only knows about generic data concepts such as templates, folders and items. We cannot provide the customizations specific to the business domain of each site, but you can. The renderItemTile pipeline can be used to add information that describes each specific item type best: a publication date of the news item, a number of comments of the blog post or a discount percentage for a sales partner. And because it’s a pipeline, you can even display different information to different types of users.

Thursday, August 14, 2008 8:57:47 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
 Monday, August 11, 2008

A quick hint today – did you know you can reorder items using drag and drop in Sitecore 6?

Drag and drop reordering in Sitecore 6

 

Hold the “ALT” key and drag the item on any other item in the tree. The item you’ve dropped will then be placed before the target item.

Monday, August 11, 2008 9:45:46 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Crestone
 Friday, August 08, 2008

(For introduction to the new publishing architecture, read the part 1: New Publishing Pipelines and Events in Sitecore 6)

Today’s example is using the publish:itemProcessed event to publish related media items.

A little background first. Imagine a new item structure being created, and some content items have an image field that uses items from the media library. Neither the content items nor the media items have been published yet. Now if the editor publishes the content item in a “single-item” mode (i.e. selects the publish in the ribbon, and not the incremental, smart or full publishing), the item will get published to the web database, but the media items will not.

The event handler below listens to the publish:itemProcessed event, and if the content item had been published in the single-item mode and has links to media items, they get published too.

public class ItemProcessedHandler {
  public void ItemProcessed(object sender, EventArgs rawArgs) {
    var args = rawArgs as ItemProcessingEventArgs;
    Assert.IsNotNull(args, "args");

    var context = args.Context;
    
    // [1] publish mode check
    if (context.PublishOptions.Mode != PublishMode.SingleItem) {
      return;
    }

    var item = context.PublishHelper.GetSourceItem(context.ItemId);
    if (item == null) {
      return;
    }

    if (!item.Paths.IsContentItem) {
      return;
    }

    // [2] Triggering publishing of the related item by running the publishItem pipeline again
    var options = new PublishOptions(
      context.PublishOptions.SourceDatabase,
      context.PublishOptions.TargetDatabase,
      PublishMode.SingleItem,
      context.PublishOptions.Language,
      context.PublishOptions.PublishDate);

    var relatedMedia = GetRelatedMedia(item);

    foreach(var mediaItem in relatedMedia) {
      PublishItemPipeline.Run(mediaItem.ID, options);
    }
  }

  // [3] related media items are retrieved using the link database
  IList GetRelatedMedia(Item item) {
    var references = Globals.LinkDatabase.GetReferences(item);
    var result = new List();

    foreach(var reference in references) {
      if (reference.SourceDatabaseName != item.Database.Name) {
        continue;
      }

      var referenceItem = item.Database.GetItem(reference.TargetItemID);
      if (referenceItem == null) {
        continue;
      }

      if (referenceItem.Paths.IsMediaItem) {
        result.Add(referenceItem);
      }
    }

    return result;
  }
}

Notes:

  1. Check the publish mode – no need to intervene in the incremental or full publishes, Sitecore will publish everything needed by itself
  2. Programmatically running the publishItem pipeline for each media item. Higher level PublishManager API could have been used as well
  3. Link database is used to retrieve the related media items. Nothing new here.

To activate the event:

<event name="publish:itemProcessed">
  <handler type="Pipelines.Publishing.ItemProcessedHandler, Pipelines" method="ItemProcessed" />
</event>
Friday, August 08, 2008 8:44:30 AM (FLE Standard Time, UTC+02:00)  #    Comments [4]
Sitecore | Crestone
 Wednesday, August 06, 2008

Sitecore 6 publishing architectureEven as the live mode is used more often, publishing remains one of the most important parts of the Sitecore world. If you look to the right, you’ll see my ugly drawing designed to contrast with the beauty of the new publishing architecture Ole implemented for Sitecore 6.

The entire publishing process is managed by the two pipelines: publish and publishItem. The publish pipeline runs once whenever a publish process is started from the user interface or programmatically. The pipeline collects all the items that need to be published, and runs the publishItem pipeline for each item separately.

PublishItem pipeline decides how to perform the actual publishing. It also raises two very useful events: publish:itemProcessing and publish:itemProcessed. Each event receives the full set of current publishing settings and the item being published.

When deciding between extending the publishItem pipeline and using the publishing events, I’d say use the events whenever reasonably possible. Publishing is still a low-level core process, so not having a chance to mess up the way the pipeline operates is good.

I’ll illustrate the new extensibility with two examples, one for each event.

Preventing an Item from Being Published

As the name suggests, publish:itemProcessing event fires before the publishing is performed, and can be used to cancel the process. In this example, the publishing of protected items is forbidden.

public class EventHandler {
  public void ItemProcessing(object sender, EventArgs rawArgs) {
    // [1] – retrieving the args.

var args = rawArgs as ItemProcessingEventArgs; Assert.IsNotNull(args, "args");

    // [2] – action check
    if (args.Context.Action == PublishAction.DeleteTargetItem) {
      return;
    }
    // [3] – retrieving the item being published
    var item = args.Context.PublishHelper.GetSourceItem(args.Context.ItemId);
    if (item == null) {
      return;
    }

    // [4] – cancel publishing if the item is protected
    if (item.Appearance.ReadOnly) {
      args.Cancel = true;
    }
  }
}

Things to note:

  1. The way arguments are passed to the event handler. This differs from the Event.ExtractParameter that had to be used for older events.
  2. The args.Context.Action check. The publishItem pipeline (and therefore the events) are run for each publishing operation, even if the publishing actually results in the item being removed from the target (web) database. In this example I don’t want to prevent item deletion, so the handler bails out.
  3. The use of args.Context.PublishHelper.GetSourceItem() method to retrieve the item being published.
  4. The operation is canceled in a traditional .NET way by setting the args.Cancel to true.

To activate the event:

<event name="publish:itemProcessing">
  <handler method="ItemProcessing" type="Pipelines.Publishing.EventHandler, Pipelines" />
</event>

In the next post I’ll show how to publish related media items using the publish:itemProcessed event.

Wednesday, August 06, 2008 11:09:07 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Crestone
 Monday, August 04, 2008

Sitecore 6 Content Editor Warning: "The item haven't been updated in a while"Sitecore 6 introduces a number of new pipelines. Some reflect new features added to the system, and some provide new customization opportunities for the previously existing features.

Today's topic is the getContentEditorWarnings pipeline.

Content Editor warnings are the yellow warning blocks that appear above sections and fields in the main Content Editor area. We have more than a dozen warnings supported out of the box, such as "the item is protected", "the item will not be published", etc.

These warnings are specific to Sitecore - we don't know anything about the business domain of the site. However it is easy to add new warnings using the getContentEditorPipeline.

As an example, I've created a warning that checks the updated date of the item, and warns if the item haven't been updated in 6 months or more:

public class GetContentEditorWarnings {
  public void Process(GetContentEditorWarningsArgs args) {
    if (DateTime.Now - args.Item.Statistics.Updated > TimeSpan.FromDays(180)) {
      var warning = args.Add();
      warning.Title = "This item haven't been updated in a while";
      warning.Text = "Consider revising the content.";
      
      warning.AddOption("Set a reminder", "item:reminderset(id={0})".FormatWith(args.Item.ID));
    }
  }
}

The steps here a simple: title and text provide warning description to the user, and AddOptions allows setting up quick fixes. In this example, a “set a reminder” dialog will popup if “Set a reminder” is clicked.

To enable the warning, just add the new processor to the getContentEditorWarnings pipeline either by modifying web.config or using auto-include files (recommended).

<getContentEditorWarnings>
  ..
  <processor type="Pipelines.ContentEditor.GetContentEditorWarnings, Pipelines" />
</getContentEditorWarnings>

A warning can also be exclusive or fullscreen. Exclusive warnings do not allow other warnings to appear. If no exclusive warning is displayed, multiple “normal” warnings can be shown. If fullscreen warning is shown, it hides the usual editing interface of the Content Editor – sections and fields are hidden. Both warning modes can be activated by setting relevant properties of the GetContentEditorWarningsArgs.

Sitecore 6 Content Editor Warning: "The item haven't been updated in a while"

Monday, August 04, 2008 12:16:08 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Crestone
 Friday, August 01, 2008

Sitecore search results grouped in a new "Draft state" category In part 2 I've shown how to customize grouping of existing search results.

Going one step further, it's also possible to inject additional search results. I don't suggest that you try to improve the way the items indexes and searched. Instead, you can increase usability by supporting special searches that are meaningful to your solution or module, or search external locations that are not indexed by Sitecore.

I'll use workflow state searcher as an example: whenever a search query matches the name of any workflow state in the system, the items in that workflow state are added to the search results.

How This Works

Client searches are handled by the <search> pipeline:

<search>
  <processor type="Sitecore.Pipelines.Search.IDResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.Search.PathResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.Search.UrlResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.Search.SecurityResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.Search.DatabaseResolver, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.Search.SearchSystemIndex, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.Search.CategorizeResults, Sitecore.Kernel" />
  <processor type="Sitecore.Pipelines.Search.AddInstantOptions, Sitecore.Kernel" />
</search>

You can see that special searches that Sitecore supports (see part 1) are implemented with separate processors. Adding a new processor in the pipeline will allow new search results to be added.

The Code

public class WorkflowSearchResolver
{
  public void Process(SearchArgs args)
  {
    foreach (var workflow in args.Database.WorkflowProvider.GetWorkflows())
    {
      foreach (var state in workflow.GetStates())
      {
        if (state.DisplayName.Equals(args.TextQuery, StringComparison.CurrentCultureIgnoreCase))
        {
          AddStateResults(args, workflow, state);
          return;
        }
      }
    }
  }

 
void AddStateResults(SearchArgs args, IWorkflow workflow, WorkflowState state)
  {
    foreach (var uri in workflow.GetItems(state.StateID))
    {
      var item = args.Database.GetItem(uri);
      if (item == null)
      {
        continue;
      }

     
args.Result.AddResultToCategory(SearchResult.FromItem(item), state.DisplayName + " state");
    }
  }
}

The logic flow is simple: iterate through all workflow states, and if the query (args.TextQuery) matches the state name, get the items in the workflow state and add them to a category named <state name> state.

All search processors must complete before the search results are displayed, so considering performance is a good idea. For production implementation, caching the workflow state names will make performance impact of the new search processor negligible.

Note that the searches only display a limited number of results (unless the standalone search application is used). Therefore consider limiting a number of search results you inject, so that other processors can also add theirs. In this example, sorting the results is also a good idea: updated date or the date of workflow state change can be used, so that the most recent items appear first. I skip both steps to make the example simpler.

The new search will work both in Content Editor and startbar (instant search) scenarios. However you can limit it to either one by checking the args.Type and aborting if needed.

Try It Out

Add a new processor to the search pipeline. A spot before the standard search system index would be a good place:

<processor type="SearchExtensions.WorkflowSearchResolver, SearchExtensions" />

Now either open the Content Editor and search any workflow state name (such as Draft), or press Ctrl-/ to focus the startbar search and type workflow state name there. You should see a result similar to the screenshot at the beginning of this post.

 

This post is a part of series about new client search introduced in Sitecore 6:

Part 1: Overview
Part 2: Categorization
Part 3: Custom Search Results

Friday, August 01, 2008 7:47:41 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
 Sunday, July 27, 2008

Sitecore 6 client search is built for extensibility and the most common scenario is to customize result categorization.

We ship with a number of default categories common for all Sitecore solutions - content items, media items (split into images and documents), layouts, system and user templates, workflows, etc.

Each solution or module, however, has its own inherent categories. Solutions benefit from content categories like news, customers and partners. Modules have distinct item types: RSS feeds, mailing lists.

All these categories can be setup in a declarative manner. There is a new section in web.config named search, which includes the categorizer definition:

<categorizer type="Sitecore.Pipelines.Search.CategorizeResults+Categorizer, Sitecore.Kernel">
<Categories hint="raw:AddCategory">
  <category path="/sitecore/content"/>
  <category displayName="Images">
    <templateID>{F1828A2C-7E5D-4BBD-98CA-320474871548}</templateID>
    <templateID>{DAF085E8-602E-43A6-8299-038FF171349F}</templateID>
    <templateID>{C97BA923-8009-4858-BDD5-D8BE5FCCECF7}</templateID>
    <templateID>{EB3FB96C-D56B-4AC9-97F8-F07B24BB9BF7}</templateID>
  </category>
  <category displayName="Documents">
    <templateID>{16692733-9A61-45E6-B0D4-4C0C06F8DD3C}</templateID>
    <templateID>{777F0C76-D712-46EA-9F40-371ACDA18A1C}</templateID>
    <templateID>{7BB0411F-50CD-4C21-AD8F-1FCDE7C3AFFE}</templateID>
    <templateID>{0603F166-35B8-469F-8123-E8D87BEDC171}</templateID>
    <templateID>{3DB3A3CA-A0A9-4228-994B-F70C8E99A1CE}</templateID>
    <templateID>{2A130D0C-A2A9-4443-B418-917F857BF6C9}</templateID>
    <templateID>{F57FB07D-332A-4934-AA67-0A629C5396E2}</templateID>
    <templateID>{CC80011D-8EAE-4BFC-84F1-67ECD0223E9E}</templateID>
  </category>
  <category path="/sitecore/media library"/>
  <category path="/sitecore/layout/devices"/>
  <category path="/sitecore/layout/layouts"/>
  <category path="/sitecore/layout/sublayouts"/>
  <category path="/sitecore/layout/renderings"/>
  <category path="/sitecore/layout"/>
  <category templateIDs="{455A3E98-A627-4B40-8035-E683A0331AC7}" displayName="Template Fields"/>
  <category templateIDs="{E269FBB5-3750-427A-9149-7AA950B49301}" displayName="Template Sections"/>
  <category path="/sitecore/templates/branches"/>
  <category path="/sitecore/templates/system" displayName="System Templates"/>
  <category path="/sitecore/templates"/>
  <category path="/sitecore/system/aliases"/>
  <category path="/sitecore/system/languages"/>
  <category path="/sitecore/system/workflows"/>
  <category path="/sitecore/system"/>
  <category path="/sitecore/content/applications/control panel" database="core"/>
  <category path="/sitecore/content/applications" database="core"/>
</Categories>
</categorizer>

The syntax is fairly self-explanatory. Declarative categories can be setup either using item path or template IDs. Whichever category matches first wins, so the more specific categories (Images and Documents) should go before the generic ones (Media Library).

It's important to understand that categories do not affect the indexes, but only how the results are grouped in the UI.

To setup a content category such as news: <category path="/sitecore/content/home/news" />. Make sure to add this line above the /sitecore/content category.

To setup a template category: <category templateIDs="{id-of-the-rss-feed-template}" displayName="RSS Feeds" />. Again, this category should go before the default ones.

 

This post is a part of series about new client search introduced in Sitecore 6:

Part 1: Overview
Part 2: Categorization
Part 3: Custom Search Results

Sunday, July 27, 2008 12:50:15 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
Archive
<August 2008>
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456
Blogroll
 Alex de Groot
Few words about SiteCore from Holland
 Alexander Shyba
Sitecore Support
 Anders Dreyer
Anders Dreyer on Sitecore Development
 Jakob Christensen
Sitecore Core Development
 Lars Fløe Nielsen
Lars's ramblings about development and business processes
 Ole Thrane
Sitecore API
 Runi Thomsen
Runi Thomsen Sitecore Toughts
 The Sitecore Experience
The Sitecore Experience
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010
Alexey Rusakov
Sign In
Statistics
Total Posts: 211
This Year: 0
This Month: 0
This Week: 0
Comments: 0
Themes
Pick a theme:
All Content © 2010, Alexey Rusakov
DasBlog theme 'Business' created by Christoph De Baene (delarou)