<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Sitecore Xperiences &#187; Development</title>
	<atom:link href="https://blog.peplau.com.br/category/development/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.peplau.com.br</link>
	<description>The things I&#039;ve seen as a Sitecore Professional</description>
	<lastBuildDate>Sun, 09 Mar 2025 21:54:22 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.41</generator>
	<item>
		<title>Custom Reset Layout in Content and Experience Editor Modes</title>
		<link>https://blog.peplau.com.br/custom-reset-layout-in-content-and-experience-editor-modes/</link>
		<comments>https://blog.peplau.com.br/custom-reset-layout-in-content-and-experience-editor-modes/#comments</comments>
		<pubDate>Fri, 09 Feb 2018 00:04:51 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Content Edition Experience]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Experience Editor]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=728</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/custom-reset-layout-in-content-and-experience-editor-modes/"></div>Recently I had to customize the code that triggers when a Reset Layout is executed. If you ever had to attach any code to it, this post is for you! You know, that sympathetic prompt: The first thing you need to know is that Content Editor and Experience Editor does that differently, so let&#8217;s go for them: Round 1 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Recently I had to customize the code that triggers when a Reset Layout is executed. If you ever had to attach any code to it, this post is for you!</p>
<p>You know, that sympathetic prompt:</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Reset-Layout-Prompt.png"><img class="alignnone size-full wp-image-730" src="http://blog.peplau.com.br/wp-content/uploads/Reset-Layout-Prompt.png" alt="Reset Layout Prompt" width="372" height="331" /></a></p>
<p>The first thing you need to know is that Content Editor and Experience Editor does that differently, so let&#8217;s go for them:</p>
<h2>Round 1 &#8211; Content Editor</h2>
<p>Content Editor uses a command for that (pagedesigner:reset), which is natively implemented by the class <em>Sitecore.Shell.Applications.Layouts.PageDesigner.Commands.Reset</em>. We first need to create a class that will inherit from the original, so we don&#8217;t lose the original behavior, and implement our custom logic on it.</p>
<p>Create a Command class like this:</p>
<pre>using System.Web.Mvc;
using Sitecore.Shell.Applications.Dialogs.ResetLayout;
using Sitecore.Web.UI.Sheer;

namespace MyProject.Commands
{
    public class ResetLayoutCommand : Sitecore.Shell.Applications.Layouts.PageDesigner.Commands.Reset
    {
        protected override void Run(ClientPipelineArgs args)
        {
            // Runs the default behaviour
            base.Run(args);

            // Skips if the Reset Layout prompt is not submited or results is undefined
            if (!args.IsPostBack || string.IsNullOrEmpty(args.Result) || args.Result == "undefined")
                return;

            // Takes the item that has been reset
            var itemReset = DeserializeItems(args.Parameters["items"])[0];

            // And here is where your custom logic will be implemented
            // .....
        }
    }
}</pre>
<p>Then we override the default command with our class in a config patch like this:</p>
<pre>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
    &lt;sitecore&gt;
        &lt;commands&gt;
            &lt;command patch:instead="*[@name='pagedesigner:reset']" name="pagedesigner:reset" resolve="true" 
                type="MyProject.Commands.ResetLayoutCommand, MyProject"/&gt;
        &lt;/commands&gt;
    &lt;/sitecore&gt;
&lt;/configuration&gt;</pre>
<p>And this is how we run the first leg. But it is not over yet, let&#8217;s go for&#8230;</p>
<h2>Round 2 &#8211; Experience Editor</h2>
<p>Experience Editor, on the other hand, uses a different approach for that. It has a request node named &#8220;<em>ExperienceEditor.</em>ResetLayout<em>.Execute</em>&#8221; under <em>&lt;sitecore.experienceeditor.speak.requests&gt;</em> that we need to replace. This request node is implemented by the native class <em>Sitecore.ExperienceEditor.Speak.Ribbon.Requests.</em>ResetLayout<em>.Execute</em>, which again we are going to inherit.</p>
<p>So our Request class will be like this:</p>
<pre>using System;
using System.Web.Mvc;
using Sitecore.Diagnostics;
using Sitecore.ExperienceEditor.Speak.Attributes;
using Sitecore.ExperienceEditor.Speak.Server.Responses;
using Sitecore.Shell.Applications.Dialogs.ResetLayout;

namespace MyProject.ExperienceEditor
{
    public class ResetLayout : Sitecore.ExperienceEditor.Speak.Ribbon.Requests.ResetLayout.Execute
    {
        [HasItemPermissions(Id = "{BE98D7F0-7404-4F97-8E4C-8FEF4ACA5DA3}", Path = "/sitecore/content/Applications/WebEdit/Ribbons/WebEdit/Advanced/Layout/Reset")]
        public override PipelineProcessorResponseValue ProcessRequest()
        {
            // Instantiates the returning object and 
            var processorResponseValue = new PipelineProcessorResponseValue();

            try
            {
                // Executes the default RESET LAYOUT process
                processorResponseValue = base.ProcessRequest();

                // Takes the item that has been reset
                var itemReset = RequestContext.Item;

                // And here is where your custom logic will be implemented
                // ..... (OF COURSE, DON'T DUPLICATE YOUR LOGIC!)
            }
            catch (Exception e)
            {
                Log.Error(
                    $"[ResetLayout] Cannot execute post Layout Reset operations to item '{RequestContext.Item.Paths.Path}'", e, GetType());
            }
            return processorResponseValue;
        }
    }
}</pre>
<p>And finally we patch it again with a config file like this:</p>
<pre>&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
    &lt;sitecore&gt;
        &lt;sitecore.experienceeditor.speak.requests&gt;
            &lt;request patch:instead="*[@name='ExperienceEditor.ResetLayout.Execute']"
                name="ExperienceEditor.ResetLayout.Execute"
                type="MyProject.ExperienceEditor.ResetLayout, MyProject" /&gt;
        &lt;/sitecore.experienceeditor.speak.requests&gt;
    &lt;/sitecore&gt;
&lt;/configuration&gt;</pre>
<p>And that&#8217;s all&#8230; You now have your custom code being triggered by both Content Editor and Experience Editor!</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/custom-reset-layout-in-content-and-experience-editor-modes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Prevent orphan components in Experience Editor when deleting composed components</title>
		<link>https://blog.peplau.com.br/prevent-a-component-to-be-deleted-in-experience-editor-when-it-has-inner-components/</link>
		<comments>https://blog.peplau.com.br/prevent-a-component-to-be-deleted-in-experience-editor-when-it-has-inner-components/#comments</comments>
		<pubDate>Fri, 29 Sep 2017 22:44:45 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Content Edition Experience]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Experience Editor]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=617</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/prevent-a-component-to-be-deleted-in-experience-editor-when-it-has-inner-components/"></div>If an editor deletes a component in Experience Editor and that component has inner components, only the outer component will be actually deleted from the page rendering. Inner components will not show anymore (and often Content Editors will be happy), so why would that be a problem? The problem Take for instance this set of renderings [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>If an editor deletes a component in Experience Editor and that component has inner components, only the outer component will be actually deleted from the page rendering. Inner components will not show anymore (and often Content Editors will be happy), so why would that be a problem?</p>
<h2>The problem</h2>
<p>Take for instance this set of renderings of a certain page:</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Orphan-Renderings-before.png"><img class="alignnone wp-image-619 size-full" src="http://blog.peplau.com.br/wp-content/uploads/Orphan-Renderings-before.png" alt="Orphan Renderings-before" width="762" height="135" /></a></p>
<p>If in Experience Editor someone tries to delete it:</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Remove-Components.png"><img class="alignnone size-full wp-image-620" src="http://blog.peplau.com.br/wp-content/uploads/Remove-Components.png" alt="Remove Components" width="261" height="108" /></a></p>
<p>The result will be a &#8220;ghost&#8221; orphan item, which will not render when the page loads because its placeholder does not exist anymore.</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Orphan-Renderings-after.png"><img class="alignnone size-full wp-image-621" src="http://blog.peplau.com.br/wp-content/uploads/Orphan-Renderings-after.png" alt="Orphan Renderings-after" width="746" height="102" /></a></p>
<p>That rendering will continue at the page rendering, being either forgotten forever or re-appearing when someone tries to add a new Carousel to the same Full-Width Container placeholder.</p>
<h2>Not just me</h2>
<p>I&#8217;ve seen more people concerned with that &#8211; such as the author of <a href="https://sitecore.stackexchange.com/questions/4094/remove-child-renderings-from-layout" target="_blank">this question at Sitecore Exchange</a> &#8211; and some other people suggested possible solutions.</p>
<p>One approach I tried was to follow <a href="https://blog.horizontalintegration.com/2015/10/09/sitecore-orphan-children-after-parent-component-removal/" target="_blank">this blog post by Mike Tschida</a> and implement a pipeline processor to clean-up the Page Rendering, removing orphan components when the page is saved. That would be perfect, however during development or debugging, it is very common to temporarily move a component to an unexistent placeholder to make it vanish from the page. In cases like that, the component would be deleted, which is not desired.</p>
<h2>Acting at the other end</h2>
<p>So what if, instead of acting later at the server, we stop content editors at the root of the problem: the Experience Editor? At that case, when an editor attempts to delete a component which has inner components, a prompt like this would be displayed. In order to delete the outer component, the editor now needs to delete the inner components first.</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Orphan-Renderings-prompt.png"><img class="alignnone size-full wp-image-622" src="http://blog.peplau.com.br/wp-content/uploads/Orphan-Renderings-prompt.png" alt="Orphan Renderings-prompt" width="307" height="146" /></a></p>
<p>Inspired by <a href="https://stackoverflow.com/questions/38634701/delete-confirmation-when-deleting-from-floating-menu-in-a-page-editor-in-sitecor" target="_blank">this simple Stack Overflow post</a>,  in which the author was looking for a way to simply ask for a confirmation before deleting a component, I ended up with the solution below.</p>
<h2>Nip the evil in the bud</h2>
<p>The deletion of a component is handled by javascript code located at \sitecore\shell\Applications\Page Modes\ChromeTypes\RenderingChromeType.js &#8211; more specifically at the deleteControl method. Our fix will comment out the original code (I will leave there for future reference in case of an upgrade) and add the following code:</p>
<pre>    deleteControl: function () {
        var canDelete = this.canDeleteControl(this.chrome);
        if (canDelete === false) {
            alert("Please delete inner controls before deleting this.");
            return false;
        }
        var placeholder = this.getPlaceholder();
        if (placeholder) {
            placeholder.type.deleteControl(this.chrome);
            return true;
        }
        return false;
    },
</pre>
<p>Along of course with the new canDeleteControl method, which does the trick of verifying if the component attempted to be deleted has inner components.</p>
<pre>    canDeleteControl: function (chrome) {
        var canDelete = true;
        var childChromes = chrome.getChildChromes();
        for (var i = 0; i &lt; childChromes.length; i++) {
            if (childChromes[i].type.key() == "placeholder") {
                canDelete = this.canDeleteControl(childChromes[i]);
                if (canDelete === false)
                    break;
            }
            else if (childChromes[i].type.key() == "rendering") {
                canDelete = false;
                break;
            }
        }
        return canDelete;
    },
</pre>
<p>And that&#8217;s all we need! Replace this file in all instances, clean up your browser caches and don&#8217;t worry about orphan components anymore!</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/prevent-a-component-to-be-deleted-in-experience-editor-when-it-has-inner-components/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Language specific MediaProvider breaking icons at Media Library</title>
		<link>https://blog.peplau.com.br/language-specific-mediaprovider-breaking-icons-at-media-library/</link>
		<comments>https://blog.peplau.com.br/language-specific-mediaprovider-breaking-icons-at-media-library/#comments</comments>
		<pubDate>Tue, 14 Feb 2017 15:00:30 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Bug fixing]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Support Ticket]]></category>
		<category><![CDATA[Upgrades]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=538</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/language-specific-mediaprovider-breaking-icons-at-media-library/"></div>UPDATE: Kamruz Jaman has contributed with a comment for a simpler, less intrusive and more generalist solution:  Inside the GetMediaUrl method of your custom MediaProvider, check for the &#8220;Thumbnail&#8221; property of your MediaUrlOptions parameter. If it is true, make your code fall back to the base, such as: if (mediaOptions.Thumbnail) return base.GetMediaUrl(mediaItem, mediaOptions); During an upgrade from [&#8230;]]]></description>
				<content:encoded><![CDATA[<blockquote><p><strong>UPDATE: </strong>Kamruz Jaman has contributed with a comment for a simpler, less intrusive and more generalist solution:  Inside the GetMediaUrl method of your custom MediaProvider, check for the &#8220;Thumbnail&#8221; property of your MediaUrlOptions parameter. If it is true, make your code fall back to the base, such as:</p>
<p>if (mediaOptions.Thumbnail)<br />
return base.GetMediaUrl(mediaItem, mediaOptions);</p></blockquote>
<p>During an upgrade from Sitecore 6.5 to Sitecore 8.1 one issue were noticed at the Media Library: when a Media Item is uploaded, the icon appears broken.</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Broken-Icon.png"><img class=" size-full wp-image-539 alignnone" src="http://blog.peplau.com.br/wp-content/uploads/Broken-Icon.png" alt="Broken Icon" width="703" height="117" /></a></p>
<p>A custom MediaProvider is used at this build to modify the way Sitecore generates Media Item urls. All it does is to add the language at beginning of the media URL so we can have language-specific media items. This is important to allow the same Media Item (etc: an image or PDF) to be served in multiple languages.</p>
<h2>Root cause</h2>
<p>When a media item is uploaded to the Media Library, Sitecore will fill the &#8220;Icon&#8221; field with the URL of the media item itself. Because of the custom MediaProvider, language is being added to the beginning of the generated URL. Apparently that was not a problem in Sitecore 6.5, but things seems to have changed at Sitecore 8.</p>
<h2>Technical explanation by Sitecore</h2>
<p>A Support Ticket #476256 were created to allow further investigation from Sitecore on this issue. According to the technical team:</p>
<blockquote><p>&#8220;The behavior you reported is expected as tree node icons are rendered by <em>Sitecore.Shell.Applications.ContentManager.Sidebars.Tree.RenderIcon(Item item)</em> method which does not use language definition, embedded to URL, to resolve item language. So when the Icon field contains URL with language definition embedded, it breaks the method functionality and leads to incorrect resolution of the item&#8217;s icon.</p>
<p>When you have versioned media item, the icon is rendered for specific language automatically even when language is not specified deliberately. For instance, if you have media item with two language versions and different images for each language, and use -/media/ItemGUID.ashx?h=16&amp;thn=1&amp;w=16 string in the Icon field, language specific icon will be rendered when you switch the language in the Content Editor.&#8221;</p></blockquote>
<p>This explains the causes but doesn&#8217;t fix the issue: <span style="text-decoration: underline;">how can we skip or bypass the custom MediaProvider, avoiding the language to be added to the URL when the &#8220;Icon&#8221; field is filled?</span></p>
<h2>Solution</h2>
<p>In order to fix that we will need to extend and override the <em>Sitecore.Resources.Media.Media</em> class, responsible for the upload and update of metadata when a Media Item is uploaded to the Media Library, then modify all Media Types to use your class instead of the original.</p>
<h3>Step 1 &#8211; Extend the Media class</h3>
<p>This is going to be responsible for removing the language from the URL when a Media Item is uploaded. In bold you see the code responsible for that, rest is basically native code to ensure compliance with default Sitecore behavior.</p>
<pre>using Sitecore;
using Sitecore.Configuration;
using Sitecore.Data.Items;
using Sitecore.Data.Proxies;
using Sitecore.Diagnostics;
using Sitecore.Resources.Media;
using Sitecore.SecurityModel;

namespace CustomMediaProvider
{
  public class Media : Sitecore.Resources.Media.Media
  {
    public override Sitecore.Resources.Media.Media Clone()
    {
      return new Media();
    }

    public override void UpdateMetaData(MediaStream mediaStream)
    {
      Assert.ArgumentNotNull(mediaStream, "mediaStream");
      var innerItem = MediaData.MediaItem.InnerItem;
      if (!innerItem.Paths.IsMediaItem) return;
      using (new EditContext(innerItem, SecurityCheck.Disable))
      {
        innerItem["extension"] = mediaStream.Extension;
        innerItem["mime type"] = mediaStream.MimeType;
        innerItem["size"] = mediaStream.Length.ToString();
        if (Settings.Media.AutoSetAlt)
        {
          innerItem["Alt"] = innerItem.Name;
        }
        var shellOptions = MediaUrlOptions.GetShellOptions();
        shellOptions.Thumbnail = true;
        shellOptions.Height = 0x10;
        shellOptions.Width = 0x10;
        var realItem = ProxyManager.GetRealItem(innerItem, true);
<strong>        // CODE ADDED TO REMOVE LANGUAGE FROM URL WHILE UPLOADING</strong>
<strong>        var iconUrl = MediaManager.GetMediaUrl(realItem, shellOptions);</strong>
<strong>        var prefix = "/" + Context.Language.Name + "/";</strong>
<strong>        if (iconUrl.StartsWith(prefix)) iconUrl = iconUrl.Replace(prefix, "");</strong>
        innerItem.Appearance.Icon = iconUrl;
      }
    }
  }
}</pre>
<h3>Step 2 &#8211; Register the Media class to all Media Types</h3>
<p>This is the painful part: we will need to register our class to every Media Type we want to cover. There is no easy way for that other than adding a node for each Media Type, paying attention to the correct way for patching that specific node (some nodes may have a Media class already defined and thus needs correct patching, others don&#8217;t).</p>
<pre>&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
 &lt;sitecore&gt;
 &lt;mediaLibrary&gt;
 &lt;!-- This is our Custom MediaProvider causing all the trouble --&gt;
 &lt;mediaProvider&gt;
 &lt;patch:attribute name="type"&gt;CustomMediaProvider.MediaProvider,CustomMediaProvider&lt;/patch:attribute&gt;
 &lt;/mediaProvider&gt;
 &lt;!-- And here goes our custom Media class being attached to several Media Types --&gt;
 &lt;mediaTypes&gt;
 &lt;mediaType name="Any" extensions="*"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider" patch:instead="*[@type='Sitecore.Resources.Media.Media, Sitecore.Kernel']"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="AVI video" extensions="avi"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="Windows Bitmap image" extensions="bmp, dib"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider" patch:instead="*[@type='Sitecore.Resources.Media.ImageMedia, Sitecore.Kernel']"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="Flash" extensions="swf"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider" patch:instead="*[@type='Sitecore.Resources.Media.SwfMedia, Sitecore.Kernel']"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="Flash video" extensions="flv"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="GIF image" extensions="gif"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider" patch:instead="*[@type='Sitecore.Resources.Media.ImageMedia, Sitecore.Kernel']"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="HTML" extensions="htm,html,stm"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="JPEG image" extensions="jpg, jpeg, jpe, jfif"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider" patch:instead="*[@type='Sitecore.Resources.Media.ImageThumbnailGenerator, Sitecore.Kernel']"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="MP3" extensions="mp3"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider" patch:instead="*[@type='Sitecore.Resources.Media.Mp3Media, Sitecore.Kernel']"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="MP4 video" extensions="mp4"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="PDF file" extensions="pdf"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="PNG image" extensions="png"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider" patch:instead="*[@type='Sitecore.Resources.Media.ImageMedia, Sitecore.Kernel']"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="SVG image" extensions="svg"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider" patch:instead="*[@type='Sitecore.Resources.Media.SvgMedia, Sitecore.Kernel']"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="QuickTime movie" extensions="mov, qt"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="TIFF image" extensions="tiff, tif"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider" patch:instead="*[@type='Sitecore.Resources.Media.ImageMedia, Sitecore.Kernel']"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="Zip file" extensions="zip"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider" patch:instead="*[@type='Sitecore.Resources.Media.ZipMedia, Sitecore.Kernel']"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="Video for Adobe Flash Player" extensions="f4v"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="Windows Media video" extensions="WMV"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="Word document" extensions="doc"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="Word 2007 document" extensions="docx"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="PPTX File" extensions="pptx"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="PPT File" extensions="ppt"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="XLSX File" extensions="xlsx"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;mediaType name="XLS File" extensions="xls"&gt;
 &lt;prototypes&gt;
 &lt;media type="CustomMediaProvider.Media, CustomMediaProvider"/&gt;
 &lt;/prototypes&gt;
 &lt;/mediaType&gt;
 &lt;/mediaTypes&gt;
 &lt;/mediaLibrary&gt;
 &lt;/sitecore&gt;
&lt;/configuration&gt;</pre>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/language-specific-mediaprovider-breaking-icons-at-media-library/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Slowness with Custom Properties on .NET Security Provider</title>
		<link>https://blog.peplau.com.br/slowness-with-custom-properties-on-security-provider/</link>
		<comments>https://blog.peplau.com.br/slowness-with-custom-properties-on-security-provider/#comments</comments>
		<pubDate>Mon, 22 Aug 2016 00:49:52 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Security Provider]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=426</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/slowness-with-custom-properties-on-security-provider/"></div>If you ever used the standard .NET Security Provider with Sitecore, you may love how easy it is to create and use Custom Profile Properties, where data can be easily saved at user profiles. But a huge issue can emerge if you attempt to retrieve users at your database by one of these custom properties. The Problem Let&#8217;s say you have a [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>If you ever used the standard .NET Security Provider with Sitecore, you may love how easy it is to create and use Custom Profile Properties, where data can be easily saved at user profiles. But a huge issue can emerge if you attempt to retrieve users at your database by one of these custom properties.</p>
<h2>The Problem</h2>
<p>Let&#8217;s say you have a custom property called <em>Document ID</em>, and you wish for some reason to retrieve the user that has a certain number on it &#8211; for instance, if your users can login to your website both using their <em>Logins</em> or <em>Document IDs</em> &#8211; then you may have something like this at your code:</p>
<pre>var userFound = UserManager.GetUsers().FirstOrDefault(f =&gt; f.Profile["Document ID"] == inputDocumentId);</pre>
<p>This simple code can bring you a big headache, because of the way .NET Security Provider builds the SQL Query responsible for executing your LINQ expression. Since all Custom Properties are stored as meta data, it is simply not directly queriable. Then what Security Provider does is one SELECT query <strong><span style="text-decoration: underline;">for each user</span></strong> at your database, deserializing the Custom Properties on memory so it can be compared to the user input.</p>
<p>If you have few users at your database, which is usually the case when you are in development phase, you&#8217;ll probably not notice any issue. But after your go-live, as your user base starts growing, it will gradually get slower and slower. At the project that inspired this blog post, we had a sudden data load of more than 20k users, and as a consequence the system got impracticably slow overnight.</p>
<h2>The Solution</h2>
<p>One of the possible technical solutions, the one we used at the project in question, was to extend the table <em>aspnet_Users</em> at our Core database. That is the main table used by .NET Security Provider to store users. What we do is to create a new column <em>Document ID</em>, where this data will be stored in a clean format:</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/aspnet_Users.jpg"><img class="alignnone size-full wp-image-440" src="http://blog.peplau.com.br/wp-content/uploads/aspnet_Users.jpg" alt="aspnet_Users" width="316" height="183" /></a></p>
<p>After that, we need to attach some code to both &#8220;user:created&#8221; and &#8220;user:updated&#8221; pipelines. This code will be responsible for updating the Document ID column when users are created or updated.</p>
<pre>&lt;configuration xmlns:patch="http://www.sitecore.net/xmlconfig/"&gt;
 &lt;sitecore&gt;
 &lt;events&gt;
 &lt;event name="user:created"&gt;
 &lt;handler type="MyProject.Pipelines.UpdateUserProfileCache, MyProject" method="OnUserCreatedUpdated" /&gt;
 &lt;/event&gt;
 &lt;event name="user:updated"&gt;
 &lt;handler type="MyProject.Pipelines.UpdateUserProfileCache, MyProject" method="OnUserCreatedUpdated" /&gt;
 &lt;/event&gt;
 &lt;/events&gt;
 &lt;/sitecore&gt;
&lt;/configuration&gt;</pre>
<p>Then your code will probably look like the following. The class <em>CustomProfileIndexManager</em>, responsible for doing the actual Update and Select at the database is not there, but you can easily guess how to build yours.</p>
<pre>namespace MyProject.Pipelines 
{
 public class UpdateUserProfileCache
 {
   public void OnUserCreatedUpdated(object sender, EventArgs args)
   {
     var scArgs = (SitecoreEventArgs)args;
     if (!scArgs.Parameters.Any())
       return;

     var user = (System.Web.Security.MembershipUser)scArgs.Parameters.First();

     // Will only act for "extranet" users
     var username = user.UserName;
     if (!username.StartsWith("extranet"))
       return;

     var scUser = Sitecore.Security.Accounts.User.FromName(username,false);

     // Following method is responsible for saving "Document ID" 
     // into the respective column at the database
     CustomProfileIndexManager.SaveUserToCache(scUser);
   }
 }
}
</pre>
<p>So your problematic code would be replaced by something like this:</p>
<pre>// Will do a simple "SELECT * FROM aspnet_Users WHERE Document ID = 'xxxx'" 
var userFound = CustomProfileIndexManager.GetUserByDocumentId(inputDocumentId);</pre>
<p>&nbsp;</p>
<h2>What about the existent base of users?</h2>
<p>Of course that will only cover users that are new or updated. If you already have a certain base of users, you can build a simple script to &#8220;touch&#8221; all your users, such as this:</p>
<pre> var startProcess = DateTime.Now;
 Response.Write("&lt;font color=\"red\"&gt;Loading users...&lt;/font&gt;");
 Response.Flush();

 // Get all users
 var users = DomainManager.GetDomain("extranet").GetUsers();
 Response.Write(string.Format("OK! ({0}ms)&lt;hr&gt;", DateTime.Now.Subtract(startProcess).TotalMilliseconds));
 Response.Flush();

 // Loop into all users
 var counter = 0;
 foreach (var user in users)
 {
   var startUserProcess = DateTime.Now;

   counter++;
   if ((counter % 10) == 0)
   {
     Response.Write(string.Format("--- Total time: {0} minutes&lt;br&gt;", DateTime.Now.Subtract(startProcess).TotalMinutes));
     Response.Flush();
   }
   Response.Write(string.Format("User #{0} - Email: {1} - Processing...", counter, user.Profile.Email));

   // Following method is responsible for saving "Document ID" 
   // into the respective column at the database
   CustomProfileIndexManager.SaveUserToCache(user);

   Response.Write(string.Format(" OK! ({0}ms)&lt;br/&gt;", DateTime.Now.Subtract(startUserProcess).TotalMilliseconds));
 }
 Response.Write(string.Format("&lt;h3&gt;TOTAL TIME: {0} minutes&lt;/h3&gt;", DateTime.Now.Subtract(startProcess).TotalMinutes));
 Response.Flush();
 Response.End();</pre>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/slowness-with-custom-properties-on-security-provider/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Faster Sitecore for Development - All in a single include</title>
		<link>https://blog.peplau.com.br/faster-sitecore-for-development-all-in-a-single-include/</link>
		<comments>https://blog.peplau.com.br/faster-sitecore-for-development-all-in-a-single-include/#comments</comments>
		<pubDate>Thu, 14 Jul 2016 21:42:48 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Development]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=391</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/faster-sitecore-for-development-all-in-a-single-include/"></div>Since Sitecore 8, load times after builds are getting slower due to the high usage of Speak at the new UI. There is a great post by Kam Figy that summarizes reasons and how to improve this performance. Tired of having to get back to his article repeating the steps for all my project, I decided to isolate everything in a single [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Since Sitecore 8, load times after builds are getting slower due to the high usage of Speak at the new UI. There is a <a href="http://kamsar.net/index.php/2015/02/sitecore-8-experience-editor-performance-optimization/">great post by Kam Figy</a> that summarizes reasons and how to improve this performance.</p>
<p>Tired of having to get back to his article repeating the steps for all my project, I decided to isolate everything in a single Include. There are three options to improve speed, and the patch authomatically covers 2 of them:</p>
<ol>
<li>Disable SPEAK Precompilation &#8211; <strong>Covered!</strong></li>
<li>Optimize Compilation &#8211; <strong>Requires manual change at the Web.config (Check the patch file for instructions)</strong></li>
<li>Disable the SPEAK Experience Editor &#8211; <strong>Covered!</strong></li>
</ol>
<p>Please make sure you read the whole article and you&#8217;re aware of the impacts.</p>
<ul>
<li>Download here the include file <a href="http://blog.peplau.com.br/wp-content/uploads/Sitecore.XFaster.zip">Sitecore.XFaster</a> (zipped)</li>
</ul>
<p>When you unzip this file will see the patch is inside a folder &#8220;XFaster&#8221;. Place this folder, and not the include alone, inside the Include folder. It has to be there due to a conflicting setting at &#8220;/Include/ContentTesting/Sitecore.ContentTesting.config&#8221; that would overwrite our settings.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/faster-sitecore-for-development-all-in-a-single-include/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SPEAK: ItemTreeView with multiple Roots</title>
		<link>https://blog.peplau.com.br/speak-itemtreeview-with-multiple-roots/</link>
		<comments>https://blog.peplau.com.br/speak-itemtreeview-with-multiple-roots/#comments</comments>
		<pubDate>Fri, 22 Apr 2016 17:52:17 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[SPEAK]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=358</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/speak-itemtreeview-with-multiple-roots/"></div>I&#8217;ve being studying SPEAK recently for a module I&#8217;m building, and it&#8217;s being a lot of fun so far. Of course, when learning anything that imposes a different paradigm, it&#8217;s common to get stuck with &#8220;simple&#8221; things that, in another programming realities, are easy to accomplish. And then it happened to me: the ItemTreeView component offers exactly the UI experience [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve being studying SPEAK recently for a module I&#8217;m building, and it&#8217;s being a lot of fun so far. Of course, when learning anything that imposes a different paradigm, it&#8217;s common to get stuck with &#8220;simple&#8221; things that, in another programming realities, are easy to accomplish.</p>
<p>And then it happened to me: the ItemTreeView component offers exactly the UI experience I want to provide. It lists Sitecore items in a Tree, just like the Content Editor, but also offers a way for the user to select items with checkboxes. That is perfect, but there&#8217;s one problem: you can only have one single Root for each ItemTreeView component.</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/ItemTreeView-OOTB.jpg"><img class="alignnone size-full wp-image-359" src="http://blog.peplau.com.br/wp-content/uploads/ItemTreeView-OOTB.jpg" alt="ItemTreeView - Out of the Box" width="188" height="128" /></a></p>
<p>This limitation simply made impossible one requirement I have, which is to list a certain Template and all their fields and Standard Values (Ok) along with all their Base Templates (impossible). Since we can&#8217;t predict how many Base Templates (if any) a certain template has, we can&#8217;t simply add one or two ItemTreeViews to the SPEAK page and expect they will cover all your needs. Instead, we need to be able to dynamically add multiple Roots to an ItemTreeView. But how?</p>
<h2>First Try &#8211; Google</h2>
<p>As a good boy I first asked Google, but looks like SPEAK components are not yet very widely being subjects of debates in forums and communities worldwide. Most of the documentation are introductory step-by-steps, along with the official documentation which is well descriptive, but not very detailed in terms of what you can do with a certain SPEAK component. Nothing really targeting the ItemTreeView component in general, or my need of having multiple Roots in specific.</p>
<h2>Second try &#8211; Sitecore Community</h2>
<p>For those who don&#8217;t know yet, the new <a href="https://community.sitecore.net" target="_blank">Sitecore Community</a> website, built on top of <a href="http://www.telligent.com/products/telligent-community/" target="_blank">Zimbra/Telligent Community</a>, is the main resource for trading Sitecore experiences. After a quick search, I also see no entries discussing what I needed, and then decided to start up my own question topic: &#8220;<a href="https://community.sitecore.net/developers/f/8/t/2919" target="_blank">ItemTreeView with SPEAK : Having multiple RootsItems? Dynamically adding a new one? (with C#)</a>&#8221;</p>
<p>Again nothing came out from that topic, so I started to think this may be a good thing to contribute, and at the same time to achieve what I&#8217;m trying to have in my component. This post brings the whole solution, along with a Sitecore package with the final code and items that you can download and use.</p>
<h2>Ok, nevermind, I&#8217;ll build my own</h2>
<p>The ItemTreeView component does not support multiple roots out-of-the-box, so I ended up solving this issue by creating a new version of the ItemTreeView component that does it.</p>
<p>Looking the original ItemTreeView component (<em>core:/sitecore/client/Business Component Library/version 1/Layouts/Renderings/Lists and Grids/ItemTreeView</em>) brought me to its View file (<em>\sitecore\shell\client\Business Component Library\Layouts\Renderings\ListsAndGrids\TreeViews\ItemTreeView.cshtml</em>).</p>
<p>These are the important parts we want to pay a special attention:</p>
<ul>
<li>Line 17 &#8211; It&#8217;s where the rootId configured by the user is taken:
<pre>var rootItemId = userControl.GetString("RootItem");</pre>
</li>
<li>Lines 56 to 65 &#8211; RootId is used to retrieve the real Sitecore item:
<pre>Item rootItem = null;
if (!string.IsNullOrEmpty(rootItemId))
{
    rootItem = database.GetItem(rootItemId, Language.Parse(contentLanguage));
}
if (rootItem == null)
{
    rootItem = database.GetRootItem();
}</pre>
</li>
<li>Lines 67 to  69 &#8211; The TreeView component is setup with the Root Item configured
<pre>var rootItemIcon = Images.GetThemedImageSource(!string.IsNullOrEmpty(rootItem.Appearance.Icon) ? rootItem.Appearance.Icon : "Applications/16x16/documents.png", ImageDimension.id16x16);
userControl.SetAttribute("data-sc-rootitem", rootItem.DisplayName + "," + rootItem.Database.Name + "," + rootItem.ID + "," + rootItemIcon);
userControl.SetAttribute("data-sc-rootitempath", rootItem.Paths.Path);</pre>
</li>
<li>Lines 86 to 88 &#8211; The div container is output with its configurations
<pre>&lt;div @htmlAttributes&gt;
&lt;ul&gt;&lt;/ul&gt;
&lt;/div&gt;</pre>
</li>
</ul>
<p>My first experience were to duplicate the div markup, so I had it twice:</p>
<pre style="padding-left: 30px;">&lt;div @htmlAttributes&gt;
&lt;ul&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;div @htmlAttributes&gt;
&lt;ul&gt;&lt;/ul&gt;
&lt;/div&gt;
</pre>
<p>This ended up showing two identical roots &#8211; and the &#8220;twin&#8221; root worked perfectly. That was the confirmation I needed to create an improved version of the ItemTreeView component that can spit multiple roots. With the goal of simplicity, my component will act the same as the original ItemTreeView, but its &#8220;RootItem&#8221; property now will accept not just one, but multiple IDs (in a pipe-delimited string).</p>
<p>Here are the steps I take:</p>
<h3>STEP 1 &#8211; Create the new component</h3>
<ul>
<li>Duplicated the original component and gave it the name &#8220;ItemTreeView2&#8243;</li>
<li>At the duplicated item, deleted the children &#8220;ItemTreeView Parameters&#8221; (we are going to use the original parameters template)</li>
<li>&#8220;Parameters Template&#8221; field &#8211; it should stay poiting to the original (<em>Client/Business Component Library/version 1/Layouts/Renderings/Lists and Grids/ItemTreeView/ItemTreeView Parameters</em>)</li>
<li>At the &#8220;Path&#8221; field I made it point to my new View file: <em>/sitecore/shell/client/Business Component Library/Layouts/Renderings/ListsAndGrids/TreeViews/ItemTreeView2.cshtml</em></li>
</ul>
<h3>STEP 2 &#8211; Make it accept multiple Roots</h3>
<ul>
<li>Comment the original line:
<pre>//var rootItemId = userControl.GetString("RootItem");</pre>
</li>
<li>Add our new logic:
<pre>var rootItemIds = userControl.GetString("RootItem").Split('|');
var rootItemId = rootItemIds.FirstOrDefault();</pre>
</li>
</ul>
<p>Most of the original component will stay as is, and the first Root will be handled exactly how it is natively done.</p>
<h3>STEP 3 &#8211; Make it spit the other Roots</h3>
<ul>
<li>At the very bottom of the View, we are going to create a new list of HtmlAttributes, which is here used to represent the Tree setup:
<pre>@{
    var lstAttributes = new List&lt;HtmlString&gt;();
    for (var i = 1; i &lt; rootItemIds.Length; i++)
    {
        rootItem = null;
        if (!string.IsNullOrEmpty(rootItemId))
        {
            rootItem = database.GetItem(rootItemIds[i], Language.Parse(contentLanguage));
        }
        if (rootItem == null)
        {
            rootItem = database.GetRootItem();
        }</pre>
<pre>        rootItemIcon = Images.GetThemedImageSource(!string.IsNullOrEmpty(rootItem.Appearance.Icon) ? rootItem.Appearance.Icon : "Applications/16x16/documents.png", ImageDimension.id16x16);
        userControl.SetAttribute("data-sc-rootitem", rootItem.DisplayName + "," + rootItem.Database.Name + "," + rootItem.ID + "," + rootItemIcon);
        userControl.SetAttribute("data-sc-rootitempath", rootItem.Paths.Path);
        lstAttributes.Add(userControl.HtmlAttributes); 
    } 
}</pre>
</li>
<li>And then have the loop for the HTML container:
<pre>@foreach (var htmlAttr in lstAttributes)
{
    &lt;div @htmlAttr&gt;
    &lt;ul&gt;&lt;/ul&gt;
    &lt;/div&gt;
}
</pre>
</li>
</ul>
<p>And that&#8217;s all!</p>
<p>Now I can add a pipe-delimited list of IDs, either by adding it tothe rendering setup or by using my PageCode file:</p>
<pre>TreeDsBaseTemplates.Parameters["RootItem"] = String.Join("|",
ComponentItem.DatasourceTemplate.BaseTemplates.Select(p =&gt; p.ID.ToString()).ToArray());
TreeDsBaseTemplates.Parameters["Database"] = ComponentItem.DatasourceTemplate.Database.Name;</pre>
<p>This way my module now has two ItemTreeViews: first is a normal (native) one, the other is my extended control with roots being dynamically added:</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/ItemTreeView2.jpg"><img class="alignnone size-full wp-image-381" src="http://blog.peplau.com.br/wp-content/uploads/ItemTreeView2.jpg" alt="ItemTreeView2" width="244" height="298" /></a></p>
<h2>The package</h2>
<p>Here is the resulting package of the new ItemTreeView2 SPEAK component. Fell free to download and use it!</p>
<ul>
<li><a href="http://blog.peplau.com.br/wp-content/uploads/ItemTreeView2-1.0.zip" onclick="ga('send', 'event', 'ItemTreeView2-1.0', 'Download', '');">ItemTreeView2-1.0.zip</a></li>
</ul>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/speak-itemtreeview-with-multiple-roots/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Rules to replace spaces by dashes in Sitecore 7.5 in 3 simple steps</title>
		<link>https://blog.peplau.com.br/replace-spaces-by-dashes-using-rules-in-sitecore-7-5/</link>
		<comments>https://blog.peplau.com.br/replace-spaces-by-dashes-using-rules-in-sitecore-7-5/#comments</comments>
		<pubDate>Tue, 28 Apr 2015 22:30:19 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Actions]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[Rules]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=201</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/replace-spaces-by-dashes-using-rules-in-sitecore-7-5/"></div>In this article I show how to use rules to rename items so, every time an item is saved, spaces gets replaced by dashes. Advantage of using rules is that you can visually setup different kind of conditions, without having to hardcode them at your code. 1) Create the Action that triggers the item renaming In your master [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>In this article I show how to use rules to rename items so, every time an item is saved, spaces gets replaced by dashes. Advantage of using rules is that you can visually setup different kind of conditions, without having to hardcode them at your code.</p>
<h3>1) Create the Action that triggers the item renaming</h3>
<p>In your master database, add your new <strong>Action</strong> using the template /sitecore/templates/System/Rules/Action. In this case I&#8217;m using the path /sitecore/system/Settings/Rules/Definitions/Elements/Script because the <strong>Script</strong> Element Folder is already referenced by the <strong>Item Saved</strong> rules.</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Creating-the-action.jpg"><img class="alignnone wp-image-204 " src="http://blog.peplau.com.br/wp-content/uploads/Creating-the-action.jpg" alt="Creating the action" width="797" height="308" /></a></p>
<p>The <strong>Type</strong> field must point to your class that handles the item renaming (use the format &#8220;<em>Namespace.ClassName, Assembly</em>&#8220;)</p>
<h3>2) Create the class that executes the item renaming</h3>
<p>This is where your code for checking and renaming the item gets executed (parameter &#8220;ruleContext.Item&#8221; brings the item being saved).</p>
<pre>using Sitecore.Diagnostics;
using Sitecore.Rules;
using Sitecore.Rules.Actions;

namespace BusinessLayer.Rules.Actions
{
    public class AddHyphensToItemName : RuleAction where T : RuleContext
    {
        public override void Apply(T ruleContext)
        {
            Assert.ArgumentNotNull(ruleContext, "ruleContext");
            var obj1 = ruleContext.Item;
            if (obj1 == null)
                return;

            // Scape if no space is at the Name
            var itemName = obj1.Name;
            if (!itemName.Contains(" "))
                return;

            // Rename the item
            itemName = itemName.Replace(" ", "-");
            obj1.Editing.BeginEdit();
            obj1.Name = itemName;
            obj1.Editing.EndEdit();
        }
    }
}
</pre>
<h3>3) Create the Rule to execute the Action above</h3>
<p>Add your new <strong>Rule</strong> using the template /sitecore/templates/System/Rules/Rule, then edit your rules.</p>
<p><a href="http://blog.peplau.com.br/wp-content/uploads/Rule-to-rename.jpg"><img class="alignnone wp-image-214 " src="http://blog.peplau.com.br/wp-content/uploads/Rule-to-rename.jpg" alt="Rule to rename" width="818" height="341" /></a></p>
<p>In this case what I&#8217;m doing is:</p>
<ul>
<li>Including everything under &#8220;/sitecore/content/Site/Home&#8221; &#8211; because I just want to apply this rule to the items under my Homepage;</li>
<li>Skipping items that doesn&#8217;t have a layout &#8211; We don&#8217;t mind if items without renderings has spaces;</li>
<li>Calling the action &#8220;Add Hyphens To Item Name&#8221; for the matching Items.</li>
</ul>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/replace-spaces-by-dashes-using-rules-in-sitecore-7-5/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Visual Studio Solution at Sitecore Projects - Avoiding IIS restarts with Robocopy in a Post Build event</title>
		<link>https://blog.peplau.com.br/visual-studio-solution-at-sitecore-projects-avoiding-iis-restarts-with-robocopy-in-a-post-build-event/</link>
		<comments>https://blog.peplau.com.br/visual-studio-solution-at-sitecore-projects-avoiding-iis-restarts-with-robocopy-in-a-post-build-event/#comments</comments>
		<pubDate>Sat, 11 Apr 2015 00:47:22 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Visual Studio]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=196</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/visual-studio-solution-at-sitecore-projects-avoiding-iis-restarts-with-robocopy-in-a-post-build-event/"></div>As very well described by Sean Kearney at this great post, there are two ways to setup a Sitecore solution on Visual Studio for development: 1) Your solution, and code, is fully immersed in the Sitecore web site; 2) Your solution, and code, is outside of Sitecore&#8217;s web site and you use some post build process to deploy. [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>As very well described by Sean Kearney at <a href="http://seankearney.com/post/Visual-Studio-Projects-and-Sitecore" target="_blank">this great post</a>, there are two ways to setup a Sitecore solution on Visual Studio for development:</p>
<blockquote><p>1) Your solution, and code, is fully immersed in the Sitecore web site;<br /> 2) Your solution, and code, is outside of Sitecore&#8217;s web site and you use some <strong>post build process</strong> to deploy.</p>
</blockquote>
<p>His post supports second option, which indeed has advantages over the first, however a huge drawback (specially for those without SSD) makes our life harder: due to the <strong>post build deployment</strong>, IIS is constantly forced to restart on every build you make.</p>
<p>In order to handle that issue I&#8217;ve invested some time looking for a better way to deploy. What if I copy only the modified changes instead of everything? Perhaps I could often skip the files that causes restarts, such as DLLs and config files&#8230;</p>
<h4>Robocopy</h4>
<p>My solution lied on <a href="https://technet.microsoft.com/en-us/library/cc733145.aspx" target="_blank">robocopy</a>, for advanced file copying. At your website project on Visual Studio, put this command at the Post-build event command line box:</p>
<blockquote><p>robocopy &#8220;$(ProjectDir).&#8221; &#8220;C:\inetpub\wwwroot\YourProject\Website&#8221; /E /FFT /XO<br /> exit 0</p>
</blockquote>
<ul>
<li> Parameters:
<ul>
<li><strong>/E</strong> &#8211; Copies subdirectories;</li>
<li><strong>/XO</strong> &#8211; Excludes older files &#8211; this is the trick, skipping old files;</li>
<li><strong>/FFT</strong> &#8211; Assumes FAT file times (two-second precision) &#8211; this somehow interferes on how robocopy defines what is &#8220;older&#8221; to be copied;</li>
<li><strong>exit 0</strong> &#8211; If we don&#8217;t add this to the end of the script, our Continuos Integration server breaks because robocopy returns a code different than &#8220;0&#8221; as success.</li>
</ul>
</li>
</ul>
<p>In my experience, even when you re-compile the solution without changing anything at the code, your IIS will not restart.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/visual-studio-solution-at-sitecore-projects-avoiding-iis-restarts-with-robocopy-in-a-post-build-event/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Best way to setup Active Directory Module in a Sitecore Solution</title>
		<link>https://blog.peplau.com.br/best-way-to-setup-active-directory-module-in-a-sitecore-solution/</link>
		<comments>https://blog.peplau.com.br/best-way-to-setup-active-directory-module-in-a-sitecore-solution/#comments</comments>
		<pubDate>Mon, 23 Mar 2015 22:37:40 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[LDAP]]></category>
		<category><![CDATA[Sitecore Modules]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=157</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/best-way-to-setup-active-directory-module-in-a-sitecore-solution/"></div>Connecting Sitecore with an LDAP Server is pretty easy with Sitecore&#8217;s Active Directory Module. Setting up the module is not hard, but if you follow the official documentation you&#8217;ll end up updating a lot of your Web.config file, which may be a problem for several reasons: You can easily lose track on your customizations; Upgrading Sitecore for a newer version may become [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Connecting Sitecore with an LDAP Server is pretty easy with Sitecore&#8217;s <a href="http://sdn.sitecore.net/Products/AD.aspx" target="_blank">Active Directory Module</a>. Setting up the module is not hard, but if you follow <a href="http://sdn.sitecore.net/Products/AD/AD12/Documentation.aspx" target="_blank">the official documentation</a> you&#8217;ll end up updating a lot of your Web.config file, which may be a problem for several reasons:</p>
<ol>
<li>You can easily lose track on your customizations;</li>
<li>Upgrading Sitecore for a newer version may become harder;</li>
<li>During development you may be forced to turn your LDAP module off, basically undoing the setup of your providers, which is not straight-forward.</li>
</ol>
<p>After facing these issues a couple times I decided to look for a better approach.</p>
<p><strong>Using Includes</strong></p>
<p>Biggest limitation is by far the need to update your Web.config, as the changes are not in the Sitecore portion and thus cannot be automatically patched by files in your <em>/App_Config/Include</em> folder. Best you can do is to create patches with the configurations, then include them at the Web.config.</p>
<p><strong>Step by step</strong></p>
<ol>
<li>Add the LDAP connection settings to your ConnectionStrings.config:<br />
<blockquote><p>&lt;add name=&#8221;ManagersConnString&#8221; connectionString=&#8221;LDAP://yourldapserver.com:389/DC=your,DC=domain&#8221; /&gt;</p></blockquote>
</li>
<li>At your Web.config, find your <em>&lt;system.web&gt;</em> section and comment out your <em>&lt;membership&gt;</em>, <em>&lt;roleManager&gt;</em> and <em>&lt;profile&gt;</em> nodes &#8211; these will be all replaced by includes;</li>
<li>At the same level you commented out, add a &lt;machineKey&gt; node as covered at the official documentation:<br />
<blockquote><p>  &lt;machineKey validationKey=&#8221;BDDFE367CD36AAA81E195761BEFB073839549FF7B8E34E42C0DEA4600851B0065856B211719ADEFC76F3F3A556BC61A5FC8C9F28F958CB1D3BD8EF9518143DB6&#8243; decryptionKey=&#8221;0DAC68D020B8193DF0FCEE1BAF7A07B4B0D40DCD3E5BA90D&#8221; validation=&#8221;SHA1&#8243; /&gt;</p></blockquote>
</li>
<li>Still at this level let&#8217;s add three includes for Membership, RoleManager and Profile providers:<br />
<blockquote><p>&lt;!&#8211; Includes &#8211;&gt;<br />
&lt;membership configSource=&#8221;App_Config\AD\Membership.config&#8221; /&gt;<br />
&lt;roleManager configSource=&#8221;App_Config\AD\RoleManager.config&#8221; /&gt;<br />
&lt;profile configSource=&#8221;App_Config\AD\Profile.config&#8221; /&gt;</p></blockquote>
</li>
<li>As well as the three includes for disabling the module. We let it commented for now, which makes the module enabled:<br />
<blockquote><p>&lt;!&#8211;<br />
&lt;membership configSource=&#8221;App_Config\AD\Membership_Disabled.config&#8221; /&gt;<br />
&lt;roleManager configSource=&#8221;App_Config\AD\RoleManager_Disabled.config&#8221; /&gt;<br />
&lt;profile configSource=&#8221;App_Config\AD\Profile_Disabled.config&#8221; /&gt;<br />
&#8211;&gt;</p></blockquote>
</li>
<li>You have also to add your mapped domain(s) to <em>App_Config\Security\Domains.config</em>:<br />
<blockquote><p>&lt;domain name=&#8221;ad&#8221; ensureAnonymousUser=&#8221;false&#8221;/&gt;</p></blockquote>
</li>
<li>Now create a folder called &#8220;AD&#8221; at App_Config and drop the six config files that are zipped at this link:<br />
&#8211; <a href="http://blog.peplau.com.br/wp-content/uploads/AD-configs.rar">AD-configs</a> &#8211; Don&#8217;t forget to review all files (except the &#8220;_Disabled.config&#8221; that stores the native Sitecore configurations) to make sure you username, password and domains are corretly set!</li>
</ol>
<p>Now when you want to turn the module off you just have to comment out the lines from #4 and uncomment #5 &#8211; pretty easy.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/best-way-to-setup-active-directory-module-in-a-sitecore-solution/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How would you do it: 2 levels menu</title>
		<link>https://blog.peplau.com.br/how-would-you-do-2-levels-menu/</link>
		<comments>https://blog.peplau.com.br/how-would-you-do-2-levels-menu/#comments</comments>
		<pubDate>Mon, 09 Feb 2015 20:24:17 +0000</pubDate>
		<dc:creator><![CDATA[Rodrigo Peplau]]></dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[How To]]></category>

		<guid isPermaLink="false">http://blog.peplau.com.br/?p=57</guid>
		<description><![CDATA[<div class="lr_horizontal_share" data-share-url="https://blog.peplau.com.br/how-would-you-do-2-levels-menu/"></div>One of our clients has a development team that will take over the project as soon as we finish our part. They have great developers with no Sitecore experience, and some of their questions are pretty valuable for those starting in the Sitecore world. My answer that follows has a consultancy approach, providing explanations and advises at a higher level. [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>One of our clients has a development team that will take over the project as soon as we finish our part. They have great developers with no Sitecore experience, and some of their questions are pretty valuable for those starting in the Sitecore world. My answer that follows has a consultancy approach, providing explanations and advises at a higher level.</p>
<p>Here is the question:</p>
<blockquote><p>In Sitecore, how would you organize architecture and static files &#8211; mainly CSS and javascript files &#8211; during development of the following two levels menu?</p>
<p>The first level shows an Image and a Title and starts closed:<br />
<a href="http://blog.peplau.com.br/wp-content/uploads/Menu2l-closed.png"><img class=" wp-image-58 alignnone" src="http://blog.peplau.com.br/wp-content/uploads/Menu2l-closed.png" alt="Menu2l - closed" width="600" height="140" /></a></p>
<p>When the user hovers a block at Level 1, a second part is displayed showing items on Level 2:<a href="http://blog.peplau.com.br/wp-content/uploads/Menu2l-hover1.png"><img class=" wp-image-64 alignnone" src="http://blog.peplau.com.br/wp-content/uploads/Menu2l-hover1.png" alt="Menu2l - hover" width="600" height="421" /></a></p></blockquote>
<p><strong>Answer</strong></p>
<p>Your static CSS and Javascript files, like in any other web application, must be loaded somehow. At the project we are working, we have a <a href="https://msdn.microsoft.com/en-us/magazine/dn451436.aspx" target="_blank">bundle and minification</a> process in place, responsible for loading, minify&#8217;ing and caching the files so everything loads faster.</p>
<p>But you can load files the old way:</p>
<blockquote>
<pre>&lt;script src="myscript.js" type="text/javascript"&gt;&lt;/script&gt;</pre>
</blockquote>
<p>The implementation itself can be split into two different challenges:</p>
<ol>
<li><strong>Front-end development</strong><br />
We clearly have a good front-end work here, some dynamic behavior when user hovers around level 1, the look and feel and everything. Basically all HTML markup, javascript and css stylesheets can be prepared without having Sitecore specifically in mind;</li>
<li><strong>Back end development</strong><br />
All necessary to enable the content edition of menu items, and make it work dynamically at a page, including:</p>
<ul>
<li><strong>Step 1 -</strong> Upload your javascript and CSS files somewhere at your site filesystem (Eg: &#8220;<em>/assets/js</em>&#8221; and &#8220;<em>/assets/css</em>&#8220;), then load them somehow (traditional, bundle, etc);</li>
<li><strong>Step 2 -</strong> Define your data structure (templates and fields) to support the content management. It all depends on your requirements &#8211; let&#8217;s have the following two possible scenarios:
<ul>
<li><strong>Scenario 1 -</strong> You may want to feed the menu with pages and subpages you already have in your content tree. In this case you would just use your existing data:<br />
<a href="http://blog.peplau.com.br/wp-content/uploads/Menu-Tree.png"><img class=" size-full wp-image-68 alignnone" src="http://blog.peplau.com.br/wp-content/uploads/Menu-Tree.png" alt="Menu Tree" width="159" height="139" /></a></li>
<li><strong>Scenario 2 -</strong> Or you may be asked to create a dedicated data structure, not pages themselves but pointing to real pages. This data structure would have the following format:<br />
<strong>Menu Item Level 1</strong><br />
<a href="http://blog.peplau.com.br/wp-content/uploads/Sitecore-Template-Menu-Level-11.png"><img class="alignnone  wp-image-71" src="http://blog.peplau.com.br/wp-content/uploads/Sitecore-Template-Menu-Level-11.png" alt="Sitecore Template Menu Level 1" width="462" height="106" /></a><strong>Menu Item Level 2</strong><br />
<a href="http://blog.peplau.com.br/wp-content/uploads/Sitecore-Template-Menu-Level-21.png"><img class="alignnone  wp-image-72" src="http://blog.peplau.com.br/wp-content/uploads/Sitecore-Template-Menu-Level-21.png" alt="Sitecore Template Menu Level 2" width="463" height="130" /></a>And you would keep the item somewhere outside your page&#8217;s content tree:<br />
<a href="http://blog.peplau.com.br/wp-content/uploads/Menu-Tree-2.png"><img class="alignnone size-full wp-image-74" src="http://blog.peplau.com.br/wp-content/uploads/Menu-Tree-2.png" alt="Menu Tree 2" width="164" height="141" /></a></li>
</ul>
</li>
<li><strong>Step 3 -</strong> Create the component/sublayout that implements the menu feature. Following the same two scenarios above:
<ul>
<li><strong>Scenario 1 -</strong> In this case you would use the Sitecore API to pragmatically get the Home item, using Children items to render menu&#8217;s level 1, and their grandchildren rendering level 2:
<pre>var homeItem = Sitecore.Context.Database.GetItem("/sitecore/content/Home");
var levelOne = homeItem.Children.ToList();
foreach (var itemLevelOne in levelOne) {
   // This item represents a Level 1 menu block
   var title = itemLevelOne.Fields["Title"].Value;
   var image = itemLevelOne.Fields["Image"].Value;
   var levelTwo = itemLevelOne.Children.ToList();
   // ... do whatever you need with Level 1
   foreach (var itemLevelTwo in levelTwo) {
      // Here you work your Level 2 item
      var titleLevelTwo = itemLevelTwo.Fields["Title"].Value;
   }
}</pre>
</li>
<li><strong>Scenario 2 -</strong> This implementation would be very similar to the first scenario, except that you would have to start at your repository folder (Eg: <em>/sitecore/content/Lists/Menu</em>) instead of the Home item.</li>
</ul>
</li>
</ul>
</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>https://blog.peplau.com.br/how-would-you-do-2-levels-menu/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
