Skip to Content

Sitecore Page Editor Tips and tricks – component datasource versions part 2

Written on July 14, 2014 at 13:35, by

In my previous post I built a rule that would hide a component based on some criterias regarding the datasource item. In the Page Editor these hidden component would show as grey blocks which is nice since you get a clear indication that there’s a component and that it isn’t translated. But now what? A natural next step would be to be able to add a version of that component to be able to translate it.

My main idea was to add a button to the component in the page editor, visible when the component was greyed out. When clicked would add a version in the current language of the related item.

As I didn’t realy know if things would work or not, my approach was kind of touch and go. My first goal was to add a button when the component was hidden (greyed out). On a rendering you can add additional buttons visible for that component when in the Page Editor using the Page Editor Buttons. However once a rendering is hidden it will be switched in the Page Editor to another rendering and all the configured Page Editor Buttons would disappear. You could probably add buttons to the Hidden Rendering which will replace the original rendering, but I didn’t have that in mind at the time :)

I went with adding a Default Rendering Button, which is located here in the Core database /sitecore/content/Applications/WebEdit/Default Rendering Buttons/. This is where all default buttons for a component is located such as the Edit Related item, Change Position and so on. So I created a button.add-version-button

Then I created a class inheriting the WebEditCommand. I didn’t know what to expect when the button executed the command. If I would get the datasouce item out of the box or if I would have to manually find it in some way. But it turned out to be quit easy. If the rendering had no datasource configured the CommandContext object passed to the command would give the current item and if the datasource was set it would pass that item instead. Since this was a default rendering button, it would be visible for all renderings all the time. So I had to override the QueryState and write my own to hide the button if the item had a version. Below is the resulting command:

public class AddDatasourceVersion : WebEditCommand
    {
        public override void Execute(CommandContext context)
        {
            Assert.ArgumentNotNull((object)context, "context");
            Item obj = context.Items[0];
            if (obj.Versions.Count > 0) return;
            using (new SecurityDisabler())
            {
                obj.Versions.AddVersion();
            }
        }
        public override CommandState QueryState(CommandContext context)
        {
            Assert.ArgumentNotNull((object)context, "context");
            Item obj = context.Items[0];
            return obj.Versions.Count > 0 ? CommandState.Hidden : CommandState.Enabled;

        }
    }

A command was defined and configured for the button, I went with:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore>
    <commands>      
      <command name="custom:adddatasourceversion" type="Lab.Sample.Commands.WebEdit.AddDatasourceVersion,Lab.Sample"/>
    </commands>
  </sitecore>
</configuration>

A recommendation though! For best user experience, use Standard Values with prefilled dummy data, because it can be hard to find the component once a version has been added if there is no content or any obvious graphical elements ;)

Sitecore Page Editor Tips and tricks – component datasource versions

Written on July 11, 2014 at 15:35, by

Out of the box, Sitecore does nothing if a components datasouce doesn’t exist or if there aren’t any versions in the current language. This means that you will have to handle this your self.
Well I thought that it would be nice to let the rules engine in Sitecore handle this.

My plan was to create a global conditional rendering rule that would check the following criterias:

  • Is the Rendering Item of the current rendering configured with a Datasource Template?
  • If not, ignore the following statements and display the rendering!
  • Does the rendering have any datasource set?
  • Does the datasource exist?
  • If the datasource item is a media item, the next statement should be ignored and the rendering displayed.
  • Does it have any versions in the current language?

If it would fail on any of these statement, the rendering should be hidden. Since there weren’t any existing condition which did this, I had to build it my self. Things said and done and the result was this:

public class HasItemVersionForDatasource : OperatorCondition
      where T : ConditionalRenderingsRuleContext
    {
        protected override bool Execute(T ruleContext)
        {
            var renderingItem = ruleContext.Item.Database.GetItem(ruleContext.Reference.RenderingID);
            var dsLocation = renderingItem.Fields["Datasource Location"].Value;
            var dsTemplate = renderingItem.Fields["Datasource Template"].Value;
            if ((dsLocation.Length &gt; 0 || dsTemplate.Length &gt; 0) &amp;&amp; string.IsNullOrEmpty(ruleContext.Reference.Settings.DataSource)) return false;
            else if (string.IsNullOrEmpty(ruleContext.Reference.Settings.DataSource)) return true;

            var datasourceitem = ruleContext.Item.Database.GetItem(ruleContext.Reference.Settings.DataSource);
            return datasourceitem.Paths.IsMediaItem || datasourceitem.Versions.Count &gt; 0;
        }
    }

This condition was added to Sitecore and enabled for the Conditional Rendering Rules. Since the condition doesn’t take any parameters you can write anything you like, I went with “where the renderings datasource has item version”.
A new rule at /sitecore/system/Settings/Rules/Conditional Renderings/Global Rules was created using the new condition looking like this:

global-conditional-rendering-rule

With this now set up, all renderings with a datasource which doesn’t have any version in the current language will be hidden. And in the Page Editor they will be visible as grey blocks like this:

hidden-components

That’s it, pretty usefull right? :D Now you’ll be relieved from performing null-checks and so on in each component. And also you will get a clear indication in the Page Editor that there are components that aren’t translated.

Note that this only handles guid and path based datasources and not query based datasources. However it could surely be extended.

I will follow up with some additional post regarding Page Editor tips and tricks :D

 

Page editor and structuring related items

Written on April 28, 2014 at 07:39, by

Since Sitecore 6.4.1 I’ve been working alot with the Page Editor in Sitecore and how to make the editor experience as good as possible. I’ve found that it’s hard to keep the editor mainly editing in the Page Editor due to various limitations. One of those are structure.

My latest Sitecore solution, using Sitecore 7.1, utilizes the designer in the Page Editor to it’s full potential where I allow the editor to completely reorganize the content the way they see fit using rows, columns and blocks. As you can imagine this puts a higher demand on structure as one page can consist of several sub layouts which each have it’s own item and then add up that you have loads of pages constructed this way.

Idealy the editor could manage the structure at the same time as he/she is adding the content to the page in the page editor. However this is not possible out of the box in Sitecore.

Many of you might at this time say Item Buckets. However this requires the editor to search for the content and my experience with our customers is that many of them aren’t ready for this because they like to manage their own structure.

Well the solution to my problem ended up being quit simple. All I wanted was to have the context menu you have in the content editor. I also remebered that this context menu was available in the media browser when selecting media, so I started out looking there.

I found this attribute on the TreeviewEx in the media browser xml file (\sitecore\shell\Applications\Media\MediaBrowser\MediaBrowser.xml):

ContextMenu='Treeview.GetContextMenu("contextmenu")'

I made a copy of the SelectRenderingDatasource.xml (\sitecore\shell\Applications\Dialogs\SelectRenderingDatasource\SelectRenderingDatasource.xml) file to put in the override folder and added that attribute to the TreeviewEx in that file and the Context Menu was there. However it ended up opening a little off as you can see in this video http://screencast.com/t/FkwhxHcM. So I had to make some adjustments to the code opening the context menu.

I ended up altering the attribute to this:

ContextMenu='Treeview.GetContextMenu("dialoguemenu")'

And make the following changes to the \sitecore\shell\Controls\Browser.js, I replaced this part:

if (dimensions.width &gt; 0) {
	switch (data.where) {
		case "contextmenu":
			x = evt.pageX || evt.x;
			y = evt.pageY || evt.y;
		break;

With this:

if (dimensions.width &gt; 0) {
	switch (data.where) {
		case "contextmenu":
		case "dialoguemenu":
			x = evt.pageX || evt.x;
			y = evt.pageY || evt.y;
		break;

And wrapped this part:

var vp = ctl.viewportOffset();
x += vp.left;
y += vp.top;

With this if case:

if (data.where != "dialoguemenu") {
	var vp = ctl.viewportOffset();
	x += vp.left;
	y += vp.top;
}

This made the context menu pop up where the mouse was when right clicking.

I know this might not be the optimal solution. I would prefer that you could configure the rendering with a folder template like you do with a datasource template which you could have a dedicated button for like the “Create new content” button and not relying on a context menu. This would increase the experience with the Page Editor it think. Unfortunatly I didn’t have more time to look into this, maybe next time :)

Global Conditional Rendering rules with Sitecore MVC

Written on January 22, 2014 at 23:39, by

So I was playing around the other day with Sitecore MVC and some View Renderings. As I’m more familiar with Web Forms than MVC I started asking my self how I translate some thing I do in Web Forms to MVC like for example how would I go about hiding a view rendering. In Web Forms with Sub Layouts it’s easily done by changing visiblity like:

this.Visible = false;

So for example if the Item that the datasource would point to, didn’t have any published version in the current language, I could just hide it using that small piece of code.

Now how would I go about doing this with MVC. The only solution I found what to used jquery to hide the rendering which wasn’t good enough. So I started looking at the rules engine and conditional renderings and found that you can define global conditional rendering rules. However only with Web Forms and not MVC. According to documentation global conditional rendering rules does not work with MVC, no reason why, it just don’t… or does it?

Weeeeeell, regular conditional rendering works with MVC. So wouldn’t it be possible to extend this to include the global rules as well? After some fiddling with dotPeak on Sitecore assemblies it was quite easy to implement.

Looking at how it was done for Web Forms in Sitecore.Pipelines.InsertRenderings.Processors.EvaluateConditions which is run for every rendering when using Web Forms. And also investigate where and when Sitecore handled conditional renderings for MVC. It was quite straight forward to implement a processor processor that would evaluate the global conditional rendering rules for the MVC renderings.

Once I was done with the processor I implemented a condition that used the ConditionalRenderingsRuleContext and check if the datasource of the rendering had any versions published in the current language. Just to see of I could hide all renderings with a datasource pointing at items with no version. Guess what… worked like a charm.

You can find the source code here

Please do comment other ways to hide renderings in MVC :)

Bulk Change Template module

Written on September 2, 2013 at 08:05, by

I’ve recently developed a module for Sitecore that allows for changing templates in bulk inside Sitecore. Reason for the module was that I was doing some changes in an existing Sitecore solution where I was facing having to change templates on a quit massive structure of items. Doing this manually would have taken forever and what’s the fun in just creating a temporary script doing this for me. So I decided to create a module that I could reuse.

My requirements were that I should be able to:

  • Select a collection of Items to go through, in this case a root Item.
  • Select a template to search for that could be replaced
  • Select a template that should replace the other template
  • Copy data from fields to others when for example a field would be removed during the change process.

With this in mind I started digging through Sitecore. I have previously created several XmlControls that opens up in dialogues with wizards. However I was facing another problem here. Depending on how many Items where found and how many fields were to be copied, the process could take a while. Thus I needed to find out how to create a “progess bar” the Sitecore way.

After some digging around in the Publishing wizard I found that the Publishing framework was using the JobManager which returned a Handle with which you could send progress status through.

With all this I had everything I needed and got to work. Since the module contains a lot of code I won’t go in to detail on it, but I will link to the source code at the bottom.

Basically it consist of three parts. The command which opens the form in a dialog. The form where you select the root item and the template to find and the template to replace it with, and finally starts the Job. And the Handler which is run using the JobManager and processes everything.

Below are some screenshots and here is the source :) and! Bulk Template Changer-1.1

Edit: There was a small bug which made the field value copy process to fail when using IE, the links above have been updated with new package and source :)

This is my first actual package that I’ve shared with others, so if you find anything that should be done differently, please contact me :) I will post the package on Sitecore Marketplace as well.

2012-11-19_1 2012-11-19_2 2012-11-19_3 2012-11-19_42012-11-19_5 2012-11-19_6 2012-11-19_7