Customizing rich text fields in Sitecore on accept action

Objective:

Post process rich text field values entered by content authors when the RTE ‘Accept’ action is triggered (Sitecore 6.5).

Introduction:

Sitecore provides a Rich Text Field which basically lets the content author use either the inbuilt rich text editor or pure HTML to insert rich text content in a given item.

In some scenarios we might want to have some level of control over the entered text programmatically. The following snippet gives you access to the text entered by the content author, when they click on accept from the rich text editor and lets you parse it and then replace the entered text with your processed text.

Please note, the pipeline in use here is not used if the content author uses the ‘Edit Html’ action from the RTF straight up!

2014-04-26_134449

But do note that you can edit Html even from the rich text editor itself!

2014-04-26_134619

Implementation:

Really the only important thing here is to use the right pipeline, provide accurate assembly / class names and use the right method signature in the class!

Here is the configuration update to add to the saveRichTextContent pipeline.


<pipelines>
	<saveRichTextContent>
        	<processor type="Sitecore.Shell.Controls.RichTextEditor.Pipelines.SaveRichTextContent.EmbedInParagraph, Sitecore.Client" />
        	<processor type="Mysite.Global.Classes.SaveRelativeLinks, Mysite" />
	</saveRichTextContent>
</pipelines>

Since the content of a rich text editor is primarily Html, you could use the HtmlAgilityPack to access html nodes with ease. In the below example, we are looping to every anchor tag in the rich text field and we could possibly transform it or even remove the anchor tag if the href url didn’t pass through certain filters!


    public class SaveRelativeLinks
    {
        public void Process(SaveRichTextContentArgs args)
        {
            // Load the HTML into the HtmlAgilityPack
            var doc = new HtmlDocument { OptionWriteEmptyNodes = true };
            doc.LoadHtml(args.Content);

            // Search for all links
            var aTags = doc.DocumentNode.SelectNodes("//a");
            if (aTags == null || aTags.Count == 0)
                return;

            foreach (var node in aTags)
            {
                if (node.Attributes["href"] != null
                    && !string.IsNullOrEmpty(node.Attributes["href"].Value))
                {
                    // perform any logic you'd want on the node here!
                    // ...
                    // ...
                }
            }
            // Replace the Rich Text content with the modified content
            args.Content = doc.DocumentNode.OuterHtml;
        }
    }

Advertisements

Workflow notifications in Sitecore (Roles & users)

Objective

To notify user(s) when an item moves into a certain state of an associated workflow in sitecore (Sitecore 6.5).

Introduction

Sitecore allows us to create workflows which can be associated with content items. In most scenarios, these workflows are a necessity seeing as any content seeking to appear in the live site, must undergo various steps of reviews and approval.

Sitecore lets you create a workflow with any number of states, each state can have a collection of commands, and each command can trigger a collection of actions.

Sitecore does provide multiple type of actions that can be added to execute when a command is triggered.

If you want to add an email action to notify users when an item is submitted / approved / rejected etc, you could sure try to use the out of the box email action (/sitecore/templates/System/Workflow/Email action). This works perfectly well when you have an email address as your recipient. When you have a role (all users in a role) or multiple roles or email addresses or a combination there of as your recipients, you will need to turn to a custom action (/sitecore/templates/System/Workflow/Action) for now.

Implementation

Add a custom action (/sitecore/templates/System/Workflow/Action) to the command which you want to add the notification functionality (Notify):

2014-04-26_013621

Available workflows are found at: /sitecore/system/Workflows.

A custom action takes a fully qualified class name, assembly name and optional parameters (available in the WorkflowPipelineArgs object)

A command (template: /sitecore/templates/System/Workflow/Command) has a Supress Comment field in addition to the Next State field. Left unchecked, the user is asked for a comment when this command is triggered. This comment appears in the item history:

2014-04-26_025107

And also note that this is available in the WorkflowPipelineArgs and is used in the highlighted line below.

Sample code of the custom action code:

using System.Configuration;
using System.Net.Mail;
using Mysite.Helpers;
using Sitecore.Workflows.Simple;

namespace Mysite.WorkflowActions
{
    public class NotifyReject
    {
        public void Process(WorkflowPipelineArgs args)
        {
            var contentItem = args.DataItem;

            var emailMessage = new MailMessage
            {
                From = new MailAddress(ConfigurationSettings.AppSettings["ContentSubmissionEmailFromId"]),
                Subject = "Content submitted: " + contentItem.Name,
                Body = "The following content item has been submitted for review: '" + contentItem.Name + "' (" + contentItem.Paths.Path + ")"
                       + " with the comment: '" + args.Comments + "'"
            };

            var userRolesSetting = ConfigurationSettings.AppSettings["ContentSubmissionEmailToRole"];
            emailMessage = WorkflowHelper.AddRecipientsToMail(emailMessage, userRolesSetting);

            WorkflowHelper.SendMail(emailMessage);
        }
    }
}

And here is the helper method which will allow you to take a configuration string of the like of ‘sitecore\Custom Content Authors|sitecore\Content Admin|admin@example.com’ and build a list of recipients to send out the email. In this snippet, the list of roles / email addresses has been stored in the web.config file. This could also be stored in a sitecore settings item, in which case it would be available to the content authors to update.

Note the highlighted lines to get the users from a role.


public static MailMessage AddRecipientsToMail(MailMessage mailMessage, string recipientsFromConfig)
        {
            var userRoleNames = recipientsFromConfig.Split('|');
            foreach (var userRoleName in userRoleNames)
            {

                if (Role.Exists(userRoleName))
                {
                    var role = Role.FromName(userRoleName);
                    var users = RolesInRolesManager.GetUsersInRole(role, true);
                    foreach (var user in users.Where(x => x.IsInRole(role)).Where(user => !string.IsNullOrEmpty(user.Profile.Email)))
                    {
                        mailMessage.To.Add(user.Profile.Email);
                    }
                }
                else
                {
                    var rgxEmail = new Regex(@"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}" +
                            @"\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\" +
                            @".)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$");
                    if (rgxEmail.IsMatch(userRoleName))
                        mailMessage.To.Add(userRoleName);
                }
            }

            return mailMessage;
        }

You might also want to send out an email to the content author that last edited the item in question:

// Get user who last edited the item
var contentWorkflow = contentItem.Database.WorkflowProvider.GetWorkflow(contentItem);
var contentHistory = contentWorkflow.GetHistory(contentItem);

if (contentHistory.Length > 0)
{
	var lastUser = contentHistory.Last().User;
	var submittingUser = User.FromName(lastUser, false);
	emailMessage.To.Add(submittingUser.Profile.Email);
}