Thursday, March 21, 2024

Sitecore Content Hub : Sending emails to a UserGroup - Part 2 : Creating Actions and Scripts

Sitecore Content Hub : Sending emails to a UserGroup - Part 2 : Creating Actions and Scripts

In Sitecore Content Hub, Actions are components that perform a specific task. These actions can either be manually triggered by a user via the User Interface, or automatically run by a trigger or via the APIs.

Integrating custom scripts into your business logic within Sitecore Content Hub can be a powerful way to extend functionality and automate processes.

For our use case to send email to a UserGroup, we are going to create a Script in Content Hub. The primary purpose of the script is to :

1.Create the Email Template in Content Hub

2.Fetch the members of the UserGroup who will be notified about the asset submitted for review.

3.Lastly, send the email notification to the members

To create a script:
  • Go the the Manage page, type 'scripts' in the search bar, and select Scripts:
  • Click + Script to add the Script.
  • Build the script for checking any errors and then Publish the script.
Below is the Script for our use case. Please feel free to update depending on your requirements. 


       using Stylelabs.M.Base.Querying;
using Stylelabs.M.Sdk.Contracts.Base;
using Stylelabs.M.Sdk.Contracts.Notifications;
using Stylelabs.M.Sdk.Models.Notifications;
using Stylelabs.M.Sdk.Extensions;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Threading.Tasks;
using System.Linq;

const string emailTemplatename = "Asset Activity Notification - submitted for review and approval";

await SendEmailAsync();

public async Task SendEmailAsync()
{
    var emailTemplate = await MClient.Notifications.GetMailTemplateEntityAsync(emailTemplatename);
    if(emailTemplate == null){
        await CreateEmailTemaplateAsync();
        emailTemplate = await MClient.Notifications.GetMailTemplateEntityAsync(emailTemplatename);
    }
    var userGrp = MClient.Users.GetUserGroupAsync("Activity Email Group").Result.Id;

    var query = Query.CreateQuery(entities =>
    from e in entities
    where e.DefinitionName == "User"
    select e);
    var iterator = MClient.Querying.CreateEntityIterator(query, new EntityLoadConfiguration { RelationLoadOption = RelationLoadOption.All});
    var groupUsers = new List();
    var parents = "";

    while (await iterator.MoveNextAsync().ConfigureAwait(false))
    {
        foreach (var users in iterator.Current.Items)
        {
            var user = await MClient.Entities.GetAsync((long)users.Id);
            var groupRelation = user.GetRelation("UserGroupToUser");

                foreach(var parent in groupRelation.Parents){
                    parents = parents +  " , " + parent;
                    if (parent == userGrp) 
                    {
                        groupUsers.Add(user);
                    }
                }
        }
    }


            
    var userNames = MClient.Users.GetUsernamesAsync(groupUsers.Select(i => i.Id ?? 0).ToList()).Result?.Select(i => i.Value).ToList();
    var emailRecipients = new List();
    var entityModified = Context.Target as IEntity;
    foreach(var username in userNames){
    if(!emailRecipients.Contains(username)){
        emailRecipients.Add(username);
        MClient.Logger.Info($"Username added  {username}  entity {entityModified.Id}");

    }
    else{
        MClient.Logger.Info($"Username already added  {username}");

        }
    }
    var notificationRequest = new MailRequestByUsername
    {
        MailTemplateName = emailTemplatename,
        Recipients = emailRecipients
    };

    notificationRequest.Variables.Add("AssetUrl", "https://ghd-p-001.sitecorecontenthub.cloud/en-us/asset/"+entityModified.Id);
    await MClient.Notifications.SendEmailNotificationAsync(notificationRequest);
}


public async Task CreateEmailTemaplateAsync()
{
var enUs = CultureInfo.GetCultureInfo("en-US");
var entity = await MClient.EntityFactory.CreateAsync(Constants.MailTemplate.DefinitionName);
var template = MClient.TypedEntityFactory.FromEntity(entity);
template.Name = emailTemplatename;
template.Subject[enUs] = "Asset Activity Notification - Submitted for review and approval";
template.Description[enUs] = emailTemplatename;
template.Body[enUs] = "Hello {{Username}}, The following asset has been submitted for review and approval: {{AssetUrl}}";
template.SetPropertyValue("M.Mailing.TemplateLabel", enUs, emailTemplatename);
template.SetTemplateVariables(new []
    {
        new TemplateVariable
        {
            Name = "AssetUrl",
            VariableType = TemplateVariableType.String
        },
        new TemplateVariable
        {
            Name = "Username",
            VariableType = TemplateVariableType.String
        }
    });
await MClient.Entities.SaveAsync(template);
}


The next step is to create an Action and then link the Action to the script.
  • On the menu bar, click Manage cog icon.
  • On the Manage page, click Actions.
  • On the Actions page, click New Action.
  • In the New action dialog, select an Action type and provide other details as needed.
  • Click Save.






Sitecore Content Hub : Sending emails to a UserGroup - Part 1

Sitecore Content Hub : Sending emails to a UserGroup - Part 1

Planning to create triggers in Content Hub for sending emails automatically when an Asset is created or submitted for approval or deleted?

This article goes through the steps in details to setup automatic emails for activities on Asset. These email notifications are not enabled in Content Hub by default, however this is highly important for the authors and approvers who are managing multiple assets in Content Hub on a daily basis.



Creating triggers in Content Hub to automatically send emails when certain events occur, such as asset submission for approval, deletion, or creation, can be a powerful way to streamline communication and workflow processes. Here's a general outline of how you might set up these triggers:
  • Define Trigger Events: Determine which events should trigger an email notification. For example, you would like to trigger emails for asset submission for approval, deletion, and creation.
  • Configure Email Templates: Create email templates for each type of notification. These templates should include dynamic fields to personalize the email content, such as the asset name, submitter's name, etc.
  • Map Trigger Events to Email Templates: Associate each trigger event with the corresponding email template. Ensure that the necessary information is included in the email content to provide context for the recipient.
  • Test Triggers: Before deploying the triggers in a production environment, thoroughly test each trigger to ensure they are working as expected. This will help identify any potential issues or errors that need to be addressed.
  • Deploy Triggers: Once testing is complete and everything is functioning correctly, deploy the triggers in your Content Hub environment.
  • Monitor and Maintain: Regularly monitor the triggers to ensure they continue to work properly. Make any necessary adjustments or updates as your workflow evolves.By setting up triggers in Content Hub to automatically send emails based on specific events, you can streamline communication and notification processes, improving efficiency and ensuring timely responses to important events.
We cover the technical details on how to configure sending the emails in the next part of the article and below are the links to it. We cover 
  • creating Scripts and Actions in Content Hub in Part 2 of the article
  • creating the Trigger in Part 3 and associating the trigger with the action and script created in Part 2 of the article.

Special mention to Vasiliy Fomichev for his blog on sending emails in Sitecore Content Hub as it helped me quite a lot in configuring the email Scripts.
Reference : https://www.cmsbestpractices.com/how-to-send-emails-in-sitecore-content-hub/



  1. Sitecore Content Hub : Sending emails to a UserGroup - Part 2 : Creating Action

Sitecore Content Hub : Sending emails to a UserGroup - Part 3 : Creating Trigger

Sitecore Content Hub : Sending emails to a UserGroup - Part 3 : Creating Trigger

The Sitecore Content Hub provides you with a trigger framework that allows you to configure triggers using the user interface. A trigger is fired when a specified event occurs under specified conditions. When the trigger fires, it can initiate a set of actions.

Here are the steps outlined for creating the trigger and setting up the conditions on when the trigger will be reacting, and finally setting up what the trigger action will be.
  • Create Triggers:
    • Open the Sitecore Content Hub. On the ribbon, click Manage.

    • Click Triggers, and click New trigger.

    • On the General tab, enter the following values:

      Field

      Value

      Enter a name

      Submit Asset for Review Email Trigger

      Enter a description

      Send emails to Approver User group once Asset is submitted for review

      Objective

      Entity modification

      Execution type

      In background



We need to assess while creating the trigger on what the objective will be: For our use case, we have chosen Entity modification since we want the trigger to reach when any entity is modified.
  • Entity creation - use if you want the trigger to react when any entity is created.
  • Entity modification - use if you want the trigger to react when any entity is modified.
  • Entity deletion: -use if you want the trigger to react when any entity is deleted.
You also need to specify the trigger execution type, which is the method with which the trigger's actions execute. For this use case, we are selecting "in background"
  • In Background: trigger actions execute using an asynchronous background job. With this execution type, trigger actions can only execute during the post phase (that is, after the trigger's event takes place).

  • On the Conditions tab, click Add definition, and in the drop-down list, click Asset (M.Asset). And then add the following definitions:
  • Using the below definitions, we are setting the rule that if the Final lifecycle status of the Asset changes to UnderReview from Created / Archived/ Approved, then the trigger will perform the action mentioned in the next step.
  • On the Actions tab, add the action you created previously (Send Asset Submitted Email).
  • Click Save and close. Confirm to activate the trigger.


Tuesday, November 14, 2023

Sitecore Search : Addressing exceptions on the website crawling for the failed pages

Sitecore Search : Addressing common exceptions on the website crawling for the failed pages

This blog is to assist on how to address common exceptions with crawling errors on Sitecore Search for the failed pages. If you're experiencing issues with a site crawler,  where the crawler is encountering errors while crawling pages. The dashboard page does show the errors , but it does not provide a detailed log of the issue. This blog will help you to locate the full details around these errors. 

For checking the status of the Scheduled scans on the Site Crawler, 
  • Login to the CEC portal and click Sources
  • The summary on the last crawling is displayed here. It basically shows:
    • Last Run Status : shows Finished if it completed crawling or Failed if it stopped due to a failure
    • Last Run time 
    • Items Indexed: Number of items indexed 
    • Also, it also shows a summary of errors if there was any errors while crawling the site.
On the below example, after finishing the Crawling, it shows there are 3 configuration errors, but it does not show any further details for additional troubleshooting. 




So, in order to get more information on the crawling results, we can find it under the Analytics tab. Below are the steps to see more information on the crawling results:

  • Navigate to Analytics -> Sources ->  Overview and then select the Source at the bottom

  • This page shows the details on the last few crawling runs and details like duration of the run, status, Items Indexed and Job Run ID.


  • Click on the last Run to see if there were any documents that was dropped or failed. 



  • The reason of the failure is that the crawling of the page https://devsite.com/about-us/news failed because the page is unavailable or throwing errors while loading, which can be looked into with some troubleshooting. So, using the above method, we can potentially identify the crawling errors for faster troubleshooting.  

Wednesday, November 8, 2023

Executing Tasks with Sitecore PowerShell Extensions: A Practical Guide

Executing Tasks with Sitecore PowerShell Extensions: A Practical Guide 

Sitecore PowerShell Extensions (SPE) is a popular module for the Sitecore CMS that enhances its capabilities by providing a powerful scripting environment and a variety of useful commands for administrators and developers. It's commonly used for automating various tasks within Sitecore, such as content management, reporting, and maintenance. This blog is a practical guide to various uses of the module Sitecore PowerShell Extensions. It is meant to present some of the examples of how Sitecore PowerShell Extensions(SPE) can be leveraged for common tasks on Sitecore.


Below are some of the examples of how Sitecore PowerShell Extensions can be leveraged for common tasks on Sitecore:

Item Manipulation:

  • Creating Items: Sitecore items can be created programmatically using SPE. For example, using the below script, a new item is created under a specific folder Articles with a specified template Article.

    • New-Item -Path "master:\content\MySite\Articles" -Name "NewArticle" -ItemType "MySite/Article"

  • Copying / Moving Items: using the below SPE scripts, items can be copied or move items from one location to another.

    • Copy-Item -Path "master:\content\MySite\Articles\Article1" -Destination "master:\content\MySite\Articles\Article2"

    • Get-Item -Path "master:\content\MySite\Articles\Article1" | Move-Item  -Destination "master:\content\MySite\Articles"

  • Delete Items: using the below SPE command, items can be deleted. Using the permanently parameter, we specify the item should be deleted rather than recycled. 

    • Remove-Item -Path "master:\content\MySite\Articles\Article1" -Permanently

  • Publish Items: using the below SPE command, items can be published from one database to another, such as from the master database to the web database.

    • Get-Item -Path master:\content\home | Publish-Item -Recurse -PublishMode Incremental

  • For publishing to multiple databases 
    • $targets = [string[]]@('web','internet')
    • Publish-Item -Path master:\content\home -Target $targets

  • Bulk Operations: using the below command, bulk updates can be made on items, such as changing the template of multiple items or updating fields.

    • Get-ChildItem -Path "master:\content\MySite\Articles" | ForEach-Object {
              $_.ChangeTemplate("MySite/UpdatedArticleTemplate")
      }
  • Create Users and Roles: Sitecore User and role creation can be automated as well using the below commands.

    • New-User -Name "dev.user" -Password "password" -Email "dev.user@example.com" -Profile "Default Profile" -Roles @("Content Author", "Content Reviewer")

Friday, November 3, 2023

Configuring Sitecore Search Document Extraction: A Step-by-Step Guide

Configuring Sitecore Search Document Extractor: A Step-by-Step Guide 

Document extraction on Sitecore Search typically refers to the process of searching and extracting specific data or DOM elements by crawling over the web pages across the website. Document extraction involves the conversion of content into a structured format that can be processed and indexed for search.

This blog is intended to demo a step-by-step guide to setting up Document Extractors in Sitecore Search. Below are some of the common Key attributes that's required for the Search to work properly:
  • Title or Name of the page 
  • Content/Description of the pages
  • meta tags
  • key Elements from page components that should be included as part of the Search 
Here is a quick demo to configure a JavaScript Document Extractor to extract attribute values for an advanced web crawler or an API crawler: 
  • On the CEC portal, click Sources, and click on the custom Source. Then on the Source Settings configuration -> click on Document Extractors -> click edit on the right.
  • Next step is to add the extractor, add a Name Demo JavaScript Extractor and select JS as the Extractor type
  • In the Taggers section, -> click Add Tagger. The function must use Cheerio syntax and must return an array of objects.


This is a sample JS script already available on the editor on the tagger. This sample already includes extracting the below fields from the pages of the website:
  • title
  • description
  • searchtitle meta tag
  • Open Graph type
  • Open Graph URL
  • Open graph description tag
  • similarly language can be extracted from body or the url

// Sample extractor function. Change the function to suit your individual needs
function extract(request, response) {
    $ = response.body;

    return [{
        'description': $('meta[name="description"]').attr('content') || $('meta[property="og:description"]').attr('content') || $('p').text(),
        'name': $('meta[name="searchtitle"]').attr('content') || $('title').text(),
        'type': $('meta[property="og:type"]').attr('content') || 'website_content',
        'url': $('meta[property="og:url"]').attr('content')
    }];
}

Conditional logic can be implemented to extract key variables based on URLs:

    if (url.includes('/blogs')) {
      type = 'Blogs';
    } else if (url.includes('about-us')) {
      type = 'About Us';
    } else ..

One key thing is to configure attributes under Textual relevance under Domain Configuration and also on Global Widget Settings to make these attributes work properly. Here is an article which describe in details to configure the attributes on Textual relevance. 

https://sitecorebasics5.blogspot.com/2023/10/sitecore-search-how-to-configure.html

There are other methods of extraction as well like XPath and CSS document extractors. Depending on your requirement, you can choose them.

Reference:
https://doc.sitecore.com/search/en/users/search-user-guide/configuring-document-extractors.html

Thursday, October 26, 2023

Sitecore Search: How to Configure Textual Relevance for Better Search Results

Sitecore Search : How to Configure Textual Relevance for Better Search Results

Textual relevance in Sitecore Search is determined by how closely a potential result matches the visitor’s search query. To configure textual relevance, you need to specify which content areas Sitecore Search should look for matching terms and the relative importance of each area. This blog is intended to demo on how to configure Textual Relevance on Sitecore Search to aim better search experience for customers. 

  • For example, If the attributes name and description are configured for textual relevance then Sitecore Search looks for matching terms in these attributes. 
  • Multiple attributes can be configured with the textual relevance feature.
  • Each attribute can be give a Weight/Priority in the Global Widget Settings. This weight is used with other factors to determine the order of documents in search results. 
Below are the steps to configure Textual Relevance in Sitecore Search:

To add an attribute and enable it for textual relevance:
  • In the CEC portal, click Administration > Domain Settings. Under Attributes click on Add Attribute at the top right corner.
  • Click Settings > Entity and choose the relevant entity. In the Display Name field, enter a display name for the attribute, e.g. Name
  • In the Attribute Name field, enter the attribute's key e.g. Name. This value is used later in the source configuration

  • On the Use For Features tab, select the Textual relevance option. Click Save and then, click Publish

The next step is to configure textual relevance at the domain level

  • In the CEC portal, click Administration > Domain Setting > Feature Configuration.
  • Click Textual Relevance > Add Attribute.
  • On the field where textual relevance needs to be added, click Add Analyzer and then click Add.
  • By default, the analyzer Multi-Locale Standard Analyzer is already set on the attribute but as per the requirement it can be selected from the list available. Click Save and Publish. 


The next step is to enable the new attribute for Textual Relevance in the Global Widget 
  • In the CEC, click Global Resources > Global Widget > Global Widget Settings > Textual Relevance. Click Advanced Mode.
  • Here weightage can be assigned numeric values for different attribute/analyzer combinations. 
  • To include an attribute, click Include.
  • In the WEIGHT column, assign a weight to the attribute, e.g. enter 2 for Name and 1 for Description.
  • Click Save and Publish.

By setting up the attributes for textual relevance, all you need to do is to run the rescan and re-index and check if the search results have updated and better potential results are shown to the search query.