Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
Experience Sitecore! | All posts tagged 'Sitecore-Improvements'

Experience Sitecore!

Martin Miles on Sitecore

Got a handy new tool for "finding ends" of presentation items - Rendering Chrome for Components

I have recently started working on a new project with a non-transparent structure. By saying non-transparent I mean non trivial locations for the code and non-matching layout and rendering items to their filesystem counterparts. So I was looking for the convenient way to identify matched pairs.

Luckily I remembered JammyKam presenting something similar at London UserGroup in January 2017 and refereed to his blog in order to find Rendering Chrome for Components package (module - ?). So I will briefly go through his solution show how it helped me and what it does:


  1. Install package as normal
  2. Add a namespace into web.config from /Views folder:
    <add namespace="ForwardSlash.SC.RenderingChrome.HtmlHelpers"></add>
    
  3. Append this to a containers element so that it generates an attribute:
    @Html.Sitecore().ContainerChrome()
  4. Now, if you go to Experience Editor and open View tab, you'll see a new checkbox Highlight Renderings clicking which turns all magic on


Here's the result:


    It works not only in Chrome, as you see I run it in firebug.

    Hope it will help you as much as it already has helped me.

    References:

    - original post by Kamruz Jaman

    - sources on GitHub

    - presentation slides from Sitecore User Group London (January 2017) - 3.5MB

    How to make Content Editor search by plain GUIDs without braces and dashes? (part 1)

    How many times while inspecting the code you've encountered something similar to:

    
    

    Of course, you've guessed that A50CC32DAC854E3D9FC3A6BFDE1C577E is nothing else but GUID of an item being modified for URL. And of course, in order to look up what this item is, you've pasted it into search box of Content Editor, as the easiest way to search. Content Editor in turn did not find anything as obviously that value isn't a properly formatted GUID. As a mature Sitecore developer, probably had to append braces and insert dashes in appropriate format, so that items becomes discoverable via search.

    To overcome this, I created animprovement module that will allow you search by both plain and properly formatted GUIDs.

    As for a starting point, I decided to find out what exactly happens after user submits value into a search box. Looking up ajax POST call to the backend suggested me that it should be a pipeline somewhere behind Content Editor application. Decompiling Sitecore.Kernel and Sitecore.Client prompted me to search pipeline, that is located at Sitecore.Pipelines.Search namespace of Sitecore.Kernel.

    The very first step of that pipeline is called IDResolver and does exactly what he is named for: resolves an item for a search term in case it is properly formatted GUID and exists in database. If not - it passed arguments further down the pipeline.

    So the idea is to create an extra processor after IDResolver that will do basically the same business but for search terms that are plain GUIDs. Okay, here's the code:

        public class SearchByPlainGuids
        {
            public void Process(SearchArgs args)
            {
                Assert.ArgumentNotNull((object)args, "args");
    
                if (string.IsNullOrWhiteSpace(args.TextQuery))
                    return;
    
                if (args.Type == SearchType.ContentEditor && IsPlainGuid(args.TextQuery))
                {
                    Item obj = args.Database.GetItem(new ID(MakeGuidQuery(args.TextQuery)));
                    if (obj != null)
                    {
                        SearchResult result = SearchResult.FromItem(obj);
                        args.Result.AddResultToCategory(result, Translate.Text("Direct Hit"));
                    }
                    args.AbortPipeline();
                }
            }
    
            private string MakeGuidQuery(string plainGuid)
            {
                return "{" + plainGuid.Substring(0, 8) + "-" + plainGuid.Substring(8, 4) + "-" + plainGuid.Substring(12, 4)
                       + "-" + plainGuid.Substring(16, 4) + "-" + plainGuid.Substring(20, 12) + "}";
            }
    
            private bool IsPlainGuid(string query)
            {
                string pattern = @"^[0-9a-fA-F]{8}[0-9a-fA-F]{4}[0-9a-fA-F]{4}[0-9a-fA-F]{4}[0-9a-fA-F]{12}$";
    
                Regex regex = new Regex(pattern);
    
                return regex.IsMatch(query);
            }
        }
    

    To make this code function, let's build that into a DLL and reference that DLL from config patch file located within include folder:

    
    
    
    
    
          
        
      
    
    
    

    Voila! Now you're able to search by item GUID regardless of its format.


    Please feel free to download ready-to-use package (5.7KB) for Sitecore 8.1 and 8.2 or source code (9.1KB).

    P.S. It all looks and works well, however what can be done better? First of all, we've modifies search pipeline, so our processor is called with every call of given pipeline. Next, we add extra DLL and extra config include file to reference that DLL. Wouldn't it better, if GUIDs were checked and modified right before entering that pipeline, ideally at the front-end? Let's try to make this function at part 2 of this story.

    Sitecore Improvements project

    I have done multiple Sitecore presentation and productivity improvements, so this time I decided to unite them all under the same umbrella in GitHub, and this blog post will go through all of them.


    1. Sitecore Style Adjustments

    2. Device Editors Shortcuts

    3. Layout Details Shortcuts

    4. Presentation Exists Gutter

    5. Publish Item Context Menu

    6. Publish Item Ribbon Icon

    7. Set Presentation Context Menu Icon


    Packages can be downloaded below:

    Sitecore 8.0 Style Adjustments-1.2.zip (29KB)
    Sitecore 8.1 Style Adjustments-1.2.zip (28.9KB)
    Device Editor Shortcuts 1.0.zip (8.6KB)
    Layout Details Shortcuts 1.1.zip (10.8KB)
    Presentation Exists Gutter 1.0.zip (12.7KB)
    Publish Item Context Menu-1.0.zip (11.1KB)
    Publish Item Ribbon Icon 1.0.zip (4.2KB)
    Set Presentation Context Menu Item 1.0.zip (11.4KB)

    Source code (and the docs / more packages) can be taken from project's GitHub page by the following link.

    Hope you find this helpful!


    Productivity Improvement: Device Editor showing datasource and previewing that right from a pop-up click

    After previous post on Layout Details dialog improvements, I decided to look even further and implement one more improvement that came into my head.

    Another dialog window, probably most important in Content Editor is missing couple things I just decided to fix. That is a case when a screenshot is better than hundred words, so here is it:


    What has been added is a datasource item path, immediately underneath rendering and placeholder. It is clickable in the same manner as from previous posts, immediately opening that (datasource) item for view and edit right in the popup window, that saves so much time!

    Additionally, rendering / sublayout name became also clickable with the same item preview popup effect.


    Download: please get the package and anti-package to revert changes. Source code is available at GitHub page by this link.

    Known minor issue: if open Control Properties dialog from Device Editor, and when you return back from that dialog - look-up links will not work and control will return to default behavior, so you may need to re-open Device Editor again.
    The reason for such a behavior is that on returning back, Sitecore runs a series of pipelines that eventually call original class from Sitecore.Client rather than the one we have overridden and referenced above. Fixing that requires patching original DLL and I highly wanted to avoid inclining into any original functionality (moreover, you are not likely allowed to do that by license)

    Productivity Improvement: Creating a Presentation Exists Gutter - get even faster access to item's Presentation Details

    Previously I have described how easily you can create a shortcut to Device Editor of Presentation Details right at the item's Context Menu - access that as much as in two clicks! But there's even easier (and more visual) way - create a specific Sitecore Gutter.
    So, what Gutters are? Gutters are sort of visual markers you can optionally enable / disable in your Content Editor. Have you seen a vertical bar, immediately left hand side from Sitecore tree? That is a Gutters Area and once you do right click on it - you may enable / disable some gutters already installed. Also, gutters can be clickable, and on click handler you may also call Sitecore commands, so why not to call our familiar item:setlayoutdetails that opens Device Editor dialog for corresponding item?

    So, let's create our own gutter. Every gutter is configured within core database under /sitecore/content/Applications/Content Editor/Gutters folder. We are going to create a new item called ... derived from /sitecore/templates/Sitecore Client/Content editor/Gutter Renderer template (all gutters derive from that one). There are only two fields we need to set there - Header which is just a gutter name and Type - fully qualified class name:

    So now let's implement PresentationExists class. Briefly, every gutter derives from GutterRenderer class which returns GutterIconDescriptor object when gutter should be shown next to corresponded item otherwise just null. Implementation below checks whether current item has a Layout associated, and if yes - it returns a GutterIconDescriptor with a item:setlayoutdetails command for that item.
    public class PresentationExists : GutterRenderer
    {
        protected override GutterIconDescriptor GetIconDescriptor(Item item)
        {
            if (item != null)
            {
                var layoutField = item.Fields[Sitecore.FieldIDs.LayoutField];
                var layoutDefinition = LayoutDefinition.Parse(LayoutField.GetFieldValue(layoutField));
    
                if (layoutDefinition != null && layoutDefinition.Devices.Count > 0)
                {
                    GutterIconDescriptor gutterIconDescriptor = new GutterIconDescriptor
                    {
                        Icon = "Applications/32x32/window_colors.png",
                        Tooltip = Translate.Text("Presentation is set for this item.")
                    };
    
                    if (item.Access.CanWrite() && !item.Appearance.ReadOnly)
                    {
                        gutterIconDescriptor.Click = string.Format("item:setlayoutdetails(id={0})", item.ID);
                    }
                    return gutterIconDescriptor;
                }
            }
    
            return null;
        }
    }
    
    So as soon as you compile and place resulting DLL under <web_root>\bin folder, your gutter wil work like below:

    Clicking that icon will immediately show Device Editor dialog. Job's done!

    Downloads: you can access source code at Sitecore Improvements project GitHub page, or you can download ready-to-use package by this link.

    Please note: improperly implemented gutters may affect performance of Content Editor, as the code above runs for each item. So please be extremely attentive on what you're doing within GetIconDescriptor() method.