I wrote this post as a follow up to my last post: Add Custom Action To SharePoint Edit Control Block. Just like with the edit control block, SharePoint Developers often need to add a custom action to the SharePoint Ribbon. I have had to do this many times myself and since there isn’t a lot of resources available on the subject, I decided to write this post for those who might want to do this sometime, and for myself as a future reference.
I have tested the general technique described here on both SharePoint 2010 and SharePoint 2013. Please note that: While SharePoint 2010 is happy with the Image32by32 parameter entered in this format:
Image32by32='//cdn.ehikioya.com/_layouts/images/dummyproject/workflow32.gif'
…this will not work for SharePoint 2013! Took me a while to figure this out. For the Image32by32 parameter, SharePoint 2013 seems to expect the actual data uri of the image instead of the server relative url.
To get the data uri of my image, I used this online tool to do the conversion.
The code I share below is the SharePoint 2013 version. If you want to work with SharePoint 2010, then change this line (your own image uri will of course be different):
Image32by32='data:image/gif;base64,R0lGODlhIAAgAPf/AGlpadx0ZexLOnJycvpeRH5+fuzs7Hh5efmKe9jY2NXV1S0tLEZGRmBgYP5yV5WVldDQ0Lq6unR1dKKiooSEhHp6elxcXEJCQd7e3vmtolpaWlZWVzo6OoKCgnBwcb6+vry8vEpKSmRkZIyMjKqqqvKKeuHh4fFLNp6enmJjY/9bPNPT021tbWZmZv77+01MTI+Pj1BQUIaGh+Lj47i4uLa2trOzs5qaml5eXnZ2dpCRkaWlpcHBweJGNlhYWPJ7av/39Kanp+Hc3G5ubpiYmDw8PUdISHx9fCYmJv39/fb29vz8/Pf39/n5+fr6+vj4+PLy8vv7++Tk5PT09PX19enp6fHx8e/v7/Pz8+jo6IGBgYuLi7CwsPv6+qioqNzc3JOTk/Dw8FNTU8bGxnt7fMjIyF1dXYiIiOXl5e7u7lVVVb6DfeR/etGln+JVRPSKfURDQ/eCecPDw1dXWXNzc/9pS0tLS2dnZ39/f9FPP/Dh38q3tPmnm/20prtXTGFiYtvX1+5URuNfTOZWR/z7+19gYFdXV0lJSexQPeNVQPTp6E5NT/55Yv9+Z/38/IyMi/WDdsJgUpCOkFhYV+/k4++uoMCAeufm5cipodbX2OHV06eoqOBZRelNQdSnpExMS3+Af8x/dVVVVlRTU9OVjYKCgZucnNXHxfCRg/+ShdVcTPXx8Obl5G9vcObm5v/g2Kurq62trce+vs+6t/ajlP+rlPS1rPy4renp6uvq6k1NTe7d2r9rXPbTzWFhYeRgUNHS0vVSPu6Sgs/Ix/W8s3x8e9O3st66s8ajn8zMzGBgX/9kRfthS9ra2u5fTff09FlZWe5gRc+XkelSRu9SQ3+AgOxVQP/p4fWBbv6GbTY3N/6njceIgMWOiPz5+f+XiIGCgfuHeqCgoGBfYNWEedyBc+BEMXd3eHx7fElKScabltpJOfqOgfFzYlFRUfZ7bepVP/GxlFtbW+5XP+ZEN++jlvPs7PPx8d/Y1/z39suQiO3p6MiVjPDn5k9PT////yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QzY3Q0ExNEZCNDAxMTFFMjhDMzI5MkZBNEI5QTZFRjUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QzY3Q0ExNTBCNDAxMTFFMjhDMzI5MkZBNEI5QTZFRjUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDNjdDQTE0REI0MDExMUUyOEMzMjkyRkE0QjlBNkVGNSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDNjdDQTE0RUI0MDExMUUyOEMzMjkyRkE0QjlBNkVGNSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAEAAP8ALAAAAAAgACAAAAj/AP8JHEiQYJIqSQoqXMhwoJIbQZ40nNhQCSwWBxJQ3FhwCZEWLDZd4dgQC4Qa4h7hKYDOwwQrJAsaiKBDBp4DObTIGFHKA5EvMf9FgUCkGpkhHuhIkFABD50G6BTEXMKDwhEyADaIGDDgHAsRGwBEsNLl36tjFHmAwiNBg68zXsqY6CCvwYAIVf5569WI178lDIGB6yDBRwG8V5hgkPcHhYI0//IRU3WC3z8nC9OAqXDAzJYVWAAz4VJgTBYm/1xkcHOC3L4mC5dEOFAMh5YESpwQupxMShTMqjmZC6BpCZSEBWfYBHBHjhLYA2FD59Nu0C9j/4DBQqOQxjkycx5Y/3HiCAiQgcj7/HBAQNq9GVsKgVAI5oAIXx8EXtsWr+AtbIyoUA4+T0yQjiEj/EUQU6LQkUkXu9SCABttDGRLCdmoEMApTBgAwyeT3JEEZgOZQcEGHUCxCi3OQPKOMJj8U8kPCMwjyCxQSPTAIQ3oEoVEA8XwxyEJPlNPD/RMww4qnpQQRyfrIHPJFIBNoM0hcDihBEGjLMABDKjtEgoiAgSSyhvhUNPDGoBgASQKSCARwhNbDnQHB3BQIIVAenBjTTDMfEOAAJEMAwVq/zBxxgILQMNEnQJpoQsDdAAzECX6wLMMe3nskQsVyGEAgDYc5EAFogIFYQED0HBBUD+kRP9TRyLqsAIFif+AAEcRF5hCBXQCQcCCHXYUYAJBinTjhyVCXAGsAQdwcMEnZUwRBUFU3GBIDPJMAOk/9sjSLKpJ7GDHJxdUcMUUyA2UwACjqAGADd8KBGwUNJjhjy5ifPBEE+0ORAIOvlgAgBd7LoQLLMoYYkEIOlTB7kJQ6GBBC2bIQ8EHCYSxxBJWfDFGB+5Ak4IdB2Dwb0NZjKBBCinMAc0BkkywAwwDLBKDL+PYIUECUYA6URU34NCAB+Oo8QIDcBzijgWtQKMLBc00MTFFU3xAhy6GiOBBMWS04os7cIgQixRKCE0SFDxskQIcjBZhog1STJFjUElEoYQVBlQP4YoUUqCRhQFh5BbwQAEBADs='
To this (with your own project name of course):
Image32by32='//cdn.ehikioya.com/_layouts/images/dummyproject/workflow32.gif'
Add The Custom Action To The SharePoint Ribbon
Lets assume you want to add the custom action to the SharePoint ribbon using a feature (Yes, this is the most common scenario). And let’s further assume that you want the custom action to open a modal dialog (this is also a very common requirement). Here’s the complete code you would need for the feature activated event handler (there are a few extra bells and whistles in the code specific to my requirements. Ignore these where necessary).
Notice how I pass the site url {SiteUrl} and item id of the selected item {SelectedItemId} as parameters.
A couple of interesting notes:
- Unlike the code for the edit control block, the ribbon code will NOT work with {ItemId}. You must enter {SelectedItemId}.
- Since we only want the ribbon custom action to be active when one (and only one) item is selected, I had to add code to specifically satisfy that condition. See the “EnabledScript” parameter within the code below.
public override void FeatureActivated(SPFeatureReceiverProperties properties) { SPSite site = (SPSite)properties.Feature.Parent; foreach (SPWeb web in site.AllWebs) { if (web.ServerRelativeUrl.TrimEnd('/').ToLower().EndsWith("dummysite")) { for (int i = 0; i < web.Lists.Count; i++) { SPList list = web.Lists.TryGetList("Dummy List"); if (list != null && list.BaseType == SPBaseType.GenericList) { web.AllowUnsafeUpdates = true; if (list.UserCustomActions.Count > 0) { foreach (SPUserCustomAction action2 in list.UserCustomActions) { if (action2.Name == "ContentTypeRibbonCustomization") { action2.Delete(); list.Update(); break; } } } SPUserCustomAction ribbonCustomAction = list.UserCustomActions.Add(); ribbonCustomAction.Name = "ContentTypeRibbonCustomization"; ribbonCustomAction.Location = "CommandUI.Ribbon.ListView"; //Notice that I added the actual data uri of the image instead of a url. //Here's the converter I used http://websemantics.co.uk/online_tools/image_to_data_uri_convertor/ ribbonCustomAction.Title = "Generate Output"; ribbonCustomAction.CommandUIExtension = @" <CommandUIExtension> <CommandUIDefinitions> <CommandUIDefinition Location='Ribbon.ListItem.Actions.Controls._children'> <Button Id='ListViewButton' Command='ListViewButtonCommand' Description='Generate Output' TemplateAlias='o2' Sequence='95' Image32by32='data:image/gif;base64,R0lGODlhIAAgAPf/AGlpadx0ZexLOnJycvpeRH5+fuzs7Hh5efmKe9jY2NXV1S0tLEZGRmBgYP5yV5WVldDQ0Lq6unR1dKKiooSEhHp6elxcXEJCQd7e3vmtolpaWlZWVzo6OoKCgnBwcb6+vry8vEpKSmRkZIyMjKqqqvKKeuHh4fFLNp6enmJjY/9bPNPT021tbWZmZv77+01MTI+Pj1BQUIaGh+Lj47i4uLa2trOzs5qaml5eXnZ2dpCRkaWlpcHBweJGNlhYWPJ7av/39Kanp+Hc3G5ubpiYmDw8PUdISHx9fCYmJv39/fb29vz8/Pf39/n5+fr6+vj4+PLy8vv7++Tk5PT09PX19enp6fHx8e/v7/Pz8+jo6IGBgYuLi7CwsPv6+qioqNzc3JOTk/Dw8FNTU8bGxnt7fMjIyF1dXYiIiOXl5e7u7lVVVb6DfeR/etGln+JVRPSKfURDQ/eCecPDw1dXWXNzc/9pS0tLS2dnZ39/f9FPP/Dh38q3tPmnm/20prtXTGFiYtvX1+5URuNfTOZWR/z7+19gYFdXV0lJSexQPeNVQPTp6E5NT/55Yv9+Z/38/IyMi/WDdsJgUpCOkFhYV+/k4++uoMCAeufm5cipodbX2OHV06eoqOBZRelNQdSnpExMS3+Af8x/dVVVVlRTU9OVjYKCgZucnNXHxfCRg/+ShdVcTPXx8Obl5G9vcObm5v/g2Kurq62trce+vs+6t/ajlP+rlPS1rPy4renp6uvq6k1NTe7d2r9rXPbTzWFhYeRgUNHS0vVSPu6Sgs/Ix/W8s3x8e9O3st66s8ajn8zMzGBgX/9kRfthS9ra2u5fTff09FlZWe5gRc+XkelSRu9SQ3+AgOxVQP/p4fWBbv6GbTY3N/6njceIgMWOiPz5+f+XiIGCgfuHeqCgoGBfYNWEedyBc+BEMXd3eHx7fElKScabltpJOfqOgfFzYlFRUfZ7bepVP/GxlFtbW+5XP+ZEN++jlvPs7PPx8d/Y1/z39suQiO3p6MiVjPDn5k9PT////yH/C1hNUCBEYXRhWE1QPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS4wLWMwNjAgNjEuMTM0Nzc3LCAyMDEwLzAyLzEyLTE3OjMyOjAwICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1IFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QzY3Q0ExNEZCNDAxMTFFMjhDMzI5MkZBNEI5QTZFRjUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QzY3Q0ExNTBCNDAxMTFFMjhDMzI5MkZBNEI5QTZFRjUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDNjdDQTE0REI0MDExMUUyOEMzMjkyRkE0QjlBNkVGNSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDNjdDQTE0RUI0MDExMUUyOEMzMjkyRkE0QjlBNkVGNSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PgH//v38+/r5+Pf29fTz8vHw7+7t7Ovq6ejn5uXk4+Lh4N/e3dzb2tnY19bV1NPS0dDPzs3My8rJyMfGxcTDwsHAv769vLu6ubi3trW0s7KxsK+urayrqqmop6alpKOioaCfnp2cm5qZmJeWlZSTkpGQj46NjIuKiYiHhoWEg4KBgH9+fXx7enl4d3Z1dHNycXBvbm1sa2ppaGdmZWRjYmFgX15dXFtaWVhXVlVUU1JRUE9OTUxLSklIR0ZFRENCQUA/Pj08Ozo5ODc2NTQzMjEwLy4tLCsqKSgnJiUkIyIhIB8eHRwbGhkYFxYVFBMSERAPDg0MCwoJCAcGBQQDAgEAACH5BAEAAP8ALAAAAAAgACAAAAj/AP8JHEiQYJIqSQoqXMhwoJIbQZ40nNhQCSwWBxJQ3FhwCZEWLDZd4dgQC4Qa4h7hKYDOwwQrJAsaiKBDBp4DObTIGFHKA5EvMf9FgUCkGpkhHuhIkFABD50G6BTEXMKDwhEyADaIGDDgHAsRGwBEsNLl36tjFHmAwiNBg68zXsqY6CCvwYAIVf5569WI178lDIGB6yDBRwG8V5hgkPcHhYI0//IRU3WC3z8nC9OAqXDAzJYVWAAz4VJgTBYm/1xkcHOC3L4mC5dEOFAMh5YESpwQupxMShTMqjmZC6BpCZSEBWfYBHBHjhLYA2FD59Nu0C9j/4DBQqOQxjkycx5Y/3HiCAiQgcj7/HBAQNq9GVsKgVAI5oAIXx8EXtsWr+AtbIyoUA4+T0yQjiEj/EUQU6LQkUkXu9SCABttDGRLCdmoEMApTBgAwyeT3JEEZgOZQcEGHUCxCi3OQPKOMJj8U8kPCMwjyCxQSPTAIQ3oEoVEA8XwxyEJPlNPD/RMww4qnpQQRyfrIHPJFIBNoM0hcDihBEGjLMABDKjtEgoiAgSSyhvhUNPDGoBgASQKSCARwhNbDnQHB3BQIIVAenBjTTDMfEOAAJEMAwVq/zBxxgILQMNEnQJpoQsDdAAzECX6wLMMe3nskQsVyGEAgDYc5EAFogIFYQED0HBBUD+kRP9TRyLqsAIFif+AAEcRF5hCBXQCQcCCHXYUYAJBinTjhyVCXAGsAQdwcMEnZUwRBUFU3GBIDPJMAOk/9sjSLKpJ7GDHJxdUcMUUyA2UwACjqAGADd8KBGwUNJjhjy5ifPBEE+0ORAIOvlgAgBd7LoQLLMoYYkEIOlTB7kJQ6GBBC2bIQ8EHCYSxxBJWfDFGB+5Ak4IdB2Dwb0NZjKBBCinMAc0BkkywAwwDLBKDL+PYIUECUYA6URU34NCAB+Oo8QIDcBzijgWtQKMLBc00MTFFU3xAhy6GiOBBMWS04os7cIgQixRKCE0SFDxskQIcjBZhog1STJFjUElEoYQVBlQP4YoUUqCRhQFh5BbwQAEBADs=' ToolTipDescription='Generate Output' LabelText='Generate Output'/> </CommandUIDefinition> </CommandUIDefinitions> <CommandUIHandlers> <CommandUIHandler Command='ListViewButtonCommand' EnabledScript='javascript: var EnableDisable = function() { this.clientContext = SP.ClientContext.get_current(); var currentWeb = clientContext.get_web(); this.selectedItems = SP.ListOperation.Selection.getSelectedItems(this.clientContext); var currentListGuid = SP.ListOperation.Selection.getSelectedList(); var ret; var ci = CountDictionary(selectedItems); return (ci == 1) }; EnableDisable();' CommandAction=""javascript: var options = { url: '{SiteUrl}' + '/_layouts/dummyproject/dummypage.aspx/?ProjectProfileID={SelectedItemId}', allowMaximize: false, width: 500, height: 440 }; SP.UI.ModalDialog.showModalDialog(options);"" /> </CommandUIHandlers> </CommandUIExtension>"; ribbonCustomAction.Update(); list.Update(); web.AllowUnsafeUpdates = false; break; } } } } }
Remove The Custom Action From The SharePoint Ribbon
When the feature is deactivated, you would typically want to undo the addition of the custom action so that your environment reverts to the original state. To do this, add the following block of code to the feature deactivating event handler:
public override void FeatureDeactivating(SPFeatureReceiverProperties properties) { SPSite site = (SPSite)properties.Feature.Parent; foreach (SPWeb web in site.AllWebs) { if (web.ServerRelativeUrl.TrimEnd('/').ToLower().EndsWith("dummysite")) { for (int i = 0; i < web.Lists.Count; i++) { SPList list = web.Lists.TryGetList("Dummy List"); if (list != null && list.BaseType == SPBaseType.GenericList) { web.AllowUnsafeUpdates = true; if (list.UserCustomActions.Count > 0) { foreach (SPUserCustomAction action2 in list.UserCustomActions) { if (action2.Name == "ContentTypeRibbonCustomization") { action2.Delete(); list.Update(); break; } } } web.AllowUnsafeUpdates = false; break; } } } } }
That removes the custom action from the SharePoint ribbon.
Leave a Reply