Adding custom social buttons to Content Editor in Sitecore 9

Reading Time: 8 minutes

This article will help you understand how ribbon is structured in Sitecore and how to add custom buttons into this ribbon.

I have used Sitecore 9 to demonstrate this functionality (hence the title of the blog post) but I believe, based on my previous experience with Sitecore 7 and 8, that ribbon is working in the same or at least in very similar way also in previous versions.

Although title says “social buttons”, this post will help you to create any button in Content Editor. I have just demonstrated the steps on real requirements as in Sitecore 9 (as of publishing this post) there is no Social Connected module integrated anymore. Take a look here for further details.

To make any changes to Sitecore Ribbon you need to be in “core” database.

Just go to Desktop:

GoToDesktop.png

and in right bottom corner click on database selector. You will probably see “master” there, so just click on it and select “core” instead:

dbselector

At the end of this article, you will be able to create custom buttons in Ribbon similar to these ones:

shareable03

 

1. Sitecore Ribbon structure

To begin with, let’s describe structure of Sitecore Ribbon.

Sitecore ribbon contains toolbars, strips, chunks and buttons.

In Sitecore there is actually only one Ribbon – Default. Remaining Ribbons are so called “contextual ribbons” which means that they are shown only for certain templates. For more information about ribbon in Content Editor and how to customize it from content editor perspective, take a look on this nice article in Sitecore documentation.

1.1. Toolbars

In Content Editor default ribbon looks like this:

ribbon01

It contains several tabs / toolbars – HOME, NAVIGATE, REVIEW, and so on.

“HOME” is one of Toolbars of Default Ribbon in Sitecore:

ribbon02a

Each toolbar is defined in core db under /sitecore/content/Applications/Content Editor/Ribbons/Ribbons/Default item respectively so HOME toolbar is defined in /sitecore/content/Applications/Content Editor/Ribbons/Ribbons/Default/Home item:

ribbon02b

You can see there reference to it’s corresponding strip.

1.2. Strips

Each Toolbar contains only one Strip. Strip contains several chunks (toolbar sections).

For HOME toolbar, there is corresponding Home Strip:

ribbon03a

Each strip is defined in core db under /sitecore/content/Applications/Content Editor/Ribbons/Strips item respectively.

Home Strip for Home Toolbar is defined in /sitecore/content/Applications/Content Editor/Ribbons/Strips/Home item:

ribbon03b

1.3. Chunks

Chunks are toolbar / strip sections which host buttons. They are divided between each other by vertical ruler.

Home Strip contains several chunks – Write, Edit, Insert, Operations, Rename, and many more. You can see title of chunk on the bottom of each with grey color.

There is for example Rename Chunk:

ribbon04a

Each chunk is defined in core db under /sitecore/content/Applications/Content Editor/Ribbons/Chunks item respectively.

Rename Chunk for Home strip is defined in /sitecore/content/Applications/Content Editor/Ribbons/Chunks/Rename item:

ribbon04c

You can see there also child items (Rename & Display Name) that define reference to buttons which chunk contains.

Reference to Chunk is defined under corresponding Strip reference item:

ribbon04b

1.4.Buttons

Most important part of ribbon are buttons. Buttons can trigger some functionality after clicking on them.

ribbon05a

Each button is defined in core db under it’s Chunk subitem /sitecore/content/Applications/Content Editor/Ribbons/Chunks respectively.

Rename Button for Rename Chunk is defined in /sitecore/content/Applications/Content Editor/Ribbons/Chunks/Rename/Rename item:

ribbon05b

Button look and feel, functionality and options are determined based on it’s template.

You can choose from these templates:

  • Small / Large Button
  • Small Check Button
  • Small / Large Combo Button
  • Small Drop Down Box
  • Small / Large Gallery Button
  • Small Input Box
  • Small / Large Menu Combo Button

 

 

2. Adding custom buttons to Contextual Ribbon

After introduction on how Sitecore ribbon is structured, let’s take a look how to add some custom button(s).

This will also conclude blog post about social sharing capabilities in Sitecore 9 as Social COnnected module is not available for this newest version of Sitecore.

I will use Contextual Ribbon for specific template. Adding button to regular Ribbon is pretty similar but you need to follow structure described above in chapter 1 instead.

2.1 Creating custom Toolbar

Under /sitecore/content/Applications/Content Editor/Ribbons/Contextual Ribbons/ I have created Social toolbar based on /sitecore/templates/System/Ribbon/Toolbar template:

social01

2.2 Creating custom Strip

Under /sitecore/content/Applications/Content Editor/Ribbons/Contextual Ribbons/Social I have created Social strip based on /sitecore/templates/System/Ribbon/Strip template:

social02

2.3 Creating custom Chunk

Under /sitecore/content/Applications/Content Editor/Ribbons/Contextual Ribbons/Social/Social I have created Social chunk based on /sitecore/templates/System/Ribbon/Chunk template:

social03

 

2.4 Creating custom Button

Under /sitecore/content/Applications/Content Editor/Ribbons/Contextual Ribbons/Social/Social/Social I have created Facebook button based on /sitecore/templates/System/Ribbon/Large Button template:

social04a

You can specify values for these fields:

  • Header – Text shown under button
  • Icon – Button Icon
  • Click – Command that is run when you click on button (see 2.5. section)
  • Tooltip – Text shown when you hover button

 

2.5. Specifying custom command in config

Now create patch file with your custom command and deploy it into your instance to apply it:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
 <sitecore role:require="Standalone or ContentDelivery or ContentManagement">
  <commands>
   <command name="social:facebook" type="YourAssembly.Foundation.Social.Commands.FacebookShare, YourAssembly.Foundation.Social" />
  </commands>
 </sitecore>
</configuration>

It will add command to the list of commands in Sitecore configuration:

socialcommand01

 

2.6 Custom command class

In your solution create a new class that will inherit “Command” class as follows:

using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Shell.Framework.Commands;
using Sitecore.Text;
using Sitecore.Web.UI.Sheer;

namespace YourAssembly.Foundation.Social.Commands
{
 public class FacebookShare : Command
 {
   /// <summary>Executes the command in the specified context.</summary>
   /// <param name="context">The context.</param>
   public override void Execute(CommandContext context)
   {
     Assert.ArgumentNotNull((object)context, nameof(context));
     
     if (context.Items.Length != 1)
        return;
 
     Item obj = context.Items[0];
 
     UrlString urlString = new UrlString(UIUtil.GetUri("control:FacebookShare"));
     urlString.Append("id", obj.ID.ToString());
     urlString.Append("la", obj.Language.ToString());
     urlString.Append("vs", obj.Version.ToString());
     SheerResponse.ShowModalDialog(urlString.ToString());
   }
 }
}

As you can see, we are referencing “control:FacebookShare” in the command.

This is effectively opening modal dialog (by calling SheerResponse.ShowModalDialog method) with given url which is url to FacebookShare control.

2.7. Create custom control

In your web project, create folder structure as follows:

sitecore\shell\Applications\Content Manager\Dialogs\Social

and place FacebookShare.xml file there with this content:

<?xml version="1.0" encoding="utf-8" ?>
<control xmlns:def="Definition" xmlns="http://schemas.sitecore.net/Visual-Studio-Intellisense">
<FacebookShare>
<FormDialog Icon="Network/24x24/spy.png" Header="Message">
<CodeBeside Type="YourAssembly.Foundation.Social.Dialogs.FacebookShare, YourAssembly.Foundation.Social"/>

<Stylesheet>
 .scConfirmationContainer td:first-child{
 width: 1px;
 }

.scConfirmationContainer td:last-child{
 padding-left: 15px;
 }
</Stylesheet>

<GridPanel class="scConfirmationContainer" Columns="2" Width="100%" >
 <ThemedImage class="scConfirmationIcon" Src="Images/warning.png" />
 <Literal id="ConfirmMessage" class="scDialogMessage"></Literal>
</GridPanel>


 document.getElementById('ConfirmMessage').innerHTML = "Do you really want to share it?";


</FormDialog>
</FacebookShare>
</control>

 

Mind the control>FacebookShare hierarchy in xml. This is how Sitecore can find this control for our command.

Also

2.7 Backend code

I have created Base class for all Social Dialogs under Dialogs.Base folder.

using Sitecore;
using Sitecore.Data.Items;
using Sitecore.Diagnostics;
using Sitecore.Links;
using Sitecore.Sites;
using Sitecore.Web.UI.Pages;
using Sitecore.Web.UI.Sheer;
using System;

namespace YourAssembly.Foundation.Social.Dialogs.Base
{
 public abstract class SocialDialog : DialogForm
 {
 private Item Item {
 get
 {
 Item itemFromQueryString = UIUtil.GetItemFromQueryString(Context.ContentDatabase);
 Error.AssertItemFound(itemFromQueryString);

return itemFromQueryString;
 }
 }

protected string ItemUrl
 {
 get
 {
 string itemUrl = string.Empty;
 var site = SiteContext.GetSite("website");

using (var siteContextSwitcher = new SiteContextSwitcher(site))
 {
 var urlOptions = LinkManager.GetDefaultUrlOptions();
 urlOptions.AlwaysIncludeServerUrl = true;
 urlOptions.ShortenUrls = true;
 urlOptions.SiteResolving = true;
 itemUrl = LinkManager.GetItemUrl(Item, urlOptions);
 }

return itemUrl;
 }
 }

protected string ImageUrl
 {
 get
 {
 var imageField = (Sitecore.Data.Fields.ImageField) Item.Fields[Templates.Shareable.Fields.Image.ToString()];
 
 var imageUrl = Sitecore.Resources.Media.MediaManager.GetMediaUrl(imageField.MediaItem);
 var protectedImageUrl = Sitecore.Resources.Media.HashingUtils.ProtectAssetUrl(imageUrl);

return protectedImageUrl;
 }
 }

protected string Title
 {
 get
 {
 var title = Item.Fields[Templates.Shareable.Fields.Title.ToString()];

return title.HasValue ? title.Value : string.Empty;
 }
 }

protected string Summary
 {
 get
 {
 var title = Item.Fields[Templates.Shareable.Fields.Summary.ToString()];

return title.HasValue ? title.Value : string.Empty;
 }
 }

protected abstract string GetUrl();

/// <summary>Raises the load event.</summary>
 /// <param name="e">
 /// The <see cref="T:System.EventArgs" /> instance containing the event data.
 /// </param>
 protected override void OnLoad(EventArgs e)
 {
 Assert.CanRunApplication("Content Editor/Ribbons/Contextual Ribbons/Social");
 Assert.ArgumentNotNull((object)e, nameof(e));
 base.OnLoad(e);
 }

/// <summary>Handles a click on the OK button.</summary>
 /// <param name="sender">The sender.</param>
 /// <param name="args">The arguments.</param>
 /// <remarks>
 /// When the user clicks OK, the dialog is closed by calling
 /// the <see cref="M:Sitecore.Web.UI.Sheer.ClientResponse.CloseWindow">CloseWindow</see> method.
 /// </remarks>
 protected override void OnOK(object sender, EventArgs args)
 {
 var url = GetUrl();

if (url.Length <= 0)
 return;
 Sitecore.Context.ClientPage.ClientResponse.Eval("try {window.open('" + url + "', '_blank') } catch(e) { alert('An error occured: ' + e.description) }");

SheerResponse.SetDialogValue("yes");
 base.OnOK(sender, args);
 }

/// <summary>Handles a click on the Cancel button.</summary>
 /// <param name="sender">The sender.</param>
 /// <param name="args">The arguments.</param>
 /// <remarks>
 /// When the user clicksCancel, the dialog is closed by calling
 /// the <see cref="M:Sitecore.Web.UI.Sheer.ClientResponse.CloseWindow">CloseWindow</see> method.
 /// </remarks>
 protected override void OnCancel(object sender, EventArgs args)
 {
 SheerResponse.SetDialogValue("no");
 base.OnCancel(sender, args);
 }
 }
}

 

And this class is derived by FacebookShare or LinkedInShare Classes that we have created under Dialogs folder:

using YourAssembly.Foundation.Social.Dialogs.Base;

namespace YourAssembly.Foundation.Social.Dialogs
{
 public class FacebookShare : SocialDialog
 {
 protected override string GetUrl()
 {
 var url = string.Empty;
 string urlSettings = Sitecore.Configuration.Settings.GetSetting("YourAssembly.Foundation.Social.FacebookUrl");

if (urlSettings.Length > 0)
 {
 url = string.Format(urlSettings, ItemUrl);
 }

return url;
 }
 }
}

and this is the patch config file for implementation:

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
 <sitecore role:require="Standalone or ContentDelivery or ContentManagement">
<settings>
 <!-- u = url to article -->
 <setting name="YourAssembly.Foundation.Social.FacebookUrl" value="https://www.facebook.com/sharer/sharer.php?u={0}" />
 <!-- url = url to article; title = title to article; summary = summary to article; source = source to article; -->
 <setting name="YourAssembly.Foundation.Social.LinkedInUrl" value="https://www.linkedin.com/shareArticle?mini=true&amp;url={0}&amp;title={1}&amp;summary={2}" />
 </settings>
</sitecore>
</configuration>

 

2.8 Module in Helix structure

This is how module looks like after adding all files mentioned above:

social buttons solution

2.9 Setting Contextual Ribbon on Template

We have created _Shareable interface template with these fields Title, Image, Short Summary and Text.

shareable01

On Standard values for this template, we have specified our contextual ribbon in Ribbon field in Appearance section:

shareable02.PNG

We have set this interface template as base template to our desired one.

This is the how it looks like when we go to items that use our desired template:

shareable03.PNG

 

When we click on “Share Facebook” button, we see this modal dialog:

shareable04.PNG

And when we click on “OK” button, we are redirected to Facebook share url:

shareable05.PNG

Same applies also to LinkedIn.

Better implementation would be to use more modern Facebook API, but this will be implemented in next version 😉

Happy coding 🙂

One comment

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.