Sitecore Kicking Idle Users

Sitecore Licenses are often based on the number of users simultaneously logged in the Sitecore Client. If the threshold of maximum logged in users is reached the next user that tries to login gets the following screen:

Over Capactiy

Here the current user has 2 choices:

  1. Temporary boost the amount of concurrent users – in case the current user has boost permissions and the instance is not using express license.
  2. Kick another user who is already logged in – in case the current user has kick permissions.

Boosting will take the user to http://sitecore.net page from where he can temporarily increase the number of users who can be simultaneously logged in the system.

Kicking will take the current user to the following page.

Kick Users

The page lists the currently logged in users. The time they logged in and the Last Request Time is shown as well. From here the current user can decide if he wants to kick any of the currently logged in users.

The nice part is that this page can also be accessed directly even if the Sitecore instance is not over capacity. The page can be accessed from here: http://[SITECORE_INSTANCE_URL]/sitecore/shell/Applications/Login/Users/Kick.aspx and comes in handy when the instance becomes slower from the many idle users that forgot to logout.

Happy Kicking ! 🙂

The Amazing World of Razl – Part 1

As a Hedgehog employee I have the pleasure of playing around with all of their tools. I find it strange that many Sitecore developers haven`t realized the potential of Razl. Most of us consider it a DB compare tool which we can only use once or twice in our day-to-day job. While Razl is a DB compare tool, Razl has much more usages than most people think it does, so I decided to put a blog post around a couple of things that can be done with Razl.

Automated Content Synchronization between Production and Staging/QA Environments

Many Sitecore developers face the problem that the Staging/QA environments don’t have fresh content. A quality assurance team working with fake/old data, is not ideal and might cause some issues. For example, imagine a client disapproving a working module because it is hard to show how  it will work once it gets to production. This is a situation in which Razl shines. Razl’s APIs allow us to write which can synchronize the Staging/QA environments with fresh content on a daily/hourly basis. The scripts are fairly simple to write and they are even simpler to execute. The scripts can be run with your favorite scheduling mechanism. For more information about Razl Scripting you can check the following articles:

Introducing Razl Scripting (Follow @me_mikeshaw)
Official Razl Documentation About Scripting 
Razl Script Mode (Follow @mikeedwards83)

Setting Up New Development Environments

When adding new people to the team, setting up their Development Environments might be a long and painful process, especially with complex solutions. Razl makes it easy for the new developer to grab all the content and/or some other necessary pieces (custom modules, things from the core database, etc.) and start working.

On Demand or Automated Synchronization between Production and Development Environments

There are some situations in which bugs are caused by the live content and are hard to reproduce on development workboxes. Razl makes it easy to get the pieces that caused issues, bring it to their local environment and now the developers to properly debug them.

Keeping Track on Content Changes

Razl comes with History View that uses the Sitecore History Engine. The history view provides an amazing option to track what has been changed and who has changed it, so when something goes wrong it is easier to check what the cause is and who caused it. For more information about Razl History View, you can check the following articles:

Official Razl Documentation About History View
Razl History View (Follow @mikeedwards83)

Simple Way to Visually Compare CMS/Master Database and CDS/Web Database

Sometimes there might be problems with content publishing from CMS to CDS Servers. Razl makes it easy to track and resolve these kinds of problems. If anything goes wrong with the publishing process, and republish is not an option, Razl can be used to compare the Master and the Web Database. It allows us to check what was left unpublished and helps us identify the problem.

Simple Way to Migrate Content from QA/Staging Content to Production

Sometimes, especially in tight deadline situations, the content is entered on some of the Pre-Production Environments. Here Razl comes in handy to easily move the content between environments.

In conclusion these are just some of the core functionalities that Razl offers in our day-to-day work. It can also be used in other automation scenarios like automatic content synchronization on deploy, moving content across environments via workflow and etc.

Make sure to check out this places for more invaluable Razl Information:

The official Razl Documentation
Hedgehog Development Razl Posts
Mike Edwards Razl Posts

Happy Razling ! 🙂

The Amazing World of RAZL Part 2 – Script Like A Boss

 

Glass Mapper and Custom Time Field

Every Sitecore developer struggled with the problem of implementing a time field and many developers found this article which provides good solution to the problem. The field works well, uses Sitecore built-in timepicker and is easy to implement. The huge problem comes when trying to use the custom time field with one of the most used Sitecore ORMs – Glass Mapper. This arises from the fact that the time picker uses TimeSpan to store its value and Glass doesn’t support TimeSpan values out-of-the-box. Fortunately there are 2 possible solutions to the problem – creating Glass Abstract Data Mapper (in order to support TimeSpan values) or modifying the Custom Time Field (in order for it to work with DateTime which is supported by the default Glass Date Time Handler).

Creating an Abstract Data Mapper Approach

Creating and registering an AbstractSitecoreFieldMapper for Glass is pretty straightforward. The only implementations required are GetFieldValue, SetFieldValue. The other important part is to call the base constructor with Type (or Type array) which is used by Glass to know which types are handled by the custom mapper.

You can find the implementation of the AbstractSitecoreFieldMapper bellow.


namespace Sandbox.GlassExtensions
{
    using Glass.Mapper.Sc;
    using Glass.Mapper.Sc.DataMappers;
    using Sitecore;
    using System;

    public class SitecoreFieldTimeHandler : AbstractSitecoreFieldMapper
    {
        public SitecoreFieldTimeHandler() :
            base(typeof (TimeSpan))
        {

        }

        public override object GetFieldValue(string fieldValue,
            Glass.Mapper.Sc.Configuration.SitecoreFieldConfiguration config, SitecoreDataMappingContext context)
        {
            return DateUtil.ParseTimeSpan(fieldValue, TimeSpan.Zero);
        }

        public override string SetFieldValue(object value,
            Glass.Mapper.Sc.Configuration.SitecoreFieldConfiguration config, SitecoreDataMappingContext context)
        {
            if (value is TimeSpan)
            {
                TimeSpan time = (TimeSpan)value;
                return time.ToString();
            }

            throw new NotSupportedException("The value is not of type System.TimeSpan");
        }
    }
}

After the handler is implemented it needs to be registered in App_Start/GlassMapperScCustom.cs. Keep in mind this code is only valid if you are using Glass with Castle Windsor (via Glass.Mapper.SC.CastleWindsor). If you are using a custom implementation with different dependency injection framework – adjust the registration.


public static void CastleConfig(IWindsorContainer container)
{
	var config = new Config();

	 container.Register(
		        Component.For<AbstractDataMapper>()
		            .ImplementedBy<SitecoreFieldTimeHandler>()
		            .LifestyleCustom<NoTrackLifestyleManager>());

	container.Install(new SitecoreInstaller(config));
}

And that is it !

If you are not happy with TimeSpans for storing time – feel free to implement you custom data type to store the value.

NOTE: If you are using TDS Code Generation with GlassV3 Templates you will need to update GlassV3Item.tt GetGlassFieldType method. Example of what should be added is shown bellow.

case "[TIMEFIELDNAME]":
   return "TimeSpan";

Modifying the Custom Time Field Approach

This approach uses the default Glass Date Time Handler (The code can be found here) and introduces small modifications to the Custom Time Field.

The modified code can be found bellow.


namespace Sandbox.TimeField
{
    using Sitecore;
    using Sitecore.Data.Items;
    using Sitecore.Diagnostics;
    using Sitecore.Shell.Applications.ContentEditor;
    using Sitecore.Web.UI.HtmlControls;
    using Sitecore.Web.UI.Sheer;
    using System;

    public sealed class GlassTimeField : Input, IContentField
    {
        private TimePicker _picker;

        public string ItemID
        {
            get { return GetViewStateString("ItemID"); }
            set
            {
                Assert.ArgumentNotNull(value, "value");
                SetViewStateString("ItemID", value);
            }
        }

        public string RealValue
        {
            get { return GetViewStateString("RealValue"); }
            set
            {
                Assert.ArgumentNotNull(value, "value");
                SetViewStateString("RealValue", value);
            }
        }

        public GlassTimeField()
        {
            Class = "scContentControl";
            Change = "#";
            Activation = true;
        }

        public override void HandleMessage(Message message)
        {
            Assert.ArgumentNotNull(message, "message");
            base.HandleMessage(message);
            string name;
            if (message["id"] != ID || (name = message.Name) == null)
                return;
            if (name == "contentdate:today")
            {
                Now();
            }
            else
            {
                if (name != "contentdate:clear")
                    return;
                ClearField();
            }
        }

        public string GetValue()
        {
            return
                (System.DateTime.MinValue +
                 DateUtil.ParseTimeSpan(_picker == null ? RealValue : _picker.Value, TimeSpan.Zero))
                    .ToString("yyyyMMddTHHmmss");
        }

        public void SetValue(string value)
        {
            Assert.ArgumentNotNull(value, "value");
            RealValue = value;
            if (_picker == null)
                return;
            _picker.Value = value.Length == 15 ? DateUtil.IsoDateToDateTime(value).ToString("t") : value;
        }

        protected override Item GetItem()
        {
            return Client.ContentDatabase.GetItem(ItemID);
        }

        protected override bool LoadPostData(string value)
        {
            if (!base.LoadPostData(value))
                return false;
            _picker.Value = value ?? string.Empty;
            return true;
        }

        protected override void OnInit(EventArgs e)
        {
            SetViewStateBool("Showtime", true);
            _picker = new TimePicker();
            _picker.ID = ID + "_picker";
            Controls.Add(_picker);
            if (!string.IsNullOrEmpty(RealValue))
                _picker.Value = RealValue.Length == 15
                    ? DateUtil.IsoDateToDateTime(RealValue).ToString("t")
                    : RealValue;
            _picker.OnChanged += (EventHandler) ((param0, param1) => SetModified());
            _picker.Disabled = Disabled;
            base.OnInit(e);
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            ServerProperties["Value"] = ServerProperties["Value"];
            ServerProperties["RealValue"] = ServerProperties["RealValue"];
        }

        protected override void SetModified()
        {
            base.SetModified();
            if (!TrackModified)
                return;

            Sitecore.Context.ClientPage.Modified = true;
        }

        private void ClearField()
        {
            SetRealValue(string.Empty);
        }

        private void SetRealValue(string realvalue)
        {
            if (realvalue != RealValue)
                SetModified();
            RealValue = realvalue;
            _picker.Value = realvalue;
        }

        private void Now()
        {
            SetRealValue(DateUtil.IsoNowTime);
        }
    }
}

The modified methods are GetValue, SetValue and OnInit. The idea is to force the Time Field to work with Sitecore`s IsoDateTimeFormat. A slightly dirty approach – but it does the job.

Happy Glass Mapping ! 🙂

 

Sitecore Admin Pages Cheat Sheet

It is doubtful that there is a Sitecore Developer who never opened /sitecore/admin/showconfig.aspx at least once in his life to check what went wrong with the amazing configuration patch that hadn`t worked. Showconfig is just one of the many admin pages that Sitecore has by default. Other admin pages are not so popular, so I decided to put a blog post about them.

Cache

URL: http://www.example.com/sitecore/admin/cache.aspx

This page displays details about the Sitecore cache for the instance. There you can find useful information  about the prefetch cache, the item cache and all the other enabled caches (if you are interested in cache optimizations, you can take a look at some of the modules in the Sitecore Marketplace).

DB Browser

URL: http://www.example.com/sitecore/admin/dbbrowser.aspx

A quick way to browse through the separate Sitecore databases. It is pretty lightweight and supports previewing of item’s fields, versions, languages etc. The DB Browser also allows preview of the file system. The most amazing thing about it is the option to delete all of the item’s children – something which is not available from the content editor itself without writing custom code.

Login

URL: http://www.example.com/sitecore/admin/login.aspx

The default admin login form. If you are not authorized to access any of the admin pages you will be redirected here. The good thing about the form is that it supports returnUrl query string parameter which comes in handy when you want to protect some custom sections on the front-end.

Restore

URL: http://www.example.com/sitecore/admin/restore.aspx

I personally never used this, but from the code of the page (or at least the one I got from decompilation of the sitecore.client.dll) it is not doing much 🙂

 protected void ButtonGo_Click(object sender, EventArgs e)
 {
    using (new SecurityDisabler())
      MainUtil.Out("Done.");
 }

Serialization

URL: http://www.example.com/sitecore/admin/serialization.aspx

A quick way to serialize/update/revert databases.Nothing special here, the serialized data will be dropped to the Data folder of the website.

Show Config

URL: http://www.example.com/sitecore/admin/showconfig.aspx

The infamous showconfig page. Shows the compiled Sitecore config. Keep in mind it just shows the <sitecore> node and its descendants. An amazing way to check how the config replacements worked out.

Stats

URL: http://www.example.com/sitecore/admin/stats.aspx

The page provides rendering statistics for all registered sites. Includes load times, cache sizes, etc.

Unlock Admin

URL: http://www.example.com/sitecore/admin/

unlock_admin.aspx

Used to unlock the admin user (if it was locked for some reason). The feature is disabled by default. To enable it, the actual aspx file needs to be edited. There is a boolean value there called enableUnlockButton which needs to be set to true.

Update Installation Wizard

URL: http://www.example.com/sitecore/admin/

UpdateInstallationWizard.aspx

Not to be confused with the package installer. This is the page which is used when upgrading the Sitecore instance, so most of the people might be familiar with it. It allows the users to upload .update packages and execute them over the Sitecore instance. It is also leveraged by some external tools (for example TDS generates .update packages for files and items). There is also a pretty cool open source tool out there, called Sitecore.Ship, which allows us to use the UpdateInstallationWizard by posting files via HTTP.

All the pages covered are available in Sitecore 6.4+. The other admin pages are available only for the listed version and higher.

Starting from Sitecore 6.6

Set Application Center Endpoint

URL: http://www.example.com/sitecore/admin/SetSACEndpoint.aspx

Used to change the Sitecore App Center endpoint. It is useful when playing whit Email Campaign Manager.

Starting From Sitecore 7.0

Fill Database

URL: http://www.example.com/sitecore/admin/

FillDB.aspx

The page was introduced in Sitecore 7.0. It allows the developers to create huge amount of test data. The page needs to be enabled via setting EnableFillDB in /App_Config/Include/Sitecore.Buckets.config. A quick walkthrough on how to use this page will be covered in a separate blog post, as the specifics are not so easy to explain. Meanwhile here is an article from the Sitecore Development Team which explains how to use the page with Sitecore 7.2 –  FillDB Updates.

LINQ Scratchpad

URL: http://www.example.com/sitecore/admin/

LINQScratchpad.aspx

A good place to test your Sitecore queries over the current context. Pretty good testing tool when executing queries over indexes or when you are not using any ORM. For more information about the LINQ Scratchpad you can check this article from the Sitecore Development Team –  Sitecore 7 LinqScratchPad.

Pipeline Profiler

URL: http://www.example.com/sitecore/admin/

Pipelines.aspx

The pipeline profiler allows the developers to profile the performance of the Sitecore Pipelines. You can check the number of executions, execution times, etc. Keep in mind that the Pipeline Profiling is not enabled by default and it needs to be enabled by renaming /App_Config/Include/Sitecore.PipelineProfiling.config.disabled to  /App_Config/Include/Sitecore.PipelineProfiling.config. There is also an option to measure the CPU usage of the pipelines by setting Pipelines.Profiling.MeasureCpuTime to true in the config file. Here is an awesome article by John West which explains how to use the Pipeline Profiler – Sitecore 7 Pipeline Profiling

Remove Broken Links

URL: http://www.example.com/sitecore/admin/RemoveBrokenLinks.aspx

Used to remove all broken links in a database. Nothing quite special about this page, but comes in handy after content reorganizations, content imports and content clean-ups. Comes with an option to auto-serialize the modified items, so they can be easily restored across instances.

Happy admining 🙂 !

Starting From Sitecore 7.5

Media Hash

URL: http://www.example.com/sitecore/admin/mediahash.aspx

As most of you know starting from Sitecore 7.5 the process for the server image resizing was changed, as this process is well described by Sean Holmesby on his blog I will not get into much detail. This page allows to generate the hash values required by Sitecore to return the resized image.

Rebuild Reporting Database

URL: http://www.example.com/sitecore/admin/RebuildReportingDB.aspx

Starting from Sitecore 7.5 Sitecore now uses MongoDB for storing analytics data, but most of the aggregated data is stored in the SQL Reporting Database. In the rare cases of inconsistencies or problems with the processed data – this page can be used for rebuilding the reporting database. Keep in mind that this process requires your instance to have secondary reporting database attached in order to transfer the data. You can find more information about rebuilding the reporting database on the official documentation.

Starting From Sitecore 8.0

Path Analyzer

URL: http://www.example.com/sitecore/admin/PathAnalyzer.aspx

Admin page for Path Analyzer Utilities. Contains the maps manager and if they are deployed correctly. Also used to rebuilding the historic maps, triggering the map agents etc.

Redeploy Marketing Data

URL: http://www.example.com/sitecore/admin/RedeployMarketingData.aspx

Used to redeploy the default Experience Analytics segments. Also has an option to redeploy the Path Analyzer Mappings.

Starting From Sitecore 8.1

Install Language

URL: http://www.example.com/sitecore/admin/InstallLanguage.aspx

Used to install a new language for the Sitecore content. Also has an option to run the Sitecore UI in the selected language, so be careful when using this feature !

Rebuild Key Behavior Cache

URL: http://www.example.com/sitecore/admin/RebuildKeyBehaviorCache.aspx

Used to rebuild the Key Behaviour Cache. You can find more information on the Key Behavior Cache on the official documentation.

Sitecore Modal Dialogs Fix For Chrome 37+

In the newest release of Chrome (37), the showModalDialog function is disabled by default (Chromium Blog). This change will affect all Sitecore instances using version lower than 7.1.

Show Modal Dialog Is not Defined

Fortunately, there are options to workaround the issue.

The first approach is to enable the showModalDialog function via the EnableDeprecatedWebPlatformFeatures policy. For more information on how to set policies you can refer to one of these two articles depending on your organization – Set Chrome policies for devices or Set Chrome policies for users. Keep in mind that this fix needs to be applied on every device.

!!!UPDATE!!!

As it seems the javascript solution with window.open is not working as it is not blocking the execution. The window is actually opened, but the changes won`t be saved because they won`t be passed back to the caller. So the only solution is enabling the deprecated web platform features (or upgrading Sitecore to 7.1+). The big problem is that Mozilla currently deprecated the Window.showModalDialog(), so if they obsolete it in the near future the only option will remain to use IE or upgrade to 7.1+.

The second approach is to replace the showModalDialog function with window.open. This should be done in [Web_Root]\sitecore\shell\Controls\Gecko.js. There are two functions which should be modified.

scBrowser.prototype.prompt

Modify the following line (Line 231 in the JS file):

From

return showModalDialog(“/sitecore/shell/prompt.html”, arguments, features);

To

return window.open(“/sitecore/shell/prompt.html”, arguments, features);

scBrowser.prototype.showModalDialog

Modify the following line (The line number varies for different versions of Sitecore. For Sitecore 7.0 it is Line 350 and for Sitecore 6.6 Line 345):

From

showModalDialog(url, arguments, features);

To

window.open(url, arguments, features);

The big difference is that now the opened windows will not block the GUI, because they are opened in a new browser window and the fabulous dim effect is gone :).

Fixed Modal

Hope this will help you stick to your favorite browser !

Here are some useful links from other sources:

Main SDN Discussion Thread – PSA: showModalDialog disabled by default in Chrome 37

Blog Post By Dheer Rajpoot which covers the chrome policies approach in details – Sitecore Modal Pop-ups are not working in Chrome

Blog Post By Ben McCallum – Sitecore modals and problems in newer browsers

Blog Post By Kamruz Jaman using jQuery UI Dialog – Fix for Dialog Modals not working in Sitecore in Chrome 37+ browsers 

Sitecore KB – Sitecore does not work in Chrome 37 and later

Useful Sitecore Query String Parameters

At the end of the day Sitecore is a web based system and as such uses query string parameters to pass viable data. They are used to switch between display modes, sites, languages etc. I found out that remembering these parameters is a huge speed improvement especially in cases when dealing with multi-language, multi-device or page editor enabled solutions. Here is a list of the Sitecore query string parameters that I are most useful in my day-to-day job.

sc_mode – Used to change the display mode of the website. Can have the following values:

  • normal – normal display – the way the users see the site
  • edit – page editor mode
  • preview – preview mode

Example: http://yoursitename.com?sc_mode=preview

sc_lang – Used to change the website language. Can have any value that is defined under /sitecore/system/languages

Example: http://yoursitename.com?sc_lang=fr-FR

sc_itemid – Used to change the current item.

Example: http://yoursitename.com?sc_itemid={12345678-1234-1234-1234-123456789ABC}

sc_site – Used to change the current website.

Example: http://yoursitename.com?sc_site=mywebsite

sc_device – Used to change the device in which the website is displayed. Can be used with the device name or the device id.

Example: http://yoursitename.com?sc_device=mobile

Example: http://yoursitename.com?sc_device={12345678-1234-1234-1234-123456789ABC}

sc_database – Used to change the database from which the content is displayed.

Example: http://yoursitename.com?sc_database=master

 

And here are some of the debug specific query string parameters.

sc_debug – Used to start/stop the debug mode. Possible values are 0 and 1.

Example: http://yoursitename.com?sc_debug=1

sc_prof – Used to start/stop the Sitecore profiler. Possible values are 0 and 1.

Example: http://yoursitename.com?sc_debug=1&sc_prof=1

sc_trace – Used to start/stop the Sitecore trace. Possible values are 0 and 1.

Example: http://yoursitename.com?sc_debug=1&sc_trace=1

sc_ri – Used to show/hide the rendering information. Possible values are 0 and 1.

Example: http://yoursitename.com?sc_debug=1&sc_ri=1

The default debugger usually starts with all three enabled – http://yoursitename.com?sc_debug=1&sc_prof=1&sc_trace=1&sc_ri=1

 

These are the query string params that I usually use in my day-to-day job. There are probably many more of them in Sitecore that are sitting there, waiting for someone to find them 🙂 !

Sitecore Custom Field Validators

In many cases developers rely on the content editors to input valid content. In reality that never happens. The only way to protect ourselves from receiving invalid data from Sitecore is by using validators. Sitecore has pretty nice “out of the box” validation rules for common scenarios. But common scenarios are much like unicorns and the guys in Sitecore know that. Because of that there is a pretty nice way to add our own custom validators. It can be achieved in 3 easy steps.

The scenario described in this example is the following: There is a single line text field which should contain exactly 16 characters. The first 8 characters must be numbers and the other 8 characters must be English alphabet letters. (Please keep in mind this can be implemented via the built in Sitecore.Data.Validators.FieldValidators.RegexValidator).

Step 1 – Creating A Custom Validator

Create a Custom Validator that inherits from StandardValidator with the following code.

using Sitecore.Data.Validators;
using System.Text.RegularExpressions;

namespace Sandbox.Validators
{
    public class SandboxIDValidator : StandardValidator
    {
        private readonly Regex numbersRegex = new Regex(@"^\d+$");
        private readonly Regex lettersRegexnew = new Regex(@"^[A-Za-z]+$");

        protected override ValidatorResult Evaluate()
        {
            string value = base.GetControlValidationValue();

            if (!string.IsNullOrEmpty(value) && value.Length == 16)
            {
                string firstPart = value.Substring(0, 8);
                string secondPart = value.Substring(8, 8);

                if (numbersRegex.IsMatch(firstPart) && lettersRegexnew.IsMatch(secondPart))
                {
                    return ValidatorResult.Valid;
                }
            }

            base.Text = "Text is not a valid Sandbox ID";

            return base.GetFailedResult(ValidatorResult.Error);
        }

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

        public override string Name
        {
            get { return "Sandbox ID Validator"; }
        }
    }
}

To create a custom validator, the StandardValidator abstract class should be inerited (which inherits the BaseValidator abstract class). The Name property is self descriptive. The evaluate method gets called when the field needs validation. It determines if the value of the field is valid and and in case it is – it should return ValidatorResult.Valid. Otherwise it should return a validation error of some kind (it might be a suggestion or warning) and error message. GetMaxValidator result is best explained by decompiling the Sitecore.Kernel and looking at the remark:

GetMaxValidatorResult

 

Step 2 – Creating a Sitecore Validation Rule

After the code is ready the validator needs to be added as a Validation Rule in Sitecore. The field validators are located under “/sitecore/system/Settings/Validation Rules/Field Rules/”. The new validation rule for the custom validator should look like this.

Creating_a_custom_validator

Step 3 – Attaching the Validator to a Field

In order to use the validator it should be attached to a field. To attach it navigate to the Template Field in the Template. After that expand the Validation Rules section and add it under the appropriate sections where the validator should appear.AttachToItem

At the end the result should look like this:

ValidatedItem

Happy Validating !

 

Switch Sitecore 7.2 Speak UI Media Browser to the good old Sheer UI Media Browser

I am posting this article as a follow up to the following SDN Topic – Sitecore 7.2: Delete image in media picker in page editor.

After upgrading to Sitecore 7.2 the content editors might complain about the new Speak UI Media Browser, as they would not find it as intuitive as the old one (or maybe they will have a hard time getting used to it). Fortunately there is a way to disable the new Speak Media Browser and switch to the good old Sheer one.

It can be achieved by disabling Speak overrideXmlControls in the Sitecore.Speak.config.

Create a custom configuration with the following code.

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
	<sitecore>
		<overrideXmlControls>
			<override xmlControl="Sitecore.Shell.Applications.Media.MediaBrowser" with="/sitecore/client/applications/Dialogs/SelectMediaDialog">
				<patch:delete />
			</override>
		</overrideXmlControls>
	</sitecore>
</configuration>

Keep in mind that the configuration file needs to be bellow the Sitecore.Speak.config in the Include folder otherwise the configuration file won’t work because the original Sitecore.Speak.config overrides won`t be registered (a good name will be z_Sitecore.Speak.Overrides.config).

The effects can be seen on the screenshots bellow.

Before:

Speak UI Media Browser
After:

Sheer UI Media Browser

You can also notice that Sitecore.Speak.config is the configuration file in which the old Sheer UI Dialogs were overridden by the new Speak UI Dialogs (under the overrideDialogs node). If you want to switch to the old Sheer Dialogs this is the place to do it.

Playing with the Sitecore Item Saved Event

There are cases in which the data for an item should get automatically populated from a service or some kind of external database. In some cases the content editors want to decide on which items exactly should be pulled from the external service. One of the ways to achieve this is by attaching to the Sitecore Item Saved Event.

Attaching to the Item Saved Event can be achieved with two simple steps.

Step 1 – Creating a custom event handler


namespace Sandbox.Events
{
    using System;
    using Sitecore.Data;
    using Sitecore.Data.Items;
    using Sitecore.Events;
    using Sitecore.SecurityModel;

    public class ItemSavedHandler
    {
        public void OnItemSaved(object sender, EventArgs args)
        {
            // Extract the item from the event Arguments
            Item savedItem = Event.ExtractParameter(args, 0) as Item;

            // Allow only non null items and allow only items from the master database
            if (savedItem != null && savedItem.Database.Name.ToLower() == "master")
            {
                // Do some kind of template validation to limit only the items you actually want

                if (savedItem.TemplateID == ID.Parse("{00000000-0000-0000-0000-000000000000}"))
                {
                    // Get the data that you need to populate here

                    // Start Editing the Item

                    using (new SecurityDisabler())
                    {
                        savedItem.Editing.BeginEdit();

                        // Do your edits here

                        savedItem.Editing.EndEdit();
                    }
                }
            }
        }
    }
}

When inside the handler all the field values that were populated by the content editor can be accessed (for example the ID of the item in the external system).

Step 2 – Creating a custom configuration

The sample configuration can be found bellow


<?xml version="1.0"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <events>
      <event name="item:saved">
        <handler type="Sandbox.Events.ItemSavedHandler, Sandbox" method="OnItemSaved">
        </handler>
      </event>
    </events>
  </sitecore>
</configuration>

The configuration is simple – it is attaching the custom code to the item:saved event.

And that`s it ! Now you are ready to attach to the item saved event and do your magic !

There are many other events in Sitecore which are a very powerful tools and allow the developers to intercept any stage of the item`s lifecyle, but they will be covered in different posts.