How to setup your site in “Live” Mode OR How can I review my site even before publishing (i.e. just after saving)? OR How can I preview items in workflow before they are approved?

 

The Problem:

How to setup your site in “Live” Mode

OR

How can I review my site even before publishing (i.e. just after saving)?

OR

How can I preview items in workflow before they are approved?

This is one of the basic requirements for the content editors to review the site just after they have saved the item/page and before publishing it to web.

The Solution no.1 

Override GetMediaUrl in MediaProvider

 

namespace NaeemSpace.CustomMediaProviders
{

public class MediaProvider : global::Sitecore.Resources.Media.MediaProvider
{
public override string GetMediaUrl(MediaItem item, MediaUrlOptions options)
{
var retUrl = base.GetMediaUrl(item, options);

var query = System.Web.HttpContext.Current.Request.QueryString;
if (query[“sc_mode”] != null)
{
return retUrl + “&sc_mode=” + query[“sc_mode”];
}
else
{
return retUrl;
}

}

}

Update the mediaProvider section in config

<mediaProvider type=”NaeemSpace.CustomMediaProviders.MediaProvider, NaeemSpace.CustomMediaProviders” patch:instead=”mediaProvider[@type=’Sitecore.Resources.Media.MediaProvider, Sitecore.Kernel’]”/>

and ensure the setting “Preview Publishing target” is checked for the preview publishing target. This will ensure that the workflow items not in the final workflow can be published in the preview website and the querystring “sc_mode=preview” will ensure that you are viewing the item from preview database.

Capture

The Solution no 2:

Sitecore provides an out of box functionality to accomplish this.

You need to setup a “review” website with some proper filters so that you can review our changes before publish or even if your workflow items are not approved state.

“Review” site/mode is also called as “Live” Mode (purely meaning that you are not live but are viewing the site as if it is live.

In the review site the items are visible as soon as you save the item.

To your ‘<Sites>’  config uration  section add a review site

<site name=”preview_website” hostName=”preview.website.com” virtualFolder=”/” physicalFolder=”/” rootPath=”/sitecore/content” startItem=”/home” database=”master” domain=”extranet” allowDebug=”true” cacheHtml=”true” htmlCacheSize=”10MB” registryCacheSize=”0″ viewStateCacheSize=”0″ xslCacheSize=”5MB” filteredItemsCacheSize=”2MB” enablePreview=”true” enableWebEdit=”true” enableDebugger=”true” disableClientData=”false” filterItems=”false” enableWorkflow=”true” />

database=”master” will ensure that the contents are loaded from master website

filterItems=”false” will ensure that’s items are not filtered

enableWorkflow=”true” will ensure that it will manage workflow items too.

Any caveats:

Yes this functionality comes up with following restrictions or a caveat

  • It will display only “publishable” items. ( I will not call it as a caveat as the site respects any publishing restrictions including workflow status, item and version visibility)
  • Caching Implications/Restrictions – the live site can’t cache rendering outputs and controls. So you need to clear up the cache as you view the site and

any search indexes pointing to web might not work.

Advertisements

How to fix the following rendering errors on saving an item

How to fix the following rendering errors on saving an item

  • “The item contains broken links in these fields: – _Renderings
  • or “The item contains broken links in these fields: – _Final Renderings

Source of error:

  • The error happens because in the presentation details of the item some control has an invalid data-source or has a missing place holder settings
  • Especially if you are not watching the item in Raw Mode and still you see a Raw GUID for the data source or place holder then that is exactly the issue.

How to fix it:

  • First of all open the item’s presentation details by clicking the “presentation” tab on the ribbon and then click on “Details” button to open the layout details.
  • Click the shared/final layout as the case may be and then “edit” link to edit the layout.

pic 01 - layout details

  • Now select controls one by one and press “edit” to check if which control has a messed up data source or placeholder setting.

pic 02 - edit layout details

  • See, that for the header control, the field Order Link is showing a GUID data source although we are not viewing it in raw mode. Simply press “Clear” and use “Insert Link” or other options there to update the link and save . You are good to go.

pic 03 - clear and update datasource

Adding a custom button to the ribbon in Sitecore Ribbon/Tab

 

Please follow the steps below to add a button (E.g. a button which calculates Time based on the Time zone with respect to the server time zone).

Step 1: First login to the CMS instance using admin privileges and select the core database.

db selector

The Sitecore Ribbon is made up of 3 things – Ribbon, Strip and Chunk.

  • The Ribbon looks like a tool bar.
  • The Strip looks like a section on the Ribbon.
  • The Chunk looks like the button on the Strip.

whats is this

Step 2:  Go to “/sitecore/content/Applications/Content Editor/Ribbons/Chunks” using content editor and create a chunk called “Calculate Time” . Set the Header and ID for the chunk.

create chunk

Step 3:  Go to “/sitecore/content/Applications/Content Editor/Ribbons/Strips” using content editor and create a strip called “Calculate Time”  inside Publish Strip and set the Reference field to the path to the “Calculate Time”  chunk.

create strip

Step 4:  Go to “/sitecore/content/Applications/Content Editor/Ribbons/Chunks/Calculate Time” using content editor and create a button called “Calculate Time”  inside strip and set the header , Icon and  click fields

create button

Step 5:  Open “Commands.config” and add a command as highlighted.

commands config

Step 6:  Now create a web page and name it ‘CalculateTime’. (The name space can be ‘CustomButtons.Core.Sitecore.Shell.Framework.Commands.CalculateTime’). Create a calendar to select date a drop down to select time and time zone and the supporting code behind to display the converted time based on time zone. And there you go.

Code Behind 1 and 2 and UI:

UI

code behind 2

code behind 1

Output: Select date, time and time zone and press “calculate”.

Output

 

Hope you liked the explanation.

Publishing Target missing Issue while publishing content

You might have experienced this issue where the publishing target is missing while publishing the content as below.

Capture

There is a very easy solution to this issue – grant a language:read permission to “/sitecore/system/Languages/en” for the base/root user so that all users can get this access.

Capture2

Hope this works for you too.

 

How to move and rename Items from Source to Destination path in Sitecore using Sitecore PowerShell

Here is the simple script for this:

# database name

$db = “master:”

# source path

$sourcePath = “/sitecore/content/Generic Content/Generic Pages/Basic Generic Item”

# destination path – task was to move the generic pages from generic location to country based locations

$destinationPath = “/sitecore/content/USA/Generic Content/Generic Pages/Basic Generic Item”

$itemsList = Get-ChildItem -recurse -Path ($db + $sourcePath) | Where { $_.TemplateName -eq “Generic Pages” }

$itemsList | ForEach-Object {

# task was to append parent name to the new item

$newName = $_.Name + “-” + $_.Parent.Name

if(![string]::IsNullOrEmpty($newName)){

Move-Item -Path $_.ProviderPath -Destination ($db + $destinationPath + “/” +                    $newName)

Write-Host “Moved Item: ” $newName  ” to path: ” ($db + $destinationPath)

}else{

Write-Host “Could not move Item: ” $newName

}

}

How to handle and configure Sitecore Launch Pad Buttons, sections, sort order and grouping

Please have a look at the Sitecore Launch pad with lots of buttons.

These buttons can be configured to show and hide based on users and roles.

Lets take an example and say that we have a role – configmanger which is responsible for managing lot of configurable items including this launch pad.

Capture

First of all switch to CORE database and go to this location – /sitecore/client/Applications/Launch Pad/PageSettings/Buttons

You can add new buttons here and also control the grouping and order of the buttons and the link which will open on clicking the button.

E.g. Suppose if you want to show 2 separate buttons to show English and French Content you can create 2 buttons in the location – /sitecore/client/Applications/Launchpad/PageSettings/Buttons/ContentEditing

Name these 2 buttons as English Content and French Content and set their title, link properties to define the title and the link where it will go to when clicked.

capture 2

Also do not forget to assign a READ permission to the 2 buttons paths for the role – configmanager.

capture 3

Now you can see 2 additional buttons on Launch pad in Content Editing sections.

capture 4

If you want to remove these 2 buttons simply revoke – configmanager roles permission on these 2 button paths. See below both buttons are missing now.

capture 5

Hope this article helps you in configuring the launch pad.

Get Rid of Extra HTML Tags(e.g p tags etc) from the Rich Text Editor while saving

Method 1: Override and disable the filters as needed

Step 1: Update the following config setting:

<settings xmlns:patch=”http://www.sitecore.net/xmlconfig/”&gt;

<setting name=”HtmlEditor.DefaultConfigurationType“>

<patch:attribute name=”value”>YourProject.Custom.Controls.CustomRichTextEditor, YourProjectDLLName </patch:attribute>

</setting>

</settings>

 

Step 2: Override Sitecore.Shell.Controls.RichTextEditor.EditorConfiguration as below:

using Sitecore.Data.Items;

using Telerik.Web.UI;

namespace YourProject.Custom.Controls

{

public class CustomRichTextEditor : Sitecore.Shell.Controls.RichTextEditor.EditorConfiguration

{

public CustomRichTextEditor(Item profile)

: base(profile)

{

}

 

protected override void SetupEditor()

{

base.SetupEditor();

Editor.DisableFilter(EditorFilters.ConvertToXhtml);

Editor.EnableFilter(EditorFilters.IndentHTMLContent);

Editor.StripFormattingOptions = EditorStripFormattingOptions.MSWordRemoveAll

| EditorStripFormattingOptions.ConvertWordLists

| EditorStripFormattingOptions.Css

| EditorStripFormattingOptions.Font

| EditorStripFormattingOptions.Span;

Editor.NewLineMode = EditorNewLineModes.Br;

}

}

}

 

Method 2: Override and remove the tags as needed

Step 1: Update the following config setting:

<settings xmlns:patch=”http://www.sitecore.net/xmlconfig/”&gt;

<setting name=”HtmlEditor.DefaultConfigurationType“>

<patch:attribute name=”value”>YourProject.Custom.Pipelines.ProcessRichTextInParagraphOnRender, YourProjectDLLName </patch:attribute>

</setting>

</settings>

Step 2: Override Sitecore.Shell.Controls.RichTextEditor.EditorConfiguration as below:

 

namespace YourProject.Custom.Pipelines

{

public class ProcessRichTextInParagraphOnSave

{

public void Process(SaveRichTextContentArgs args)

{

if ((args.Content.Trim().StartsWith(“<p>”) && args.Content.Trim().EndsWith(“</p>”)))

args.Content = string result = Regex.Replace(HttpUtility.HtmlEncode(args.Content), @”</?p\b.*?>”,

String.Empty,RegexOptions.IgnoreCase);

}

}

}

A list of filters are listed in Telerik’s documentation – http://docs.telerik.com/devtools/aspnet-ajax/controls/editor/managing-content/content-filters

 

Sitecore PowerShell Common Utilities

Below are some Sitecore PowerShell Common Utilities:

 

# Get a list of all Sitecore users

$lstSitecoreUsers = Get-User -Filter “sitecore\*”

$lstSitecoreUsers | ForEach-Object  {

Write-Host $_.Name

}

 

# Get a list of Admin users only

$lstSitecoreUsers = Get-User -Filter “sitecore\*”

$lstSitecoreUsers | Where{$_.IsAdministrator -eq $true } | ForEach-Object  {

Write-Host $_.Name

}

 

# Get a list of users who are managers

$lstSitecoreUsers = Get-User -Filter “sitecore\*”

$lstSitecoreUsers | Where{$_.Name -like “*manager*” } | ForEach-Object  {

Write-Host $_.Name

}

 

# Get a List of all items under a node – e.g Home

$allItemsUnderHome = Get-Item master: -Query “/sitecore/content/Home//*”

$allItemsUnderHome | ForEach-Object {

Write-Host “Item name: ” + $_.Name

}

 

# Update an Item – e.g. Test Items under Home

$item = Get-Item “master:/sitecore/content/Home/Test”

$item.Editing.BeginEdit();

$item[“Header Title”] = “New title for the test item here”;

$item.Editing.EndEdit();

 

# Get a list of items update in last ‘x’ number of days e.g 30 days

Get-Childitem -Path “master:/sitecore/content/Home”  -recurse |

Sort $_.”__Updated” |

Where-Object   {  $_.”__Updated” -gt (Get-Date).AddDays(-30) }

 

# Show results in a List View – Get a list of items update in last ‘x’ number of days e.g 30 days

get-childitem -Path “master:/sitecore/content/Home” -recurse | `

Sort $_.”__Updated” | `

Where-Object   {  $_.”__Updated” -gt (Get-Date).AddDays(-30) }    |

Show-ListView -property Name, `

@{Label=”Last Updated Date”; Expression={$_.”__Updated”}}, `

@{Label=”Last Updated By”; Expression={ $_.”__Updated By” } } `

-Modal -Width 690 -Height 600 -PageSize 200

Show-Result -Text

 

# Find and Replace – e.g. Find all items under Home with template ‘Generic Page’ and update/replace their ‘Header Subtitle’ with ‘Header title’

Get-Childitem -Path “master:/sitecore/content/Home” -recurse `

| Where-Object { $_.TemplateName -match “Generic Page”  } `

| ForEach-Object { $_.”Header Subtitle” = $_.”Header Title”}

 

# Remove or Create Users, setting user permissions(adding and removing permissions)

$usr =”sitecore\testuser001.admin”;

Remove-User -Identity $usr -ErrorAction SilentlyContinue;

New-User -Identity $usr -Enabled -Password “testpwd001” -Email “testuser001@companymail.com” -FullName “Test User 001” -ErrorAction SilentlyContinue;

Set-User -Identity $usr -IsAdministrator $true;

@(“sitecore\ContentOwner,sitecore\ContentAuthor”).Split(‘,’).Trim()
|
ForEach-Object {

Remove-Rolemember -Identity $_ -Members $usr -ErrorAction SilentlyContinue;

Add-Rolemember -Identity $_ -Members $usr -ErrorAction SilentlyContinue;

}

 

# assign specific security rights to an item
$theHeader = Get-ChildItem -Path “master:/Sitecore/Content/Header” -ErrorAction SilentlyContinue

if($theHeader -ne $null) {
@(“item:create”,”item:write”,”item:delete”,”item:rename”) | ForEach-Object {
$aclRight = $_

$acl1 = New-ItemAcl -AccessRight $aclRight -PropagationType Any -SecurityPermission AllowAccess -Identity “sitecore\Content Owner”
$acl2 = New-ItemAcl -AccessRight $aclRight -PropagationType Any -SecurityPermission AllowAccess -Identity “Content Author”

$theHeader | Add-ItemAcl -AccessRules $acl1,$acl2
}
}

 

# Compare/Count items in Sitecore databases(Master and Web)

$childsMaster = Get-ChildItem master:/sitecore/content/Catalog/Products -Language en-CA -Version *
$childsMaster= $childsMaster | Where { $_.ProductExpireDate -gt (Get-Date) } #| ForEach-Object {$_.ProductExpireDate}
write-host “Count of items Canada Product Catalog(Master): ” $childsMaster.length

$childsWeb = Get-ChildItem web:/sitecore/content/Catalog/Products -Language en-CA -Version *
$childsWeb= $childsWeb | Where { $_.ProductExpireDate -gt (Get-Date) } #| ForEach-Object {$_.ProductExpireDate}
write-host “Count of items Canada Product Catalog(Web): ” $childsWeb.length

#write-host “Compare master Vs Web Databases”
Compare-Object $childsMaster $childsWeb -PassThru

 

# Compare items in different master and Slave Solr

$items_product_index_master = wget “http://solrslave.companysite.com/solr/product_index_master/select?q=product_id%3A*&fq=_language%3Aen-US&rows=9999&fl=product_id&wt=json&indent=true&#8221; | ConvertFrom-Json
write-host “Count of items product_index_master: ” $items_product_index_master.response.numfound
#$items_product_index_master.response.docs.product_id

$items_product_index_web = wget “http://solrmsater.companysite.com/solr/product_index_web/select?q=product_id%3A*&fq=_language%3Aen-CA&rows=9999&fl=product_id&wt=json&indent=true&#8221; | ConvertFrom-Json
write-host “Count of items product_index_web: ” $items_product_index_web.response.numfound
#$items_product_index_web.response.docs.product_id

#write-host “Compare product_index_master Vs product_index_web”
Compare-Object ($items_product_index_master.response.docs.product_id) ($items_product_index_web.response.docs.product_id)

 

# Compare items in sitecore database and Solr

#write-host “Compare Master Database Vs product_index_web”
Compare-Object ($childsMaster.ProductID) ($items_product_index_web.response.docs.product_id) -PassThru

 

# Remove items or fields of an item/template ( lets say we want to remove Header Subtitle and Footer SubTitle, use Remove-Item
@(
‘master:/sitecore/templates/Rendering Templates/Header/Header SubTitle’,
‘master:/sitecore/templates/Rendering Templates/Footer/Footer SubTitle’
)| ForEach-Object {
$items = Get-Item -Language * -Path $_ -ErrorAction SilentlyContinue
$items | Remove-Item -ErrorAction SilentlyContinue
}

# Remove  specific language versions only of ‘Header Parameters/__Standard Values’ except say English (en), use Remove-ItemLanguage
@(
‘master:/sitecore/templates/Rendering Templates/Header/Header SubTitle/__Standard Values’, ‘master:/sitecore/templates/Rendering Templates/Footer/Footer SubTitle/__Standard Values’
)| ForEach-Object {
$items = Get-Item -Language * -Path $_ -ErrorAction SilentlyContinue
$items | ForEach-Object {
if($_.Language.Name -ne “en”){
$_ |Remove-ItemLanguage -ErrorAction SilentlyContinue
}
}
}

 

….more to continue…

How to monitor EC2, CloudWatch, EBS, RDS, ELB, ElasticCache using metrics

AWS is the front runners when it comes to have highly available, fault tolerant, secure and high scaling service which can integrate with almost everything in cloud as well as your own data center.

For monitoring your VPC(Virtual Private Cloud), AWS has these two very renowned services:
– CloudWatch and
– CloudTrail

While ‘CloudTrail’ is primarily used to monitor the API calls made to other services or Applications, ‘CloudWatch’ is used for monitoring and logging events periodically (default every 5 minutes, detailed every minute).

It can be used to monitor:
– Compute resources like EB2s, ELBs, Route53, Auto Scaling Groups,
– Storage & CDN resources like  S3, CloudFront, EBS Volumes,
– Database and Analytics services like DynamoDB, Elastic cache, RDS, Elastic MapReduce, Redshift
– SNS, SQS etc.
Let’s cover them one by one on how CloudWatch monitors different services:

A- EC2(Elastic Compute Cloud)

CloudWatch can monitor the following metrics:

# CPU 

– CPUCreditUsage (number of CPU credits consumed by the instance. One CPU credit equals one vCPU running at 100% utilization for one minute)

– CPUCreditBalance (number of CPU credits available for the instance to burst beyond its base CPU utilization, expire every 24 hrs)

– CPUUtilization (percentage of allocated EC2 compute units)

# Network

– NetworkIn (number of bytes received on all network interfaces by the instance)

– NetworkOut (number of bytes sent out on all network interfaces by the instance)

– NetworkPacketsIn (number of packets received on all network interfaces by the instance)

– NetworkPacketsOut (number of packets sent out on all network interfaces by the instance)

# Disk

– DiskReadOps (Completed read operations from all instance volumes)

– DiskWriteOps (Completed write operations to all instance store volumes )

– DiskReadBytes (Bytes read from all instance store volumes )

– DiskWriteBytes (Bytes written to all instance store volumes)

# Status Check

– StatusCheckFailed (Reports whether the instance has passed both the instance status check and the system status check in the last minute)

– StatusCheckFailed_Instance (whether the instance has passed the instance status check in the last minute.)

– StatusCheckFailed_System (whether the instance has passed the system status check in the last minute.)

– You can create alarms based on these above metrics to watch the health of the host and the instances.

Rest of the article to be continued…

 

How to manage website Failover using AWS Route 53 and a website hosted on an external domain

Scenario:

You have 2 websites:

  • “futureCloud.technology”, which is the primary website, is hosted on AWS EC2 Instance supported though an ELB(Elastic Load Balancer). Please keep in mind that GoDaddy.com is just the site registrar for the site name the site is not hosted there.
  • “mohdnaeem.wordpress.com”, which is the secondary/failover website is hosted on WordPress.com domain.
  • You are using Route 53 DNS service to resolve the domains.

Problem:

  • “futureCloud.technology” should be the primary website and should run when the EC2 Instance is healthy.
  • In case of failover the external website “mohdnaeem.wordpress.com” becomes the failover website. The requests for “futureClod.technology” should be routed to this external secondary website in case of the primary websites failure.

Solutions:

  • There can be various solutions. Let’s see them one by one.
  • Solution 1:
    • It is very primitive solution. Just write a domain forwarding rule on your registered websites domain manager panel. Any requests for “futureCloud.Technology” website will automatically be forwarded to “mohdnaeem.wordpress.com”
    • See snapshot below:
    • godaddy forwarding
    • Issue – this is a very basic solution and AWS Route 53 never comes into picture. It should be Amazon’s Route 53 which should dictate the failover logic not registrar.

 

  • Solution 2:
    • We will use AWS Route 53 to dictate the website failover from Primary to Secondary.
    • I am assuming the following:
      • That you created an AWS EC2 instance. (Ideally you create a couple of Instances hosting WordPress website and couple of MySQL Instances for your site to by highly available, fault tolerant and failover tolerant. But assuming that you have installed the WordPress website only on one LAMP server (Linux, Apache, MySQL and PHP). So that in case this primary website goes down then you can run the secondary from an external domain.)
      • That you already installed and configured ‘WordPress’ on the server.
      • That this site is configured behind an ELB (Elastic Load Balancer).
      • That your primary website is running on EC2 instance and failover secondary website (“mohdnaeem.wordpress.com”) is running on WordPress domain.
      • That you have registered a domain name ( say futureCloud.technology) at any domain registrar. I did at Godaddy.com)
    • So now let’s take the things forward from here.
      • First you will have to create a hosted zone exactly matching your registered domain name “futureCloud.technology” for your primary website in Route 53.
      • As you create a hosted zone in Route 53, it creates a couple of NS(Name Server) records. A SOA(Start of Authority) record. You will have to add a ‘A’ record for your EC2 website configured behind the ELB and another ‘A’ record for a S3 bucket (exactly matching the name of the registered website and configured as a static website). We will use this bucket for redirection.
      • See snapshot:
      • AWS Hosted ZOne futureCloud for EC2
      • AWS Hosted ZOne futureCloud for S3
  • Note down the 4 name servers and login to your registrars domain manager control panel(mine was GoDaddy.com) and add those 4 entries as Name Server records.
  • See snapshot:
  • godaddy nameservers
  • Now are configured to run your primary website, go ahead and open a browser and run the website – “futureCloud.technology”.
  • See snapshot:
  • AWS S3 buckets
  • Now you have to configure the failover so that when the EC2 instance is not healthy or not running your secondary failover website should run.
  • To do that first you have to create another bucket (exactly matching the name of the external failover website “mohdnaeem.wordpress.com”.
  • See snapshot:
  • S3 Redirect from futureCloud S3 to wordpress S3
  • In the bucket “futurecloud.technology” configure it as a website with a redirection rule to redirect to the other bucket “mohdnaeem.wordpress.com”.
  • See snapshot
  • S3 Redirect from futureCloud S3 to mohdnaeem.wordpress.com
  • In the bucket “mohdnaeem.wordpress.com” configure it as a website with a redirection rule to redirect to the external website “mohdnaeem.wordpress.com”.
  • See snapshot:
  • AWS S3 buckets
  • In case of EC2 is not healthy or not running the request will first reach “futurecloud.technology” bucket but it will redirect to the other bucket which is configured to redirect it to your external site.
  • Go to the Route 53 to configure another “hosted zone” which exactly matched the name of the external domain name (“mohdnaeem.wordpress.com”) and add an ‘A’ record as failover to the bucket by the same name.
  • As EC2 instance is down, the Route 53 first looks for s3 bucket “futureCloud.technology” but sees a redirection rule for bucket “mohdnaeem.wordpress.com” and which in turn has a redirection to the actual external website “mohdnaeem.wordpress.com”. The hosted zone entry thus maps this failover and redirects you to the external website.
  • Now go to the bowser and run “futureClod.technology”, but this time you will see that the website is redirected to “https://mohdnaeem.wordpress.com”
  • See snapshot:
  • external website running
  • All these redirection setting are being done because the AWS Route 53 is still not a very powerful DNS tool.

Thanks for reading this article. Please contact me in case you need any help. Please go to “About Us” page to view my details.