Tuesday, 22 July 2014

Disable Schedule Email Reminder Task for multiple items in Sitecore

4 comments
Today I have noticed a post in Sitecore SDN forum regarding how to disable Schedule Email Reminder task for multiple items in Sitecore. I thought it'd be better to turn it into a Blog post with more detail. It might come useful to someone. :)

Occasionally an author may wish to be reminded of something regarding the item he is working on. Sitecore Reminders are made just for that. They also make the Administrator's work easier, by providing a suitable way of notifying Editors and other staff members about changes needed to be made. Reminder settings for an item are set in the Tasks section:
You can also set reminder settings for an item by clicking on Set Reminder in Review Strip of Sitecore Content Editor Ribbon.

Disabling Schedule Email Reminder task

Schedule Email Reminder task for Sitecore item can be disabled by following ways:
  1. Using Sitecore Content Editor: You can disable reminder settings for an item by clicking on Clear Reminder in Review Strip of Sitecore Content Editor Ribbon.
    You can also disable reminder settings for an Item by clicking on Clear link in the Tasks section.
    This approach will work only for one item at a time.
  2. Updating tasks table of Core Database: You can disable EmailReminderTask for multiple items by modifying tasks table of Core database using below SQL query:
    Update [Tasks] set Disabled=1 where taskType='Sitecore.Tasks.EmailReminderTask,Sitecore.Kernel'
    Take a backup of Core db before executing this query.
  3. Disabling TaskDatabaseAgent in web.config: In web.config, you will find below entry related to TaskDatabaseAgent
      <!-- Agent to process tasks from the task database (TaskDatabase) -->
          <agent type="Sitecore.Tasks.TaskDatabaseAgent" method="Run" interval="00:10:00" />
    
    TaskDatabaseAgent gets all pending tasks ( for example: EmailReminderTask, ArchiveItem, ArchiveVersion) from the tasks table of Core db and executes them one by one. So basically TaskDatabaseAgent runs scheduled tasks from the Core database.
    So in order to suspend EmailReminderTask you have to disable TaskDatabaseAgent by setting its value to 00:00:00 ( 00:00:00 means that Agent/Job is disabled).
    Disabling TaskDatabaseAgent will also suspend execution of other pending tasks like ArchiveItem or ArchiveVersion.
  4. Using Custom Code: Below function ClearReminder(Item item) takes Sitecore item as input parameter and clear reminder for specific item. Call this function iteratively for multiple items.
  5. Item item = Sitecore.Data.Database.GetDatabase("master").GetItem(new ID("{D833E825-4948-4264-9D77-68CE50C72F94}"));
                ClearReminder(item);
    public void ClearReminder(Item item)
            {
                if (item[FieldIDs.ReminderText].Length > 0 || item[FieldIDs.ReminderRecipients].Length > 0 || item[FieldIDs.ReminderDate].Length > 0)
                {
                    using (new Sitecore.SecurityModel.SecurityDisabler())
                    {
                        item.Editing.BeginEdit();
                        item[FieldIDs.ReminderText] = string.Empty;
                        item[FieldIDs.ReminderRecipients] = string.Empty;
                        item[FieldIDs.ReminderDate] = string.Empty;
                        item.Editing.EndEdit();
                        string[] strArrays = new string[] { AuditFormatter.FormatItem(item) };
                        Log.Audit(this, "Clear reminder: {0}", strArrays);
                    }
                }
            }
    
Comments and suggestions are most welcome. Happy coding!
Read More...

Monday, 21 July 2014

ReferenceError: Sys is not defined while working in Sitecore Content Editor

Leave a Comment
Today I was working on clean installation of Sitecore CMS 7.0 rev. 130918 and configured it to support MVC. Somehow I started getting below error while working with rich text editor in Sitecore Content Editor.
Uncaught ReferenceError: Sys is not defined.

It seems that embedded scripts were not getting loaded by Webresource.axd and Scriptresource.axd handlers. While troubleshooting, I’ve checked for WebResource.axd in IgnoreUrlPrefixes setting to ensure that necessary javascripts are getting loaded. Below entry was present in web.config:
<setting name="IgnoreUrlPrefixes" value="/sitecore/default.aspx|/trace.axd|/webresource.axd|/sitecore/shell/Controls/Rich Text Editor/Telerik.Web.UI.DialogHandler.aspx|/sitecore/shell/applications/content manager/telerik.web.ui.dialoghandler.aspx|/sitecore/shell/Controls/Rich Text Editor/Telerik.Web.UI.SpellCheckHandler.axd|/Telerik.Web.UI.WebResource.axd|/sitecore/admin/upgrade/|/layouts/testing"/>
I’ve also added Scriptresource.axd in IgnoreUrlPrefixes settings but it didn’t work in my case then I started to check MVC routes. The routes for the MVC Web Application are defined in the RouteConfig.cs under the App_Start folder of the MVC Project. In static function RegisterRoutes(RouteCollection routes) below route was defined:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
The route with the pattern {resource}.axd/{*pathInfo} was included to prevent requests for the web resource files such as WebResource.axd or ScriptResource.axd from being passed to a controller. I’ve deleted above route entry and build the solution. Bingo! I was no longer getting any error message. Please drop a comment if anybody knows more detail about this error and let me know your opinion.

Comments and suggestions are most welcome. Happy coding!
Read More...

Saturday, 19 July 2014

Configuring Sitecore Item Buckets with different bucket folder path : Part 2

Leave a Comment
In my previous post, I’ve explained about changing the bucketing strategy by using predefined bucketing rules. In this post I am going to explain how to implement bucketing strategy by writing custom code.

Bucketing Strategy: Using Custom Code

Now I demonstrate how newly created bucketable items will be auto organized into content tree based on item name with dictionary index hierarchy with up to two levels. I’ll write custom code to achieve this behavior.
In Sitecore, create a template field titled Enable Custom Dynamic Bucket Folder Path as a checkbox field to /sitecore/templates/System/Templates/Sections/Item Buckets.
I’ve created a bucket folder named Article and enable checkbox for Enable Custom Dynamic Bucket Folder Path field in Item Buckets section.
I’ve written a CustomBucketFolderPathResolver class which implements IDynamicBucketFolderPath interface. In the function GetFolderPath, I am checking value of Enable Custom Dynamic Bucket Folder Path checkbox. If it is true then I am creating custom dynamic bucket folder path else path will be auto generated based on Bucketing Rule Context or by the creation date of the item.
Below is the code of CustomBucketFolderPathResolver class:
using Sitecore;
using Sitecore.Buckets.Rules.Bucketing;
using Sitecore.Buckets.Util;
using Sitecore.Data;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Rules;
using Sitecore.StringExtensions;
using System;

namespace Sitecore.Ramblings
{
    public class CustomBucketFolderPathResolver : IDynamicBucketFolderPath
    {
        public CustomBucketFolderPathResolver()
        {
        }

        public string GetFolderPath(Database database, string itemName, ID templateId, ID itemId, ID parentItemId, DateTime creationDateOfNewItem)
        {
            Assert.ArgumentNotNull(database, "database");
            Assert.ArgumentNotNull(itemId, "itemId");
            Assert.ArgumentNotNull(parentItemId, "parentItemId");

            string resolvedPath = null;

            Item parentItem = database.GetItem(parentItemId);

            if (parentItem != null)
            {
                if (parentItem.Fields["Enable Custom Dynamic Bucket Folder Path"].Value == "1")
                {
                    if (itemName.Length == 1)
                    {
                        resolvedPath = itemName;
                    }
                    else
                    {
                        resolvedPath = itemName.Substring(0, 1) + "/" + itemName.Substring(0, 2);
                    }
                    return resolvedPath;
                }
            }

            BucketingRuleContext bucketingRuleContext = new BucketingRuleContext(database, parentItemId, itemId, itemName, templateId, creationDateOfNewItem)
            {
                NewItemId = itemId,
                CreationDate = creationDateOfNewItem
            };
            BucketingRuleContext bucketingRuleContext1 = bucketingRuleContext;
            Item item = database.GetItem(Sitecore.Buckets.Util.Constants.SettingsItemId);
            Assert.IsNotNull(item, "Setting Item");
            Item[] itemArray = new Item[] { item };
            RuleList<BucketingRuleContext> rules = RuleFactory.GetRules<BucketingRuleContext>(itemArray, Sitecore.Buckets.Util.Constants.BucketRulesFieldId);
            try
            {
                if (rules != null)
                {
                    rules.Run(bucketingRuleContext1);
                }
            }
            catch (Exception exception)
            {
                Log.Error(string.Format("BucketFolderPathResolver: Cannot resolve bucket path for item {0}. Parent = {1}", itemId, parentItemId), exception);
            }

            resolvedPath = bucketingRuleContext1.ResolvedPath;
            if (resolvedPath.IsNullOrEmpty())
            {
                resolvedPath = creationDateOfNewItem.ToString(BucketConfigurationSettings.BucketFolderPath, Context.Culture);
            }
            return resolvedPath;
        }
    }
}
Go to App_Config\Include\Sitecore.Buckets.config file and set value of BucketConfiguration.DynamicBucketFolderPath setting as below:
<!--<setting name="BucketConfiguration.DynamicBucketFolderPath" value="Sitecore.Buckets.Util.BucketFolderPathResolver, Sitecore.Buckets"/>-->
<setting name="BucketConfiguration.DynamicBucketFolderPath" value="Sitecore.Ramblings.CustomBucketFolderPathResolver, SitecoreRamblings "/>
The value format is “<namespace>.<class name>, <assembly name>”. For example:Sitecore.Ramblings is namespace, CustomBucketFolderPathResolver is class name and SitecoreRamblings is assembly name.

Create a new item under Article bucket folder and it will auto organized into content tree based on item name with dictionary index hierarchy with up to two levels. Comments and suggestions are most welcome. Happy coding!
Read More...

Configuring Sitecore Item Buckets with different bucket folder path : Part 1

Leave a Comment
An item bucket acts as a repository or container in the content tree where you can store other content items. Also the parent to child relationship between the content items in an item bucket is completely removed and instead the items are automatically organized into folders. Auto organizing content items at the time of creation is based on bucketing strategy. By default, the items are organized according to the date and time of when the item was created, but this can be configured to use different behavior, such as the item’s globally unique identifier (GUID).
As you can see in above image; ACE item is auto-organized by the creation date of the item i.e. Date 14 July 2014, Time 20:00 Hrs. In this blog post; I am going to explain few different bucketing strategies while using Sitecore Item bucket.  Note that I am working on Sitecore 7.2 release. We can change the bucketing strategy by two ways:
  • Using predefined bucketing rules. I’ll be explaining this approach in this blog post.
  • Writing custom code for bucketing strategy. This scenario will be explained in next blog post.
  1. Bucketing Strategy – Using new item creation date: Newly created bucketable items will be auto organized into content tree based on item creation date in yyyy/MM/dd format. I’ve created a new template NEWS and made it as bucketable.  
    Navigate to item bucket settings stored at /sitecore/system/Settings/Buckets location and create a new rule (Bucketing Strategy: Item Creation Date) for resolving the bucket folder path.


    Create a new news item based on News template under bucket folder and it will auto organized by item creation date in yyyy/MM/dd format.
  2. Bucketing Strategy – Using new item name: Newly created bucketable items will be auto organized into content tree based on item name with up to three levels. I’ve created a new template PRODUCT and made it as bucketable. Navigate to item bucket settings stored at /sitecore/system/Settings/Buckets location and create a new rule (Bucketing Strategy: Item Name) for resolving the bucket folder path.
    Create a new product item based on Product template under bucket folder and it will auto organized by item name format.
  3. Bucketing Strategy – Using new item id: Newly created bucketable items will be auto organized into content tree based on item id with five levels. I’ve created a new template MEMBER and made it as bucketable. Navigate to item bucket settings stored at /sitecore/system/Settings/Buckets location and create a new rule (Bucketing Strategy: Item Id) for resolving the bucket folder path.
    Create a new member item based on Member template under bucket folder and it will auto organized by item id format with five levels.
Comments and suggestions are most welcome. Happy coding!
Read More...

Sunday, 13 July 2014

Check user’s access rights on Sitecore item programmatically

Leave a Comment
Recently I’ve got into a situation where I have to identify programmatically whether given user is having read or write access on specific Sitecore item. I’ve thought of sharing my solution via blog post. It might come in handy for someone else. Below function CheckReadAccess(string itemId, string UserName) accepts User Name and Item Id of Sitecore item as input parameter and returns true or false after assessing access rights.
public bool CheckReadAccess(string itemId, string UserName)
        {
            bool ReadAccess = false;

            if (Sitecore.Data.ID.IsID(itemId))
            {
                Item item = Sitecore.Context.Database.GetItem(Sitecore.Data.ID.Parse(itemId));
                if (item != null)
                {
                    Sitecore.Security.Domains.Domain domain = Sitecore.Context.Domain;
                    string domainUser = domain.Name + @"\" + UserName;
                    if (Sitecore.Security.Accounts.User.Exists(domainUser))
                    {
                        Sitecore.Security.Accounts.User user = Sitecore.Security.Accounts.User.FromName(domainUser, false);
                        // UserSwitcher allows below code to run under a specific user 
                        using (new Sitecore.Security.Accounts.UserSwitcher(user))
                        {
                            ReadAccess = item.Access.CanRead();
                        }
                    }
                }
            }
            return ReadAccess;
        }
Explanation: I’ve used the Sitecore.Security.Accounts.UserSwitcher class to cause a block of code to run in the context of a specific user, regardless of the context user. The Sitecore.Security.Accounts.UserSwitcher constructor sets the context user to the specified user. The code within the using statement block has the effective rights of the user specified by the first parameter passed to constructor of the the Sitecore.Security.Accounts.UserSwitcher class. Sitecore.Security.AccessControl.ItemAccess class is responsible to check various access rights on given item. In my code, I am checking read access rights on Sitecore item by calling item.Access.CanRead(). ItemAccess class is having below inbuilt functions:
namespace Sitecore.Security.AccessControl
{
    public class ItemAccess
    {
        public ItemAccess(Item item);

        public virtual bool CanAdd(BranchId branchId);
        public virtual bool CanAdd(TemplateID templateID);
        public virtual bool CanAdmin();
        public virtual bool CanCopyTo(Item destination);
        public virtual bool CanCreate();
        public virtual bool CanDelete();
        public virtual bool CanDuplicate();
        public virtual bool CanMoveTo(Item destination);
        public virtual bool CanRead();
        public virtual bool CanReadLanguage();
        public virtual bool CanRemoveVersion();
        public virtual bool CanRename();
        public virtual bool CanWrite();
        public virtual bool CanWriteLanguage();
    }
}
Write a comment if you are aware of some other ways of checking access rights on Sitecore item programmatically. Comments and suggestions are most welcome. Happy coding!  
Read More...

Saturday, 12 July 2014

Impact of Sitecore Aliases on SEO

Leave a Comment
Today I’ve noticed a post in Sitecore SDN forum regarding impact of Sitecore Aliases on SEO. While answering to the post; I thought it'd be better to turn it into a Blog post with more detail. :)

From SEO point of view, using aliases in Sitecore is not good option. The main reason is multiple URLs will be created for a single page URL. This in turn shows up in Google search engine as two pages and will consider as duplicate content. Search engines try to index pages with distinct and unique content. Duplicate content affects adversely the hits for the page in the results rankings. So it will be better to avoid aliases in Sitecore whenever possible.

No redirect (no 301 or 302 HTTP status code) happens when you are using aliases in Sitecore. You can monitor HTTP status code and web traffic using Fiddler.  Suppose you’ve created aliases for a Sitecore item /sitecore/content/Home/sample/sample1/sample2 as sampleitem. If you open www.yourwebsite.com/sample/sample1/sample2 then you will see HTTP status code as 200 and if you open www. yourwebsite.com/sampleitem then also you will see HTTP status code as 200 which means that we are having two URLs which is generation same content (duplicate content).

Set canonical URL link into the head of the page whenever you are using aliases in Sitecore. Using canonical URLs to improve link and ranking signals for content available through multiple URL structures is recommended practice.

How to implement Canonical URL link in Sitecore:

Override AliasResolver processor in HttpRequest pipeline and write custom logic to handle aliases and generate canonical link. In web.config you will see below line related to AliasResolver processor:
<processor type="Sitecore.Pipelines.HttpRequest.AliasResolver, Sitecore.Kernel" />
Below is the custom code for CustomAliasResolver:
using Sitecore;
using Sitecore.Links;
using Sitecore.Pipelines.HttpRequest;
using System.Web;

namespace Sitecore.Ramblings
{
    public class CustomAliasResolver : Sitecore.Pipelines.HttpRequest.AliasResolver
    {
        public CustomAliasResolver()
        {
        }

        public override void Process(HttpRequestArgs args)
        {
            base.Process(args);
            if (Context.Item != null)
            {
                string href = "{0}://{1}{2}";
                args.Context.Items["CanonicalUrl"] = string.Format(href, HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Host, LinkManager.GetItemUrl(Context.Item));
            }
        }
    }
}
Modify web.config as below:
<!--<processor type="Sitecore.Pipelines.HttpRequest.AliasResolver, Sitecore.Kernel" />-->
<processor type="Sitecore.Ramblings.CustomAliasResolver, SitecoreRamblings" />
The type format is “<namespace>.<class name>, <assembly name>”. For example: Sitecore.Ramblings is namespace, CustomAliasResolver is class name and SitecoreRamblings is assembly name.

Now in the header control or in layout of your website check whether HttpContext.Current.Items["CanonicalUrl"] is not null and set canonical URL into the head of page. Below is the sample code to set canonical URL in layout of Sitecore MVC website.
@if (Context.ApplicationInstance.Context.Items["CanonicalUrl"] != null)
    {
 <link rel="canonical" href="@Context.ApplicationInstance.Context.Items["CanonicalUrl"].ToString()" />
    }
Comments and suggestions are most welcome. Happy coding! 
Read More...

Wednesday, 9 July 2014

Find all the items that are referring to particular item in Sitecore

Leave a Comment
In this blog post I am going to explain how to get all the items (referrers) which are referring to a particular item (may be template, sublayout or rendering etc.) in Sitecore. There are few ways to achieve this goal:
  1. Using Sitecore Content Editor UI
  2. Writing custom C# code
  3. Using Sitecore Powershell Console Module
  • Using Sitecore Content Editor UI: The simplest way of seeing these referrer links is to go to that particular item and go to the Navigation Strip and then click on Links. This should show you all the items (referrers) that point to this current item and all the items that the current items points to (references).
  • Writing custom C# code: Below function GetReferrers(string itemId) takes item id as input parameter and return the list of items which are pointing to this particular item.
    public Item[] GetReferrers(string itemId)
            {          
                Item item = Sitecore.Data.Database.GetDatabase("master").GetItem(new Sitecore.Data.ID(itemId));
                // getting all linked Items that refer to the Item
                ItemLink[] itemLinks = Globals.LinkDatabase.GetReferrers(item);
                if (itemLinks == null)
                {
                    return null;
                }
                else
                {
                    ArrayList items = new ArrayList(itemLinks.Length);
                    foreach (ItemLink itemLink in itemLinks)
                    {
                        // comparing the database name of the linked Item
                        if (itemLink.SourceDatabaseName == "master")
                        {
                            Item linkItem = Sitecore.Data.Database.GetDatabase("master").Items[itemLink.SourceItemID];
                            if (linkItem != null)
                            {
                                items.Add(linkItem);
                            }
                        }
                    }
                    return (Item[])items.ToArray(typeof(Item));
                }
            }
    
  • Using Sitecore Powershell Console Module: Download Sitecore Powershell Console Module from Sitecore MarketPlace and install the package. Go to Start > Development Tools > PowerShell ISE.

    Enter below powershell script in script field and execute.
    $props = @{
       InfoTitle = "Referrers"
        InfoDescription = "Lists all items that are using this item"
        PageSize = 25
    }
    
    function Get-ItemReferrers {
        $item = Get-Item -Path "/sitecore/templates/Launch Sitecore/Job Function"
        $linkDb = [Sitecore.Globals]::LinkDatabase
        $links = $linkDb.GetReferrers($item)
        foreach($link in $links){
            $linkedItem = Get-Item -Path master:\ -ID $link.SourceItemID
            $linkedItem
        }
    }
    
    $items = Get-ItemReferrers
    $items | Show-ListView @props -Property @{Label="Name"; Expression={$_.DisplayName} },
                @{Label="Updated"; Expression={$_.__Updated} },
                @{Label="Updated by"; Expression={$_."__Updated by"} },
                @{Label="Created"; Expression={$_.__Created} },
                @{Label="Created by"; Expression={$_."__Created by"} },
                @{Label="Path"; Expression={$_.ItemPath} }
    
    Close-Window
    
Above approaches require that Link Database should be up to date. Link database should be updated automatically but you can force rebuild command manually. Go to Start > Control Panel > Databases > Rebuild Link Database
Sitecore Powershell References:
  1. Blog by Adam Najmanowicz 
  2. Blog by Michael West 
  3. How to create custom report using PowerShell blog by Mike Reynolds
Comments and suggestions are most welcome. Happy coding!
Read More...

Sunday, 6 July 2014

Customizing Page Editor Ribbon in Sitecore : Part 3

Leave a Comment
In my previous blog post; I’ve explained how to customize Sitecore Page Editor Ribbon by using predefined webedit:fieldeditor command. In this blog post I am going to discuss how to write custom code for click command.
  1. Create a new large button item Edit Meta Data by using template /sitecore/templates/System/Ribbon/Large Button under /sitecore/content/Applications/WebEdit/Ribbons/WebEdit/Page Fields/Hidden Fields path. Update Header field to specify button name and enter unique id with no white spaces in ID field. Tooltip is used to display a short description when a user points at the button. Type a char in Access Key and you can access your button by pressing [alt] + [Access key]. Content tree of core database should look like as below figure:
  2. Open visual studio and create a new class CustomFieldEditor and inherit Sitecore.Shell.Applications.WebEdit.Commands.FieldEditorCommand class. Write below code in class.
    using Sitecore;
    using Sitecore.Data.Items;
    using Sitecore.Diagnostics;
    using Sitecore.Shell.Framework.Commands;
    using Sitecore.Web;
    using Sitecore.Web.UI.Sheer;
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Web;
    
    namespace Sitecore.Ramblings
    {
        public class CustomFieldEditor : Sitecore.Shell.Applications.WebEdit.Commands.FieldEditorCommand
        {
            /// <summary>
            /// The name of the parameter in <c>ClientPipelineArgs</c> containing 
            /// Sitecore item identification information.
            /// </summary>
            private const string URI = "uri";
    
            public override void Execute(CommandContext context)
            {
                Assert.ArgumentNotNull(context, "context");
                if (context.Items.Length >= 1)
                {
                    ClientPipelineArgs args = new ClientPipelineArgs(context.Parameters);
                    args.Parameters.Add("uri", context.Items[0].Uri.ToString());
                    if (args.Parameters["fields"] == String.Empty) { args.Parameters.Add("fields", context.Parameters["fields"]); }
                    Context.ClientPage.Start(this, "StartFieldEditor", args);
                }
            }
    
            /// <summary>
            /// Gets the configured Field Editor options. Options determine both the look of Field Editor and the actual fields available for editing.
            /// </summary>
            /// <param name="args">The pipeline arguments. Current item URI is accessible as 'uri' parameter</param>
            /// <param name="form">The form values.</param>
            /// <returns>The options.</returns>
            /// <example>
            /// ItemUri uri = ItemUri.Parse(args.Parameters["uri"]);
            /// Item item = Database.GetItem(uri);
            /// var options = new PageEditFieldEditorOptions(form, new List&lt;FieldDescriptor&gt; {
            /// new FieldDescriptor(item, "Title"),
            /// });
            /// options.Title = "Field Editor Test";
            /// options.Text = "Tests the Mini Content Editor system";
            /// options.Icon = "people/16x16/cubes_blue.png";
            /// return options;
            /// </example>
            protected override Sitecore.Shell.Applications.WebEdit.PageEditFieldEditorOptions GetOptions(Sitecore.Web.UI.Sheer.ClientPipelineArgs args, NameValueCollection form)
            {
                Sitecore.Diagnostics.Assert.IsNotNull(args, "args");
                Sitecore.Diagnostics.Assert.IsNotNull(form, "form");
                Sitecore.Diagnostics.Assert.IsNotNullOrEmpty(args.Parameters[URI], URI);
                Sitecore.Data.ItemUri uri = Sitecore.Data.ItemUri.Parse(args.Parameters[URI]);
                Sitecore.Diagnostics.Assert.IsNotNull(uri, URI);
                Sitecore.Diagnostics.Assert.IsNotNullOrEmpty(args.Parameters["fields"], "Field Editor command expects 'fields' parameter");
                Sitecore.Diagnostics.Assert.IsNotNullOrEmpty(args.Parameters["command"], "Field Editor command expects 'command' parameter");
                string flds = args.Parameters["fields"];
                string coreItemId = args.Parameters["command"];
    
                Sitecore.Data.Items.Item item = Sitecore.Data.Database.GetItem(uri);
                Sitecore.Diagnostics.Assert.IsNotNull(item, "item");
                Item coreItem = Client.CoreDatabase.GetItem(coreItemId);
                Assert.IsNotNull(coreItem, "command item");
    
                List<Sitecore.Data.FieldDescriptor> fields = new List<Sitecore.Data.FieldDescriptor>();
    
                foreach (string fieldName in flds.Split('|'))
                {
                    if (item.Fields[fieldName] != null)
                    {
                        fields.Add(new Sitecore.Data.FieldDescriptor(item, item.Fields[fieldName].Name));
                    }
                }
    
                // Field editor options.
                Sitecore.Shell.Applications.WebEdit.PageEditFieldEditorOptions options = new Sitecore.Shell.Applications.WebEdit.PageEditFieldEditorOptions(form, fields);
                options.PreserveSections = false;
                options.DialogTitle = coreItem.Fields["Header"].Value;
                options.Icon = coreItem.Fields["Icon"].Value;
                options.Title = coreItem.Fields["Header"].Value;
    
                return options;
            }
    
            /// <summary>
            /// Determine if the command button should be displayed or hidden.
            /// </summary>
            public override CommandState QueryState(CommandContext context)
            {
                if (WebUtil.GetQueryString("mode") != "edit")
                {
                    return CommandState.Hidden;
                }
                return CommandState.Enabled;
            }
        }
    
    }
  3. Define command definition in App_Config/Commands.config file as below:
    <command name="cutomsitecore:customfieldeditorbutton" type="Sitecore.Ramblings.CustomFieldEditor, SitecoreRamblings"/>
    Few important things here to note are:
    • Command name should be in lower case. For example: cutomsitecore:customfieldeditorbutton
    • The type format is “<namespace>.<class name>, <assembly name>”. For example: Sitecore.Ramblings is namespace, CustomFieldEditor is class name and SitecoreRamblings is assembly name.
    • This type is the link to the class which inherits the field editor command class (Sitecore.Shell.Applications.WebEdit.Commands.FieldEditorCommand).
  4. Write below line in Click field of Edit Meta Data (Large Button):
    cutomsitecore:customfieldeditorbutton(fields=Browser Title|Meta Tag|Meta Description,command={5D7A9F2B-9EB5-429B-AA08-DC743A7189E0})
    First argument fields is pretty much understandable. You have to specify field names that should be shown in the field editor separated with “|” (pipe symbol). You have to enter GUID of Edit Meta Data (Large Button) along with command parameter.
  5. Browse the page in edit mode and you will see new customized button in ribbon.
Comments and suggestions are most welcome. Happy coding!
Read More...

Customizing Page Editor Ribbon in Sitecore : Part 2

Leave a Comment
In my previous post I’ve given introduction about Customizing Sitecore Page Editor Ribbon. In this post; I’ll explain step by step how to customize Sitecore Page Editor Ribbon. The definition for the Sitecore Page Editor Ribbon is located in the Core database. The path is /Sitecore/Content/Applications/WebEdit/Ribbons/WebEdit.
  1. Create a new strip item Page Fields by using template /sitecore/templates/System/Ribbon/Strip under /Sitecore/Content/Applications/WebEdit/Ribbons/WebEdit path. Update Header field to specify strip name and enter unique id with no white spaces in ID field. Tooltip is used to display a short description when a user points at the strip. Type a char in Access Key and you can access your strip by pressing [alt] + [Access key]. In below example you can access strip by pressing alt+p.
  2. Create a new chunk item Hidden Fields by using template /sitecore/templates/System/Ribbon/Chunk  under /sitecore/content/Applications/WebEdit/Ribbons/WebEdit/Page Fields path. Update Header field to specify chunk name and enter unique id with no white spaces in ID field. Tooltip is used to display a short description when a user points at the chunk. Type a char in Access Key.
  3. Create a new large button item Edit Menu Options by using template /sitecore/templates/System/Ribbon/Large Button under /sitecore/content/Applications/WebEdit/Ribbons/WebEdit/Page Fields/Hidden Fields path. Update Header field to specify button name and enter unique id with no white spaces in ID field. Tooltip is used to display a short description when a user points at the button. Type a char in Access Key and you can access your button by pressing [alt] + [Access key]. Content tree of core database should look like as below figure:
  4. Now the main task is triggering click command on Edit Menu Options button click and load the field editor by specifying a parameterized command in the Click field. There are two ways of configuring click event:
    • Use predefined webedit:fieldeditor command
    • Writing custom code for click command
  5. In this blog post; I’ll be explaining first approach by implementing Edit Menu Options button. How to write custom code for click command will be explained in next blog post by implementing Edit Meta Data button.
  6. We don’t have to write a single line of code by using predefined webedit:fieldeditor command. This command is built-in Field Editor command which is invoked by Field Editor Button based buttons. You can see definition of this command in App_Config/Commands.config file.
    <command name="webedit:fieldeditor" type="Sitecore.Shell.Applications.WebEdit.Commands.FieldEditor, Sitecore.Client"/>
  7. Write below line in Click field of Edit Menu Options (Large Button):
    webedit:fieldeditor(fields=Menu Title|Show Item In Menu|Show Children In Menu|Show Item In Secondary Menu, command={20D9CC76-A946-4613-87D4-7520DEF2CB07})
    First argument fields is pretty much understandable. You have to specify field names that should be shown in the field editor separated with “|” (pipe symbol). You have to enter GUID of Edit Menu Options (Large Button) along with command parameter.
  8. Browse the page in edit mode and you will see new customized button in ribbon.
Comments and suggestions are most welcome. Happy coding!
Read More...

Customizing Page Editor Ribbon in Sitecore : Part 1

Leave a Comment
In this blog post I am going to explain how to customize Sitecore Page Editor Ribbon in Sitecore. This topic is going to be a bit lengthy so I’ve decided to complete this topic in three blog posts.
  1. Customizing Page Editor Ribbon in Sitecore : Part 1
  2. Customizing Page Editor Ribbon in Sitecore : Part 2
  3. Customizing Page Editor Ribbon in Sitecore : Part 3
Let’s start with brushing up common fundamentals related to Sitecore Page Editor Ribbon Components.
Recently I’ve come across a situation where I need to allow content editors who were using the Sitecore Page Editor to edit some hidden page-level fields like Page Title, Meta Keywords, Meta Description and various Menu options. Thus I’ve decided to add some custom additional buttons in Sitecore Page Editor Ribbon in order to modify these fields. Adding additional buttons in Sitecore Page Editor Ribbon is good idea as these fields will never be displayed and don’t belong to any specific component. The definition for the Sitecore Page Editor Ribbon is located in the Core database. The path is /Sitecore/Content/Applications/WebEdit/Ribbons/WebEdit.
I’ll create one new strip Page Fields. Underneath this strip, I’ll be adding one new chunk (Hidden Fields) and two large buttons (Edit Meta Data and Edit Menu Options) in Sitecore Page Editor Ribbon. Clicking the Edit Meta Data button and Edit Menu Options button opens a field editor with relevant the fields which allows content editors to modify page-level fields.

With these additions to the ribbon, the content editors no longer have to open the Sitecore Content Editor to modify page-level fields that are not visible. In the next blog post I’ll explain step by step how to customize Sitecore Page Editor Ribbon.

Comments and suggestions are most welcome. Happy coding!
Read More...