Sitecore CMS and everything related RSS 2.0
 Tuesday, June 02, 2009

image Sitecore Online Marketing Suite campaign has started - check out http://www.sitecore.net/en/Products/Sitecore-Online-Marketing-Suite.aspx.

The product is to be available on June 30th, and I'm very happy we're finally going public with it.

This is going to be fun.

Tuesday, June 02, 2009 12:28:21 PM (FLE Standard Time, UTC+02:00)  #    Comments [1]
Sitecore
 Thursday, April 16, 2009

UrlString provides a simple wrapper around URLs, both relative and absolute. Many Sitecore UI components receive data from querystring parameters, and UrlString provides convenient  method for constructing URLs with querystring parameters.

Assembling an URL:

UrlString url = new UrlString("/path/to/mypage.aspx");

url["id"] = "{some-id}";
url["db"] = "master";

string result = url.ToString(); // "/path/to/mypage.aspx?id=some-id&db=master"

Tweaking existing url:

UrlString url = new UrlString("/path/to/mypage.aspx?id=some-id&db=master");

url["db"] = "web";
url["mode"] = "new";

string result = url.ToString(); // "/path/to/mypage.aspx?id=some-id&db=web&mode=new"

Some methods in Sitecore API accept UrlString to add more data. ItemUri class can embed itself in a UrlString, so that you can pass information uniquely identifying a Sitecore item in a URL:

UrlString url = new UrlString("page.aspx");

Sitecore.Context.Item.Uri.AddToUrlString(url);

string result = url.ToString(); // "page.aspx?id={id}&la=en&v=1&db=master"

Compared to System.Uri, Sitecore's UrlString is very lax in accepting any kinds of input and giving it back.

Thursday, April 16, 2009 12:30:48 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | API
 Monday, April 13, 2009

Most of the data in Sitecore ends up stored and passed around as a string, hence we have quite a few helper classes to deal with string values. ListString class helps maintaining a list of strings that is serialized as a string itself. Like this:

“Fred|John|Derek”

What you see above is three strings, “Fred”, “John” and “Derek” serialized to a single string, each string being separated by the pipe ‘|’ symbol. Here’s how to use the ListString to create similar list:

ListString list = new ListString();

list.Add("Fred");
list.Add("John");
list.Add("Derek");

string result = list.ToString(); // -> "Fred|John|Derek"

Now you need to parse it somewhere else:

string rawValue = “Fred|John|Derek”;

ListString list = new ListString(rawValue);

int count = list.Count; // -> 3
string first = list[0]; // -> "Fred"

foreach(string s in list)
{
  // supports enumeration too
}

list.Add("Mary");
string result = list.ToString(); // -> "Fred|John|Derek|Mary"

Note that the class doesn’t check and escape incoming strings, so it’s your responsibility to make sure the values you pass do not contain a separator symbol.

Sitecore uses ListString alot internally, but it’s always better to use higher level API designed for each specific case, if such exists. A good example of that is MultilistField. So when else ListString can be handy? Whenever you need to pass multiple values as one, such as passing parameters, implementing a new field type that stores multiple values, etc.

Monday, April 13, 2009 4:54:23 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | API
 Saturday, March 28, 2009

Another update to Sitecore FieldTypes shared source project, featuring a new Filtered Multilist field and important bugfixes for other fields.

I've dropped the beta and decided to add sequential release numbers. This one is Drop-2.

Filtered Multilist

Filtered Multilist is a modification of standard Sitecore multilist field, with inline search for values in the left panel. Handy if you have multilist with a large amount of selectable values.

This is a simple drop-in replacement, you can change field type of existing multilist fields to filtered multilist to benefit from the filter, without loosing any values.


Filtered multilist

The field is contributed by Alexander Doroshenko from Sitecore Ukraine Solution Department

Bugfixes

* Fixed external javascript references. If you saw javascript errors like "Sitecore.FieldTypes.TextList is null or not an object" (or similar in other fields), this release fixes that.

* A few improvements to Text List

Saturday, March 28, 2009 6:16:04 PM (FLE Standard Time, UTC+02:00)  #    Comments [1]
Sitecore | Crestone | Open Source
 Saturday, March 14, 2009

Another new field type in the FieldTypes shared source project: introducing Text List, a field for maintaining lists of predefined items with autocomplete and drag & drop reordering. Most people should be familiar with it by now.

Selected items and adding a new item, autocomplete:

textlist autocomplete

Drag & drop reordering:

textlist reorder

Text List field should be a good fit for maintaining a list of tags, email addresses and such:

textlist tags

While looking fairly different, it is a typical Sitecore list field, storing list of selected item IDs and requiring source to prefetch a list of items to select from.

More details on FieldTypes wiki.

It took a bit of work, and some features could be missing - please report any issues.

Saturday, March 14, 2009 9:49:32 PM (FLE Standard Time, UTC+02:00)  #    Comments [3]
Sitecore | Crestone | Open Source
 Saturday, March 07, 2009

I've just commited a new field to the FieldTypes shared source project: Limited Single-line Text.

Limited Single-line Text field

Limited Single-line Text field - over the limit

A modification of Single-line Text, that allows to limit its length and that displays the amount of remaining characters. Can be configured to disallow further input once the limit is reached.

See project wiki for usage and configuration instructions.

Inspired by SDN request and twitter input box.

Saturday, March 07, 2009 4:48:30 PM (FLE Standard Time, UTC+02:00)  #    Comments [3]
Sitecore | Open Source
 Thursday, February 19, 2009

Sitecore 6 Service Release One is officially out by the name of Sitecore 6.0.1 rev.090212.

A massive list of fixed issues, props to our documentation team for providing nicely formatted change log.

I've done my share of work on it, so I'm just as excited to see it being released. Yay!

This is not a recommended release yet, as we require builds to be used in production for some time to ensure stability first. So make sure to read this notice: It is appropriate for use if it contains fixes for issues that you encounter with the recommended release.

Thursday, February 19, 2009 3:34:20 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
 Monday, January 19, 2009

Yan Sklyarenko started his Sitecore blog, which is great.

Yan is the leader of our modules team, overseeing everything concerning Sitecore module development. He's also been working on our installer, among other things, and is a generally nice guy, which is good for me, because my desk is next to his in Sitecore Ukraine office. Welcome!

Monday, January 19, 2009 12:44:01 PM (FLE Standard Time, UTC+02:00)  #    Comments [3]
Personal | Sitecore
 Wednesday, January 14, 2009

Sitecore has a number of ways to reference an item. Most common are ID and path, and most methods will accept either System.String or Sitecore.Data.ID parameter.

Item item = Context.Database.GetItem("/sitecore/content/somepath");
Item item = Context.Database.GetITem(ID.Parse("{11111111-1111-1111-1111111111111111"});

Our internal convention is that the ID can be used instead of path. You can supply the id as a string to methods that expect a path:

Item item = Context.Database.GetItem("{11111111-1111-1111-1111111111111111"}");

However you have to remember that neither path nor ID identify a piece of content in a unique way. Because Sitecore supports versions and multiple languages, a single item can have 3 versions in English and 2 in Danish. If you only use path or ID when retrieving items, you will get the latest version in the current (Sitecore.Context.Language) language.

Sometimes you need to be specific, so the GetItem() methods have overloads allowing to specify language and version:

Item item = Context.Database.GetItem("/some/path", Language.Parse("en"), Version.Parse(2));

Items can also come from different databases. Notice that I have been using the context database in the above examples, which depends on the current site and Sitecore configuration.

To identify an item, or rather a version, in a unique way, Sitecore has an ItemUri class. ItemUri is an ID or path, language, version and database name bundled together, as well as a number of convenience methods. This is how it looks like:

// get the item URI
ItemUri uri = Context.Item.Uri;

// string representation
string uriString = uri.ToString() -> "sitecore://master/{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}?lang=en&ver=1"

// parsing a string
uri = ItemUri.Parse(uriString);

// get an item by URI. Static Database.GetItem method can be used because URI includes database name.
Item item = Database.GetItem(uri);

There is a reason why paths or IDs remain most common ways to reference an item - usually it is a good thing that code adapts to current context and configuration. For some less typical Sitecore tasks, URIs can be handy.

Wednesday, January 14, 2009 1:07:50 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore
 Thursday, December 18, 2008

Presentation Usage ReporterA new project by Alenka Caserman: Presentation Usage Reporter integrates in Content Editor and shows where your presenation components, such as renderings and sublayouts, are used.

Thursday, December 18, 2008 9:27:30 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Open Source
 Tuesday, December 09, 2008

Changelog:

  1. Fixed: Installation wizard didn’t install files marked to skip if exists.

  2. Fixed: XSL renderings might fail occasionally under high server load.

  3. Fixed: Creator-Owner role might be ignored when resolving access rights.

Download.

Tuesday, December 09, 2008 6:13:12 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
 Saturday, November 15, 2008

This post continues the series about the new field editing infrastructure introduced in Sitecore 6: I’ve talked about the renderField pipeline, and how you should be using renderField from .NET. Today is the example day.

Let’s start with links. You can put sc:Link control directly on the aspx page:

<sc:Link Field="Link" runat="server" />

This is a minimum set of parameters – you need to specify the field name at least. The control will use context item to get the field value. If you need any other item, you can use Datasource property in a declarative manner:

<sc:Link Field="Link" DataSource="/sitecore/content/home" runat="server" />

To change the text of the link, you can use the Text property, but Link control is also able to render embedded content:

<sc:Link Field="Link" DataSource="/sitecore/content/home" runat="server">
  Link text
</sc:Link>

And of course  it can render child controls:

<sc:Link Field="Link" DataSource="/sitecore/content/home" runat="server">
  <sc:Image MaxWidth="200" MaxHeight="200" Field="Image" runat="server" />
</sc:Link>

The same using C#:

var link = new Link {Field = "Link", Item = Sitecore.Context.Database.GetItem(someId)};
var image = new Sitecore.Web.UI.WebControls.Image {Field = "Image", MaxWidth = 200, MaxHeight = 200};
link.Controls.Add(image);

MainPanel.Controls.Add(link);

Notice that controls also have the Item property. The difference between Item and DataSource is that one is designed for API use and accepts Item class, and the other is designed for declarative use and accepts strings.

All of the examples above support Page Editor, including the image nested inside link.

Saturday, November 15, 2008 4:19:55 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
 Monday, November 03, 2008

I’m starting on twitter at http://twitter.com/a_rusakov – I’ll experiment with format and content, but the primary focus is still Sitecore and everything related to it. It will not interfere with this blog, but hopefully supplement it in a useful way.

Twitter is a micro blogging platform, most known for limiting the length of one message (“update” or “tweet”) to 140 symbols, which dictates its own format. However twitter has also grown to a social platform with its unique flavor, supporting public conversations.

If you don’t want to use twitter but would still like to subscribe to (“follow”) my updates, you can use RSS.

Monday, November 03, 2008 12:39:04 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Personal | Sitecore
 Sunday, November 02, 2008

Sitecore 6 Update 6 is released, and the only fix is the support for uploading files with Flash 10 installed.

Download.

A little bit of insight: you probably heard that Adobe has introduced a new “security” rule in Flash 10 that says that Open file dialog can only be shown in a response to user interaction in flash. The rule effectively broke all javascript/flash uploaders, including the one we’ve used. The simplest hack around that rule is to overlay your HTML UI with a transparent flash object, and the updated flash-10-supporting libraries allow this overlay to be created using javascript.

As a positive side effect of having to redo the upload UI, uploading from media folder should open somewhat faster now. I’ve also switched our underlying library from SWFupload to YUIupload, which seemed like a better supported project.

Sunday, November 02, 2008 1:12:35 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Web development
 Wednesday, October 22, 2008

We’ve released a major overhaul of the poll module. Improvements:

  • Sitecore 6 support, including using Page Editor to modify existing polls
  • New polls can be added using Sitecore 6 Page Editor
  • Staging support
  • AJAX voting
  • Fully automated installation
  • Simplified architecture: the module no longer uses an additional database, which also allowed us to completely remove the settings application
  • Better looks
  • Easier customization: we’re using more xhtml and css, and less tables. Instead of c# webcontrol code, we’re using an ascx sublayout that is much easier to tweak without having to compile the code
  • Refactored code and reviewed design

The Poll module is part of Sitecore shared source program, and it stays that way. However we’ve dedicated our QA and development to reshape the module and release a clean and well tested Sitecore 6 version. We used the same open svn/trac server for entire development process, and you can see change history.

From now on, the module continues its life as a shared source component, meaning that you can (and very welcome to) contribute. I was doing product management type of work on the project, while Michael Baranov gets all the praise for beautifying the code.

My favorite feature is the ability to add new polls directly through the Sitecore 6 Page Editor.

1. Click “Insert Poll”

image

2. Setup poll using a pop-up wizard
image

3. Select a placeholder

image

4. Done.

You can also edit existing polls from the Page Editor:

image

Content layout is changed, so that you’re no longer required to store all polls in a single location. This setup beautifully supports multisite solutions.

image

And bugs, lots of bugs were fixed:

image

 

Hope you like the update. Downloads, documentation and source code are all available at http://trac.sitecore.net/Poll.

Wednesday, October 22, 2008 5:13:12 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Open Source
 Friday, October 17, 2008

Changes:

Issues fixed:

  1. Fixed: Cross site links were not working as expected. Such links now include the hostname of the target site and are generated relative to the start item of the target site. This functionality can be disabled by setting Rendering.SiteResolving to “false” in the web.config file.

  2. Fixed: a selected Publishing Target of an item was not taken into account when performing Publish operations.

  3. Fixed: The performance of item creation has been significantly improved.

New features:

  1. The FastQueryDescendantsDisabled setting has been added to the web.config file. It may be set to true to disable the ability to use fast query to select items through Ancestors/Descendants axes. This will give a small performance increase of item creation/moving/deletion.

 

Download.

Friday, October 17, 2008 10:12:02 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Thursday, October 16, 2008

Adobe released Flash player version 10 that breaks uploading in Sitecore.

We’re working on a solution,  do not upgrade to Flash 10 if you can. Another option is to set Upload.Classic = “true” option in web.config – this will replace Sitecore 6 upload with the one used in Sitecore 5, which doesn’t rely on flash.

Thursday, October 16, 2008 1:05:11 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Tuesday, October 14, 2008
Getting sublayout parameters in Sitecore 5

One of the popular questions about Sitecore is how to get sublayout parameters. Sitecore 5 way of doing that involves advanced API – parsing layout definition for the current item, finding the rendering item, etc.

Sitecore 6 makes this simple enough to remember – the parameter string is stored as a “sc_parameters” attribute of the sublayout.

string rawParameters = Attributes[“sc_parameters”];
NameValueCollection parameters = Sitecore.Web.WebUtil.ParseUrlParameters(rawParameters);

Tuesday, October 14, 2008 1:07:29 PM (FLE Standard Time, UTC+02:00)  #    Comments [5]
Sitecore | Crestone
 Thursday, October 09, 2008

Today I’ll go with the example suggested by Lars. Suppose we’re implementing a new money field type to store both the numeric amount and the currency (229 US Dollars). Both bits of information are stored in a single field using XML, which is a typical approach for Sitecore.

I’ll skip the whole implementing a new field type part (no need to repeat SDN); lets say that the Sitecore Client part is already implemented, and editors are able to use the Content Editor to change field value.

One problem remains – how to output money values on the website? The field contains XML, so we can’t just do sc:fld(‘money’, .). Different currencies have different signs which can go before or after the amount, which makes non-trivial rendering logic. The typical Sitecore 5 solution would be to implement a new XSL extension method and/or .NET web control.

In Sitecore 6, however, you can use the renderField pipeline to make existing rendering methods properly render custom field types.

Once again, this is a clean renderField pipeline:

<renderField>
  <processor type="Sitecore.Pipelines.RenderField.GetFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.ExpandLinks, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.GetImageFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.GetLinkFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.GetInternalLinkFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.GetMemoFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.GetDateFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.AddBeforeAndAfterValues, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.RenderWebEditing, Sitecore.Kernel"/>
</renderField>

Most processors are responsible for rendering specific field types, plus there are some additional processors supporting Sitecore architecture.

Following the naming convention, we’ll create a new GetMoneyFieldValue processor and place it after all Get* processors, but before the AddBeforeAndAfterValues:

  <processor type="Sitecore.Pipelines.RenderField.GetDateFieldValue, Sitecore.Kernel"/>
  <processor type="Money.GetMoneyFieldValue, Money" />
  <processor type="Sitecore.Pipelines.RenderField.AddBeforeAndAfterValues, Sitecore.Kernel"/>

The processor responsibility is to render HTML. I’m assuming that money field contains the following XML: <money currency=”USD” amount=”229.99” />

public class GetMoneyFieldValue {
  public void Process(RenderFieldArgs args) {
    if (args.FieldTypeKey != "money") {
      return;
    }

    var doc = new XmlDocument();
    doc.LoadXml(args.FieldValue);

    string currency = doc.DocumentElement.GetAttribute("currency");
    string amount = doc.DocumentElement.GetAttribute("amount");

    string result = string.Empty;

    if (currency == "USD") {
      result = "$" + amount;
    }
    else if (currency == "DKK") {
      result = amount + " kr.";
    }

    args.Result.FirstPart = result;
  }
}

First, and most importantly, the processor has to check the type of the field being rendered. It’s only supposed to render money fields and ignore everything else. Then we retrieve the field value – notice the FieldValue property. The value is parsed, and depending on the currency we nicely render the monetary amount of either American dollars or Danish kroner. The result is stored in args.Result.FirstPart - money field is not supposed to be able to wrap other values, so nevermind the LastPart.

Why Bother?

Implementing the above processor gives website developers the ability to use standard Sitecore field rendering methods to properly render money fields. Developers can do sc:field(‘money’, .) or use the FieldRenderer class and never have a second thought.

Thursday, October 09, 2008 10:57:00 PM (FLE Standard Time, UTC+02:00)  #    Comments [5]
Sitecore | Crestone
 Thursday, September 18, 2008

FieldRenderer control being added to the page using the Sitecore Page DesignerIn the last post I’ve mentioned the new ways of rendering fields using .NET code using web controls. Today I’ll focus on them more closely.

The purpose for introducing these controls is two-fold: to allow .NET developers enjoy the same simplicity of rendering various Sitecore field types available in the XSL world, and to support the Page Editor.

The most notable addition is the Sitecore.Web.UI.WebControls.FieldRenderer web control. This is basically a renderField pipeline wrapped in a web control form. You need to at least specify the field name and the control will do the rest. Optional parameters include the context item, html to render before and after the field and additional parameters. Another useful thing about FieldRenderer is that it’s also registered as a web control rendering in Sitecore, which allows power users to output different field types right from the Page Designer.

The same FieldRenderer class also contains a static shortcut render method: Render(Item item, string fieldName [, string parameters]): string. This is the easiest way to render a field – use it when having web control is not desirable, and you’d rather just get result as a string.

Along with FieldRenderer we’ve also introduced a number of web controls tailored to render specific field types:

Sitecore.Web.UI.WebControls.Date
Sitecore.Web.UI.WebControls.Image
Sitecore.Web.UI.WebControls.Link
Sitecore.Web.UI.WebControls.Text

The benefit of these controls is that they provide strongly typed properties, similar to the ones available in their XSL counterparts. For example the Image web control has Alt, MaxHeight and MaxWidth properties. If you want to use these controls but still just get a string as a result, use the Sitecore.Web.HtmlUtil.RenderControl(Control):string convenience method.

The most important thing to remember is that if you’re using .NET code to output field values, you have to use one of the above ways to support the Page Editor , because something like Response.Write(item[“FieldName”]) just won’t do it.

Thursday, September 18, 2008 6:45:29 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Crestone
 Monday, September 15, 2008

Sitecore’s renderField pipeline is a supporting pillar for the Page Editor. The pipeline ties together XSL and .NET field rendering code into one and provides a single place to affect how each field type (rich text, image, link) is rendered on the website.

It doesn’t matter if the field is being output using XSL extension methods (sc:field, sc:image), XSL controls (<sc:text />, <sc:image />) or the new family of .NET web controls (Sitecore.Web.UI.WebControls.FieldRenderer, Date, Image, etc) – the renderField pipeline is always the one that provides the actual output.

How does this support the Page Editor? Whenever a page is being run in the page editor mode, the renderField pipeline knows that and renders additional html/javascript around each field.

How is the pipeline useful to you? The ability to hook into a field rendering process and modify the look of any field on a website is a powerful feature. For example you could completely change the way some or all images are rendered, or merely postprocess the rich text fields, like in the following example. This pipeline would also interest implementers of new field types, because it’s now possible to teach standard output methods to render third party fields types.

The code below checks all links rendered as a part of the rich text field and adds the “external” CSS class to all external links. This can be useful to style external links differently, like using different colors or adding an icon next to them.

public class MarkExternalLinks {
  public void Process(RenderFieldArgs args) {
    if (args.FieldTypeKey != "html" && args.FieldTypeKey != "rich text") {
      return;
    }

    if (!args.Result.ToString().ToLower().Contains("<a")) {
      return;
    }

    var firstPart = new HtmlDocument();
    firstPart.LoadHtml(args.Result.FirstPart);
    MarkLinks(firstPart);
    args.Result.FirstPart = firstPart.DocumentNode.OuterHtml;
  }

  private void MarkLinks(HtmlDocument document) {
    var nodes = document.DocumentNode.SelectNodes("//a");
    if (nodes == null || nodes.Count == 0) {
      return;
    }

    foreach (var node in nodes) {
      if (node.GetAttributeValue("href", string.Empty).Contains("http")) {
        var className = node.GetAttributeValue("class", string.Empty);
        if (className.Length > 0) {
          className += " ";
        }

        className += "external";
        node.SetAttributeValue("class", className);
      }
    }
  }
}

OK, what happens here? First, the check for the field type is performed. This processor is only designed to alter the output of html and rich text fields. If the field contains any links, output is being processed using the Html Agility Pack. The rendered field is stored in args.Result. The reason for having both FirstPart and LastPart is to render fields that can have other content embedded in them, such as general link; rich text fields only have the FirstPart.

Now the processor needs to be placed in web.config. I’m putting it just before the RenderWebEditing processor, so that it doesn’t affect the additional links rendered to support Page Editor. It’s also important that it comes after the GetLinkFieldValue processor:

<renderField>
  <processor type="Sitecore.Pipelines.RenderField.GetFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.ExpandLinks, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.GetImageFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.GetLinkFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.GetInternalLinkFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.GetMemoFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.GetDateFieldValue, Sitecore.Kernel"/>
  <processor type="Sitecore.Pipelines.RenderField.AddBeforeAndAfterValues, Sitecore.Kernel"/>
  <processor type="Pipelines.MarkExternalLinks, Pipelines" />
  <processor type="Sitecore.Pipelines.RenderField.RenderWebEditing, Sitecore.Kernel"/>
</renderField>

Once again, here are the different ways of properly rendering a field:

  1. sc:field XSL extension method, and the family of field type specific methods such as the sc:image, sc:link, sc:date and so on
  2. XSL controls: <sc:text />, <sc:image />, <sc:date /> and so on
  3. The Sitecore.Web.UI.WebControls.FieldRenderer web control, and a family of field type specific web controls, such as Sitecore.Web.UI.WebControls.Image, Date, etc [new]
  4. The Sitecore.Web.UI.WebControls.FieldRenderer.Render() shortcut method. Use it when having the web control is not desirable, and you’d rather just have a string. [new]

It’s important to understand when the renderField pipeline is not used:

  1. sc:fld XSL extension method returns raw field value, bypassing the pipeline.
  2. Field values read using the Sitecore API (item[“FieldName”] or item.Fields[“FieldName”].Value) also return raw values.
  3. Any static html included in the aspx or ascs files is also not processed.

Consequently, these are also the ways of supporting the new Page Editor in Sitecore 6: as long as you output the field using any of the options from the first list so that the renderField is used, you’re automatically getting the full Page Editor support.

In the next post I’ll focus on the new FieldRenderer web control and the family of field controls, added to make rendering fields in .NET to be as easy as using XSL controls.

Monday, September 15, 2008 6:33:45 AM (FLE Standard Time, UTC+02:00)  #    Comments [1]
Sitecore | Crestone
 Monday, September 01, 2008

Sitecore CMS 6.0.0 Update rev.080820 is released: http://sdn5.sitecore.net/SDN5/Resources/Sitecore%206/Sitecore%206.0.aspx.

The most notable fix is .NET 3.5 Service Pack 1 compatibility.

Monday, September 01, 2008 9:36:19 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
ASP.NET | Sitecore | Crestone

Sitecore Content Editor shortcuts as revealed by Alt-F1 Sitecore comes with some keyboard shortcuts predefined. The purpose of this post is to compile a full list of these shortcuts and for a little extra, show how to define new ones.

Global Shortcuts

F9 – Publish
F2 – Expose (tiles all windows so that you can select the one you need)
Ctrl+/ – Focus in the startbar search

Content Editor Shortcuts

Tabs (hover over each tab to reveal the shortcut):

Alt+H – Home
Alt+N – Navigate
Alt+R – Review
Alt+P – Publish
Alt+V – Versions
Alt+C – Configure
Alt+E – Presentation
Alt+S – Security
Alt+I - View

Some ribbon commands have direct shortcuts. Most important one is Alt+F1, which reveals the shortcuts assigned to ribbon buttons:

F2 – Rename
F7 – Validation
F8 – Edit (Lock / Unlock)

Ctrl+S – Save
Ctrl+D – Duplicate

Ctrl+Shift+F – Launch the search application
Ctrl+Shift+Home – Move to the Home  item
Ctrl+Shift+Alt+L – Protect / Unprotect

Ctrl+Shift+Alt+Up – Sort Up
Ctrl+Shift+Alt+Down – Sort Down

Assigning New Ribbon Shortcuts

c83 keycode assigned to the Save command in the Content Editor ribbon Each item representing a ribbon button has a KeyCode field, accepting a shortcut string. How to build this shortcut string?

First, you need to know they keycode corresponding to each key. This is the code used by the javascript event model, and here you can find a list of these keycodes. Then, if Shift, Control or Alt buttons are involved in the shortcut, prepend the code with “s”, “c” and “a”  respectively.

Examples: Ctrl+S is translated into c83 - c for control, 83 for “s”. Ctrl+Shift+Alt+Down is sca40 – s for Shift, c for Control, a for Alt and 40 is the keycode for the down key.

As an exercise, lets assign a shortcut to start the page editor. Page Editor button belongs to the Publish chunk in the Content Editor ribbon. So switch to the core database, and go to the /sitecore/content/Applications/Content Editor/Ribbons/Chunks/Publish/Page Editor.

The shortcut I want for the Page Editor is Ctrl+Shift+E. This translates into sc69 shortcut string (s for Shift, c for Control and 69 is the keycode of “e”), so write “sc69” in the KeyCode field.

image

That’s it. Not only pressing Ctrl+Shift+E will start the page editor from now on, but pressing Alt+F1 will also reveal the shortcut along with the ones that came predefined with Sitecore.

Monday, September 01, 2008 6:52:17 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Tuesday, August 26, 2008

Sitecore installation wizard post stepI’m sure some people have noticed that the Sitecore Package Designer contains a “Post Step” field. How can that be used and what for?

The Post Step lets you input a method to be run after the package has been installed.

To make it work, you need a class that either already exists on the target Sitecore or is in the assembly that is installed with the package.

The class should implement Sitecore.Install.Framework.IPostStep interface that has a single RunPostStep(ITaskOutput output, NameValueCollection metaData) method.

Your code will run in the “shell” site. What’s more important, it will run in the background thread, so you cannot use the ClientResponse or SheerResponse methods. Instead, the output parameter provides a few basic methods of interaction, such as showing the alert box or a confirm dialog.

Below is a trivial example that renames the home item after the package installation:

public class Sitecore6Patch2 : IPostStep {
  public void Run(ITaskOutput output, NameValueCollection metaData) {
    var home = Context.ContentDatabase.GetItem("/sitecore/content/home");
    if (home != null) {
      home.Name = "Home upgraded";
    }
  }
}

 

Note: the above example is for Sitecore 6. In Sitecore 5, your class should have a parameterless RunPostStep method instead, which is also supported in Sitecore 6 for compatibility purposes.

Tuesday, August 26, 2008 2:01:27 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
 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
 Thursday, July 17, 2008

Search-driven navigation is getting more and more popular as amount of data increases and it gets harder to organize and access it using the traditional structured approach. I'm also a big fan of the application launchers, having tried most of the tools on the Scott Hanselman's list and then some. In fact, if you're not on Vista and don't use any of those, I highly recommend trying a few.

In Sitecore 6 we took a step in that direction, enhancing the UI with two large-scale search options.

Content Editor Search

Content Editor search sits right on top of the content tree. The simplest mode is the basic search:

 Sitecore 6 Content Editor search

All search results are grouped into categories. Some categories are contextual (subitems), most are based on items paths and some use item templates (like Jpeg image). Clicking the result moves the Content Editor to the selected item.

The search input can also be expanded to allow field-level search:

Field search in Sitecore 6 Content Editor

The new search has a few special abilities, being able to recognize item IDs and paths:

ID:
Searching for the item ID in Sitecore 6

Item path (a few variations of paths are supported, you can omit /sitecore or /sitecore/content):
Searching for the item path in Sitecore 6

Startbar Search

The familiar startbar search has also been upgraded, now operating in the live search mode:

Sitecore 6 starbar search: search in progres

Sitecore 6 starbar search showing the search results

To enable keyboard-only searches, there is a new global shortcut: press Ctrl-/ and the startbar search will get focused so you can start typing immediately.

Both searches operate using a new "Quick Search" index. If you don't get any results - rebuild the index using the same Rebuild the Search Index control panel applet.

The startbar search has a few extra abilities compared to the Content Editor, being able to launch applications, provide shortcut to the user editor and database switcher.

Application launcher (supports both traditional applications and control panel applets):
Application search in Sitecore 6 starbar

Users (the user name has to be an exact match, clicking the result opens the Edit User dialog):
User search in Sitecore 6 starbar

Databases:
Database search in Sitecore 6 starbar

The application launcher makes the search really handy in the developer scenario. In the deployed website the ability to search through content is likely to provide more value to the editors.

The geek beauty of the new search architecture is that it allows shell developers to hook in and provide own categorization, additional search results and implement new actions. In the following parts, I'll get to that.

 

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

Thursday, July 17, 2008 2:01:29 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
 Monday, July 14, 2008

Validation fixes are left for dessert. It's entirely possible to build great validation implementation into a site and never use fixes, but they make a perfect finishing touch.

Show me the Fixes

The setup: the Title field has a max length validator. If the field value is longer than 40 symbols, the validator displays an error even before the item is saved (no refresh required)

 Sitecore 6 max length validator shows an error because the field value is longer than 40 symbols

Now right click the red square in the validator bar:

"Trim" option appears after the validation error is right-clicked in Sitecore 6

Click "Trim" and the field value gets cut back to 40 symbols, and again - save operation is not required, content editor doesn't refresh.

The field value is cut to 40 symbols and validation error no longer appears

How to Make One

Now back to our business requirement: we need to make sure no one spells Sitecore as "SiteCore". In part 3 we made a validator that checks for this situation, but it's also fairly easy to fix the spelling without human involvement.

Step 1. Back to the validator definition at /sitecore/system/settings/validation rules/field rules. Under the validator item, create a new item based on the menu item template (as often, its easier to duplicate an existing fix, for example the one under the max length validator). There are two important fields to fill: Display Name and Message.

Field setup for Sitecore's validator fix

Step 2. Register the validator:fixsitecore command. This should be familiar if you do any Sitecore client development. Open then /App_Config/commands.config file and add a new command:

<command name="validator:fixsitecore" type="Validators.Actions.FixSitecore, Validators"/>

Step 3. The code. Similar to other client commands, but inherit from Sitecore.Shell.Framework.Commands.ContentEditor.Validators.ValidatorCommand. Key points are noted in the comments:

  public class FixSitecore : ValidatorCommand {
    public override void Execute(CommandContext context) {
      // gets the validator. use it to access validator parameters, if needed.
      var validator = GetValidator(context);
      if (validator == null) {
        return;
      }

      // get the field web control that we want to interact this. This really
      // depends on the way the content editor field is implement. Remember
      // that we deal with a simple single-line text field in this example.
      var rawControl = GetControlToValidate(validator);
      if (rawControl == null) {
        return;
      }
      var control = rawControl as Sitecore.Web.UI.HtmlControls.Control;
      if (control == null) {
        return;
      }

      // The actual fix logic
      control.Value = control.Value.Replace("SiteCore", "Sitecore");

      // Re-run the validation, so that red light turns to green in the UI.
      Validate();
    }
  }

 

The hardest part is having to deal with asp.net control structure. We cannot provide the familiar Sitecore item and field API here because validator bar validation runs in real time before the item is saved. This means that the field value might not even exist in the database, and is only available on the UI level.

This means that most fixes are tied to the field implementation. Changing the text field value is fairly easy. To do the same for the rich-text field, a different approach is required: javascript is probably the way to go, because rich text field embeds editor in an iframe.

Step 4. The result:

'Fix capitalization' option appears if 'Sitecore' is capitalized in a wrong way

Summary

While not all validation fixes are straight-forward to implement, they can provide that finishing touch you need for a perfect validation system or a great demonstration.

This concludes the series of posts about new validation features implemented in Sitecore 6, hope you can put it to a good use soon.

Part 1: Introduction, configuration, validation types.
Part 2: Error levels, built-in validators.
Part 3: Making a custom validator.
Part 4: Making a validator fix action.

Monday, July 14, 2008 5:34:07 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
 Friday, July 04, 2008

Today we're building a custom field validator. The business requirement will be simple: a lot of people at Sitecore get upset when Sitecore is spelled as "SiteCore" (oh, the joy of rebranding). We'll be making a validator to detect the incorrect capitalization and make sure items containing such atrocity never get published.

The Code

Start with the code. Here's what you should keep in mind:

  1. The class should inherit from Sitecore.Data.Validators.StandardValidator.
  2. The validator should be serializable: notice the [Serializable] attribute and serialization-supporting constructor.
  3. Evaluate() method is responsible for the actual validation. The field value is available through the ControlValidationValue property. Return ValidationResult.Valid if no errors are found.
  4. If there are errors, use the Text property to set the human-readable error description, and GetFailedResult method to return the default error value. This will allow solution architects to override the error level later (I've covered this in part 2).
  5. Use the GetMaxValidatorResult method to return the maximum error level the validator can result in. Sitecore needs this to decide if your validator can potentially block a UI operation and therefore it must wait for validator to execute before the operation starts.

Now to the code:

  [Serializable]
  public class FieldValidator : StandardValidator {
    public override string Name {
      get {
        return "Sitecore capitalization validator";
      }
    }

    public FieldValidator() {}

    public FieldValidator(SerializationInfo info, StreamingContext context) : base(info, context) {}

    protected override ValidatorResult Evaluate() {
      var value = ControlValidationValue;

      if (string.IsNullOrEmpty(value)) {
        return ValidatorResult.Valid;
      }

      if (value.Contains("SiteCore")) {
        Text = "Invalid 'Sitecore' capitalization";
        return GetFailedResult(ValidatorResult.Error);
      }

      return ValidatorResult.Valid;
    }

    protected override ValidatorResult GetMaxValidatorResult() {
      return GetFailedResult(ValidatorResult.Error);
    }
  }

Registering the Validator in Sitecore

Once the validator is ready, the next step is to let Sitecore know about it. Open the /sitecore/system/settings/validation rules/field validators, create a new item using the Validation Rule template, and fill in the type field:

image

Now we need to setup when and where the validator should execute.

In this case we don't have to consider performance because the validation logic is simple, and we do want the validator to block workflows. So we'll enable this validator for all four scenarios for all single-line text and rich text fields in the system.

Open the /sitecore/system/settings/validation rules/field validators/field types and find the item named Rich Text.

The Rich Text will already have a number of rules set up - these are the default validations. Add the validator you've created to all of the four fields, that is the Quick Action Bar, Validate Button, Validator Bar and Workflow:

image

for single-line text fields (the new name for old text field) repeat the same, but you'll also need to create the Single-line text field under the field rules, because no global validators are setup for this field type by default. You can simply duplicate any existing item and remove all validators.

Action!

We're done, "SiteCore" no more:

image

Reusability

For a little extra reusability, this validator can easily be made configurable.

Step 1: go back to the validator definition (at /sitecore/system/settings/validation rules/field validators), and add the parameter specifying the word the validator should look for:

image

Step 2: update the code.

      var pattern = Parameters["Find"];
      if (value.Contains(pattern)) {
        Text = "Invalid capitalization";
        return GetFailedResult(ValidatorResult.Error);
      }

 

Notice the usage of Parameters dictionary instead of the hardcoded value. That's it.

Next

I promise, next part will be the last, and we'll build an action that fixes the errors automatically in the single-line text field.

 

This post is a part of series about new validation features introduced in Sitecore 6:

Part 1: Introduction, configuration, validation types.
Part 2: Error levels, built-in validators.
Part 3: Making a custom validator.
Part 4: Making a validator fix action.

Friday, July 04, 2008 3:40:40 PM (FLE Standard Time, UTC+02:00)  #    Comments [1]
Sitecore | Crestone
 Thursday, July 03, 2008

Error Levels

So apart from lighting up the red lights in the user interface, how does the validation affect the content flow?

Each validator evaluates to one of the following error levels:

Unknown
Valid
Suggestion
Warning
Error
Critical Error
Fatal Error


Suggestion and Warning display colored hints in the UI but never prevent users from completing their tasks:
image

Error prevents the item from changing the workflow state (see part 1 of this article), but like a lot of other details, this is a default that can be changed. Error level also displays scarier red markers in the UI:
image


Critical Error displays a modal warning whenever an item is being saved in the Content Editor. However it's up to editor to decide if she wants to proceed:
image

Fatal Error displays a warning and prevents the item from being saved:

image

 

Overriding the Default Error Level

As a solution architect or administrator, it's up to you to decide the level of error each validator should return.

Crestone ships with a Url Characters validator that displays a warning if the item name will have to be encoded in the URL. However you might be taking your URLs really seriously, and you want the Url Characters validator to result in a Critial Error, to make sure that editors get an in-your-face warning and the item cannot get to the final state of the workflow.

Url Characters is an item-level validator, which means it's registered at /sitecore/system/settings/validation rules/item validators. To change the error level, add the Result=CriticalError parameter to the parameters field:

image

 

Some validators allow further configuration: maximum length validator defaults to 40 characters, but you can change that using the same parameters field.

Built-in Validators

Sitecore 6 ships with a number of item and field validators you can use:

Item validators
Broken Links – Checks the item for broken links.
Duplicate Name - Checks that the item name is unique among siblings.
Full Page XHtml – Renders the entire page and validates against local XHTML schema.
Media Size Too Big – Checks if media is too big to load in memory or store in the database.
Url Characters - Checks if an item name contains characters that must be escaped in URLs.

Field validators
Broken Links - Checks if a field contains broken links.
Is Email, Is Integer - Checks if a field contains an email address or an integer value.
Is XHtml – Validates field XHTML against a local schema.
Max Length 40 - Checks if a field contains a value of 40 or less characters (limit can be changed)
Rating 1 to 9 - Checks if a field contains a value between 1 and 9.
Required - Checks if a field contains a value.
Spellcheck - Checks spelling using the RAD Editor spell check validation, also used in the Rich Text editor.
W3C XHtml Validation - Validates the field HTML using the remote W3C validation service.

System field validators
Alt Required - Checks that the alt text is filled in on the media item.
Extension May Not Start with a Dot - Checks that the media file extension does not start with a dot.
Extern Link Target – Checks that external links open in a new window.
Image Has Alt Text - Checks the image field has alt text set.
Image Has Alt Text from Media Library - Checks if the media item has default alt text.
Image Size - Checks the size for the images referenced through image fields.
Rich Text Image Size - Checks the image dimensions for the images included in the rich text fields, i.e. if the image is too big to look good in the site design.

 

In part 3 I'll show how to build a validator of your own.

 

This post is a part of series about new validation features introduced in Sitecore 6:

Part 1: Introduction, configuration, validation types.
Part 2: Error levels, built-in validators.
Part 3: Making a custom validator.
Part 4: Making a validator fix action.

Thursday, July 03, 2008 11:29:57 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
 Wednesday, July 02, 2008

Validation received a major upgrade in Crestone, going from regular expressions firing up when the item is saved, to a powerful setup of validator classes running at different stages and providing UI feedback through different means.

Configuration

Validators are configured in a new content tree location in the master database:

/sitecore/system/settings/Validation Rules
image

Field Rules and Item Rules folders define available validators, and Field Types and Global rules configure the validators to be run for all items and fields of given field type.

In addition to the global configuration, it's possible to add validators for individual items and fields.

For items, there are four new fields in standard template, grouped in the new Validation section. As usual, the best practice is to only change these at template level and use standard values to propagate data to individual items.

For fields, "template field" template also has four additional fields that allow validators to be added at field configuration level.

So the formula is:

Item validators = Global Rules + Validators defined on the item itself using new standard template fields
Field validators = Field Types rules (matched by the field type) + rules defined on the template field.

Whichever strategy you use to configure validation, you'll always have to deal with these four treelist fields:

image

Validation Types

So what are these? Quick Action Bar, Validate Button, Validator Bar and Workflow represent four distinct sets of validations you can define for each item and field:

image

Validator Bar is the most powerful validation device. Notice the red marker to the left of the field - it indicates that the field contains an error. Hovering over the bar will display a tooltip with the error message returned by the validator. Validator bar to the right of the Content Editor duplicates this information, providing validation summary for the entire item and all of its fields.

Important: Validators configured to run in the validator bar are updated in the real time. As soon as you stop editing the field, the validators will be run asynchronously in background, and the UI will be updated.

Quick Action Bar (left) is another Content Editor upgrade that displays status for each item visible in the tree and allows quick actions, such as check in, to be performed. Validation is turned off by default, so to enable it, you need to right click the Quick Action Bar and make sure that "Validation Rules" menu item is checked.

Validate Button represents a new Validation Results dialog, that displays the most detailed validation status for the current item:
image

Workflow defines the validators, which will be run when the item is moved from one workflow state to another. It's implemented with a new workflow action, which allows to define workflow states that should be guarded by the validation:

image

Item with significant validation errors will not be allowed to the next state. I'll show how define which errors are "significant" and what other effects they have in the UI in the following parts.

 

This post is a part of series about new validation features introduced in Sitecore 6:

Part 1: Introduction, configuration, validation types.
Part 2: Error levels, built-in validators.
Part 3: Making a custom validator.
Part 4: Making a validator fix action.

Wednesday, July 02, 2008 9:56:46 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
 Tuesday, July 01, 2008

Sitecore 6 is out, phew.

New features? See for yourself: What's new (PDF, 35 pages), Download, Product page.

For me this sums up 10 months on the user interface side of development, and I'm looking forward to seeing people use and abuse, complain and praise what we have done.

Tuesday, July 01, 2008 9:21:50 AM (FLE Standard Time, UTC+02:00)  #    Comments [1]
Personal | Sitecore | Crestone
 Monday, June 23, 2008

Fast Query is an exciting Crestone feature that is usually off the marketing radar. It is a subset of Sitecore Query that executes with SQL speed, meaning fast.

While it's not as expressive as Sitecore Query, you can still retrieve items using item paths, IDs or names, field values and parent/child relationships, which is what people need 80% of the time. The performance gain is outstanding - think writing an SQL query instead of going through all the items using the Sitecore API.

How to Use the Fast Query?

Much like standard Sitecore Query before, you can use Fast Query either in field sources or in the API. To indicate that that your query must be executed in the "fast" mode, prefix it with "fast:" :

image

The API way:

Sitecore.Context.ContentDatabase.SelectItems("fast:/sitecore/content/home/*");

Note that relative queries starting from a specific item are not supported, you cannot use fast query in item.Axes.SelectItems.

So What Queries are Supported?

  • Only child and descendant axes are supported. For example you cannot search for a parent of a specific item or following-sibling.
  • The following special attributes are supported: @@id, @@name, @@templateid, @@masterid and @@parentid.
  • String comparison is converted to SQL LIKE operator.
  • Functions are not supported, contains() is replaced by string comparison which behaves like SQL LIKE.
  • Subqueries are not supported. i.e. the following query won't work: //*[../@name='Home']
  • It is not possible to query from a context item, only the whole database.

(More on query syntax in the original Crestone beta forum post by Dmitry Kostenko)

How to Test?

The XPath Builder works great with Fast Query. Open Developer Center, select Tools menu and then XPath Builder. Remember to prefix your queries with "fast:":

image

Performance

XPath Builder actually shows how much time it spent executing the query, so we can see the difference the fast query makes:

Switch the XPath Builder to the core database (it's much bigger than the master in a clean Sitecore installation).

fast://*[@@name = 'Home'] takes 1-2ms.

//*[@@name = 'Home']  takes 350-500ms after the first couple of runs.

New Usage Scenarios

Fast Query enables scenarios that weren't possible before because of the query speed:

In Sitecore 5 we have a shared source "My Locked Items" module that has to use caching and subsequently cache invalidation to get a list of items locked by the user with a decent performance.

In Crestone we have a built-in Locked Items application, that does pretty much the same but was trivial to make, because all it has to do to get the list of items locked by the user is to run the following query:

Database.SelectItems("fast://*[@__lock='%sitecore\\Admin%']"

The Crestone version of the RSS module will also use the fast query to retrieve items while building the feed, which will hopefully make generating feeds per-demand more feasible.

Summary

It doesn't get much simpler: the new query is fast, use it to make your sites more responsive or to provide better features which you couldn't implement before.

 

Update: As of June 14th, 2008, the fast query is considered an experimental feature in Sitecore 6.0. It's recommended that you test the results of the query first - in some situations it's possible that queries relying on parent-child relationships can return results that are slightly out of date. This is likely to be fixed in the following versions of Sitecore.

Monday, June 23, 2008 4:29:36 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Crestone
 Thursday, June 12, 2008

After the Carousel, Slider and Visual list field types, I've decided to take a pause to work on the  quality and make an actual release. This includes all of the housekeeping well-behaved Sitecore fields should do, bugfixes (thanks for the feedback, really) and documentation.

What's changed:

  • Carousel and Visual list can be used outside of the media library. They will default to using the content item icon, but it's also possible (and expected) to supply an image field name to take the image from. Same works for item titles. See the documentation for configuration examples
  • All fields now properly indicate their changed state to Sitecore, which results in timely "Do you want to save the item" prompts
  • All fields also support readonly state - if the item is protected, or the user does not have write permissions, the field will be rendered in readonly state ("grayed out")
  • Carousel and Visual list fields support link checking
  • Production and Items Only (development) packages and package projects are included.

It's time to call it a Beta - see the Field Types trac site for downloads.

The goal is to apply more polish and make a quality release when the time Crestone ships, so that the fields can be used right away.

Some tickets are already piling up for the next release. If you have ideas for new field types - send them in, or contribute.

Thursday, June 12, 2008 12:51:46 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone | Open Source
 Sunday, May 25, 2008

RSS module trunk is shaped up to support Crestone. The module no longer requires web.config to be modified after the installation, packages are updated, and the project structure is changed to match rest of the modules more closely.

After some surface testing the module appears to work fine on Crestone, the updated Crestone beta should do.

Trunk development has moved to Crestone;  Visual Studio 2008 is required to work with the project. Use Sitecore5 branch for the stable Sitecore 5.3.x version.

From the feedback, accumulated during the module lifetime, these are the goals I see for the next version:

  • Update the module to work with Crestone (almost there, needs more testing)
  • Simplify feed creation, configuration and troubleshooting - ease of use.
  • Add more extensibility points, to allow partners to better fit the module to their needs without modifying the module itself.

What do you think?

As always, packages, source code and updates are available at the trac site.

Sunday, May 25, 2008 8:11:00 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone | Open Source
 Saturday, May 24, 2008

Another field type is up and running: introducing Visual List, allowing to maintain a list of images (or any items, in future) in a very simple and visual way. The field allows editors to select any number of images from a specified source, and supports drag-and-drop reordering.

Good usage scenarios for this fields include maintaining a list of banners to rotate on the page, a list of product images, etc. An advantage over using a set of subitems to achieve the same functionality is editor experience: no not having to switch items saves a lot of editing time, and its easy to see all selected items at once.

visuallist

The Outercore fieldtypes project, which now includes Carousel, Slider and Visuallist fields, has moved to Sitecore shared source repository, so no more download links in the blog.

Use the project trac site to view or update the documentation, download the source, file tickets or watch the updates. I'll continue to post update summaries in the blog.

Bug reports, new field type ideas are welcome.

Contributors are most welcome, of course, mail me to become one.

Saturday, May 24, 2008 4:35:58 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone | Open Source
 Saturday, May 17, 2008

The Crestone beta update was made available on Friday (requires beta forum access).

Apart from numerous fixes and tweaks, it should be able to run both Carousel and Slider fields.

Have fun, and let us know how it feels.

Saturday, May 17, 2008 1:23:53 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Crestone
 Wednesday, May 14, 2008

Continuing with additional field types for Sitecore: introducing Slider.

Slider is a fairly simple control, that currently only supports numeric values. To set up the field, you need to define minimum and maximum values, and an optional list of allowed values.

Here is what you get with Source= Min=0&Max=200&Values=1, 5, 10, 15, 25, 35, 100, 200

image


(if you're reading this through rss reader, you might not see the flash movie above)
 
The field shares the same project with the Carousel, named Outercore Fieldtypes. It also requires Crestone and will not run on the beta build. I'm still putting the updated package online, which also includes Carousel fixes, just in case.
 
Download package (includes source code). Use FieldTypes Trac site for downloads.
Wednesday, May 14, 2008 12:38:46 AM (FLE Standard Time, UTC+02:00)  #    Comments [3]
Sitecore | Open Source
 Tuesday, May 13, 2008

I've pushed RSS module updates to the shared source repository. These are some small tweaks that were made after the latest release (i.e. what is available on the SDN). From commit logs:

  • Scheduled command to update RSS feeds in database
  • Ability to use $(dataFolder) macro when defining disk location for xml feed
  • Fixed bug with dates not being converted to UTC, which is required for ToString("r") to work properly
  • Added 'Date Field' field - possibility to specify which field should be used to get the publication date of the item

Future plans include conversion to Crestone and Visual Studio 2008, and some Crestone-specific tweaks.

Tuesday, May 13, 2008 10:46:13 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Open Source
 Monday, May 12, 2008

A little weekend project to add more field types to Sitecore's arsenal: introducing Carousel.

What you hopefully see below (once the flash loads) is a "Carousel" field type, with a source set to a media library folder. User can select one of the thumbnails, or, if there are more items than can be fit in the available space, scroll to see more . The field value is an ID of the selected item, as you would expect.

 
Possible enhancements include multi-selection support, ability to work with regular (non-media) content items, better customization (how to get image and text) - the feedback is welcome.
 
The field requires Crestone and will hopefully run on the beta build. It's in a rough alpha shape, only tested in IE7, but hey, the CMS is in beta too. Ideally I'd like to move it to our shared source repository once it matures a little.

Download package (includes source code). Use FieldTypes Trac site for downloads.
Monday, May 12, 2008 1:05:55 AM (FLE Standard Time, UTC+02:00)  #    Comments [3]
Sitecore | Open Source
 Friday, January 25, 2008

“Haml is a markup language that‘s used to cleanly and simply describe the XHTML of any web document, without the use of inline code. Haml functions as a replacement for inline page templating systems such as PHP, ERB, and ASP. However, Haml avoids the need for explicitly coding XHTML into the template, because it is actually an abstract description of the XHTML, with some code to generate dynamic content.”

Basically Haml is a domain specific language for XHTML. Unlike Velocity, which can be used to output any text data, Haml focuses entirely on xhtml output — and does it well.

Instead of:

  
<h2><%= ViewData.CategoryName %></h2>
<ul>
    <% foreach (var product in ViewData.Products) { %>
      <li>
        <%= product.ProductName %>
        <div class="editlink">
          (<%= Html.ActionLink("Edit", new { Action="Edit", ID=product.ProductID })%>>
        </div>
      
    <% } %>
  </li></ul>
  <%= Html.ActionLink("Add New Product", new { Action="New" }) %>

You can do this:

%h2= ViewData.CategoryName
%ul
  - foreach (var product in ViewData.Products)
    %li
      = product.ProductName 
      .editlink
        = Html.ActionLink("Edit", new { Action="Edit", ID=product.ProductID })
        = Html.ActionLink("Add New Product", new { Action="New" })

(It does look like python, doesn't it?)

Do we need it?

Andrew Peters has created a NHaml, .NET port of Haml made as an alternative view engine for ASP.NET MVC.

I assume it wouldn't be too hard to take it apart and create a Haml rendering type for Sitecore as a downloadable extension. Is this something you find interesting? I love its clarity and wrist-friendliness, and it should be much easier to type online using Developer Center or even Content Editor.

The downside is that you'd lose intellisense in visual studio, but personally I'm much more annoyed by visual studio trying to format my <% %> code the way it thinks i like it. And yes, it's yet another templating engine.

 

* Haml reference

Friday, January 25, 2008 5:52:07 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Web development
 Saturday, October 06, 2007

September has been a terrific month. Sitecore Ukraine is proud to have it's first intructor, certified for teaching both SCD1 and SCD2 level courses in English, Russian and Ukrainian - congratulations, Sergey!

Peter Johansson has joined Sitecore as a Solution Architect. You know Peter from the SDN forum and all the cool Sitecore things he has made before and after becoming a Sitecore MVP. In a lucky turn of events we've met here in Copenhagen - thanks for the beers, Peter, I owe you some.

And for me it's been a developer's dream - spending the month working with amazing people, discussing new ideas and getting the old ones to be heard. I am now allowed into the holy shrine of Sitecore, the source code repository, and that includes write access. Working on the core product is obviously very exciting.

This is also a chance to explore my new found passion: designing and building user interfaces that do not suck.

Saturday, October 06, 2007 12:10:12 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Personal | Sitecore
 Thursday, August 16, 2007

We have implemented a Single Sign-On system for SDN, SPN, Personal Portal and License System. It means that you only have to log in once on any of the sites to be able to access the rest. The side effect is that all remembered passwords are expired sooner than they usually do, which I hope is a minor inconvenience.

The solution behind it is very low-tech: by setting the cookie domain to ".sitecore.net" (note the leading dot) we can share the same cookie accross multiple subdomains.

Thursday, August 16, 2007 12:39:35 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Thursday, August 02, 2007

As Peter was first to notice, we have recently made available a preview edition of the Search Engine Optimization module. It's purpose is to help website maintainers and contributors to get insight into SEO related aspects of the site and avoid common errors. To achieve the goal in a very visual way, the module embeds inself in live pages, similar to Sitecore WebEdit.

The only limitation of the preview edition is that it expires on January 1st, 2008. It is of fairly solid beta quality and is avaiable for a download from SDN free of charge, along with documentation. The earlier version is also preinstalled in the latest SC Printers demo site (version 3.0.15)

We're especially interested in feedback at this stage - good or bad, drop us a note: mail to ar at sitecore net, leave a comment or discuss at SDN forum.

To continue with the visual theme, below is a short tour:

Page Information provides a 'big picture' overview.

Page Information tab - displays page title, url, keywords and highlights errors

 

Text Only View shows the page through the eyes of a search engine. Headings are stressed by larger font size, links are underlined and image alt texts are displayed in [square brackets].

Text Only View tab - shows page content like similar to text browsers

 

Keywords shows statistics on how often 1, 2 and 3 word combinations are used on the page. It also allows quick search for any of the combinations on major search engines.

Keywords tab showing statistics on keyword density

 

Headings, Images and Links list all respective elements found on the page, along with some quick information. Clicking on any element highlights it's actual position on the page.

Images tab, showing thumbnails of all three images found on a page along with alternate text, url and dimensions  

 

Errors are easy to spot. They show up on the overview tab and the respective element tab. The coolest part is that the element itself is marked as erroneous on the page itself. Hovering over error marker displays the error information tooltip. The module also checks for broken links and presents them in the same way.

 

Hope you like it. For more information, please refer to SDN documentation.

Thursday, August 02, 2007 5:14:21 PM (FLE Standard Time, UTC+02:00)  #    Comments [1]
Search Engine Optimization | Sitecore
 Monday, July 23, 2007

We've got a several reports about SDN5 being unresponsive, throwing Application Unavailable errors and having poor search quality in the last several days. From what it looks like, it's another windows update that became evil.

Symptoms: random "Application Unavailable" screens caused by worker pool restarts.

To diagnose the error, open the Event Viewer and look for the error below, following by a notice that asp.net was stopped unexpectedly:

EventType clr20r3, P1 aspnet_wp.exe, P2 2.0.50727.832, P3 461ef1db, P4 system.web, P5 2.0.0.0, P6 461ef1d2, P7 297c, P8 8d, P9 system.nullreferenceexception, P10 NIL.

The solution for me was to uninstall the Security Update for .NET Framework 2.0 (KB928365) and then repair the .net framework 2.0.

Unfortunately the update was pushed to fix a critical remote code execution vulnerability - so I'm not really happy with the solution, hope the new update is out soon. SDN5 runs on older Windows 2000, our newer Windows 2003 box is fine.

Found it by googling the error message, which lead me to the asp.net forum post regarding the KB928265 that also mentions that other possible issues. Internet is full of other fun ways this update breaks .net applications and reading through the reports is similar to browsing wikipedia - getting to the wet t-shirt contest page is only matter of time.

Technorati tags:

update: if you continue to see SDN fail with Application Unavailable - please let us know.

Monday, July 23, 2007 2:54:00 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Thursday, July 19, 2007

 If the title sounds like I've made yet another barely useable app, it's wrong. This is what you can do with Developer Center in Sitecore:

  1. Start Developer Center
  2. Close all portlets / pages
  3. Add Content Explorer (View -> Content Explorer). You might also choose to dock it according to your preferences.
  4. [optional] Open any number of Content Editors for items by double clicking on them in Content Explorer. Could be useful as a start items, if you edit them often but adds startup time.
  5. Window -> Save Workspace.
  6. Ta-da: next time you need it, open Developer Center and choose Window -> Restore Workspace. Use Content Explorer to open additional tabs, for any items in any of the databases:

developercenter

Fineprint: Cross database editing is not 100% perfect - some things will still work as if you haven't switched the database.

Thursday, July 19, 2007 1:19:51 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | 5.3 | Rich Text Editor
 Tuesday, July 17, 2007

contextual tab example - media tab is showing for all media itemsContextual tabs are the special ribbon tabs that are displayed only for specific item types. A good example is a Media tab which is displayed for all media items. Contextual tabs help reduce complexity and provide context-sensitive actions to the user.

I'll use our website as an example and will add a contextual tab to all partner items.

Designing the Ribbon

I'll design the ribbon first, which will be rather simple containing a single 'Open Website' button.

Note: It is essential to do this in the core database.

  1. Switch to the core database
  2. Open Content Editor and navigate to /sitecore/system/ribbons folder. I suggest that you create a subfolder and keep all your additions there for ease of future upgrades. I name the folder Website Contextual.
  3. Select New -> From Template and choose /templates/System/Ribbon/Toolbar template.
  4. Select the newly created item, then again New -> From Template and choose /templates/System/Ribbon/Strip template. Fill in header field (Partner)
  5. Repeat with /templates/System/Ribbon/Chunk template, also fill in header.
  6. Now create the item on /templates/System/Ribbon/Large Button template, fill in header, icon and click fields. The later defines the action to be performed on button click, by tying the button to a command. The template defines the look and behaviour of the ribbon element - in this case it will be a large button. After following these steps you should have the following setup:
    ribbon item setup

Adding the Ribbon to Content Items

When the ribbon is designed, it's time to setup content items to display it. In this example we're adding the ribbon to all partner items. Luckily for me, partners have own Partner template:

  1. Copy the ID of the Partner Toolbar item to the clipboard. Developer tab is super useful for this.
  2. Switch to the master database, navigate to the Partner template.
  3. Click "Standard Values" to edit standard values for Partner template. This will apply the changes we're making to all items on the partner template, including the ones that have already been created.
  4. In the View tab, make sure both Standard Fields and Raw Values are checked. Find the Ribbon field in the Appearance section and paste the ID you've copied in step 1:
    Ribbon field with ID set

Check if everything is set up correctly - refresh, select any item on the template (or the __StandardValues item) and you should see the contextual tab:

Partner tab showing up for __standard values item

The button doesn't do much, we'll fix that next.

Wiring up the Button

Last thing we're going to do is assigning action to a button - the example will open the partner website in a new window.

First, I create the following Command class:

namespace Sitecore.Website.Commands
{
   public class OpenWebsite : Command
   {
      public override void Execute(CommandContext context)
      {
         PartnerItem partner = context.Items[0];
         SheerResponse.Eval(string.Format("window.open('{0}', '_blank')", partner.Website.Url));
      }
   }
}

The Execute method gets the current item and then opens a partner website in a new window. What remains is to bind this class to "website:openwebsite" command which we assigned to the button.

Open /App_Config/commands.config file and add the following line:

<command name="website:openwebsite" type="Sitecore.Website.Commands.OpenWebsite,Sitecore.Website" />

Now it's all in place - restart and click the button to see it perform the action.

Design Considerations

When the new item is selected, the contextual tab will always be active instead of default one (Home). Be careful and do not overuse these - I'm not actually adding a tab to all partners only for the sake of 'Open Website' button, but it served well as an example.

If you do add the context tab, consider duplicating some most often commands from the Home tab. For example the Media tab repeats the Save button by using the 'Sticky Chunk' option on toolbar item:

image

Another option providing more control is using items of /templates/system/references template which provide "include" functionality for the ribbon.

 

Hope you find it helpful. Have any questions or requests to dig into these topics in greater detail - leave a comment or contact me: ar at sitecore net.

Tuesday, July 17, 2007 12:55:19 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Sheer UI
 Thursday, July 12, 2007

If you're lucky to have IIS6 serving your site, turning on the HTTP compression is a really easy way to decrease page loading times and cut bandwith. With compression enabled, web server can zip static and dynamic content before sending it over the wire. For this to happen the receiving side has to support compression too, as do all modern browsers.

There are two types of compression: static is essentially free. IIS will compress files on first request and store them on disk for future use, for minimal performance overhead. This works best for javascript and stylesheets. Dynamic compression allows .aspx output compressing; it's done on the fly and does add some CPU load. If processor isn't your bottleneck, enabling it is still a good idea.

For both types you need to define which file types should be compressed because the defaults are really lame: no css and no javascript.

On the new www.sitecore.net I've started with total frontpage load being 260kb and combining both compression types decreased it to 142kb. My favorite part is that prototype and scriptaculous (effects module only) javascript frameworks are 27kb total - at this point I refuse to take "prototype is too big" argument into consideration.

Useful links:

Thursday, July 12, 2007 6:11:50 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Web development
 Tuesday, July 10, 2007

imageLess than a year from the last update, we've flipped the switch on the new public website this weekend. I hope you like it and find it better than the old one.

While it's not a total overhaul, I think it ended up being a major change. What I like about it is increased friendliness - more whitespace, text is easier to read and navigation is improved.

Some technical facts: the site is running on Sitecore 5.3.1 rev.070515 in a live mode. We use a simple two step "editing - published" workflow instead of publishing to control item visibility.

Your comments and criticism are very welcome, especially since I'm lucky to have people much more experienced in building websites reading this blog.

Tuesday, July 10, 2007 9:43:02 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Web development
 Monday, June 25, 2007

We've talked about setting the device programmatically and when it can be handy. Another trick that goes in the same category is layout substitution. Say we're building a mobile version of the web site and we want exactly the same set of sublayouts and renderings as in the desktop version, but placed on a different layout so that renderings can be rearranged freely using the placeholders.

Similar to the device resolver, we build a custom layout resolver processor to customize Sitecore's httpRequestBegin pipeline with out logic. The flow here is simple: if visitor uses handheld device, switch to a predefined layout. 

public class LayoutResolver
{
if (IsMobileRequest())
{
  using (new SecurityDisabler())
  {
    LayoutItem mobileLayout = Context.Database.GetItem(ID.Parse("{C10DBF03-F810-40A9-8ACB-5354428CC6BF}"));
    if (mobileLayout != null)
    {
      Tracer.Info("Overriding layout to mobile layout");
        // Change the layout to mobile layout  
      Context.Page.FilePath = mobileLayout.FilePath;
     }
     else
    {
// writes error to Sitecore trace, visible in debug mode

       Tracer.Error("Mobile layout not found");
    }
    }
}
}

Make sure to place your layout resolver after the standard one, so that you override Sitecore's choice of layout and not vice versa:

<processor type="Sitecore.Pipelines.HttpRequest.LayoutResolver, Sitecore.Kernel" />
<!-- Sets mobile layout for requests from mobile devices -->
<processor type="Sitecore.Website.Pipelines.LayoutResolver, Sitecore.Website" />

Monday, June 25, 2007 1:21:40 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Friday, June 01, 2007

Set up a naming convention for common fields and follow it. If the item has a title field, name the field "title" - no need to get creative here.

By coming up with something smart like "office title", or "news-headline" you're dooming yourself (or worse - someone else) to write boring and totally unnecessary code:

<xsl:choose>
  <xsl:when test="sc:fld('office title', .)">
    <xsl:value-of select="sc:fld('office title')" />
  </xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="sc:fld('title')" />
  </xsl:otherwise>
</xsl:choose>

etc..

  • if you want editors to see a different field in the content editor, use the template field title, but make the internal field name follow the convention.
  • consider avoiding duplicate fields altogether by using template inheritance.
Friday, June 01, 2007 10:00:07 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Wednesday, May 16, 2007

Continuing on the settings you might want to know about, lets talk about the WebStylesheet:

<!-- WEB SITE STYLESHEET
CSS file for HTML content of Sitecore database.
The file pointed to by WebStylesheet setting is automatically included in Html and Rich Text fields.
By using it, you can make the content of HTML fields look the same as the actual Web Site
-->
<setting name="WebStylesheet" value="default.css" />

Having the preview mode is great, but it's better if rich text editor looks as close as possible to what visitors see on the live website.

For a quick fix, try pointing WebStylesheet to your main css file and see how it looks like. Depending on the styles, it might or might not be all you need to do. Sometimes styles depend on specific containers in html that are not there inside rich text editor: then you can create a simplified stylesheet that only includes styling for the basic elements such as eadings, paragraphs and some custom classes that your editors use.

Wednesday, May 16, 2007 9:07:20 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Tuesday, May 15, 2007

Neil Pullinger created a Sitecore google co-op search that searches through 18 Sitecore related sites, which is definitely a nice thing to have in your troubleshooting arsenal.

For better or worse there are three distinct places you would dig Sitecore gems from: SDN5 search, the evergrowing SDN5 forum search, and all of the public blogs that you can use this custom google search for.

Update: Jukka-Pekka Keisala mentions another Sitecore blog search made as a netvibes portlet.

Tuesday, May 15, 2007 9:48:05 AM (FLE Standard Time, UTC+02:00)  #    Comments [3]
Sitecore
 Friday, May 11, 2007

<!-- HTML EDITOR LINE BREAK
Specifies the tag that the HTML editor inserts on Enter. Values can be
"br", "div" and "p".
-->
<setting name="HtmlEditor.LineBreak" value="br" />

HtmlEditor.LinkBreak is one of those settings you should know about. By default it's set to 'br', which means that every time editor presses Enter in Sitecore Content Editor, a '<br />' tag is inserted.

I think it's wrong - isn't the enter button supposed to start a new paragraph? Changing the setting to "p" gets you there. Shift+enter, on the other hand, does the line break - here goes the <br /> tag.

Here is the difference between two; first, the default br setting:

Paragraph 1 [click enter]
<br />
Paragraph 2 [click enter]
<br />
..

Changing it to p:

<p>Paragraph 1 [click enter]</p>
<p>Paragraph 2 [click enter]</p>

It is semantic html, it feels right and is easier to style, even if you're not concerned with standard compliance. I wonder if there is still a compelling reason to keep having <br /> as a default?

Friday, May 11, 2007 9:48:27 AM (FLE Standard Time, UTC+02:00)  #    Comments [5]
Sitecore
 Thursday, April 12, 2007

Most methods in XslHelper are virtual, so it's possible to tweak the output of sc:something() functions and <sc:something /> controls in XSL renderings. To change the behaviour of all renderings in Sitecore solution, modify the sc xsl extension registration in web.config:

<xslExtensions>
  <extension mode="on" type="Sitecore.Xml.Xsl.XslHelper, Sitecore.Kernel" namespace="
http://www.sitecore.net/sc" singleInstance="true" />
  <extension mode="on" type="MyNamespace.MyClassDerivedFromXslHelper, MyAssembly" namespace="
http://www.sitecore.net/sc" singleInstance="true" />

To use the derived extension selectively, just register it as a new xsl extension.

Note that it's a fairly crude hack probably involving some string manipulation, but as such it can also help when other methods fail.

Wednesday, April 11, 2007 11:00:43 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | XSLT
 Thursday, April 05, 2007

Today's post shows how to add Default Layout to your Sitecore devices. This can be handy if you don't want to tediously update multiple templates / items just to configure the same layout for the new device over and over.

A good example of that is enabling RSS output for every item: it's natural to use a separate device/layout for that, but the layout is the same for all items in the solution. So instead of modifying templates and items, httpRequestBegin pipeline processor is used:

public class DefaultLayoutResolver
{
  private static readonly ID xmlLayoutID = ID.Parse("{8CF08867-5789-40CA-A0A4-01D059E50E11}");

  public void Process(HttpRequestArgs args)
  {
    if ((Context.Device != null) && (Context.Device.Name.ToLowerInvariant() == "xml") &&
     (Context.Item != null) && (Context.Item.Visualization.Layout == null))
    {
      LayoutItem layout = Context.Database.Items[xmlLayoutID];
      if (layout != null)
      {
        Context.Page.SetLayout(layout);
      }
    }
  }
}

Add the processor right after the standard Sitecore LayoutResolver processor, so that Sitecore configuration takes precedence.

The same code is reused in Printers Inc to output raw item XML. For more flexibility, you can add the "Default Layout" lookup field to a device template and modify the DefaultLayoutResolver to read that value.

Thursday, April 05, 2007 11:21:24 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Wednesday, April 04, 2007

Sitecore has two kinds of item XML representation, or flavors if you will.

Serializer XML is the heavyweight format, containing everything Sitecore needs to know to get the item from one solution and paste into other: all attributes, field values in all versions and languages. It is used by the packager.

To get serializer xml programmatically:

item.GetOuterXml(deep);

XSLT XML is the internal interpretation that is fed to XSL renderings (tranformations). This is the lightweight brother, containing only item attributes and field ids. No field values, only the current version and language. You would want to know how it looks like if you code XSL renderings.

To get XSLT xml programmatically:

ItemNavigator navigator = Factory.CreateItemNavigator(rootItem);
writer.Write(navigator.OuterXml);

 

In the next (3.0.13, soon to be released) version of demo site, we have added the option to output item XML in both flavors to demonstrate what it feels like:

http://<demositeurl>/?xml=    => Serializer XML flavor of the current item (no children)
http://<demositeurl>/?xml=&deep=true    => Serializer XML flavor of the current item and all descendants
http://<demositeurl>/?xml=&xslt=true    => XSLT XML flavor of the current item and all descendants (always 'deep')

Thanks to John West for the idea.

Wednesday, April 04, 2007 3:13:07 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Demo site | XSLT
 Tuesday, April 03, 2007

I'll probably be the last one to point out that the Sitecore 5.3.1 is out: check out Peter's series of posts on new features. What I can add is that our www.sitecore.net is also updated from the Sitecore 5.2 it was originally built on, the media content is moved to the database, all of the fancy stuff.

The migration went fairly painful, although I must admit it does help to have the mastermind of the whole migration framework sitting nearby. Thanks Sergey!

Tuesday, April 03, 2007 6:55:55 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | 5.3
 Wednesday, March 21, 2007

The Email Alert add-on allows the visitors of a web site to subscribe to different areas of interest and receive a notification when a certain article is updated.

Email alert will be included in the next build of the SC Printers Inc demo site, and below is the quick installation walkthrough. The module requires Sitecore MailingList to work, so I assume you have it working (i.e. the mails are sent out OK)

Install the package

Download and install the package, update configuration according to readme.

Define target groups

The package will install /sitecore/content/Target Groups branch. We want the users to be able to subscribe to news and product areas; it should be possible to subscribe to monochrome and color laser printers separately. With that in mind, define the following structure instead of the sample one:

Target Groups branch

Update site templates

Next we need to update templates of the product and news items; add /sitecore/templates/Email Alert system/EmailAlert.Target Groups template as a base template to Product and News item templates:

Base templates of the product template

This will add the Target Groups field to products and news.

Bind items to target groups

Now when relevant templates have the Target Groups field included, use it to define relationship between items and target groups.

It's simple for news: find the News Item template, and edit the standard values so that 'News' checkbox is checked in target groups field:

News standard values: target groups field

Because products have two separate branches (monochrome and color) that are based on the same template but should belong to different target groups, we need to set the checkboxes manually:

Laser printers content branch

Then update product masters to make sure that new items are automatically set up in future.

Add the subscription page

The subscription page will allow extranet users to subscribe to target groups they are interested in.

Email alert installs a sample 'Subscribe' sublayout. Pick a page and setup presentation to add the sublayout:

Adding subscribe sublayout

With Printers Inc, the page is tweaked to match the site design and the ability to create new users is removed:

subscription control

Now extranet users can use the page to subscribe to one or more topics.

See it working

Now the module is finally set up. Next time editor wants to update the product, she opens Content Editor, updates some details:

Content change: "updated with new information"

and then clicks save:

Comment pop up

Because laser printers are watched by email alert, comment notification pops up and editor enters a brief description of the change.

Nothing happens until the product is published; after the publish email agent kicks in and sends notification emails to all users subscribed to particular target group (Product -> Laser):

EmalAlert notification email

The templates are customizable at /sitecore/system/modules/EmailAlert/Settings.

Wednesday, March 21, 2007 3:35:44 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Demo site
 Thursday, March 15, 2007

Everyone knows that it's bad-bad-bad to substitude headers with text styles. Using headers, however, is good-good-good because search engines love them (and for semantics, which always loses to search engines).

It's easy to remember about them in 'document-like' pages with clear title, chapters, etc. On navigational pages, headings are probably omitted more often.

For SC Printers Inc demosite I believe it means that following headers should be added (among others):


(front page and section pages)

 

(product list)

Could this somehow backfire?

Thursday, March 15, 2007 9:28:40 AM (FLE Standard Time, UTC+02:00)  #    Comments [1]
Sitecore | Demo site
 Wednesday, March 14, 2007

It's a bad practice for a page to link to itself, unless its an anchor. It is a small difference, but it's all about the details, isn't it?

Preferably, both markup and visual appearance should be different. For demosite, it means:

instead of

instead of

(although I don't think the site needs a third link home anyway)

instead of

In xslt, it's as simple as a check for "@sc_currentitem/@id = @id" or "@sc_currentitem/@id = sc:GetLinkItem(...)/@id".

Below is the difference between xslt of vertical menu (the most complex of 3 changes). Before:

<a href="{sc:path(.)}" class="text_2">
  <!-- link content we don't want to duplicate -->
</a>

After:

<xsl:variable name="tagname">
  <xsl:choose>
    <xsl:when test="@id = $sc_currentitem/@id">span</xsl:when>
    <xsl:otherwise>a</xsl:otherwise>
  </xsl:choose>
</xsl:variable>

<xsl:element name="{$tagname}">
  <xsl:attribute name="href"><xsl:value-of select="sc:path(.)" /></xsl:attribute>
  <xsl:attribute name="class">text_2</xsl:attribute>

  <!-- link content we don't want to duplicate -->
</xsl:element>

Wouldn't it be nice if <sc:link /> could handle it by itself? It is a breaking change, unfortunately.

Wednesday, March 14, 2007 3:01:41 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | XSLT | Demo site
 Friday, February 23, 2007

When designing packages in Sitecore 5.3, you really need to take a moment and consider following options for each source:

- Is it possible that the item already exists? Yes / No
- Does it make sense for a solution people to modify this item? Never / Sometimes / Always.

Each source has a Collision Behaviour setting, which is used to "Specify behavior when installing package over existing items"

AskUser setting is the default, it's not the part of the source creation wizard and it's hidden in the third tab in source options which means it is never changed from the default.

But really, who should know better how to install and upgrade your product - you, or the user? Does the user really need the "MyProduct.dll already exists, do you want to overwrite" pop up? Why wouldn't she want to? Why should he care?

If you can, which means if you know what should be done, always set the collision behavior. Save the precious user attention span for dialogs that really matter - most people can tolerate only a couple, and after that they'll set it to 'Overwrite All' (or 'Merge All' if you're lucky) and go get some coffee.

Friday, February 23, 2007 1:25:26 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | 5.3
 Thursday, February 15, 2007

From the Sitecore Developer Network Forum: you can use the 'Filter' property of DataContext to filter the items being displayed in DataTreeview or DataListview controls.

<DataContext Filter="'FieldName='value'" /> will only show items with certain value in FieldName field, for example.

Read more (SDN Forum).

Thursday, February 15, 2007 12:09:48 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Sheer UI
 Thursday, February 08, 2007

Custom Fields are very similar to custom items, but serve a different purpose. While custom items are used to group item level logic, custom fields are handy when a Sitecore field is used to store non trivial value. It can be a single value serialized as string, or a composite of several values. If you're new to this custom items and custom fields, make sure to read Custom Items Explained article first.

Purpose

A common use of custom fields is to provide access to a several values or a composite value, stored in a Sitecore field. Just like Custom Items, it is easier to explain using an example:

Our solution stores a lot of names, and we're tired of splitting the values to get first name to greet the visitor nonchalantly in one part of the application, and doing exactly the opposite to get the last name in the other.

In our simplified world, we there is no middle names and first and last names do not contain spaces. A programmers dream. This way we don't need any custom UI to set the values: just type the John Doe as usually, we'll do the rest.

Boilerplate code

The most simple custom field:  

public FullnameField : CustomField
{
   public FullnameField(Field innerField): base(innerField)
   {}

   public static implicit operator FullnameField(Field field)
   {
      if (innerField != null)
      {
         return new FullnameField(innerField);
      }
      return null;
   }
}

Very similar to custom item, but wrapping the Sitecore.Data.Fields.Field class instead.

A custom field of some use

We're going to parse the field value, to extract first and last name.

public FullnameField(Field innerField): base(innerField)
{
   public string FirstName
   {
      get
      {
         string[] parts = InnerField.Value.Split(' ');
         if (parts.Length >= 1)
         {
            return parts[0];
         }
         return string.Empty;
      }
   }

   public string LastName
   {
      get
      {
         string[] parts = InnerField.Value.Split(' ');
         if (parts.Length >= 2)
         {
            return parts[1];
         }
         return string.Empty;
      }
   }
}

Using custom fields

In C# you can rely on implicit casting operator. Otherwise, explicitly wrap the field with custom field using the constructor.

Item company = Sitecore.Context.Item;
FullnameField primaryContact = company.Fields["primary contact"];
Response.Write("Hello " + primaryContact.FirstName);

Link Fields

With Sitecore 5.3 custom field can also integrate in the Sitecore link database. This is extremely useful when you develop a custom field that links to other Sitecore items, similar to link, multilist or a treelist. It deserves a separate article on it's own, I'll just cover the outline here:

Custom field classes are registered in /App_Config/FieldTypes.config file, so that Sitecore can retrieve the custom field class by field type:

<fieldType name="multilist" type="Sitecore.Data.Fields.MultilistField,Sitecore.Kernel" />

The CustomField base class has 4 virtual methods: ReLink, RemoveLink, UpdateLink and ValidateLinks. By overriding these methods you can hook into the Sitecore link infrastructure, removing the difference between native and custom fields.

Native Sitecore link fields store the list of IDs of items they are linking to, separated by '|' character. If this sounds fine to you, inherit from DelimitedField instead of CustomField and get the Link database integration for free.

Custom fields in Sitecore

Sitecore contains a number of useful custom fields, including MultilistField, HtmlField, LayoutField and SecurityField, most of them are bundled in Sitecore.Data.Fields namespace.

Thursday, February 08, 2007 10:19:57 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | 5.3
 Monday, January 22, 2007

The biggest disappointment about NVelocity is that the project is pretty much dead. Well, guess what:

Due to the lack of releases, support and bug fixes on the original port, the Castle Team decided to fork the project, bringing it to our code repository, fixing the bugs and improving it with more features.
Castle Project, NVelocity page.

And it's not only cleanup and bug fixes. How about this for an improvement?

Inspired on FogCreek's CityDesk language, the following type of foreach is supported.

#foreach($i in $items)
#each (this is optional since its the default section)
       text which appears for each item
#before
       text which appears before each item
#after
       text which appears after each item
#between
       text which appears between each two items
#odd
       text which appears for every other item, including the first
#even
       text which appears for every other item, starting with the second
#nodata
       Content rendered if $items evaluated to null or empty
#beforeall
       text which appears before the loop, only if there are items
       matching condition
#afterall
       text which appears after the loop, only of there are items
       matching condition
#end

Very cool.

I know, "Lame Perl, check out asp:Repeater/asp:DataGrid/.., dude" you'll say. Yes, sometimes. But I don't know why people are often blind to all of the related casting and DataBinder.Eval issues. It is seriously ugly.

TODO:
  * upgrade NVelocity.
  * add NVelocity rendering type.

Hopefully.

Monday, January 22, 2007 11:13:55 AM (FLE Standard Time, UTC+02:00)  #    Comments [4]
Sitecore | NVelocity
 Saturday, January 20, 2007

Going dynamic is so hot these days. And, arguably, for a reason.

Restarting the entire solution just to change a tiny bit sucks. This used to be one of the main advantages of pumping up xslts with all the presentation and logic details you possibly could. Isn't it nice, changing it with a notepad and see the site being updated in less than a second? It is, but only if it's humanly possible to understand what's going on in that huge xslt in the first place.

What changes here?

First, asp.net 2.0 sets the trend in .net world. Dynamic code behinds, /App_Code folder - all are clearly designed to bring more dynamism and web like experience in asp.net web development. Too bad that the first attempt doesn't work well in some situations - hence the highly demanded web application model, which is basically "leave everything as it was". But check the VS2005 and Sitecore 5.3 setup without Web Application Project scrapbook post for an alternative.

Then check out this post by Alex Shyba, showing how to use /App_Code to define workflow actions in Sitecore:

Thanks to Ole, starting with 5.3 BETA 060825 we have made reflection work with App_Code. Therefore, custom processors in App_Code simply work out of the box. In the processor definition, simply leave out the assembly part of the type string.

What this means is that ReflectionUtil.CreateObject can find a class loaded through the asp.net app_code, if you omit the assembly name. CreateObject is in the center of Sitecore extensibility - whenever you input a class name somewhere in configuration, it's used to create an actual object. Workflow actions? Yes, but also event handlers, pipeline processors, scheduled tasks, you name it. However /App_Code is not exactly dynamic - it just does the compilation for you, but whenever it happens the application still gets restarted.

Next in line is dynamic xsl extension compilation. Move some of your logic to xsl extension, change the .cs file later and have it recompiled without any restarts, just like xslt itself. I think it's a nice thing to have, but what's interesting is that it's built on dynamic compilation magic used in Sitecore 5 for years to make X(A)ML controls happen; much earlier than asp.net 2.0 was released. Reusing that was a snap, and only took one evening.

I'd finish with a Iron Python ASP.NET CTP. Coding your views in python is one of the most cutting edge developments in asp.net world. I've blogged about it before, but check the recent hanselminutes show on iron python and language extensibility - Scott Hanselman is quite a bit better at explaining things. Monorail is an interesting alternative version of this: ASP.NET with Model View Controller and without page lifecycle and viewstate is a really delicious thought.

I'm not saying that dynamism in it's current form is the "right" thing to have for everyone - but being able to choose is certainly welcome. I have little doubt that it's role will only increase in future

Saturday, January 20, 2007 1:10:24 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Workflow
 Saturday, January 13, 2007

Resharper 2.5 introduces value analysis - it checks code flow to detect possible null reference errors:

If you use Sitecore assertions, adding them to Resharper assertion list will help it understand that the value is asserted and no warning is necessary (Resharper -> Options -> Highlighting -> Value Analysis):

Saturday, January 13, 2007 12:22:58 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Tuesday, January 09, 2007

I won't try to explain what microformats are, just read an excellent series of posts on the topic by Alex Faaborg, who is a user experience designer at Mozilla. Instead I'd like to show them from the Sitecore developer perspective, and I will use SC Printers demosite for the illustration. I will use the operator firefox extension, which is also introduced in Alex's posts, to demonstrate browser integration. 

SC Printers site contains a contact section, which lists all SC Printers offices around the world and also shows relevant contacts. The page is supported by a standard Sitecore data-driven hierarchy model.

The page is ok, but the best level of interaction it is able to provide is user clicking at Alison's email address and sending a message. It is a pity, since we have so many useful and structured data here.

We're going to modify the demo site to share the structured data we possess to anyone who cares to use it, with the help of microformats. Let's walk through the changes (notice that before rendering can differ from the in the latest release build of demosite, which is 3.0.12 at the moment of writing).

First, we'll make the employee contact information available, that is Alison P. Rogers on the image above. Below is the xsl/office details.xslt, with modifications highlighted with bold typeface.

<xsl:for-each select="descendant::*[@template='contact person']">     
  <div class="contactContainer normal vcard">
...

     <strong class="fn">
       <sc:text field="first name" />&#160;
       <xsl:if test="sc:fld('middle name',.)!=''"><sc:text field="middle name" />&#160;</xsl:if>
       <sc:text field="last name" />
     </strong><br />
     
     <xsl:if test="sc:fld('job title',.)!=''">
       <span class="title"><sc:text field="job title" /></span><br />
     </xsl:if>
     
     <xsl:if test="sc:fld('email',.)!=''">
       <a href="mailto:{sc:fld('email',.)}" title="Send an e-mail to {sc:fld('first name',.)}" class="link_2 email">
         <sc:text field="email" />
       </a><br />
     </xsl:if>
     <sc:html field="description" />
  </div>
</xsl:for-each>

What I did here is embed elements of hCard microformat into existing html presentation, so that any microformat understanding html consumer (browser) can easily parse the data, and let the user get the most of it. The most crucial part is the vcard class on the container element. Then, the data fields are marked with classes defining their meaning. 'fn' stands for full name, and title and email are self-explanatory.

Now, assuming that you have the firefox browser with operator extension installed, here's what you will see while on the SC Printers Inc UK page:


Then you click into Alison P. Rogers, and instantly get a outlook new contact dialog with name and email fields being filled in, provided that outlook is your mail application of choice. But the point is that even if you any other contact management application, web or desktop, you will be able to do meaningful things with the contact as long as

a) The application has the API
b) Your browser knows how to use the API to talk to the application, either out of the box, or via additional download. Given the huge firefox add on community, it's clear that there'll be no problem in that.

so much better then dozen of "add to <one of the contact applications>" buttons.

Now, let's make it clear that it's not a particularly useful thing to support today, as the market adoption is very low. At the moment, none of the browsers supports them natively. In firefox, there's at least two microformats extensions (operator and tails). There's also a number of smaller extensions and greasemonkey scripts, which may support one or a few related microformats.

It is, however, the future. It is very likely that firefox 3 will introduce microformats support (with better user interface, for sure), followed by some hints about Internet Explorer 8 and Apple's safari. You can play with it once the next build (3.0.13) of SC Printers demo site is out, and I'll try to post a follow up adding more microformats to the site.

Useful links:
1. Introducing Microformats (Alex Faaborg)
2. Introducing Operator (Alex Faaborg)
3. hCard microformat (contact)
4. geo microformat (location)

Tuesday, January 09, 2007 3:42:20 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Friday, January 05, 2007

One of the downsides of XSL extensions is that an entire Sitecore solution needs to be restarted both when a new extension is registered (web.config change) and existing extension is modified (recompilation). Compilation itself can also be a burden. Plain XSLTs, in contrary, are easy to modify, and the result is immediately visible on the website.

Dynamic extension compilation is an attempt to solve this and make extensions more viable. It will compile and register all extensions in /App_XslExtensions (configurable) folder in Sitecore root both when Sitecore starts, and when extension is created or updated.

Below is the example of such extension file:

using Sitecore.DynamicXslExtensions.Attributes;
namespace Sitecore.DynamicXslExtensions.Tests
{
   [XslExtension("http://www.sitecore.net/testnamespace")]
   public class TestExtension
   {
      public string helloWorld()
      {
         return "Hello, World!"
      }
   }
}

If the file is placed inside the /App_XslExtensions folder, it will be compiled automatically, and you can register the http://www.sitecore.net/testnamespace extension as usual. What is not usual is that you can tweak the helloWorld() method in any file editor (or using Sitecore IDE) and see the changes live on the website.

Underlying process is similar to how Sitecore compiles XML controls. And just as in XML control code, you can modify a list of assembly references during automatic compilation using ui/references section of web.config.

Installation is as simple as I could make it: install the package, and add
<processor type="Sitecore.DynamicXslExtensions.Loader, Sitecore.DynamicXslExtensions" />
to pipelines/initialize in web.config.

Download Package.

Friday, January 05, 2007 1:21:31 PM (FLE Standard Time, UTC+02:00)  #    Comments [3]
Sitecore | XSLT
 Thursday, January 04, 2007

With the introduction of "standard values" in 5.3, setting a list of valid masters for items of certain type is changed in a major way.

For example we want all Product Category items to have Product master assigned, so that editors can add new products under a product categories.

Sitecore 4, 5.0, 5.1 and 5.2:

Create Product and Product Category masters. In Product Category master, assign the Product master. Make sure all product categories are created from masters.

How it works: Each time editor creates new product category from a master, value of the available masters field gets copied.

What's wrong with this approach: Inheritance chain doesn't work, so there's no easy way to add another master to all product category items (imagine that you have added new Hot Product template later)


Sitecore 5.3:

When designing Product Category template, open it's standard values and populate masters field with Product master (or use assign masters in the ribbon). Make sure that Product Category master does not have any masters assigned, if you're upgrading from earlier versions of Sitecore.

How it works: when Product Category items are created from respective master, the masters field remains empty. Because of this, standard values are used, so that the list of masters is shared between all items of the same template.

What changes: it gets really easy to control a list of allowed masters for all items of the same template. However if you need some item to have a different set of masters, you will need to reassign a list of masters for this item which turn off the standard values inheritance. If you have more than one items of this special kind, consider making a new template and using template inheritance.

Because in earlier Sitecore versions some items might have a custom set of masters, it's hard to automate converting content to use 5.3 approach. Also, take a look at 'Reverting Field Back to Standard Values' post for a related gotcha.

Thursday, January 04, 2007 12:32:41 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | 5.3
 Thursday, December 28, 2006

A scottGu style gotcha: if you have a field with some data in it and you want to clear it, so that the default values are applied again, erasing all content is not enough. In other words, if you simply erase all data in the field using Content Editor or db browser, the field will store exactly that: nothing, empty string.

To make the field use standard values again, you need to reset the field. Either click a cross next to the field value in dbbrowser, or use Sitecore.Data.Fields.Field.Reset() method in API.

Thursday, December 28, 2006 12:24:10 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore
 Thursday, December 14, 2006

So how to use the Sitecore workflow engine to approve item deletion? Here's what happens inside and it's a bit more complicated that I'd like it to be:

  1. A new field in workflow template is used to setup a deletion workflow for items in this workflow (there are many alternative options for this):
  2.  A custom processor in uiDeleteItem pipeline is invoked every time a user deletes an item. If the item has deletion workflow set up (pt. 1), the actual deletion is cancelled and instead:
    1. Current workflow gets suspended for all versions of the item being deleted (in all languages) that are currently not in the final workflow state. This hides them from the workbox. To be able to remember the workflow/state, a new field is added to standard template.
    2. Latest version in default language gets switched to deletion workflow. This ensures that only one entry for the item will show up in the workbox.
    3. Item is protected (item.Appearance.ReadOnly = true) and custom ribbon panel displays warning (the item is marked for deletion) in Content Editor.
  3. If the item deletion is approved, item gets deleted / recycled.
  4. If the deletion is denied, all changes in pt.2 are reverted:
    1. Workflow is resumed for all existing versions in all languages.
    2. Item is made writeable.

(Am I missing anything?)

I belive the main reason for the whole process being not entirely straighforward is that Sitecore workflows are targeted at versions, making item level operations such as delete are a bit harder to fit. Apart from uiDeleteItems processor, the rest of the logic is wired up using workflow events:

I wonder if custom workflow engine (and provider) could've been a better choice.

Download sources and package (5.3). This is still more of demonstration and haven't been used in a production site yet, and you might want to adapt it to your specific requirements. Comment, use sdn5 forum or mail me at 'ar at sitecore net' if you have questions or help getting it working.

Thursday, December 14, 2006 5:47:11 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Workflow
 Thursday, December 07, 2006

Brent Turner asked on the forum for a way to use workflow to approve the item deletion. The idea is that when an editor deletes an "important" item, the item doesn't go right into the recycle bin. Instead the decision must be approved using Sitecore workflow.

The idea got Alex, Kim and me interested, we exchanged a number of emails and Alex had a nice entry on the topic.

Actually approved decision is the easiest part: place item in workflow when the user clicks delete button and delete the item once it gets to the right state.

If the deletion is denied, however, it'd getter be back in it's original state, whatever that was before someone decided to delete the item. And while the item is pending for a deletion, editors should see a warning - no sense in modifying the item that might be deleted tomorrow. And then if you consider multiple languages.. There's all sorts of interesting details and somehow I'm sure I didn't get everything right.

As an experiment, I did a screen cast to show how it works. Take a look (SDN5 access required):

Thursday, December 07, 2006 7:56:54 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Workflow
 Monday, December 04, 2006

The Sitemap standard has been developed by Google, but lately has also gained support by Microsoft and Yahoo. From the sitemap.org:

Sitemaps are an easy way for webmasters to inform search engines about pages on their sites that are available for crawling. In its simplest form, a Sitemap is an XML file that lists URLs for a site along with additional metadata about each URL (when it was last updated, how often it usually changes, and how important it is, relative to other URLs in the site) so that search engines can more intelligently crawl the site.

The sitemap protocol is basically a flat list of site pages you want indexed, allow with ability to indicate the last modification date, change frequency and relative importance of each pageoften the . Obviously it cannot influence your overall search rankings, but rather properly indicate importance of individual pages related to other site items.

We've been using the generator on www.sitecore.net for a while, and google webmaster tools seem to be quite happy with it (no errors). I haven't tried submitting to yahoo/msn yet, not sure if it's already available.

An interesting question is how to automatically set page importance. In the default implementation, the deeper the page in Sitecore content hierarchy, the less important it is. I can see that often the opposite is required, so that users are actually more likely to be dropped to a more specific page, rather than the generic one.

Ideally, the editors should be able to override the setting for individual pages (and possibly branches), but there still has to be a default algorithm.

The updated date is used as last modified, but actually it would be better to use publish date. Change frequency is not supported.

The sample code is shared at SDN Forums.

Monday, December 04, 2006 11:40:50 AM (FLE Standard Time, UTC+02:00)  #    Comments [1]
Sitecore
 Friday, December 01, 2006

Just in case you don't read the SDN5 feeds: the plus package is out there, in download area. It's a number of applications packaged as a single download / installation, including:

  • Autodoc.
  • SSL Redirector: redirect http requests to https.
  • XML Importer: import data into Sitecore.
  • Bug report: easily report bugs from Sitecore Client.
  • A number of workflow actions, including wait for language helping to deal with translations.
  • Sitecore Today portal, including custom portlets like My Locked Items portlet, that were previously available as a shared source download.
Friday, December 01, 2006 6:05:53 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Friday, November 17, 2006

In the previous Configuration changes in 5.3 post I've briefly mentioned that starting with 5.3 configuration change should not necessarily trigger an application restart. The really good question was if configuration watching means that it's possible to update <sites> definition without restarting the whole site. The quick answer is yes, it is definitely possible and might be a good idea to do.

For the longer version, lets see how configuration watching works.

First and foremost, there's the new Sitecore.Configuration.ConfigWatcher class that watches for all file changes inside /App_Config folder. The class exposes a static ConfigChanged event available for all interested parties. Sitecore subsystems subscribe to the event and make sure to flush their internal cache or re-read configuration when files in App_Config folder are changed.

I will cover rest of the systems later, but what matters now is that Sitecore sites are aware of the configuration changes and will flush all cached settings on any configuration change. The only thing that is missing in default Sitecore distribution is a separate configuration file for site definitions: the <sites> section is still embedded directly in web.config file and therefore any chang will still lead to asp.net application restart.

It doesn't mean that it should stay that way, and since we already know about <sc.include /> its just too tempting not to mess with it.

1. Cut and paste the <sites> node to a /App_Config/sites.config and replace it with <sc.include file="/App_Config/sites.config />
2. There's no second step, really. Load Sitecore, change sites.config and see how it takes effect immediately. Let there be joy.

Detailed instructions

So all the rambling aside, here's detailed instructions on how to change web.config to be able to update <sites> section without application restart:

1. Locate <sites> section in web config. It will look similar to:

[web.config]:

<sites>
  <site name="site1"  ... />
  <site name="site2" ... />
</sites>

2. Create a Sites.config file in /App_Config folder with the following contents:

[/App_Config/sites.config]:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
</configuration>

3. Now cut everything between <sites>..</sites> from web.config and paste it between <configuration>..</configuration> in Sites.config we've created in the previous step:

[web.config]:

<sites>
</sites>

[/App_Config/sites.config]:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <site name="site1"  ... />
  <site name="site2" ... />
</configuration>

4. The final step. In the web config, use the <sc.include /> to include Sites.config into <sites> section:

[web.config]:

<sites>
  <sc.include file="/App_Config/sites.config" />
</sites>


Run the website. Try changing startItem or database parameters for the 'website' site and see how they take effect immediately.


Other Applications

List of other subsystems reacting to changes in /App_Config folder includes:

* Caches - whatever the change, caches are obviously have to be flushed.
* Settings - similarily to <sites> section, you can move portion of the <settings> in a separate file inside /App_Config and always have up-to-date values reported by Sitecore.Configuration.Settings class.
* Events - event subscriptions can be updated on the fly.
* Commands - similarily to events, command information is updated dynamically.
* Factory - for hardcore tweakers, factory creates and caches objects such as databases based on web.config definitions, acting as Dependency Injection container. It is also capable of reacting to configuration changes.


Module Developers

For module/solution developers it's a good opportunity to support on-the-fly configuration changes: subscribe to the Sitecore.Configuration.ConfigWatcher.ConfigChanged event and re-initialize your subsystem where it makes sense (you can also get the name of the changed file from event arguments if it matters) to make lifes of your fellow Sitecore developers easier.

Code sample:

using Sitecore.Configuration;
ConfigWatcher.ConfigChanged += ConfigWatcher_ConfigChanged;

void ConfigWatcher_ConfigChanged(object sender, ConfigChangedEventArgs e)
{
  if (e.ConfigFilePath == "myfile.config")
  {
    ResetMySettings();
  }
}

note: the sites idea has already been explored by Alex de Groot in great detail here and here previously.

Friday, November 17, 2006 11:38:47 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | 5.3
 Wednesday, November 15, 2006

Sheer UI doesn't work during initial load stage. To be able to send sheer commands (anything in ClientResponse.*) you need to wait for or trigger an event (ClientPage.IsEvent == true). Below is the javascript one liner that does just that: sends a 'sheer:load' message once the window load occurs in browser.

<script language="javascript">
  scForm.browser.attachEvent(window, 'onload', function() { scForm.invoke('sheer:load'); });
</script>

[HandleMessage("sheer:load")]
protected void SheerLoad(Message message)
{
  // Send load Sheer UI commands from here
}

And since we're talking sheer UI: ever felt tired typing [Sitecore.]Context.ClientPage.ClientResponse all the time? If so, check out Sitecore.Web.UI.Sheer.SheerResponse static class.

Wednesday, November 15, 2006 10:21:27 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Sheer UI
 Monday, November 13, 2006

We have launched a forum at SDN5: http://sdn5.sitecore.net/Forum.aspx. Welcome message. See you there.

The software is Pentia Forums, which is a big step forward from the messageboard we had on sdn4 long time ago. Hope you like it.

Monday, November 13, 2006 5:25:56 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore

Time for another update on my endeavors - since last post, the change tracking application grabbed my full attention. It helps to have at least one potential "customer" around, available to bounce ideas off and ask all sorts of silly questions. And in all of my humbleness, that customer is me.

The main scenario I'm keeping in mind is the following: I have a production server running either a pre-production / production site, and a separate development instance I'm working on. I want it to be really easy to change a few things, add a feature or fix an annoying bug, and quickly update production server with that.

My current take on a solution: change tracking / uploading application. The flow:

  1. [optional] Start tracking changes
  2. Do the work, add a feature, close the bug, rewrite that code that suddenly doesn't look as beautiful, you know, things that developers do. Some items might get changed, new items are added. Finish, run the tests or whatever personal QA you do.
  3. Open change tracker and see the changes done since you've started the change tracking, item or files-that-matter wise. If you haven't, manually select date range, like all changes done today. Possibly discard some of the changes as irrelevant. Then use the ones, that matter:
    * Upload directly to the Sitecore server.
    * Add the changes to existing or new package project. This can be used to accumulate the changes, or to have the ability to use package designer to manually retouch the changes before they go further: add   something important, for example, like your latest photo.

How it looks at the moment:

As I mentioned in the last post, it's not currently possible to replicate all types of changes using packager - i.e. you cannot tell package project to delete an item when the package is installed. That's just the way it works for now - only created and updated changes are supported. If it proves to be useful (even if only to that one customer) - I'll have more time and inspiration to enhance it.

That's also why I'm not trying to do everything at once: currently there's no intention to solve concurrency or versioning issues, with anything beyond standard Sitecore means. I just assume that you are either a single active developer on the project at the moment, or this is being handled by some other means. Hacking it is very tempting, but the ideas I came with quickly started to transform into writing something almost of source control management scale. Since I'm only working on it in my personal, spare time and being the only developer I really need to keep things simple (and fun); that's all my unfinished projects talking to me from the repositories in "inactive" folder, the dark, grim and boring graveyard of theirs.

* Previous post: Communication Between Sitecore Servers

Monday, November 13, 2006 9:51:26 AM (FLE Standard Time, UTC+02:00)  #    Comments [4]
Sitecore | Automation
 Wednesday, November 08, 2006

Found an interesting whitepaper discussing the use of dynamic languages with asp.net, related to recent release of IronPython asp.net ctp.

If you have used ASP.NET data-binding expressions, you are likely familiar with the Eval method. For instance, you might have a GridView control with a templated column containing the data-binding expression <%# Eval("City") %>. Here, the Eval method is used to get the value the column named City for the current row in the database (or for whatever data source you are using). This works, but the fact that you must go through this Eval method is rather awkward.

In the new model, the equivalent is to simply use the snippet <%# City %>. Here, City is an actual code expression in the dynamic language, instead of a literal string that must be interpreted by the Eval method. Hence, you are free to write arbitrary code in the expression. For example, with IronPython you could write <%# City.lower() %> to display the City value in lower case. This improved syntax is made possible by the late-bound evaluation supported in dynamic languages. Even though the meaning of City is not known at parse time, the dynamic language engine is able to bind it to the correct object at run time.

Casting is really one of the most awkward parts of using code snippets inside aspx pages, which I do enjoy here and there sometimes as a alternative XSLTs. I wonder how much LINQ can help make it an even better alternative.

Wednesday, November 08, 2006 12:01:06 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Monday, November 06, 2006

From the Sitecore news:

The inventive use of the Sitecore WCMS as the development platform to power the visually inspiring front-end of the “Magnum in Motion” site ( www.magnuminmotion.com ) has been nominated for Best in Innovation in Content Management at the “International Information Industry Awards 2006”. (Link)

The site is really slick, flash blends in really well. I found myself listening to the front page narratives in no time. Can't help aching to log in and see what's inside..

Congratulations to Enzym!

Monday, November 06, 2006 4:40:51 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore

I've ended last post saying that I'd like to be able to send packages over the wire to other Sitecore servers. Starting last weekend, it is officially cold here in Ukraine. The snow broke on Friday, and now we're steady below zero. Not much fun outside, but I had a chance to explore the communication idea a bit more.

Making Sitecore know it's neighbors.

Production Sitecore server is very rarely alone: starting from partner developers having individual instances, to build servers, QA, etc. These servers, however, do not know anything about each other.

 

List of known servers, or endpoints, is stored in core database. Endpoint is basically an url to Sitecore instance along with credentials matching the user account in that instance. It's not required to store username and/or password - you can type them in when they are needed instead.

Sending Data.

Now, when Sitecore knows some addresses, we can start sending gift wrapped packages. Right click on item -> Copying -> Send To -> Select one of the servers:

Then choose whether you want to send sub items or not, input credentials if they are needed and click Next. Behind the scenes, the items are placed in a package, which is then sent to a target Sitecore instance and installed there.

The usefulness of this depends on your 'process', I suppose. Working on our sites, I often have to make incremental changes and upload them to production, both before and after the site launch. When the change is really small, the burden of building / uploading / installing package is heavy enough to try to avoid adding items altogether, if possible. I'd love to hear how it works for others and what are the repetitive bits you'd like to avoid.

Change Tracking.

This part is more like what I'm looking at next, as it's very incomplete. The idea is to use history of item changes to allow developer to bundle all items she changed today, for example, and send them away in package, much like sending individual items or branches in previous part. Some prototype bits:

A bit of impedance mismatch is that it's not possible to package item deletion, i.e there's no 'anti-item' to place in package so that it deletes a certain item during installation. I enjoy using packages as communication protocol though and extending packager is an option.

 

Previous posts:

* Automated Package Operations
* Sitecore Build Automation

Monday, November 06, 2006 9:50:45 AM (FLE Standard Time, UTC+02:00)  #    Comments [1]
Sitecore | Automation
 Wednesday, November 01, 2006

During the first request to your site the asp.net Session is not available during the execution of httpBeginRequest processors, that is HttpContext.Session being null. Unless you're into manually-creating-session trickery, you should not rely exclusively on it for your processor logic.

Wednesday, November 01, 2006 2:55:07 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Friday, October 27, 2006

After the build automation post I felt like coding and decided to pick the low hanging fruit of package operations, that is being able to automatically install a package and build a package from package project.

Here's the current design:

1. Package installation
/Package_Install folder inside Sitecore installation is being watched for new files. Once the package file is dropped there, Sitecore automatically installs the package. Then the maintenance stuff like moving the file out and reporting is performed.

2. Package generation
Similar to installation, /Package_Generate is being watched for packager project files. Once the project file is dropped in the folder, Installer generates a package and places it near the project file.

The best part is that it almost works. Package generation works reasonably well, while instalation still requires a "don't-ask" package, installs it and then throws an exception - no big deal, we'll fix it. I'd like to add real webservices in future and be able to send packages over the wire, but this local version seems easier to use both manually and in automation scenarios.

Friday, October 27, 2006 8:32:02 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Automation
 Thursday, October 26, 2006

One of the things I really want to be able to do with Sitecore is build automation. It might not be as pressing when you have one or two projects in development, but here in Sitecore Ukraine we need to constantly update and maintain a number of modules which easily exceed a number of programmers. The usual build stuff like updating and checking in the package can get pretty tedious.

The good news is that we're getting much closer to this goal with 5.3, and the new packager is a big part of this. So what do we need to make the build magic happen?

1. Building the project package(s) automatically.

It's were the new packager really rocks. Separating package definition (package project) from the actual data file is a much needed change. One of the killer features of this is being able to dynamically (conditionally) include items in the package. For instance the package project could say that all children of /system/modules/my_module and /system/templates/my_module should be included in the package when it is built - no need to update the definition each time you decide to add a new template field.

What is missing: there's still no readymade way to automatically build the package. The packager API makes it really simple though, and it would be a trivial task to add a web service that builds the package from package project file.

2. Automated package / module installation.

First, there needs to be a way to automatically install the package. The hard part then is being able to automate configuration changes as most of the settings are still stored in configuration files while packager speaks items, not xml. 5.3 makes is somewhat easier with _sc.include_. Dealing with external module dependencies can be even harder, but that's mostly out of scope of Sitecore and can be dealt with on individual basis.

What can be done: Again, packager provides API that can be used to issue 'install package x' command, so it's not hard to have this available via web service of some sort. At the moment it also involves designing a package in a way that ensures that no 'overwrite' confirmations are required - packager needs to be enhanced with 'quiet install' mode.

Automated configuration changes is still an untouched territory. Truly automated module installations is a major (and very noble) task involving lots of changes, but for the sake automated builds some shortcuts could be made. Basically you need a way of adding your custom bits to default web.config, but not sure if the half-solution is worth it though.

3. Running unit tests.

Once the package is built and installed into a prototype Sitecore instance, it's testing time. To recap: we use a custom NUnit test runner (which is simply a web page) to run NUnit tests against Sitecore in a fully setup web environment. A number of helper methods such as programmatically setting up the Sitecore site support the test framework. he custom test runner is already able to execute all tests in the supplied assembly and save the standard NUnit test report .xml to disk, which then can be analyzed to decide if the build is successful or broken. 
 

So yes, we're getting closer but not quite there yet. A lot can be built on top of what we're already have in 5.3, and apart from that I'd really like the configuration issue to be tackled. Another thing we all can benefit from is known conventions of how you do develop with Sitecore, making it easier to support it using the automation.

Thursday, October 26, 2006 8:50:40 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Automation
 Tuesday, October 17, 2006

Content dot is a tricky beast. What happens if you forced out of the warm, causy XSLT environment and no longer have <sc:dot /> around? Editors will rarely accept this excuse, they want their dots now! So you use the Sitecore.Web.UI.WebControls.ContentDot control. And here's when the tricky part starts.

XSLT is caring - your job is to drop the dot somewhere. Done. Webcontrol couldn't care less. Most of it's rendering methods will not check if the site is actually in Web Editing mode and therefore the dots should be displayed. What would you typically use ?

// Will be dispayed no matter what. WRONG.
myContainerControl.Controls.Add(new ContentDot());

// Same as above.
new ContentDot().RenderControl(myHtmlWriter);

// Will take effort to check whether it should actually present itself or not
<%= new ContentDot().Render() %>

Using first two methods will usually result in lots of gray dots visible to all visitors. No one likes it: editors are confused, they want their dots green. Visitors are confused even more - they don't want no stupid dots.

So what do you do? Well, smart dot to the rescue:

public class SmartDot : ContentDot
{
   // All roads lead to Babylon and all different render methods will meet
   // in DoRender(HtmlTextWriter).
   protected override DoRender(HtmlTextWriter output)
   {
      if (Sitecore.Context.Site.DrawDots)
      {
         base.DoRender(output);
      }
   }

   // Bonus feature, a friendlier constructor
   public SmartDot(Item item) : base(new ItemNavigator(item))
   {}
}

Smart Dot will keep you happy!

Tuesday, October 17, 2006 6:09:44 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Thursday, October 12, 2006

Sitecore 5.3 introduces another performance-booster feature called prefetch. Using prefetch, you can tell Sitecore to populate its item cache with certain items immediately at startup, instead of waiting for someone to access them (and have slower initial response) first.

Basically prefetch is a tradeoff between faster startup times and smoother experience.

Configuration

Prefetch is defined per database, and for convenience settings for each database are stored in separate configuration file at /App_config/Prefetch/<database_name>.xml. There’s also a list of items to prefetch for all databases, defined in common.xml.

There are a few options you can use to define prefetched items:

1. Prefetch an item
<item desc="home">{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}</item>

2. Prefetch children of the item
<children desc="main items">{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}</children>

3. Prefetch all items by template
<template desc="layout">{3A45A723-64EE-4919-9D41-02FD40FD1466}</template>

Defaults

What items are being prefetched by default? It varies greatly from database to database:

All databases prefetch templates (so it’s a second level template cache), languages and devices.

Core database prefetches application items: now there’s one less item that has to be loaded when you start the application for the first time.

Master database prefetches menu items, ribbon pieces, html editor settings, masters and settings like field types.

Web database is an interesting example. First, it prefetches renderings for obvious reasons. But also, it gets home item with all children. In the typical Sitecore site home item represents the front page with its children being top sections – those are usually the most visited pages and it makes great sense to preload them and save a few milliseconds for people visiting the site after startup.

Customization

Web database prefetch is probably of biggest interest for site constructors. Sitecore can only make guesses based on strong convention such as preloading home items and its children – but site creators are in position to know which items are also required for most of the pages, on which items home page relies heavily, etc. Modifying the prefetch configuration accordingly can make restart slowdowns less noticeable for site visitors.
Thursday, October 12, 2006 11:41:59 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | 5.3
 Friday, September 29, 2006

A neat enhancement in 5.3 Query is the ability to escape literals using #literal# syntax.

You couldn't do this in 5.2 because of 'and' being a reserved word in query:

/sitecore/content/Home/Day and Night

in 5.3, you can:

/sitecore/content/Home/#Day and Night#

The same goes to spaces in field names, and probably other issues I cannot think of at the moment.

Thanks to Alexander Shyba for bringing this up.

Friday, September 29, 2006 12:04:34 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | 5.3
 Wednesday, September 06, 2006

I was adding syndication support to www.sitecore.net site (and to sdn5 before that) and decided to share the experience. The walkthrough below uses the latest 1.1 beta version of Sitecore RSS module, but most of the concepts apply to release version.

If you would like to use module and have rss feeds on your site but something just doesn't work or feel right, mail me: ar at sitecore net or leave a comment, and the next version might get a little better.

1. Install the Sitecore RSS shared source module

2. Obey the manual, and add pipeline and publish handler (in our case, it publish:end event handler that matters)

<handler type="Sitecore.Modules.RSS.PublishingHandler, Sitecore.Modules.RSS" method="OnPublishEnd" />

3. Navigate to /sitecore/content/RSS feeds in Content Editor

4.Now we're ready to setup our news feed. Duplicate the 'Example feed' into 'News' and get ready to editing. We'll start from the Syndication Info section. On the left side is unmodified example feed and on the right is the result of our work.

  

Input channel information that will be visible in user's RSS aggregators like Feed title, description, copyright and link. We don't want to include author information, just like the actual website.

5. Syndication feed section.

 

/home/news/breaking news is where the all news items leave under, so we input that into Syndication root field. We also give a bit more meaningful name to the feed xml file.Since our website lives under default Sitecore <site> in web.config, site name field is left unchanged.

6. Syndication settings section

Include updates: we don't want old news to pop up again if someone updates them, disabling include updates
Maximum age: we increase maximum age to 60 days, just to be safe in slow news times.
Allow embedded feeds: At this point we're only interested in generating physical xml file on each publish, embedded feeds disabled.

7. Syndication fields section


By lucky accident, our news item template is really standard with both title and text fields.
News items do not link to everything else, so we make sure that link field is empty so that rss feed items will link back to our news automatically.

8. Syndication Filters (advanced)

In our site we don't have news items all lying around in one folder, and they are neatly orginized by years and months instead:

However it doesn't mean that we want to have all those year, month and page setup items to be included in the feed (nor does it make sense), and this is just what the filters section is for. What we really want to do, is to only include news items themselves and we express that by selecting the template in 'only include template' field

9. Save the item, and publish. Look into the data folder, and here it is: news_en.xml file, the result of all the hard work.But it wasn't really hard, was it?

Wednesday, September 06, 2006 4:02:30 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Tuesday, September 05, 2006

Using a software instead of writing it usually does open a few "insights". Without further rambling:

* RSS Module 1.1 beta download (Compiled for Sitecore 5.1.1, runs fine on 5.2)

First of all, please notice that it's a beta - it hasn't been tested "properly". Moreover, it will never be: the next official release will be built for upcoming Sitecore 5.3. There's no update package, but the only item you want to preserve (in case you've been using it) is global settings under /system/modules/rss.

Changes:

* 'static site' feed setting - sets site context during static feed generation
* 'host name' feed setting - uses predefined hostname to autogenerate full links
* 'include in feed field' setting - ability to specify field controlling individual item inclusion
* bugfixes and minor improvements

I've seen a few requests for Sitecore 5.2 compatible version in Yahoo! groups: while this version doesn't add or fix anything in this area, I don't see why it wouldn't run just fine under asp.net 2.0. In fact it does, both on sdn5 and sitecore.net.

Tomorrow, I will post a tutorial on using the module to add syndication to your site without spending much time and effort.

Tuesday, September 05, 2006 5:40:44 PM (FLE Standard Time, UTC+02:00)  #    Comments [3]
Sitecore
 Monday, September 04, 2006

Core API .net remoting will not be available in Sitecore 5.3 release. Yes, its still there in recent beta versions but don't count on it.

That said, it's certainly possible to use remoting for your own remotable API layer - but the core Sitecore API classes like Database / Item will remain non-remotable.

Monday, September 04, 2006 9:55:48 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | 5.3
 Wednesday, August 30, 2006

We've sneaked in a few more feeds to SDN5. The full list available:

Scrapbook
FAQ
Articles (only new articles for now, back history is incomplete)
Downloads
Products

There's still an aggregate feed, including all of the above. And OPML file for your subscription convinience.

Wednesday, August 30, 2006 4:49:55 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore
 Wednesday, August 23, 2006

I have once wrote about a rare security setup, in which there is a parent item that is less visible than a child. To recap, consider this setup:

home (allow read)
|
--news (deny read : browse only item)
   |
   --news_item (allow read)

Now theres another catch if you need to retrieve the 'news item' (in bold) using the api:

database.Items["/sitecore/content/home/news/news_item"] -> OK, news_item
database.Items["{id-of-news_item}"] -> OK, news_item

database.GetRootItem().Axes.SelectItems["/sitecore/content/home/news/news_item/*"]
-> null
database.GetRootItem().Axes.SelectItems["//news_item"] -> null (at least on sqlexpress)
database.GetRootItem().Axes.SelectItems["//{id-of-news-item}"] -> OK, news_item

(Tested on Sitecore 5.3 beta 060731)

Peter Johansson, who has the full credit for spotting this, made the following wrapper around SelectItems to be able to query over hidden items, but still respect security in the end:

public static List<Item> SelectItems(Item RootItem, string Query)
{
   List<
Item> itemsList = new List<Item>();
  
if (RootItem != null)
   {
      
Item[] items = null;
      
using (new Sitecore.SecurityModel.SecurityDisabler())
       {
           items = RootItem.Axes.SelectItems(RootItem.Paths.Path + Query);
       }
      
if (items != null)
       {
          
foreach (Item itm in items)
           {
              
if (itm.Access.CanRead())
               {
                   itemsList.Add(itm);
               }
           }
       }
   }
  
return itemsList;
}
 

As this is tested on beta version of Sitecore, I will followup if anything changes or I discover more. And now, it's time for a little vacation: see you on Monday.

Wednesday, August 23, 2006 5:49:20 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | 5.3 | Security
 Sunday, July 23, 2006
DotLucene is the engine behind search in Sitecore client. Sitecore itself provides most common patterns of advanced search, allowing to specify ‘created/updated’ date interval, or filter by author.

Here’s how search query looks like when searching for items authored by ‘Admin’ user: author:"sitecore\Admin".
In lucene terms it says to look for documents containing ‘sitecore\Admin’ in ‘author’ field. Don’t confuse lucene’s fields with those of Sitecore, though. To see which fields are there for you to search by (and to add own ones, if you fancy) refer to ‘system’ index declaration in web.config:

<index id="system" singleInstance="true" type="Sitecore.Data.Indexing.Index, Sitecore.Kernel">
  <param desc="name">$(id)</param>
  <fields hint="raw:AddField">
    <field target="created">__created</field>
    <field target="updated">__updated</field>
    <field target="author">__updated by</field>
    <field target="published">__published</field>
    <field target="name">@name</field>
    <field storage="unstored">@name</field>
    <field target="template">@tid</field>
    <field target="id" storage="unstored">@id</field>
    <type storage="unstored">memo</type>
    <type storage="unstored">text</type>
    <type storage="unstored" stripTags="true">html</type>
    <type storage="unstored" stripTags="true">rich text</type>
  </fields>
</index>


And finally, refer to DotLucene Query Syntax for more options, including wildcard and ‘fuzzy’ searches. And since Sitecore 5.3 uses asynchronous search index updates, there’s much less incentive to turn the indexing off.

Sunday, July 23, 2006 4:38:35 PM (FLE Standard Time, UTC+02:00)  #    Comments [1]
Sitecore
 Thursday, July 13, 2006
Ranting about new multiple template inheritance capabilities and its virtues made me think what’s missing: you still cannot extend the template without manually modifying the template itself.

Specific scenario bugging me is extending Sitecore templates, like ‘standard template’, fields, etc. Long story short, I’ve hacked together a quick prototype to share the idea.

The solution adds ‘/sitecore/system/template extenders’ folder, a place to add template extender items. Each extender can extend a list defined templates with  another list of mix-in templates. ‘Extending’ a template basically means making sure that it has mixed-in template as one of the base templates.

sample_extender.jpg
Extending 'Standard Template' with two additional templates.
 
So from the technical point of view the prototype hooks into the initialize pipeline, and registers all extenders found in /sitecore/system/template extenders each time Sitecore starts up. Initialize pipeline was just the quickest way to hook somewhere, good enough for prototype.

Unlike modifying base templates manually, extending templates in this manner can be done automatically via the package install. It is also more future proof: if the standard template gets modified later, extenders make sure to add base template again, so you can rely on the additional fields being there.

The package requires old packager (developer tools -> packager) to install, and in beta 060705 it looks like you have to fix ‘package folder’ setting in web.config.

Package also installs a sample: two dummy templates (‘A’ and ‘B’) and an extender to add them to standard template. If everything’s alright, you will see two more fields on all items. If not – oh well, this should have been clean throw-away instance.

Package: templateextender_prototype_oldpackager.zip (21.08 KB)
Sources: TemplateExtender_prototype_src.zip (11.81 KB)
Thursday, July 13, 2006 4:18:07 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | 5.3
Next 5.3 (almost) feature I’m putting my eye on is multiple template inheritance. It looks like a small UI fix, leading to very cool aspect-like stuff.

Notice how ‘base template’ field of every template allows adding multiple templates. Inheriting from more than one template means inheriting union of their fields, simply enough. Sitecore is also first to use the feature:  instead of containing all the sections directly, standard template now inherits from multiple base templates (all defined at /sitecore/templates/system/templates/sections), each containing one particular section.

standard_template.jpg
Standard template inherits each section from separate templates.
Also notice the ‘treelist’ field bundled with Sitecore.


That’s probably the only example needed to get excited. From solution perspective, it is really easy to create own aggregations, design ‘aspects’ and mix them as appropriate to create concrete templates. It can be sets of common content fields, meta-data or smaller things like image links. If some of the solution item kinds are designed to have graphical links, you can group ‘image’, ‘link’ and ‘text’ fields together and mix it in as base template when needed.

For module vendors it means that there’s no need to feel guilty about extending standard template any longer. It is often really tempting to have your module add new fields to some of the items. RSS Module, for instance, can benefit from having fields controlling feed generation for content items.  5.1-compatible version has ‘Rss Settings Base’ template and instructs user to inherit their template from it. This obviously gets a little more complicated when there’s a lot of existing inheritance in solution. In 5.3 it is possible to either mix base rss template into default template to add rss-specific fields to all items, or decide which of your templates should have that section and add it individually.

And no need to worry about accidentally mixing the same fields twice – this multiple inheritance is a safe one.
Thursday, July 13, 2006 11:19:33 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | 5.3
 Wednesday, July 12, 2006
As a follow up to the previous post, here’s very subjective comparison of storage engine performance in 5.3.

Microsoft SQL Express. Clear winner. Fastest all around file-based storage option, while still being free. The only downside is that it requires a separate install.

SQLite. Runner-up. While almost matching ‘read’ speeds of SQL express in pure API tests, Sitecore client feels less responsive. Significantly slower on writes, which is most noticeable during the publishing process. Faster than firebird on the same ‘client responsiveness’ scale.

Doesn’t require separate installation, meaning that Sitecore Installer is all you need to get up and running. Due to nature of SQLite, performance might degrade when having large number of concurrent editors.

Firebird. The only file based storage previously existed in 5.x, the slowest choice for 5.3.
Wednesday, July 12, 2006 4:05:11 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | 5.3 | Performance
 Tuesday, July 11, 2006
Sitecore 5.3 beta1 (or beta 060705 to be precise) is live on SDN5 and the word is out. Everyone reading the Sitecore blogs must have seen the really cool, sheer and 2007-ready Content Editor screenshots. True, it is an impressive stuff, but there must be more to new release than just rehauled Content Editor. I’ve been working with production builds lately and haven’t really had a chance to dive into 5.3. So I’m going to change that and blog at the same time.

After downloading your hot copy, there are things you notice before ever having a chance to play with Content Editor:

Running the .exe file gets you to new installation wizard. After providing a valid Sitecore license (old 5.x licenses work fine) you can pick database engine, installation folder and create new IIS site. Basically it does everything needed to get Sitecore instance up and running, asking minimum amount of questions.

new_installer.jpg
Installation wizard

Database selection screen unveils yet another change: new storage engine options. Sitecore 5.3 adds Microsoft SQL Server Express and SQLite support. Both are free file-based storages and last time I saw performance test results, they run faster than Firebird.

Another bit is that SQLite can successfully compete with SQL Express on read operations, which is what serving content is mostly about, while being slower on writes. I’ll check on test results to get back with some more details.

Overall, new installation wizard coupled with fast file-based storage options make deployment a lot easier. I've never used automatic installs previously, but the new one is a nice thing to have.

storage_engine_options.jpg
Storage engine options

To wrap off the post, here are 5.3 recourses available:

SDN5:

Blogs covering 5.3:
Tuesday, July 11, 2006 9:49:20 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | 5.3
 Thursday, May 18, 2006
Make sure you have webresource.axd included in your ignoreUrlPrefixes in Sitecore. It is used to serve resources embedded in assemblies, anything from javascript to images - atlas and some of the asp.net 2.0 rich controls won't work otherwise.

Thursday, May 18, 2006 8:29:55 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore
 Tuesday, May 16, 2006

SDN5 site received a minor facelift and become a bit more firefox firefox 1.5 friendly. If I've broken anything, let me know.
sdn5

Update:
It looks like the layout is broken on Firefox versions < 1.5. Upgrading to 1.5 helps.

Tuesday, May 16, 2006 12:15:55 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore
 Friday, May 12, 2006
SDN5 gets rss feeds, done using Sitecore RSS Module. Check out and subscribe to downloads feed to get notified of new releases. Still need to find a place to stick pretty 'xml' button to.

Finally making use of DefaultButton of asp.net's Panel: searching at sdn5 should work fine with enter button now. If there are other places where enter behaviour should be fixed, send them in.

Speaking of search, sdn5 search autocomplete is finally live. Fixed the issue with list buttons appearing in IE after you hower over menu while autocomplete box is displaying (reported by Alex de Groot, thanks).

Microsoft released the Web Application Project for Visual Studio 2005, which is probably the best option you have working with Sitecore 5.2+ in MSVS. Download.

Very cool Microsoft's Monad shell gets RC1 under a brand new 'Windows PowerShell' name.

Friday, May 12, 2006 5:18:12 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Wednesday, April 19, 2006
I’m using asp.net 2.0 portal on Sitecore front end in the current project, and personalization features such as portlet drag-n-drop just won’t work unless asp.net understands that the user is logged in and can tell the difference between users.

Here’s my hack-n-slash solution: it envolves shim classes implementing IPrincipal and IIdentity, delegating everything to Sitecore. User id is returned as user name to asp.net, so that each user gets own personalization data (actually user names would also work, since they're unique). On each request, a custom processor in HttpBeginRequest pipeline (named AspnetUserSetter) puts the Sitecore principal in asp.net context.

And since I'm humble enough to allow asp.net do the rest, using default personalization database and provider - it just works. Now I wish it was easier to create custom frames around web parts.

public class SitecorePrincipal : IPrincipal
{
  
private IIdentity identity;
  
public IIdentity Identity
   {
      
get { return identity; }
   }
  
  
public SitecorePrincipal()
   {
      identity =
new SitecoreIdentity();
   }

  
/// <summary>
   /// Checks whether Sitecore user is in the given role. Supports both role names and ids.
   /// </summary>
   public bool IsInRole(string role)
   {
      
if (MainUtil.IsID(role))
        
return Sitecore.Context.User.IsInRole(ID.Parse(role));

      
RoleItem roleItem = Sitecore.Context.Domain.GetRole(role);
      
if (roleItem != null)
        
return Sitecore.Context.User.IsInRole(roleItem.ID);
      
else
         return false;
   }
}

public class SitecoreIdentity : IIdentity
{
  
public string Name
   {
      
get { return Sitecore.Context.User.ID.ToString(); }
   }

  
public string AuthenticationType
   {
      
get { return "Sitecore Authentication"; }
   }

  
public bool IsAuthenticated
   {
      
get { return Sitecore.Context.IsLoggedIn; }
   }
}

public class AspnetUserSetter
{
  
public void Process(PipelineArgs args)
   {
      
HttpContext.Current.User = new SitecorePrincipal();
   }
}
Wednesday, April 19, 2006 9:41:41 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Security
 Saturday, April 15, 2006

P1020170.JPGTons of great happened to Sitecore while I was keeping quiet. Completely revamped Content Editor looks amazing, and performs too.


In a weird turn of things, I have installed Office 12 after having a chance to try out our new interface.  It looks like I’m writing the post just to enjoy the experience.  Jakob and Lars have lots of screen shots and detailed info on their blogs.

For the developer goodness, Runi has made most of the main Sitecore API classes support remoting, and it is very simple to use – check out his post for a how to.  There is much more to it, like multiple template inheritance, and hopefully it will start getting out soon.

The best part is that is still the same Sitecore underneath - no breaking changes and no need to start anything from scratch.

And what about me? Well, my mission was to cruise the city promoting the new secret Sitecore Office 13 look and feel using our branding weapon:

P1010676.JPGP1010679.JPG

I am flying back to Ukraine on Sunday morning. It sure has been a very exciting month thanks to everyone around – I truly appreciate that!

Saturday, April 15, 2006 12:07:58 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Personal | Sitecore
 Wednesday, March 29, 2006
When you run your site in a live mode, you can still have the publishing restictions such as publish dates for items, do not publish flag and lifetime for versions to remain in effect. All you need to do is to find your site in <sites> section of web.config file, and add filterItems="true" to it.

The attribute is actually described in inline help above the sites section, but its often missed. Turning it on makes running some sites in live mode much more feasible. The catch that still remains (for live mode) is that if you use html cache, it will not be cleared because there's no publishing event to trigger that.

Wednesday, March 29, 2006 10:34:45 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Performance
 Monday, March 27, 2006
When converting a non-trivial Sitecore 4 solution to V5, consider switching off the search indexes in Sitecore. It should help to speed up the process quite a bit.

update: removing item:save event handlers might also save you some time:

<event name="item:saved">
  <handler type="Sitecore.Links.ItemEventHandler, Sitecore.Kernel" method="OnItemSaved"/>
  <handler type="Sitecore.Tasks.ItemEventHandler, Sitecore.Kernel" method="OnItemSaved"/>
  <handler type="Sitecore.Globalization.ItemEventHandler, Sitecore.Kernel" method="OnItemSaved"/>
  <handler type="Sitecore.Data.Indexing.ItemEventHandler, Sitecore.Kernel" method="OnItemSaved"/>
</event>


although out of these standard four, the first one is more likely to produce some impact, if you've already switched off indexing.

Unless you are running conversion on top of already existing items in V5 database, there's no need to look into item deletion. Saving an item, on the other hand, happens quite a few times.

Once you feel that you're getting close to the desired result, you can use Control Panel in Sitecore to rebuild link database and search indexes, to restore the standard functionality.

Monday, March 27, 2006 5:44:15 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Performance | Upgrading to Sitecore 5
 Friday, March 24, 2006
Since I don't have much to do in evenings, I'm having a great time reading "Getting Real" by 37Signals .. I think V5 is a fairly large product, but just like with less is better, you can stay small in big.

And speaking of getting real, SPN site has finally had a facelift this morning. Now I just need (apart from keeping my fingers crossed) to stretch SDN5 to be just as wide - I have no idea why we haven't done that before.

Friday, March 24, 2006 1:12:40 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore

I think its quite common for various pieces of code in Sitecore to climb the item hierarchy up, seeking some inherited wisdom. A less common scenario, however, is to have a parent which is less visible than its child.

home
|
--news
   |
   --news item

(please bear with my advanced graph engine)

Imagine that you're not allowed to see the news section, but individual news items are just fine - either by mistake, or deliberately. So what happens if you have a code that goes up the tree ? (think breadcrumb)

Item item = this;
while (item != null)
{
   Collect(item.Fields["Menu Title"].Value);
   item = item.Parent;
}

You'll start with news item, which is fine. Then you go up to the news section, trying to read its field.. and get an exception, with a pretty clear message. That item that you don't have access to is considered to be "BrowseOnly", and reading fields of browse only items is bad.

To avoid seeing that exception in future, you need to add a guard clause looking for item.RuntimeSettings.BrowseOnly.

Hopefully this one stops biting me now.

Friday, March 24, 2006 12:48:20 AM (FLE Standard Time, UTC+02:00)  #    Comments [4]
Sitecore | Security
 Thursday, March 02, 2006
Thanks to staying at home with cold I had a chance to add a couple of new features to sdn5. I've also added a 'beta mode' so that they can be tested first. To enable the beta, just go to the http://sdn5.sitecore.net/?sdn5beta= - it will set the beta cookie and thats basically it. You can click 'back to normal' any time, but I'd appreciate if you also let me know whats wrong.

To the features:
sdn5beta.png
1. Search autocomplete

Thats actually the reason I wanted a beta mode first to make sure that javascript works fine for everyone, and doesn't annoy people. The autocomplete data is supplied by new MondoSearch Behaviour Tracking web service based on actual search queries at sdn5, which is very neat.

For client side I've used prototype and scriptaculous javascript frameworks, and I've enjoyed using them both very much. Prototype adds a lot of basic stuff making js coding much easier, and scriptaculous builds high-level effects using prototype. And it even has ready-made ajax and local autocomplete controls making the task really easy. I look forward to playing with them more, but don't want to abuse sdn with cheesy effects.

I'd also like to make use of behaviour in future so that html is totally clean from javascript bits. The downside of all that is of course that its quite a bit of javascript code to download at first visit.

2. Remember me and logout

I think was a very popular request and its a shame that I haven't added it before. I've set it to expire in a day for now, but with sliding expiration enabled. Anyway, this one is also in beta for a while because its not an optimal solution yet, unfortunately.

Hopefully this won't turn into a google-like betas, and I'll move it to a live version soon. Let me know if something doesn't work for you or you simply don't like it.


ps. Sdn5 also has page titles now (again, shame on me), but I was brave enough to make that huge modification on a live site at once.

Thursday, March 02, 2006 10:32:33 AM (FLE Standard Time, UTC+02:00)  #    Comments [5]
Sitecore
 Friday, February 24, 2006
After another unfortunate accident at sdn, I had a strong desire to have at least a couple of simple tests to check that the sites are online and people can log in. With so many infrastructure changes it would hopefully help to reduce human element errors. Having the dense day schedule, it had to became a 'Thursday Night' project (thursay because I though of it at thursday and coudn't sleep until I try it)

Thanks to Scott Hanselman's blog, WATIR was the first thing that popped into my mind. WATIR stands for Web Application Testing in Ruby, and Ruby is being praised by its followers for elegance and joy most of all.

Cutting the long story short (it's actually a short story thanks to ruby) it worked out pretty well, and in a few hours I had tests that would check that

1. The homepage can be loaded and doesn't redirect anywhere else
2. It is possible to log in

WATIR uses Internet Explorer automation, so it will only work with IE available. Obviously it's not the tool of choice to have thorough UI tests, ensuring that everything works as it should in all browsers. However in my case, I think it does a great job with minimum effort.

[ruby source code]

Assuming that you have Ruby and Watir installed, you need to unzip it somewhere and start either cocrete tests (sdn5.rb, sdn4.rb..) or a complete suite (sdnSuite.rb). Double click the file and you should see IE window having its own life. Here's how the sdn5 test case looks like:

require 'Watir'
require 'SdnBase'
require 'test/unit'

class Sdn5 < SdnBase
   def setup
      super
      @homepage = "http://sdn5.sitecore.net/"
   end
 
   def test_homepage
      assert_homepage(/welcome/i)
   end
  
   def test_login
      go_homepage
      @browser.text_field(:id, /username/i).set(@username)
      @browser.text_field(:id, /password/i).set(@password)
      @browser.button(:name, /loginbutton/i).click
      assert(@browser.contains_text(/welcome ar@sitecore.net/i), "failed to log in")
   end
 end


Note that login tests will fail because I've removed my password in SdnBase.

Here's what will get you started:
1. Install Ruby for Windows. The simpliest way is Ruby one click installer
2. Install WATIR [http://wtr.rubyforge.org/]. Again, there's a windows installer available
3. Read WATIR user guide for starting steps
4. A great companion to WATIR would be either Firefox DOM explorer or IE web developer toolbar
[5]. If you want to get serious, Scott Hanselman has an NUnit-Watir integration guide

Another interesting thing to look at is Selenium:

"Selenium uses JavaScript and Iframes to embed a test automation engine in your browser. This technique should work with any JavaScript-enabled browser."

It supports xpath to access DOM elements, which is nice and familiar to Sitecore developers. I think it might even be reasonable to make Sitecore shell tests with something like that. It would definitely involve a combined effort, but might be worth looking at.

Friday, February 24, 2006 1:21:57 PM (FLE Standard Time, UTC+02:00)  #    Comments [3]
Ruby | Sitecore | QA
 Thursday, February 23, 2006

Html Agility Pack is shipped with Sitecore for a while, but now I actually needed something to process html fields. When you see a new API an API you haven't used before, write some code against it without looking into any reference (because the names are descriptive and/or somehow familiar) and it works the first time - doesn't it gives a kind of pleasant warm feeling inside?

HtmlField html = (HtmlField)item.Fields["text"];
foreach (HtmlNode node in html.SelectNodes("//img[@src]"))
{
  if (!string.IsNullOrEmpty(node.Attributes["src"].Value))
  {
    node.Attributes["src"].Value = ReplaceText(node.Attributes["src"].Value);
  }
}

Thursday, February 23, 2006 9:40:01 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore
 Monday, February 20, 2006
Web application project has been a bless for me so far.. Although there's no migration wizard yet, converting the www.sitecore.net MSVS 2005 project (which I'm currenly working on) was a snap, and it was a huge relief from the first minute.

The project is basically a good old class library but with working asp.net designers, and thats good.

* Upgrading VS 2005 Web Site Projects to be VS 2005 Web Application Project
* Upgrading VS 2003 Web Projects to be VS 2005 Web Application Projects

Monday, February 20, 2006 10:10:17 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Visual Studio
Beware of Credential Cache

As I've told before, we're now using Microsoft CRM system to manage extranet users. When you log in, the user data is being fetched from sql table, a virtual user is assembled using the ID from CRM and given the Sitecore security roles based on CRM permissions.

There's one catch though - Sitecore maintains a credential cache (since around 5.1 I think), so that it doesn't have to repeatedly calculate effective permissions for a given user to a given item. Once the user accesses the item the first time, permissions are calculated and stored in cache. Sitecore also makes sure to clear the cache when required. In our case, however, the user is changed inside the CRM system, and its our responsibility to let Sitecore know about it. Failing to do so might result in permission changes only taking effect after application restart.

There are several options to handle that:

1) Clear the cache once any entities affecting access permissions were changed.

In the case with Microsoft CRM that would mean registering a callout on 'account' or 'contact' entities change. The web service on Sitecore side listens for notifications and clears the cache on demand.

Pro: Security updates are in effect immediately
Con: More complicated, requires an outgoing connection from CRM to Sitecore web server

2) Clear the credential cache for a user each time he logs in

Overriding Sitecore.SecurityModel.Domain.Login(string, string) will hook you up right in there - it gets called each time the user tries to log in suppling her login and password

Pro: Simple
Con: Security might not be updated until user session times out. Cache is clearead unconditionally

To be honest I've wasted time on both. The CRM callout didn't fit in because of the need of active outgoing connection, and we're now using the second one.

[CredentialCacheController]

Monday, February 20, 2006 7:34:47 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Security
 Thursday, February 16, 2006
Speaking of web application projects in MSVS, it looks like they had a brand new refresh with long awaited codebeside updater. Known issues look unsignificant, except for Migration Wizard, perhaps. Looking forward to try that.

Thursday, February 16, 2006 1:24:59 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Visual Studio

It’s been a while since I’ve posted and the blank page looks scarier than ever.

SDN and SPN sites went live on Sitecore 5.2 two weeks ago, on January 30th; it’s not exactly ‘news’ at this point. It has been a significant change in a number of ways: moving to a latest Sitecore from 4.3.2.5, using asp.net 2.0 and weird web projects in MSVS.2005.

We’ve also integrated our security with Microsoft CRM 3.0 system - there are no extranet users in Sitecore itself, and everything being fetched from CRM database and turned into virtual users with appropriate roles assigned.

The last but definitely not least is the MondoSearch search engine and Behavior Tracking by MondoSoft that we’re now using on all three (sdn4/sdn5/spn) sites. More posts to come on this.

It looks like we did fine – there was no downtime during the change (although, uhh, server had run out of disk space last weekend... and, uhh, some exceptions were flying around a couple of times) and everyone had to bear with me and stop updating the site for less than two weeks only.

What we’ve gained from that is a better performing solution (no kidding) and a large amount of very-own-dog-food. The later is especially important even from my limited experience – hopefully I’ve did a number of good things along the way.

Database migration wizard received the most attention obviously, trying to make sure that it can handle all the little Sitecore 4 oddities I’ve encountered. However, It will not be released in it current form, becoming a component in new Data Transfer tool instead. It’s expected to be released pretty soon, from what I know.

The last few days were spent on capturing my ‘experience’ on paper; I’ll put up a draft soon, begging for feedback.

Now I need a bottom line, and it looks like “I RULE!” doesn’t fit. I’ll try this: if anyone is considering moving to Sitecore 5 from 4, let me know. Let me know what bothers you the most, let me know what areas you’d like to see covered in migration guide – I’m information hungry. Hopefully (for me) I’ll have something to share in return.

Thursday, February 16, 2006 1:08:37 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Upgrading to Sitecore 5
 Sunday, January 15, 2006
There's a number of options to speed up your Sitecore development installation:

1. Disable the indexes. Indexes are responsible for the little search bar in Sitecore taskbar. If you can happily live without it, then comment out the <indexes> section inside your database section in web.config (that is most probably /databases/master/indexes). The search will go away, along with index updates on each item create/update/delete operation.

2. Switch your site to the 'live' mode. Live mode completely eliminates the need for publishing, which can be pretty annoying in development scenarios, by taking all items directly from the content authoring database. To activate find your website in <sites> section of web.config (the site is called 'website' by default) and change database="web" to database="master". This is the way Sitecore client site works on core database. Naturally, by switching the publishing off you also lose the publishing restrictions, that is 'do not publish'/'publish date' stuff.


Sunday, January 15, 2006 11:46:59 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Performance
 Friday, January 13, 2006
A new Sitecore blog by Mark Cassidy - welcome.
Metanauts - CMS discussion forum. You've probably seen this one in yahoo groups.

Friday, January 13, 2006 8:02:13 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Thursday, January 12, 2006

I'm not sure whether it's a great example of Sitecore extensibilty or of things you shouldn't do, but I though I'd share it anyway :)

TaskbarSections.png

This little snippet adds shortcut to all content sections (and a little unsupported yet indispensable dbbrowser) to the Sitecore task bar. What is good about is, is that its very easy to install: download and unpack to your /sitecore/shell/override, its just two xml layouts with embedded code. The dark side is that you have to put them in override folder to replace the standard Sitecore start bar. So if the start bar changes in future builds - yours won't.

Fortunatelly, uninstalling is just as easy: remove the Startbar.xml and StartbarSections.xml files and thats it. Standard disclaimers apply: if your PC turns into evil alien monster and starts dissecting humans - you have been warned. Although it might be a good idea to keep your production server clean, I (humbly) find this control to be very useful in development environment.

Once again - download link (3kb).

Thursday, January 12, 2006 10:07:46 AM (FLE Standard Time, UTC+02:00)  #    Comments [5]
Sitecore | Open Source | Sheer UI
 Wednesday, December 28, 2005
I've mentioned earlier in Sitecore yahoo group the possibility of creating a replacement of multi list field by replacing left select box with a tree view. The control now is available at SDN5 in shared source form and I encourage everyone to take a look at it, as I believe the field to be very useful in situations when you have large number of items to choose from (Multi list with 100 items doesn't look pretty).

Tree list field

Wednesday, December 28, 2005 11:54:56 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Open Source | Sheer UI
 Wednesday, December 21, 2005
Sitecore 4 developers are familiar with the login rendering concept: It is possible for any rendering to have its counterpart login rendering which gets shown if the user doesn't have required permission to access content.

I'll use SDN as an example - try to access an item that anonymous user is not allowed to read, like http://sdn.sitecore.net/articles.ascx. You can still see the layout. Moreover, top menu renders items accessible to the current user (Documentation is a public section) and the breadcrumb shows your correct location (home / articles) even though you cannot see the item itself.

The main content rendering (the one in the centre) shows the 'please login' info because it has the login rendering set, and Sitecore layout engine knows that the current user (anonymous) is not allowed to access the current item (/home/articles).

The concept is fundamentally changed in Sitecore 5 because of one difference: if the current user is not allowed to access the current page, he is redirected to:

1. Login page if the login page is specified for the current site, controlled by the loginPage property of each individual site.
2. No access page, controlled by NoAccessUrl setting in web.config.

in any way, he won't be able the access the item as he used to in Sitecore 4 at SDN, even without the content.

This logic is baked in the ExecuteRequest processor in httpRequestBegin pipeline. It’s not easy to change it though (I've moved the explanation to the end of the post to avoid clutter). And it's not a good idea to modify bunch of processors only to make things as they were before anyway. Two common requirements for scenarios when user is not allowed to access content he tries to are:

1. User is presented with a friendly message explaining what happened.
2. Along with the friendly message, user can login and see the page he's trying to access.

Login page supports both:

1. Create a new item, and allow 'read' for everyone. Locate your site in the <sites> section of web.config, and set a loginPage property:
<sites>
  <website loginPage="/home/login.aspx" .. />
</sites>


This item will probably have the default layout of the site, but instead of the content rendering it should have a 'login rendering' explaining that a user has to login to access the item.

2. When redirecting to login page, Sitecore will fill two query string parameters: 'item' and 'login'. This solves the last requirement - how to redirect user back to the requested item.

I've made a little class to handle this for sdn/spn sites, here's how it can be used:

DomainAccessResult result = new LoginManager().Login(emailTextBox.Value, passwordTextBox.Value);


It performs the usual Sitecore.Context.Domain.Login() and
a) redirects user back to the requested item if any
b) redirects user to 'login failed page' if it’s specified either in web.config or class property.

download link: LoginManager.cs

--
If you allow all users to see restricted pages and allow ItemResolver processor (earlier in the same pipeline) to set the Sitecore.Context.Item property - you're creating a possible security hole. Renderings do not perform explicit permission check every time they need to output some content - having the Sitecore.Context.Item set is enough to know that the item meets all criteria and can be shown.

The other option is to leave standard ItemResolver processor but still modify ExecuteRequest: this way user will be redirected to layout but Sitecore.Context.item will remain null. Security is ok this way, but because context item is not set Sitecore layout engine has no clue which item user wanted to access (and wasn't able to) - therefore it cannot decide (among other things) whether it should show the login rendering or not.

Wednesday, December 21, 2005 1:00:57 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Security | Upgrading to Sitecore 5
 Friday, December 16, 2005

One of the most common issues in Sitecore 4 to 5 migration is item names. Sitecore 5 has much more strict item naming rules by default:

  1. Item name cannot be longer than 100 characters
  2. Item name cannot end with a dot
  3. Item name cannot start or end with blanks
  4. Item name must not contain any of the characters specified by the 'InvalidItemNameChars' setting
  5. Item name must match the regexp pattern specified by ItemNameValidatation setting

You can control 2 out of the 5 restrictions via the web.config. Their default values are:

<setting name="InvalidItemNameChars" value='\/:*?"&lt;&gt;|[]' />
<setting name="ItemNameValidation" value="^\w[\w\s\.]*$" />

You should try to avoid removing any chars from the InvalidItemNamechars - items with invalid characters in names can be source of unpredictable errors. ItemNameValidation, although more restrictive, is another case - its main purpose is to enforce url 'friendliness'. An url to the item is built using item name so it is important that the name is kept simple and in compliance with W3C standards so that url is short, easier to remember and not messed up with special characters encoded with their unicode values or Sitecore url encoding rules. Sitecore query is also quite sensitive to item names.

When developing solutions with Sitecore 5 right from the start it is good practice to leave the item name validation intact - keep item names simple, and use DisplayName property (found in Appearance section) to control title of the item in client. DisplayName is a languaged field so you will probably use it anyway in multilanguaged solutions.

Migration from Sitecore 4 is another story. It is desired to have as little changes as possible to preserve your urls and item links. Sitecore database migration tool does have the following logic baked in when item name is not 'good enough' for Sitecore 5: it enforces item naming rules from 1 to 4 one by one: cuts the item name to 100 characters, removes trailing dot, trims the name and then strips InvalidItemNameChars characters. If the item name is still not accepted by Sitecore 5 it means that the name doesn't match the ItemNameValidation pattern and upgrade tool has no other choice but to give up and replace the name with 'Invalid Name'. To avoid that you can tweak the ItemNameValidation pattern or even disable it completely when performing upgrade and then reenable it again to make sure that new items follow the 'best practice' rules.

The new release of upgrade tool will also keep track of all items it had to rename in a separate log file so that you can inspect it later and make sure that there are no broken links.

When the items are successfully transferred to Sitecore 5 you can use its built-in link checking capabilities to rename items without breaking any internal links. Please note however, that external links will be changed even in this case.

Friday, December 16, 2005 6:19:03 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Upgrading to Sitecore 5

As with many other frameworks, you need a bit of insight on internal processes to create effective solutions.

 

Sitecore Query is XPath-like query language that allows both simple 'by name' or 'by path' resolutions and complex expressions. What is special about it is that query can be handled either directly in the database on data provider level or by the data manager tier. When the query is being resolved, data manager tries to use its data providers first and resorts to  higher level (read: slower) API in case of failure.

 

Sql server data provider (as well as the other standard providers I think) supports only a small subset of query: '/sitecore/content/home' - resolving item by path and '//home' - resolving item by name.

 

What does this really mean? Imagine that you have a large site with sql server database backend and you're trying to find some content items. For most simple scenario, we need to find all content items named 'needle':

 

Item content = Sitecore.Context.Database.Items["/sitecore/content"];
Item[] needles = content.Axes.SelectItems("//needle");

Sql server data provider supports this kind of query, so the query gets resolved directly in the database fairly fast even though we have a large number of content items. 

Then we complicate the requirements a bit: say our items have 'IsHidden' checkbox field and we only want needles that are not hidden:

Item content = Sitecore.Context.Database.Items["/sitecore/content"];
Item[] needles = content.Axes.SelectItems("//needle[@IsHidden != 1]");

Predicates are not supported by the sql server data provider, so it ignores the query. We don't have any other data providers in our database, so as I said earlier data manager resorts to higher level query api. This basically means that all items in the query scope (all descendants of /sitecore/content in this example) are loaded so that predicate can be evaluated against each item and the matching items are returned.

 

The difference between database and item evaluation can be quite dramatic. Now understanding how data manager and data providers work together to evaluate the query, lets improve our solution:

Item content = Sitecore.Context.Database.Items["/sitecore/content"];
// Limit ourselves to dataprovider-supported query
Item[] allNeedles = content.Axes.SelectItems("//needle");

// Do the additional filtering - [@isHidden != "1"] predicate evaluation.
List<Item> nonHiddenNeedles = new List<Item>();
foreach(Item item in allNeedles)
{
   if (item["IsHidden"] != "1")
   {
      nonHiddenNeedles.Add(item);
   }
}

By using '//needle' query we obtain all items named 'needle' in a very efficient way because the query is resolved in the database. There are probably only a few such items, so iterating through each of them to check the 'isHidden' field should also be fairly inexpensive and it only requires a few additional lines of code.

 

Sql server data provider will be able to support field value predicates soon, but the point remains the same: understand what kinds of query are supported by your database backend when querying against large item sets.

 

And there's another one: when creating data providers, support common query scenarios to avoid performance downfalls.

Friday, December 16, 2005 1:45:49 AM (FLE Standard Time, UTC+02:00)  #    Comments [5]
Sitecore | Performance
 Monday, December 12, 2005
Please welcome new Sitecore blog - Alex de Groot: Few words about SiteCore from Holland. Its great to see Sitecore partners starting blogs too.

Monday, December 12, 2005 6:02:16 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Tuesday, December 06, 2005
There's one common gotcha when adding your own web service to Sitecore: if you allow Visual Studio to do the job for you, it will create a new application for the web service to be placed in. This is always bad idea with Sitecore, and you will get 'httpRequestBegin' pipeline not found exception. To fix it simply remove the application.

And if for some reason your web service has file extension different from '.asmx' - create a custom httpBeginRequest processor to ignore all requests with that extension or add your webservice to IgnoreURLs setting.

Tuesday, December 06, 2005 12:33:18 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
Perhaps some of these will help better manage Sitecore solutions in VS 2005: Some Techniques for Better Managing Files in Visual Studio 2005 Web Projects (MSDN). In short: if you have a really large upload folder, you can make it a virtual folder (but not an application!) and open your web project as 'Local IIS' project instead of 'Filesystem' in visual studio. Then upload folder will not be a part of the site and will not be published by VS 2005.

And you can always use Sitecore MediaFolder setting to place your upload outside of the site root.

Tuesday, December 06, 2005 12:22:22 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Friday, December 02, 2005

We have an interesting shared source release that I'd like to point your attention to. Xml data provider is a custom data provider that allows you to import any external data as long as you provide a transformation to Sitecore item xml format. So why is this so useful?

The provider comes with an example of importing RSS/Atom feed data. All you need to do is to create a new feed definition item, point it to valid feed and set settings like refresh rate. If the feed has any entries they will be shown as children of your item, being perfectly valid (although immutable) Sitecore items.

Atom feed entries as Sitecore items

 

While we had some RSS reader components in past, this one is totally different: your presentation doesn't have to handle feed data in some different way - you can reuse your renderings and your skills, setting up rss feeds in no time.

However its important to see that RSS aggregation is merely an example of what can be done. To import any other kind of external data, all you have to do is to provide a xsl tranformation and a simple class to register it. Provider understands a fairly simple xml format that is similar to Sitecore item xml: you can find an example in provider documentation.

And with source code available to download, its easily extendable and a great example of writing your own data provider.

Friday, December 02, 2005 10:32:58 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Open Source

Give your warmest greetings to new Sitecore Support blog by Alexander Shyba. We have a fairly large number of interesting support cases each day, so I believe this is a must-subscribe for anyone dealing with Sitecore solutions. There are already a number of unusual entries that can save you some hair-pulling.

Friday, December 02, 2005 10:11:54 AM (FLE Standard Time, UTC+02:00)  #    Comments [1]
Sitecore
 Monday, November 28, 2005

Jukka-Pekka Keisala posted a link to a great firefox extension: welcome IETab! It seamlessly embeds IE in a firefox tab, and guess what - Sitecore runs just fine in it, so now you can have IE-flawored Sitecore inside a firefox.
Must have - install.

Update: the only glitch I've found so far is that Ctrl+S doesn't work.
Monday, November 28, 2005 11:43:39 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Monday, November 21, 2005
An interesting read considering upcoming Sitecore .net 2.0 support  : breaking changes in .NET 2.0

Monday, November 21, 2005 11:30:28 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Friday, November 18, 2005

Contrary to Sitecore 4 which only understood one or several item pointers in field source, it is possible to use Sitecore query in version 5 to control which items should be displayed in multilist/lookup controls.

Examples
(put these in 'source' of the field):
query:/sitecore/content/sdn5//* - gets all descendants of /sitecore/content/sdn5 item.
query:/sitecore/content/sdn5//*[@@templateid='{76036F5E-CBCE-46D1-AF0A-4143F9B557AA}']- gets all descendants of /sitecore/content/sdn5 item based on 'document' template.

Friday, November 18, 2005 11:55:14 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Tuesday, November 08, 2005
Shared source library got reinforced with Sitecore RSS portlets. There are basically two kinds of portlets - "Feed subscription manager" is used to subscribe/modify/unsubscribe, and feed reader portlets retrieve and render feeds. When you add a new feed, subscription manager adds a new portlet in portal and then users can add it to portal using the 'Add Content' button.

rss_portlets.png
RSS portlets

Portlets are installed in Sitecore Today portal by default, but you can move them to any portal of your choice.
Please note that its more of a demo, so there's no caching or uniform feed model. You can subscribe to atom feeds, but you will need to create and use different transformation for them.
Tuesday, November 08, 2005 4:35:40 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Open Source | Sheer UI
 Monday, November 07, 2005

Handy Sitecore.Contex is thread-local storage, so as soon as leave you leave sweet and warm asp.net request thread, you need to set it up for yourself. Fortunately, it is an easy task: you should pass a Sitecore site name to your child thread  (available as Sitecore.Site.Name in the parent thread if you want to execute in the same site context), and then do a Sitecore.Context.SetActiveSite(aSiteName).

Optionally you might choose to either switch the security checks off
  Sitecore.Context.Security.EnterState(SecurityState.Disabled)
or leave the security intact, pass a user name or id to your thread and do a
  UserItem user = Sitecore.Context.Domain.GetUser(aUserName);
 Sitecore.Context.Security.EnterUser(user);

Sites are setup in <sites> section of the web.config file, so if you want your thread to execute in specific context with its own settings (own database, perhaps) - set up another site in web.config and use its name instead.

Setting up context when you spawn a new thread is rather important - even if you don't use it directly, most of the higher-level API does.
Monday, November 07, 2005 11:23:40 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Security
 Wednesday, October 19, 2005

Sitecore Open Source Library was recently reinforced by three portlets by Yan Sklyarenko. They differ in complexety level, but all three are must-see example for anyone developing Sitecore portlets. All three portlets are 100% practical and can benefit almost any Sitecore solution.

The simplest of the three porlets - Logged In Users, shows a list of currenly logged in users, allowing to kick someone if you have run out of user licenses. (Note that the kick won't work if you still have free licenses). The list of logged in users is provided by the Users property of Sitecore.Web.Authentication.DomainAccessGuard class, and the rest of the code handles the UI and kick logic.

Logged in Users portlet

Unapproved Items portlet lets any user see which of his items got stuck unapproved higher up the workflow. This allows editors to track the state of their articles and see how far did they manage to get in the reviewing process. The portlet uses the Sitecore workflow API: IWorkflowProvider, IWorkflow and WorkflowState to get the list of items created by the particular users which are not yet in the final state of the workflow.


Unapproved Items portlet

The My Locked Items portlet is the most complex one. The logic itself is fairly simple: the portlet shows the list of all items checked out by the current user, and allows user to either selectively check-in one item or check in all. Sitecore.Data.Locking.ItemLocking class is used to get the current locking status of an item, particulary its HasLock() method. However what makes it complicated is that you need to iterate through all items in database to get the list of items locked by a user, and that is not a wise choise to do each time someone opens the portal. To avoid the performance hit the portlet subsribes to the check-in and check-out events and maintains its own checked out items cache, so that it only needs to iterate through all the items if the cache is not populated yet.

I'm sure that the portlets not only can serve as the example for the developer, but also add functionality useful in most of the Sitecore solutions. I think they integrate in the Overview portal by default, but you can easily change that since the portals are defined in the 'core' database by the content items - so you will only need to copy the porlet definition item from one portal to another.

Related article: Understanding Workflows.
Wednesday, October 19, 2005 10:24:01 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Open Source
 Friday, October 14, 2005

I've run into another Sitecore blog by accident: The Sitecore Experience is a blog run by a team of people developing Sitecore solutions. It's not very active at the moment but hopefully that will change in future.

If you know any other Sitecore related blogs, please let me know.
Friday, October 14, 2005 7:49:05 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Thursday, October 13, 2005

One of the 'neat' tricks in Sitecore RSS module is a fast way of getting all items based on the certain template.

RSS module supports different kind of feeds, and some of them (static feeds) are only refreshed on publish event to gain performance. For simplicity sake the logic is pretty straight-forward: when the publish:end event is fired, get all the feed items in the publish target database and rebuild rss feeds.

Iterating through the entire database is very expensive operation though, even if it is only performed on each publish. The most simple, but restraining solution is to only allow placing feeds under some specific folder, like 'RSS feed'. Performance is ok, but the user cannot place the feed items whererever he likes.

One way to speed up the search while still allowing user to place items anywhere in the database would be using Sitecore query: //*[@@templateid='{11111111-1111-1111-111111111111}']. It will still take a few seconds on a relatively empty database in 5.0.7.3 because its not actually that empty anyway.

However in this particular case, we can resort to the Link database. Link database is used by Sitecore to resolve all the linking issues - what referers and what references does the item have. And if an item is based on a template, it also counts as a reference from the item to the template. The solution then is very simple: get all the referers for the rss feed template item and then sort them to only include specific items. This is how it's done in RSS module:

private static Item[] GetFeedsInDatabase(Database database, Language language)
{
   TemplateItem feedTemplate = database.Templates[Constants.FeedTemplateID];
   if (feedTemplate == null)
   {
      return null;
   }

   // Get all items refering to the feed template
   ItemLink[] links = Globals.LinkDatabase.GetReferers(feedTemplate.InnerItem);
   if (links == null)
   {
      return null;
   }

   ArrayList result = new ArrayList(links.Length);
   // and filter the referers - we dont need to include masters
   foreach(ItemLink link in links)
   {
      if (link.SourceDatabaseName == database.Name)
      {
         Item item = database.Items[link.SourceItemID, language];
         if ((item != null) && (IsMaster(item) == false))
         {
            result.Add(item);
         }
      }
   }

   return (Item[])result.ToArray(typeof(Item));
}

I regret that It wasn't me who came up with the idea itself (kudos to Dmitry Kostenko). I can imagine that it can still take some time to complete on fairly large databases - I haven't done any real big scale tests, but it works a lot faster than query in my environment and it is possible to place 'articles' rss feed into the articles content tree where it belongs, intead of the global rss feeds folder.

And since the module is open source, it will take 5 minutes to rewrite it to only look inside the 'RSS feeds' folder instead of the whole database or 15 minutes to make that optional.

Thursday, October 13, 2005 12:15:54 PM (FLE Standard Time, UTC+02:00)  #    Comments [4]
Sitecore | Open Source
 Wednesday, October 12, 2005

The Open Source library quietly spins off in the shadows of 5.1 beta. The main purpose it to provide Sitecore developers with a number of practical examples, showing how to develop with Sitecore, the best practices and cool tricks.

Another very important goal of the open source library is to help building a Sitecore developer community and it means that feedback and user contributions are most welcome! The current library structure will improve as the library grows bigger, so that it will be easier to stay updated, provide feedback and contribute to the projects.

At the moment there are Sitecore web controls library, part of which was previously available in the Articles section, and a newly released Sitecore RSS Module. It grows quickly though - a number of portlets showing the logged in users, items that are checked out and items in specific workflow state are to be available in the nearest future, again, with full source code.

Sitecore RSS module allows you to easily syndicate your content providing RSS feeds to end users. All you need to do is install the RSS module and create one or more RSS feeds syndicating the specific content branch, single site or the whole Sitecore solution and then provide users with a feed link.



Then a user may choose to subscribe to the feed of one’s interest (one may only be interested in new downloads or new articles on xaml technology) and have all of the updates delivered to one’s PC automatically. It is really simple and convenient!



Sitecore RSS Module supports different kinds of feeds, like the ones that are refreshed on each Sitecore publishing, thus saving server resources, or the dynamic feeds which are generated upon surfer’s request and support item-specific security.

It is also possible to turn any content item into RSS feed so that the users are completely free in their choice of subscription, whether it’s the whole articles section, a specific content branch or even a single article.

At the moment there is no standard way to provide feedback, so if have any comments on the RSS module you can use yahoo groups or mail me directly.
Wednesday, October 12, 2005 6:33:55 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Open Source
 Wednesday, October 05, 2005

I have added the velocity master variables replacer to the extended mail action, and put them together into one project and package.
Thanks to Jakob, adding master variables replacer is as easy as it gets now, just put your class into
<setting name="MasterVariablesReplacer" value="Sitecore.Data.MasterVariablesReplacer,Sitecore.Kernel.dll" />
in web.config and derive from default Sitecore.Data.MasterVariablesReplacer. No need to hook in the pipelines!

VelocityMasterReplacer works much like the Extended mail action. Instead of having only a few predefined macro expansions like $name and $parentName, you can now use pretty much anything accessible via the Sitecore API: $user.Name, $item.Children.Count, $item.Paths.Path, $item.Fields["Text"] and even the flow control:
#foreach($child in $item.Children)
   Child - $child.Name
#end
(Make sure that you know this before trying that trick with children)

It is also backwards compatible - after the velocity replacer does its job, it calls the base method to finish the rest.
Anyway, here's the source files - SitecoreVelocity_1.1.0.0.zip (411.82 KB). (You will need Sitecore 5.1.0.4 aka 5.1 beta1 for that)

If you just need a package - its in the /data/packages folder of the archive.

Update: sorry, link fixed.
Wednesday, October 05, 2005 3:43:41 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | NVelocity
 Friday, September 30, 2005

I've started Sitecore MySQL provider - to make Sitecore run on my sql database. The first part naturally is to convert existing Sitecore MS SQL databases to MySQL ones. They've been developing 5.0 version for 3 years now and just released the Release Candidate.. but as much as I'd like to do it 5.0 only, we still need to support stable 4.1 versions, so - no stored procedures and no views. I think we will have the 5.0 enabled version in future and I'll try to make the transition as easy as possible, but for now getting Sitecore run on 4.1 is definitely a priority.

MySQL has the MySQL migration toolkit that helps to convert existing databases, and it does support MS SQL. So sure, I've decided to try it first. However it wouldn't connect to my local MSDE server, giving me the "Network error IOException: Connection refused: connect". So I've started writing a error report to mysql forums while banging my head on the wall, and here's the results:

"
I'm having exactly the same problem: "Network error IOException: Connection refused: connect" both on the source database selection screen (clicking the [...]) and connecting to servers screen in MySQL migration toolkit.

I have MSDE 2000 installed locally on my machine, so I'm quite positive that host names (I've tried any possible combination), port, user name and password are correct. I can connect to the server using the enterprise manager, query analyzer or whatever else with the same credentials.

I've also ensured that both named pipes and tcp/ip are enabled. This post suggests that MS SQL SP3a helps: I've installed SP4 but again with no luck.

I'm resorting to manual migration at the moment, but I'd really appreciate if I could get migration toolkit working.

Update:
I've searched the web, and tried using named pipes instead of the tcp/ip: jdbc:jtds:sqlserver://127.0.0.1;user=user;password=password;namedPipe=true.

First it gave me some error code instead of the 'connection refused' error and then the migration toolkit application crashed. But it actually worked after restart!

Hope this helps.
"

I'm proceeding with the migration at the moment, hopefully more info will follow.
Friday, September 30, 2005 2:57:26 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
MySQL | Sitecore
 Wednesday, September 28, 2005

Extended mail action 1.0.0.1, built against Sitecore 5.0.7.3 and NVelocity 0.4.2.8582_Sitecore.

[Sitecore package]
Package now doesn't include NVelocity binaries - they need to be installed separately.

[Source]
Extract in the root of the Sitecore solution.

NVelocity 0.4.2.8582_Sitecore
[Source]

The only difference code wise is the 'if' clause in the constuctor of RecourceLocator class. It makes the recource locator skip the dynamic modules - they don't support GetManifestResourceNames() method

if (a is AssemblyBuilder == false)
{
    String prefix = a.FullName.Substring(0,a.FullName.IndexOf(",")).ToLower();
    String[] names = a.GetManifestResourceNames();
    foreach(String s in names) {
        if (s.ToLower().Equals(fn) || s.ToLower().Equals(prefix + "." + fn)) {
           this.filename = s;
           assembly = a;
           isResource = true;
        }
    }
}

Apart from that, I've excluded the supplementary projects like nAnt tasks from the solution. I wonder if I should merge commons into the nvelocity assembly..
Wednesday, September 28, 2005 10:33:05 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | NVelocity | Extended mail action

Sitecore blog ring is finally getting in shape:
Jakob Christensen, Ole Thrane, Runi Thompsen and Yours Truly ('yours truly' could be some scandinavian guy)

Make some space in your rss aggregators.
Wednesday, September 28, 2005 6:42:38 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore

I've put up a custom build of NVelocity tailored to run inside Sitecore as a separate download here:

This is a custom build of NVelocity project, tailored to run inside Sitecore CMS.
Original NVelocity had a couple of issues:

  • It referenced signed log4net assembly that conflicted with the one in Sitecore distribution
  • It was failing while trying to get its default properties due to a bug in RecourceLocator: dynamic modules where not supported
I needed a quick fix (it seems that nvelocity projects is not very active at the moment) so I went with the custom build.

Wednesday, September 28, 2005 12:02:36 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | NVelocity
 Monday, September 26, 2005

Extended mail action adds a little extra to the standard Sitecore workflow mail notification by using the NVelocity template engine. In case you didn't know, standard Sitecore email action supports three hard-coded macro expansions: $itemPath$, $itemLanguage$ and $itemVersion$. So instead of sending a completely static mail notification saying that something had been changed somewhere you can add something like "Hello. Item $itemPath$ had been changed".

Well, thanks to the NVelocity template engine, extended mail action takes it to the next level! Here's the example message template:

Time: $time

State of the $item.Name item (located at $item.Paths.Path) had been changed from '$state.DisplayName' to '$nextState' by $user.Name ($user.Email).

Item workflow history:
#foreach ($historyItem in $history)
Date: $historyItem.Date | User: $historyItem.User | Action: $historyItem.Text
#end

The item was last updated on $item.Statistics.Updated.

and here's the the result:

Time: 26.09.2005 1:03:25

State of the Extended Mail Item item (located at /sitecore/content/Home/Extended Mail Item) had been changed from 'Editing' to 'Done' by Admin (jc-[at]-sitecore.net).

Item workflow history:
Date: 26.09.2005 1:02:45 | User: sitecore\Admin | Action: Item created

The item was last updated on 26.09.2005 1:03:22.

Even though it mostly looks like an additional number of hardcoded macros, its much more powerful: using the NVelocity templates you can code against the Sitecore API using the Sitecore client as long as the method/property evaluates to string. So now you don't have to start Visual Studio every time you need to change your custom template, and the educated users can do it themselves.

How to use it:

  1. First of all, if you're not familiar with the Sitecore V5 workflows and workflow actions, I suggest that you read about them first.
  2. Download and install the package.
  3. Extended email action template is installed to the /templates/workflow folder.
  4. There's also an example 1-step workflow installed with the package - Extended Mail Demo Workflow.

Here's how the shortcuts are defined:

/// <summary>
/// Populates the velocity template context. Only the objects that were
/// added in this method will be accessible in the mail template.
/// </summary>
/// <remarks>Override this to add your own data to the context</remarks>
protected virtual void PopulateContext(WorkflowPipelineArgs args)
{
   velocityContext.Put("args", args);
   velocityContext.Put("item", args.DataItem);
   velocityContext.Put("processor", args.ProcessorItem);
   velocityContext.Put("user", Sitecore.Context.User);
   velocityContext.Put("history", args.DataItem.State.GetWorkflow().GetHistory(args.DataItem));
   velocityContext.Put("state", args.DataItem.State.GetWorkflowState());
   velocityContext.Put("nextState", GetNextState(args));
   velocityContext.Put("site", Sitecore.Context.Site);
   velocityContext.Put("time", DateTime.Now);
}

As it says, if you need your own shortcuts/helpers than override the method, place your assembly into the /bin folder and change the 'type' field in the action item in Sitecore.

The Velocity itself is a powerful tool: you can define your own macros and variables, use basic conditions (#if) and loops (#foreach) and parse external templates. Google it if you need more information - most of the hits will come from the java version of Velocity, but it's almost the same.

Monday, September 26, 2005 1:40:07 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Extended mail action | Workflow
 Thursday, September 22, 2005

There's an interesting problem related to publish event and getting the full url to the item. Sometimes you'd like to get the full or relative link to the item in publish:end event to rebuild your own data cache/structures. However if you try to get item.Paths.GetFriendlyUrl() in publishing context, you will only get '/', and its a 'feature', not a bug.

If you look at the <sites> section in web.config you'll see that publisher site definition is quite scarce:
<site name="publisher" domain="sitecore" enableWorkflow="true" />
virtualFolder, physicalFolder and rootPath properties are all missing, because well, publisher site is only used to publish items from one database to other.

You could set those properties for yourself, if only you knew which site will be serving the item to the user. The same goes with host: to assemble a full url you need an actual http request to get the host and construct the full url from the host and item friendly url.

You can, however, go around this friendly url issue by yourself, if you only have one site that will be serving items, or if you have multiple sites but there's strict n-1 relation between items and site, i.e. each item can only be served by one and only one site.
Thursday, September 22, 2005 9:51:47 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Monday, September 12, 2005
How to add a custom button to Sitecore rich text editor (Html Editor). Soon to be available as an article on SDN5.

Buttons displayed in the html editor tool bars are determined by the editor profiles. However a 'click' in 'html editor button' item contains a button name that is recognizable by the Cutesoft editor, and not the actual client side command to execute. So two steps should be made to properly add a new button to the html editor toolbar...
Monday, September 12, 2005 7:09:04 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Rich Text Editor
 Friday, September 02, 2005

I haven't been updating in a while. One of the reasons is that we now have a lot of new projects breeding inside, but the actual one is that at the moment we're at the St.Tomas hotel in Copenhagen, Denmark, enjoying the Sitecore Summer Party!

We arrived yesterday and Henrik gave was a wonderful tour around the city and we had a huge dinner later. The city is beautiful and I'm looking forward to seeing everyone in the Sitecore Denmark office today. I hope so see an many people I know from emails as possible!

Friday, September 02, 2005 8:14:38 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Monday, August 22, 2005

Sitecore.Data.Items.ItemAxes has a lot of handy methods, and its often overlooked. I can easily remember that I manually recursed items children to iterate through all of the item's descendants a few times, while I could simply use anItem.Axes.GetDescendants(). This reminds me of the .NET framework itself, where you can often find a nice little (or pretty complex) class that does the job you used to do by yourself, at least when you're only starting to get into it.
Monday, August 22, 2005 7:53:07 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Saturday, August 20, 2005

We've put on hold the two big articles I've told about in the last post. Reason? We expect similar articles right from the heart of the Sitecore development, and we expect them soon!

So, we've decided to keep converting our support knowledge base into the smaller articles. Here are the new ones:

Item-Specific Context Menu. How to dynamically create the context menu depending on the list item that was clicked.
Toggling Control Visibility. Shows how to show or hide any control in the application based on user preference (using the Registry).
Customizing Upload Process. How to tweak the media upload process (customizing the uiUpload pipeline)

All articles I've put here previously as the word documents are now available at the SDN5:

Understanding Workflows. Basic information on the Sitecore V5 workflows.
My First XAML Application. XAML application basics.
Publish Queue Viewer. Creating the real-world application and using the advanced controls.

Next week I'll go through the last ones and update them basing on the feedback I've received.
Saturday, August 20, 2005 9:05:37 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Sheer UI | Workflow
 Wednesday, August 17, 2005

Having the first draft of the SDN5 go live, we're focusing on producing the new content. So we've started a couple of concept articles.

The first one is the "Sheer UI Architecture", and it covers different aspects of the new rendering engine, going from the client to server side and showing what makes those neat selective ajax-style postbacks possible. It is being written by Dmitry Kostenko, our lead developer here, and I know that a few people at yahoo groups demanded that docs should be written by the developers - this is exactly how it happens.

The second one is called "Pipeline Architecture". Topics covered include the explanation of the pipeline pattern, how the Sitecore is built around the pipelines, how to add your processor to tweak the existing pipelines and how to add a completely new pipeline to make your module (or a custom solution) to maintain the high level of extensibility. I'll try to post the sample code for this one by the end of the week, and here's an illustration:
pipeline assembly line.jpg

Our plan is to cover new major concepts in the first place, while adding small practical snippets at the same time. As I'm also the supervisor for the documentation here in Ukraine, I'm looking for any feedback regarding the existing articles, what should be covered next and the current documentation system. Mail me directly or leave a comment here. One of the next articles will focus on database/domain/site concepts, showing how these three connect, as it seems that it is one of the troublesome areas.
Wednesday, August 17, 2005 9:22:22 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
 Monday, August 15, 2005

The Sitecore Development Nerwork V5 went live last friday. Old SDN accounts should work fine.
Monday, August 15, 2005 12:10:43 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
Right clicking doesn't select a Listview item, so you cannot use .Selected property to determine which item was clicked. But you often will need to know that, because context menu items can depend on the actual item. Content Editor, for example, dynamically populates list of masters available for the item when you right click it in the content tree. This is where ClientRequest.Source comes in handy.
Monday, August 15, 2005 9:26:26 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Sheer UI
 Friday, August 12, 2005
Notice: an updated version of the article is available at Sitecore Developer Network.


Sometimes you'll want user to be able to show/hide controls in the application. Here's a small example.

A sample application:

<Action ID="HideAction" Checked="true" />
<Listview ID="Listview" View="Icons" Background="White>
   ...
</Listview>
<Button Header="Toggle Listview" Click="ToggleListview" />

protected Listview Listview;
protected Action HideAction;

// Show / hide the Listview control
protected void ToggleListview()
{
    // Hide if previously shown, and otherwise
    if (HideAction.Checked)
    {
        Context.ClientPage.ClientResponse.SetStyle("Listview", "display", "none");
    }
    else
    {
        Context.ClientPage.ClientResponse.SetStyle("Listview", "display", "");
    }
    // Remember the current visibility status
    // If you want to persist the user setting, you'll also have to throw in a Registry.GetBool / Registry.SetBool
    HideAction.Checked = !HideAction.Checked;
}

Note: This is only needed when changing visibility during postbacks. You can simply use control's .Visible property in OnLoad() method

Friday, August 12, 2005 12:41:38 PM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Sheer UI
Notice: The up-to-date version of the article is available at Sitecore Developer Network.

This article is a sequel to last one.

This installment starts right where the last article, “My First XAML Application” has left. If you haven’t read it and are not familiar with XAML programming concepts, it is advised that you read it first.

We will build a publish queue viewer application. It will allow us to see the list of items that were changed since the previous publishing and thus wait to be published. Of course the main purpose of the article is educational: showing how to create a real-world application and work with advanced controls. However the application itself is fully functional and can be used in the day-to-day work.

01-application_overview.jpg

Building Publish Queue Viewer.doc (663.5 KB)
SDN5 Source Code
Friday, August 12, 2005 12:14:50 PM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Sheer UI

Notice: An updated version of the article is available at Sitecore Developer Network.

From the introduction to the article:

XAML (eXtensible Application Markup Language, pronounced as ‘zaml’) is the new declarative markup language used to create user interfaces. XAML combined with the Avalon graphics engine is one of the main pillars of ‘Longhorn’ new generation OS from Microsoft. However, you don’t have to wait that long in order to use it. Sitecore V5 introduces new feature called XML layouts. Now you can create rich and powerful user interfaces faster than ever before, using the XAML markup and Sheer UI as a rendering engine.

The article guides you through the process of creating your first XAML application for the Sitecore client. We will create a playground for you to toy with the new technology and explore its possibilities.

Once you’ve comfortable with this material, you will be able to advance to the next article – building a real-world valuable application. We will build a Publish Queue Viewer application that will show a list of items waiting for the publishing, showing how to work with most advanced and ready-to-use controls.

[Please use the Sitecore Developer Network downloads]
Friday, August 12, 2005 11:39:38 AM (FLE Standard Time, UTC+02:00)  #    Comments [2]
Sitecore | Sheer UI

'Understanding Workflows' is the basic article on one of the new cornerstone concepts in the Sitecore V5. I apologize for posting the articles in MS Word format, but this is the how they were edited and I really don't want to waste any time cleaning word's html. And if you have a lot of comments, you can use reviewing tools in Word and send the entire document back to me.

Since the articles themselves are more or less in the draft stages, I appreciate any comments or suggestions you might have, so we can fix the things up before going live with the new SDN and also better understand what topics should be addressed next.

Understanding workflows.doc (359 KB)
Friday, August 12, 2005 11:31:31 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore | Workflow
Hi everyone.

First of all, let me introduce myself. My name is Alexey Rusakov and I work at the Sitecore Ukraine office. My primary responsibilities include module development and partner support.

I guess those of you, who started using the new product noticed a great number of new concepts, changes and a totally new slick API. It’s all nice and shiny, but it can be hard to understand the whole picture because of its size.

As you probably know, we’re in the process of rolling out the new Sitecore Development Network site that will solely focus on version 5. The site itself isn’t ready yet, but we have some draft materials and we’ve been sending them a lot lately.

I’ll put some of them up in the next posts, and I’ll see what I can do next.
Friday, August 12, 2005 10:25:56 AM (FLE Standard Time, UTC+02:00)  #    Comments [0]
Sitecore
Archive
<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910
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)