Experience Sitecore ! | More than 200 articles about the best DXP by Martin Miles

Experience Sitecore !

More than 200 articles about the best DXP by Martin Miles

StackOverflow: How to use Redirect Module in Sitecore

One guy recently posted a question on StackOverflow on how to use Redirect Module. So I decided to reply about that, but thought it is a good topic for a blog post.

First of all, he probably meant a Sitecore Redirect Module from Marketplace. I have heard multiple complaints on that one and that it doesn't work as expected, moreover it seems to be discontinued.

Luckily, there are many forks of that one on the internet, as ability to control 301 redirects right from Sitecore is well in demand. I want to suggest probably the best fork I found and am successfully using myself - done by Chris dams and Max Slabyak. Why?

  • module is developing with time - just recently there was new version 1.4 that introduced ability to specify various status codes
  • good documentation included
  • sourcecode is available on Github under MIT license - feel free to use imn your commercial projects
How to get it: all you need including sources, packages for all versions and documentation is available from GitHub by this link.


Let's now create a sample redirect from a virtual URL of non-existing page to some page item in Sitecore.

We want everyone who tries accessing http://our.sample.website/pagename (note that there is no pagename item in Sitecore) to be redirected to another existing page that sits at /sitecore/content/Home/landingPage in Sitecore. For the first time, for sure, as 301 redirects are cached in user's browser and next time he/she would be taken directly to landing page (by browser).

  1. Under /sitecore/system/Modules/Redirect Module folder in Sitecore create a new redirect pattern called Pagename Test
  2. Set requested expression to ^/pagename/?
  3. Leave response status code equal 301
  4. Set source item to the actual page item serving that redirect request
  5. Do not forget to publish redirect pattern (and module itself if not yet)

A screenshot below shows how it looks in Sitecore:


Hope you find that useful!

Sitecore Personalization based on URL query string parameters

Once I was asked to personalize Sitecore component depending on custom URL query string parameter, to identify users coming by a promo campaign in order to display them slightly modified component reflecting campaign presentation. Easy, I thought, but in next couple minutes struggled to find that condition in Rules Engine. It is not in Sitecore, what a surprise!..

So, let's go through and see what conditions are in Sitecore and how you can create any custom condition you would ever imagine.


First of all, all stuff for Rules Engine is specified as Sitecore items underneath /sitecore/system/Settings/Rules folder. So let's create an item named Query String Value Presents of /sitecore/templates/System/Rules/Condition template within /sitecore/system/Settings/Rules/Conditional Renderings/Conditions/URL Query String Conditions folder. There are just two important fields we are going to set. Type field, as it is very common to Sitecore, specifies fully qualified class and assembly names, where business logic is implemented. Another, Text field, is more interesting on that stage - it shows wordings that would be presented to user when using his condition with Rules Engine. Here is what we set there:

Where the User [QueryStringName,,,QueryString Name] has a value that [operatorid,StringOperator,,compares to] [QueryStringValue,,,QueryString Value].

Pay attention to parameters in square brackets - they would be replaced by Rules Enging to selectors.

Now let's look at the code. Fom the item we ahave referenced the class.

public class QueryStringCondition<T> : StringOperatorCondition<T> where T : RuleContext

All derived condition classes should have same definition and derive from base StringOperatorCondition class. As the absolute minimal, we are to override just one Execute(T ruleContext) method. Additionally we must create public string properties named exactly the same as in parameters above from Text field from condition definition item in Sitecore.

public string QueryStringName { get; set; }
public string QueryStringValue { get; set; }
protected override bool Execute(T ruleContext)
{
    // process QueryStringName and QueryStringValue properties here
    // return true if personlization parameters falls within the condition 
}

QueryStringName and QueryStringValue would be auto-populated by Rules Engine.

With our next example we are trying to display an additional promo component when user access our website by URL with sourceId=campaign as parameters.


Full implementation of QueryStringCondition<T> class can be found on GitHub by this link.

Hope you find this helpful!

Productivity Improvement: Device Editor showing datasource and previewing that right from a pop-up click

After previous post on Layout Details dialog improvements, I decided to look even further and implement one more improvement that came into my head.

Another dialog window, probably most important in Content Editor is missing couple things I just decided to fix. That is a case when a screenshot is better than hundred words, so here is it:


What has been added is a datasource item path, immediately underneath rendering and placeholder. It is clickable in the same manner as from previous posts, immediately opening that (datasource) item for view and edit right in the popup window, that saves so much time!

Additionally, rendering / sublayout name became also clickable with the same item preview popup effect.


Download: please get the package and anti-package to revert changes. Source code is available at GitHub page by this link.

Known minor issue: if open Control Properties dialog from Device Editor, and when you return back from that dialog - look-up links will not work and control will return to default behavior, so you may need to re-open Device Editor again.
The reason for such a behavior is that on returning back, Sitecore runs a series of pipelines that eventually call original class from Sitecore.Client rather than the one we have overridden and referenced above. Fixing that requires patching original DLL and I highly wanted to avoid inclining into any original functionality (moreover, you are not likely allowed to do that by license)

StackOverflow 2 questions on Multi-Site configuration: Multisite Best Practice for setting up Visual Studio Project and Manage web.config in multisite solution

Got to answer two question about multi-site configuration working with Sitecore:

1. Sitecore Multisite Best Practice for setting up Visual Studio Project (link to original question)

I'm seeking an advise on best practice that has worked for creating a asp.net MVC visual studio solution that supports multisite (multi tenant). One thing we would like to do is minimize the regression defects so that developer don't modify the wrong website code base etc.
That the solution needs to support more than 8 web sites.

2. Manage web.config in sitecore multisite solution (link to original question)

We have a multisite solution with individual visual studio solutions for each websites. Then we have master solution to build/deploy all websites.
Firstly, not sure whether it's a best practice to include web.config in Visual Studio solution. But I think all the nuget packages needs web.config to add their settings.
As a result, we have web.config for each solution. However when we deploy from master web.config gets overwritten by each sites. Could someone please suggest how this issue can be fixed?

Answers:

I have got one more alternative to address that. Currently working on a huge project, with dozens of developers and quite bureaucratic process of deployments, we have introduced the following approach:

  1. Project consists of multiple logical subparts, which in fact are individual websites.
  2. Each of those websites we set up as an MVC Area with own controllers, views etc
  3. Most important - we set up MVC Areas as individually pluggable DLLs. So each of that websites is a separate project under solution, with its own resources and statics; on build everything is copied under their required paths and DLL goes to the \bin folder.
  4. One more class library for shared (by all websites) resources, it is being referenced only by those sites, that need that functionality
  5. In Sitecore, we have the same strict principles - the content, layouts, renderings are isolated as higher as possible, no individual content may be re-used (unless from shared resources folder).

This approach serves us almost a year already and has proven for its agility, much easier deployment and fairly less code merge conflicts. If you are working under just one site - you don't need to re-compile and re-deploy everything - just replace one dll at bin folder.

Thus, combining that with your question, Approach 1 would be an answer.

References (more to read):

Regarding managing configuration, I would advise for each website (under its individual project) to create it's own App_Config/Include folder and create _project_name_.config within that folder in order to keep all site-specific settings there (for further merge into resulting config).

On build you set up (for each individual project) that file to be copied into main SITECORE_INSTANCE_WEB_ROOT\App_config\Include folder along with the rest of include patch config files.

Hope someone finds that helpful!

Productivity Improvement: Creating a Presentation Exists Gutter - get even faster access to item's Presentation Details

Previously I have described how easily you can create a shortcut to Device Editor of Presentation Details right at the item's Context Menu - access that as much as in two clicks! But there's even easier (and more visual) way - create a specific Sitecore Gutter.
So, what Gutters are? Gutters are sort of visual markers you can optionally enable / disable in your Content Editor. Have you seen a vertical bar, immediately left hand side from Sitecore tree? That is a Gutters Area and once you do right click on it - you may enable / disable some gutters already installed. Also, gutters can be clickable, and on click handler you may also call Sitecore commands, so why not to call our familiar item:setlayoutdetails that opens Device Editor dialog for corresponding item?

So, let's create our own gutter. Every gutter is configured within core database under /sitecore/content/Applications/Content Editor/Gutters folder. We are going to create a new item called ... derived from /sitecore/templates/Sitecore Client/Content editor/Gutter Renderer template (all gutters derive from that one). There are only two fields we need to set there - Header which is just a gutter name and Type - fully qualified class name:

So now let's implement PresentationExists class. Briefly, every gutter derives from GutterRenderer class which returns GutterIconDescriptor object when gutter should be shown next to corresponded item otherwise just null. Implementation below checks whether current item has a Layout associated, and if yes - it returns a GutterIconDescriptor with a item:setlayoutdetails command for that item.
public class PresentationExists : GutterRenderer
{
    protected override GutterIconDescriptor GetIconDescriptor(Item item)
    {
        if (item != null)
        {
            var layoutField = item.Fields[Sitecore.FieldIDs.LayoutField];
            var layoutDefinition = LayoutDefinition.Parse(LayoutField.GetFieldValue(layoutField));

            if (layoutDefinition != null && layoutDefinition.Devices.Count > 0)
            {
                GutterIconDescriptor gutterIconDescriptor = new GutterIconDescriptor
                {
                    Icon = "Applications/32x32/window_colors.png",
                    Tooltip = Translate.Text("Presentation is set for this item.")
                };

                if (item.Access.CanWrite() && !item.Appearance.ReadOnly)
                {
                    gutterIconDescriptor.Click = string.Format("item:setlayoutdetails(id={0})", item.ID);
                }
                return gutterIconDescriptor;
            }
        }

        return null;
    }
}
So as soon as you compile and place resulting DLL under <web_root>\bin folder, your gutter wil work like below:

Clicking that icon will immediately show Device Editor dialog. Job's done!

Downloads: you can access source code at Sitecore Improvements project GitHub page, or you can download ready-to-use package by this link.

Please note: improperly implemented gutters may affect performance of Content Editor, as the code above runs for each item. So please be extremely attentive on what you're doing within GetIconDescriptor() method.

StackOverflow: Including MVC in existing Sitecore Project

Recently one chap has asked a question oh how to include MVC into existing Sitecore project. A guy coming from classical ASP.NET MVC background experienced confusion with MVC implemented in Sitecore (here's an original link on StackOverflow). I decided to give a comprehensive answer on how MVC work with Sitecore:


Answer: In the very simplest way, you need to have the following:

  1. Item for your page, the one that has URL; that is as normal in Sitecore
  2. That page Item should have Layout assigned. From Presentation --> Details menu select at least a layout on that stage. If you do not have layout yet, you need to create a layout definition item under /Layout/Layouts folder and associate it with certain *.cshml file. Also mention that layout should have a placeholder where you will "inject"your rendering.

    @Html.Sitecore().Placeholder("Main")
    
  3. You need to create a Controller Rendering under /Layout/Renderings folder in Sitecore. Make sure you set Controller and Controller Action fields to your controller name and action method name. enter image description here

  4. Finally, go again to Presentation --> Details --> Edit --> Controls and add your newly created rendering into a placeholder that you have on your layout *.cshtml file. enter image description here

That's all done.


Item not published. Why? Let's troubleshoot that!

Have you experienced that at least once? You perform publishing, and refresh the website with strong anticipation of new viewing fresh changes and.... not updated. Why? What's going on? Do not panic, let's carefully troubleshoot that step by step.

1. First, and most frequent reason for item tot being published is a case when item is in a workflow, and current workflow state is not final (ie. draft). For that scenario solution is pretty easy as there's nothing wrong - just follow the workflow until item gets to its final state and would be automatically published (that is configured as default behavior). If workflows are not part of your solution - just remove item's template and standard values out of workflow; as well as individual items manually configured; then re-publish.


2. If previous step dodn't help, find out is the item publishable at all? Check item's Publishing Restrictions. You may check that clicking Change button from Publish ribbon in Sitecore. Please find official documentation by this link, as it may be helpful to understand what Publishing Restrictions are and how they work; also there's another great article by John West about those restrictions. Ensure that your item either doesn't have time limit frames, or falls within them.


3.
Most of publishing issues occur just because of inattentiveness. Are you publishing the right version of item? if that's about child items not being published, haven't you forgotten check Publish Subitems for that (or deep=true if publish from the code)? Are you publishing to the right target? Sure about this? OK for that, but what about that target in ConnectionsString.config, does it match desired database as well? All those questions may seem silly once, but still may hurt and stole fair portion of your time and efforts.


4. Next, do not forget about security and permissions. Here is the wide range of thing to consider! Can logged user perform publish, does he have enough permissions to do that? Check if user is in Sitecore Client Publishing role. Further, does default/anonymous user have access rights for the item (or any of its parents), aren't they removed? Not obvious, but publishing won't work otherwise. If publishing is scheduled and performed by the PublishAgent, does it have rights? Please read one more great article by John West.


5. Running on Publishing Instance (that's just a dedicated clone of CM instance, scaled by design for publishing performance on highly loaded environments)? Ensure it is up and running (lol! but sad truth of life).

6. Sill with us here? It's now time to check EventQueue. Ensure all your instances have the correct time set and synced. Just to remind, Sitecore internally stores everything in UTC format. but timezones should match as well. Check Event Queue settings and ScalabilitySettings.config as well.

7. Any issues with caches? Generally, the rule is: less cache you have, slower publishing is, with a bottom moment where it stops at all. Another silly assumption - aren't you running out of free space on system drive? Also make sure HtmlCacheClearer is added to your publish:end:remote event. It will produce a log record like that:

5760 19:57:16 INFO  HtmlCacheClearer clearing HTML caches for all sites

8. Once I came across the case of a new article not being published. The item looked as normal with no publishing restrictions and outside of workflow. However, it did not appear at the publishing target, as since I was using Sitecore Publishing Service I could only see that "0 versions published".

While investigating around at publishing target, I also noted that parent item was missing. When looking at parent at master database I noticed an information bar saying that parent items had 0 versions. That was the exact reason: parent item was not published due to the lack of versions, and its actual child item did not do through because Sitecore does not allow having orphaned items - a given item did not have a parent at the destination. Creating and publishing a version for the parent item has fixed that problem.

9. The last, quite a rare scenario: some of those curious experimenters like I am, who frequently install dozens of fresh instances of Sitecore for their sandbox trials, usually forget to initially publish entire site on a fresh install, so that it process all the required dependencies. Normally, I would not mention that, but still want to share as many cases as I know.

OK, so many things to consider? Agree with you, that's why I wrote that article, sort of cheat sheet in order to have it at my fingertips. But that's not all. Look for the general troubleshooting plan when something is not been published.

  • as given, item does not present there (on target), but what about its parent item? If missing, what about parent of the parent? Go to master database and carefully inspect the highest unpublished descendant, what isn't correct with it?
  • check workflows, publishing restrictions etc. mentioned above in the beginning of this article.
  • check logs for anything helpful
  • create a copy unpublished item and try to publish that one to the same destination.
  • create another new item of the same template and try to publish it. Succeeded with that?
  • delete and recreate that and related items (layouts, renderings, template) on target, and re-publish
  • handle publish:fail event and try to identify the reason; would be great to step into the method with debugger, if available.
Finally, (remember, I said no panic in the beginning), there is a buletproof solution as the last resort - copy items between databases manually. Go to Control Panel --> Database --> Move an item to another database, where you can move items between databases. One thing to mention - do not forget to update caches after you finish copying items to your target environment.


There are few more things I'd like to mention regarding publishing:

1. I would highly recommend The Published Item Comparer - a Sitecore module that quickly validates the current item in the content tree with the same item in a target database such as the “web” database; this helps to identify publishing issues effectively.

2. Unlike presented, Smart Publishing just cannot be trusted entirely, if reliability is your number one criteria - use re-publish instead.


Hope this post helps and wish your items always to appear on targets!

Sitecore Item Extension Methods

Below, there is my collection of Sitecore Item's extension methods, I've collected them within few recent years of my career from various sources. I decided to store them here, all at the same place, so that I can pick them up from here when necessary, case by case.

Here they are:



Programmatically Get Datasource Items of a Sitecore Item

If you need to get the datasource item’s of a particular Sitecore item, we can write a few extension methods to help us out!
public static class ItemExtensions
{
        public static RenderingReference[] GetRenderingReferences(this Item i)
        {
            if (i == null)
            {
                return new RenderingReference[0];
            }
            return i.Visualization.GetRenderings(Sitecore.Context.Device, false);
        }
 
        public static List<Item> GetDataSourceItems(this Item i)
        {
            List<Item> list = new List<Item>();
            foreach (RenderingReference reference in i.GetRenderingReferences())
            {
                Item dataSourceItem = reference.GetDataSourceItem();
                if (dataSourceItem != null)
                {
                    list.Add(dataSourceItem);
                }
            }
            return list;
        }
 
        public static Item GetDataSourceItem(this RenderingReference reference)
        {
            if (reference != null)
            {
                return GetDataSourceItem(reference.Settings.DataSource, reference.Database);
            }
            return null;
        }
 
        private static Item GetDataSourceItem(string id, Database db)
        {
            Guid itemId;
            return Guid.TryParse(id, out itemId)
                                    ? db.GetItem(new ID(itemId))
                                    : db.GetItem(id);
        }
}

Example of the call:
foreach (Item dataSourceItem in Sitecore.Context.Item.GetDataSourceItems())
{
    // do something
} 

Programmatically Get Personalization Datasource Items of a Sitecore Item

In the previous blog post, Programmatically Get Datasource Items of a Sitecore Item we learned how to get the datasource items from the rendering references. This does not include the items that have been added through personalization and rules. By adding the following methods to our previous post, we can get those items.
public static List<Item> GetPersonalizationDataSourceItems(this Item i)
{
    List<Item> list = new List<Item>();
    foreach (RenderingReference reference in i.GetRenderingReferences())
    {
        list.AddRange(reference.GetPersonalizationDataSourceItem());
    }
    return list;
}
 
private static List<Item> GetPersonalizationDataSourceItem(this RenderingReference reference)
{
    List<Item> list = new List<Item>();
    if (reference != null && reference.Settings.Rules != null && reference.Settings.Rules.Count > 0)
    {
        foreach (var r in reference.Settings.Rules.Rules)
        {
            foreach (var a in r.Actions)
            {
                var setDataSourceAction = a as Sitecore.Rules.ConditionalRenderings.SetDataSourceAction<Sitecore.Rules.ConditionalRenderings.ConditionalRenderingsRuleContext>;
                if (setDataSourceAction != null)
                {
                    Item dataSourceItem = GetDataSourceItem(setDataSourceAction.DataSource, reference.Database);
                    if (dataSourceItem != null)
                    {
                        list.Add(dataSourceItem);
                    }
                }
            }
        }
    }
    return list;
}
This code loops through the rules of your personalized component and if the action is Sitecore.Rules.ConditionalRenderings.SetDataSourceAction, then we know that this will be:
foreach (Item personalizationItem in Sitecore.Context.Item.GetPersonalizationDataSourceItems())
{
     // do something
}

Get Multi Variate Test Datasource Items of a Sitecore Item

In the previous two blog posts, Programmatically Get Datasource Items of a Sitecore Item and Programmatically Get Personalization Datasource Items of a Sitecore Item we learned how to get the datasource items and personalization datasource items from the rendering references. This does not include the items that have been added through Multi Variate Testing. By adding the following methods to our previous post, we can get those items.
public static List<Item> GetMultiVariateTestDataSourceItems(this Item i)
{
    List<Item> list = new List<Item>();
    foreach (RenderingReference reference in i.GetRenderingReferences())
    {
        list.AddRange(reference.GetMultiVariateTestDataSourceItems());
    }
    return list;
}
 
private static List<Item> GetMultiVariateTestDataSourceItems(this RenderingReference reference)
{
    List<Item> list = new List<Item>();
    if (reference != null && !string.IsNullOrEmpty(reference.Settings.MultiVariateTest))
    {
        using (new SecurityDisabler())
        {
            var mvVariateTestForLang = Sitecore.Analytics.Testing.TestingUtils.TestingUtil.MultiVariateTesting.GetVariableItem(reference);
            //var mvVariateTestForLang = reference.Settings.GetMultiVariateTestForLanguage(Sitecore.Context.Language); // < Sitecore 7.5
            Sitecore.Data.Items.Item variableItem = null;
 
            if (mvVariateTestForLang != null)
            {
                variableItem = mvVariateTestForLang.InnerItem;
                //variableItem = reference.Database.GetItem(mvVariateTestForLang); // < Sitecore 7.5
            }
 
            if (variableItem != null)
            {
                foreach (Item mvChild in variableItem.Children)
                {
                    var mvDataSourceItem = mvChild.GetInternalLinkFieldItem("Datasource");
                    if (mvDataSourceItem != null)
                    {
                        list.Add(mvDataSourceItem);
                    }
                }
            }
        }
    }
    return list;
}
 
public static Item GetInternalLinkFieldItem(this Item i, string internalLinkFieldName)
{
    if (i != null)
    {
        InternalLinkField ilf = i.Fields[internalLinkFieldName];
        if (ilf != null && ilf.TargetItem != null)
        {
            return ilf.TargetItem;
        }
    }
    return null;
}
This code shown is for Sitecore 7.5 and above while the commented out lines are for versions of Sitecore below 7.5. Now that we have these extension methods, we are able to write some nice code like this:
foreach (Item multiVariateTestDataSourceItem in Sitecore.Context.Item.GetMultiVariateTestDataSourceItems())
{
     // do something
}

Is Media Item / Is Content Item

Those two properties are built in and come with sitecore initially. They simple verify item path, wether that falls under /sitecore/content or /sitecore/media library
item.Paths.IsContentItem;
item.Paths.IsMediaItem;

DoesLanguageVersionExist

This extension method will be used to check ifitem exist in current provided language
        
public static bool DoesLanguageVersionExist(this Item item, Language languageToCheck)
        {
            bool isExist = false;
            Sitecore.Data.Items.Item itemInLanguage = item.Database.GetItem(item.ID, languageToCheck);
            isExist = itemInLanguage.Versions.Count > 0;
            return isExist;
        }

GetBooleanField

Gets value of Checkbox field
        public static bool GetBooleanField(this Item item, string fieldName)
        {
            Field fieldValue = item.Fields[fieldName];

            if (fieldValue != null)
                return (fieldValue.Value == "1" ? true : false);
            else
                return false;
        }

GetMediaItemField

Returns MediaItem from Media Field
        public static MediaItem GetMediaItemField(this Item item, string fieldName)
        {
            Field fieldValue = item.Fields[fieldName];
            MediaItem mediaItem = null;

            if ((fieldValue != null) && (fieldValue.HasValue))
                mediaItem = ((ImageField)fieldValue).MediaItem;

            return mediaItem;
        }

GetStringField

Retrieves value of a string-based field - Single Line, Multiline, etc.
        public static String GetStringField(this Item item, String fieldName)
        {
            string fieldValue = string.Empty;
            if (item != null)
            {
                Field field = item.Fields[fieldName];
                if ((field != null) && (!string.IsNullOrEmpty(field.Value)))
                    fieldValue = field.Value;
            }
            return fieldValue;
        }

GetDateField

Gets DateTime value out of Date of DateTime field
        public static DateTime GetDateField(this Item item, String fieldName)
        {
            DateField fieldValue = item.Fields[fieldName];
            DateTime dateTime = DateTime.Now;
            if ((fieldValue != null) && (fieldValue.InnerField.Value != null))
                dateTime = fieldValue.DateTime;

            return dateTime;
        }

GetHtmlField

Gets the value of HtmlField
        public static HtmlField GetHtmlField(this Item item, String fieldName)
        {
            HtmlField htmlField = item.Fields[fieldName];
            return htmlField;
        }

Gets LInk Field out of corresponding item
        public static LinkField GetLinkField(this Item item, String fieldName)
        {   
            LinkField linkField = item.Fields[fieldName];
            return linkField;
        }

GetReferenceField

Gets Reference Field out of corresponding item - Droplink, Droptree, Grouped Droplink etc.
        public static ReferenceField GetReferenceField(this Item item, String fieldName)
        {            
            ReferenceField referenceField = item.Fields[fieldName];
            return referenceField;
        }

GetReferenceFieldItem

Gets an associated item out of Reference Field of an item - Droplink, Droptree, Grouped Droplink etc.
        public static Item GetReferenceFieldItem(this Item item, String fieldName)
        {
            Item targetItem = null;
            ReferenceField referenceField = item.Fields[fieldName];
            if ((referenceField != null) && (referenceField.TargetItem != null))
                targetItem = referenceField.TargetItem;

            return targetItem;
        }

GetMultilistField

Returns Multilist Field
        public static MultilistField GetMultilistField(this Item item, String fieldName)
        {
            MultilistField multilistField = item.Fields[fieldName];
            return multilistField;
        }

GetMultilistFieldItems

Returns associated items of Multilist Field; works also with Checklist, Treelist, Treelist-Ex
        public static Item[] GetMultilistFieldItems(this Item item, String fieldName)
        {            
            Item[] targetItems = null;
            MultilistField multilistField = item.Fields[fieldName];
            if ((multilistField != null) && (multilistField.InnerField != null))
                targetItems = multilistField.GetItems();

            return targetItems;
        }

Publish

Performs publishing of an item. Deep parameter makes publishing recursice against all the subitems
public static void Publish(this Item item, bool deep)
{
    var publishOptions = new PublishOptions(item.Database,
                                        Database.GetDatabase("web"),
                                        PublishMode.SingleItem,
                                        item.Language,
                                        DateTime.Now);
    var publisher = new Publisher(publishOptions);
    publisher.Options.RootItem = item;
    publisher.Options.Deep = deep;
    publisher.Publish();
}

Unpublish

Unpublishes current item
public static void UnPublish(this Item item)
{
    item.Publishing.UnpublishDate = DateTime.Now;
    item.Publish(true);
}

IsPublished

Finds out if item is already published
public static bool IsPublished(this Item pItem)
{
    Database lWebDb = Factory.GetDatabase("web");
    if (pItem != null && lWebDb != null)
    {
        Item lWebItem = lWebDb.GetItem(pItem.ID, pItem.Language, pItem.Version);
        if (lWebItem == null || pItem.Statistics.Updated > lWebItem.Statistics.Updated)
        {
            return false;
        }
    }
    return true;
}

ParentList

Gets an array of all hierarchial parent items of a current item, can be useful for creating breadcrumbs
public static IEnumerable<Item> ParentList(this Item item, Boolean descending = true)
{
    if (item == null)
        return null;
 
    List<Item> parents = new List<Item>();
 
    Item currentItem = item.Parent;
    while (currentItem != null)
    {
        parents.Add(currentItem);
 
 
        currentItem = currentItem.Parent;
    }
 
    if (descending)
        parents.Reverse();
 
    return parents;
}

GetReferrersAsItems

Get referrers of an item using the link database
public static IEnumerable<Item> GetReferrersAsItems(this Item item)
{
    var links = Globals.LinkDatabase.GetReferrers(item);
    return links.Select(i => i.GetTargetItem()).Where(i => i != null);
}

IsDerived

Tells, if a given item derives from a specific template
public static bool IsDerived(this Item item, ID templateId)
{
  if (item == null)
    return false;
 
  if (templateId.IsNull)
    return false;
 
  TemplateItem templateItem = item.Database.Templates[templateId];
 
  bool returnValue = false;
  if (templateItem != null)
  {
    Template template = TemplateManager.GetTemplate(item);
 
    returnValue = template != null && template.ID == templateItem.ID || template.DescendsFrom(templateItem.ID);
  }
 
  return returnValue;
}

ChildrenDerivedFrom

Returns children items derived from a specific template
 
public static IEnumerable<Item> ChildrenDerivedFrom(this Item item, ID templateId)
{
    ChildList children = item.GetChildren();
    List<Item> childrenDerivedFrom = new List<Item>();
 
    foreach (Item child in children)
    {
        if (child.IsDerived(templateId))
            childrenDerivedFrom.Add(child);
    }
 
    return childrenDerivedFrom;
}

IsTemplate

Checks wether specific item is a template item
public static bool IsTemplate(this Item item)
{
    return item.Database.Engines.TemplateEngine.IsTemplatePart(item);
}

HasLanguage

Tells, if an Item has a version in a specific language
public static bool HasLanguage(this Item item, string languageName)
{
    return ItemManager.GetVersions(item, LanguageManager.GetLanguage(languageName)).Count > 0;
}

public static bool HasLanguage(this Item item, Language language)
{
    return ItemManager.GetVersions(item, language).Count > 0;
}

LanguageVersionCount

Gives the amount of versions that a given item has in a given language
public static int LanguageVersionCount(this Item item, Language lang)
{
    if (item == null)
        return 0;
    Item currentItem = item.Database.GetItem(item.ID, lang);
    if (currentItem.Versions.Count > 0)
        return currentItem.Versions.Count;
    else
        return 0;
}

AddItemToIndex

Adds given item into specified index
public static void AddItemToIndex(this Item item, string indexName)
{
    var tempItem = (SitecoreIndexableItem)item;
    ContentSearchManager.GetIndex(indexName).Refresh(tempItem);
}

UpdateItemInIndex

Updates current item within an index
public static void UpdateItemInIndex(this Item item, string indexName)
{
    var tempItem = (SitecoreIndexableItem)item;
 
    ContentSearchManager.GetIndex(indexName).Delete(tempItem.UniqueId);
    AddItemToIndex(item, indexName);
}

PublishItem

One more version of Publish method for current item
public static void PublishItem(this Item item)
{
    var publishOptions = new PublishOptions(item.Database,
        Database.GetDatabase("web"),
        PublishMode.SingleItem,
        item.Language,
        DateTime.Now); // Create a publisher with the publishoptions
 
    var publisher = new Publisher(publishOptions);
 
    // Choose where to publish from
    publisher.Options.RootItem = item;
 
    // Publish children as well?
    publisher.Options.Deep = true;
 
    // Do the publish!
    publisher.Publish();
}

Url

Returns user-friendly URL of an item
public static string Url(this Item item)
{
    return LinkManager.GetItemUrl(item);
}

GetMembershipUser

Returns the System.Web.Security.MembershipUser associated with a Sitecore.Security.Accounts.User object
public static MembershipUser GetMembershipUser(this Account account)
{
return Membership.GetUser(account.Name);
}

HasBaseTemplate

Returns true if current template item is derived from another template
public static bool HasBaseTemplate(
      this TemplateItem me,
      ID templateID,
      bool includeSelf = false,
      bool recursive = true)
    {
      if (includeSelf && me.ID == templateID)
      {
        return true;
      }
 
      if (recursive)
      {
        foreach (TemplateItem baseTemplate in me.BaseTemplates)
        {
          if (baseTemplate.HasBaseTemplate(
            templateID,
            true /*includeSelf*/,
            true /*recursive*/))
          {
            return true;
          }
        }
      }
 
      return false;
    }

HasChild

Identifies if current item has a child with a specific ID
public static bool HasChild(this Item item, string childIdStr)
{
    ID childId = new ID(childIdStr);
    return HasChild(item,childId);
}

public static bool HasChild(this Item item, ID childId)
{
    foreach (Item child in item.Children)
    {
        if (child.ID == childId)
            return true;
    }
    return false;
}

HasDescendant

Identifies if current item has a decscendant with a specific ID
public static bool HasDescendant(this Item item, string descendantIdstr)
{
    ID descendantId = new ID(descendantIdstr);
    return HasDescendant(item, descendantId);
}

public static bool HasDescendant(this Item item, ID descendantId)
{
    foreach (Item child in item.Children)
    {
        if (child.ID == descendantId)
            return true;
        
HasDescendant(child, descendantId); } return false; }

IsStandardValue

Indicates whether an item is a standard value item or not
public static bool IsStandardValues(this Item item)
{
  if (item == null)
    return false;
  bool isStandardValue = false;
         
  if (item.Template.StandardValues != null)
    isStandardValue = (item.Template.StandardValues.ID == item.ID);
         
  return isStandardValue;
}

HasRenderings

Indicates if an item has versioned renderings.
public static bool HasRenderings(this Item item)
{
    return item.Visualization.GetRenderings(Context.Device, false).Any();
}
public static bool HasRenderings(this Item item, DeviceItem device)
{
    return item.Visualization.GetRenderings(device, false).Any();
}

HasVersionedRenderings

Indicates if an item has versioned renderings.
public static bool HasVersionedRenderings(this Item item)
{
   if (item.Fields[FieldIDs.FinalLayoutField] == null)
      return false;

   var field = item.Fields[FieldIDs.FinalLayoutField];
   return !string.IsNullOrWhiteSpace(field.GetValue(false, false));
}

public static bool HasVersionedRenderingsOnLanguage(this Item item, Language language)
{
    return item != null && item.Database.GetItem(item.ID, language).HasVersionedRenderings();
}
public static bool HasVersionedRenderingsOnAnyLanguage(this Item item)
{
   return ItemManager.GetContentLanguages(item).Any(item.HasVersionedRenderingsOnLanguage),
}
public static bool HasVersionedRenderingsOnContextLanguage(this Item item)
{
   return item.HasVersionedRenderingsOnLanguage(Context.Language);
}

StackOverflow: Is it possible to change a Page to branch?

Another question I have explained on StackOverflow - (original link on StackOverflow):

Is it possible to change the Template of a page to Branch Template? When I try in Sitecore 7.0 UI it gives a error message stating to "Select a Template".

Is there any other way to change an Item's Template to be a Branch Template?

Answer: You cannot just substitute a template of an item with a branch template. You might be probably confused by mutual term template they both use and the fact the both exist undet /sitecore/templates node, however they are absolutely different in their internals.

Branch templates are just template sub-nodes that are being copied in instantiation. You may still use tokens and they would apply for every single item in a branch. But each of the items from a branch would still origin from certain individual template.

enter image description here

Thus, you cannot just do Configure --> Change on an item and then select a branch template instead of ordinary template, that's why Branches node is highlighted with grey color and even if you try to select any - sitecore will tell you "please select a template".

enter image description here

What you can do is just to re-create your item from branch template and (assuming) previous item now becomes a part of your branch - you may simply manually copy all the presentation details. However an ID of that item would differ with an ID of initial item (unless you manually replace original item into a branch instantiated)

I previously wrote an article on how to copy presentation detail manually between items, it will help you with your case:

https://blog.martinmiles.net/post/copying-presentation-details-manually

Sitecore 8: Federated Experience Manager - what is all about?

One of the greatest features of Sitecore 8 is Federated Experience Manager (FXM). What is FXM about and how can it help us?

Previously we had Page Editor - the tool allowing content editors to author and save content inline, right on the page. It also offered other flexible options to operate with non-visible content of features that cannot be edited inline (ie. Edit Frames), also do customisation (A/B multivariate testing), personalisation on rule-based criteria and much more. So far, so good.

In Sitecore 8, Page Editor was replaced with a new feature called Experience Editor (EE). EE is not just a rename for Page Editor, despite it does all the same old good features, it brings great new opportunities in chain with FXM.

With FXM it is now possible to customise any other website page, not only those coming from Sitecore, but even any PHP or just static HTML. And further on, with EE it is now possible to do all good old Page Editor features, such as replace content on external website, create placeholders and append sitecore components there, apply personalisation, set goals etc.

Sounds fantastic and impossible? Not as much - all that is working out box now, and moreover is very simple. Let's take a look on how that works and what is involved.


FXM is an applications shipped out of box and is available from Launchpad - just a usual SPEAK application. As soon as it loads, you'll get a management screen to register external websites. Clicking Add External Website will load you the following screen:


What is required on that step is to provide a hostname for external website and add one line of code into external website pages - a javascript reference for a beacon:


So, it stands obvious that you need to have an access to modify the code of pages on that website. Normally you'd do that for all pages, so it makes sense to modify some master layout or any sort of global header.

One important thing to note: external html should be properly formed, otherwise there will be an error. Saying properly formed I mean just opening and closing tags for html head and body, as minimal as:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head></head>
    <body></body>
</html>
After that done - it becomes possible to open that external website with Experience Editor. And here you can perform:
  • tracking of external website into xDB
  • create placeholders before, after or instead certain html elements on external website
  • having Sitecore-controlled placeholders it is now possible to append components from Sitecore there
  • components from Sitecore can be literary everything, even WFFM forms (however not yet in current version)
  • cleaning up, replacing or extending original content from external website
  • apply customisation and / or personalisation to external content, controllable from Sitecore
  • set goals


It is essential to understand that those features work due cross site scripting called CORS, so certain limitations should be taken off, other wise it won't work

After site has been created at /sitecore/system/Marketing Control Panel/FXM/External you need to open that node and create a rule in order to match the same domain. Without doing that it would work only in Experience Editor, but not on the live website.



When opening external website it in Experience Editor, click on Add Placeholder button twice (to get it activated), then click first paragraph. You will see it identified as div with three options on how to insert a Sitecore-controllable placeholder: before, after or replace that div element. Let's choose after, in order to implement sitecore controllable rendering in between those two paragraphs on external website:

After choosing where exactly to implement a placeholder, you'll be prompted to enter placeholder name and select parent website:


Note: licensing is important to mention. FXM works only with new license issued with Sitecore 8, so if you have license file from one of previous versions, it would not have appropriate permission (Sitecore.Federated Experience) for running FXM. For some reasons Sitecore did not implement obvious message telling that you are not able to set a placeholder externally because of license. I spent decent time previously trying to understand why that did not work for me. Please find more details in my answer on StackOverflow for that question.

Once done, there will be last screen, showing newly created placeholder exactly in between those two paragraphs and offering to append a rendering to it:


To make things easier, I have just slightly modified Sample Rendering that comes with Sitecore, so that it now looks like that:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:sc="http://www.sitecore.net/sc"
  xmlns:sql="http://www.sitecore.net/sql"
  exclude-result-prefixes="sc sql">
  <xsl:output method="html" indent="no" encoding="UTF-8"  />

  <xsl:template match="*">
    <div>
      <h3>FXM-powered placeholder</h3>
      <span>This content comes from Sitecore and is editable with Experience Editor. 
      Other cool features as personalization are also available with FXM.</span>
      <br/><br/>
    </div>
    
  </xsl:template>
</xsl:stylesheet>
That's mostly done! Do not forget to publish your site definition (under FXM node) with children (there will be placeholder item we've just created) to content delivery environment in order to work there. Let's now test it! I enter http://external into a browser and get exactly what expected - there is a sitecore controllable placeholder in between the paragraphs and it has a rendering being set into it:



Opening that in any dev. tools like Firebug will show the following nice and clean code has been rendered: