Thursday, December 18, 2014

Sitecore User Group (SUG) BELUX #3 - WFFM (The What, How, When and Why)

That is right,

our third User Group is comming !
Next year, on the 29th of January !

Short intro :

The SUG board members would like to welcome you to the third Sitecore User Group event (BeLux). This third session is meant as a mix of a both Developer and Product information on WFFM.

Webforms for marketers is the Form generation module offered by Sitecore. During the sessions we will explain the value of using the WFFM module for marketers, the flexibility it offers and the limitations the product has.

And to sweaten the deal, we'll go into detail on how you can work around the limitations, show the code that drives this and zoom in on what capabilities the module has.

Optionally, the differences between the versions of WFFM can be looked at in more detail as well as the roadmap from Sitecore on this module.

For the full agenda:
http://www.meetup.com/Sitecore-User-Group-Belgium/events/219021476/

Feel free to contact me with questions, or agenda requests !


Thursday, December 11, 2014

Sitecore bug solution: Media Library item Title meta info field not working

The problem

We have found that a number of Sitecore versions (at minimum up to 7.2) have a problem with defining the Title field (used for onhover's) of Media items such as images.
Even though Sitecore has a Title field on media library items (metadata), it is not rendered correctly. We tested this on multiple sitecore environments with these scenarios:

  • using the sc:image fieldrenderer
  • rich text field using an inclosed image from the media library

I opened up a ticket with Sitecore and they acknowledged the problem as a bug and will take this up with their patching and version releases.

In the meanwhile you can

As a workaround, you can do the following:

To resolve this issue in the <sc:image> XSL Extension Control

You can override the <processor type="Sitecore.Pipelines.RenderField.GetImageFieldValue, Sitecore.Kernel" /> processor in the <renderField> pipeline.

You should create your own class.
For example:

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class GetImageFieldValue
    {
        protected virtual ImageRenderer CreateRenderer()
        {
            return new ImageRenderer();
        }

        public void Process(RenderFieldArgs args)
        {
            if (args.FieldTypeKey == "image")
            {
                ImageRenderer renderer = this.CreateRenderer();
                renderer.Item = args.Item;
                renderer.FieldName = args.FieldName;
                renderer.FieldValue = args.FieldValue;
                renderer.Parameters = args.Parameters;
                //
                if (!args.Parameters.Keys.Contains("title"))
                {
                    Field innerField = args.Item.Fields[args.FieldName];
                    ImageField imageField = new ImageField(innerField, args.FieldValue);
                    if (imageField.MediaItem != null)
                        renderer.Parameters.Add("title", imageField.MediaItem.Fields["title"].Value);
                }
                //
                args.WebEditParameters.AddRange(args.Parameters);
                RenderFieldResult result = renderer.Render();
                args.Result.FirstPart = result.FirstPart;
                args.Result.LastPart = result.LastPart;
                args.DisableWebEditContentEditing = true;
                args.DisableWebEditFieldWrapping = true;
                args.WebEditClick = "return Sitecore.WebEdit.editControl($JavascriptParameters, 'webedit:chooseimage')";
            }
        }
    }


Build the solution and move the .dll file to the /Website/bin folder. 
Change the <processor type="Sitecore.Pipelines.RenderField.GetImageFieldValue, Sitecore.Kernel" /> processor.
 Example:
   <processor type="Namespace.YourProcessorClass, AssemblylName" />

To resolve this issue in the Rich Text field

You can override  <CodeBeside Type="Sitecore.Shell.Controls.RichTextEditor.InsertImage.InsertImageForm,Sitecore.Client"/>  in the InsertImage.xml file (Website\sitecore\shell\Controls\Rich Text Editor\InsertImage).
You should create your own class and inherit it from the Sitecore.Shell.Controls.RichTextEditor.InsertImage.InsertImageForm class.
Override the OnOk method.
Example:

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
protected override void OnOK(object sender, EventArgs args)
        {
            Assert.ArgumentNotNull(sender, "sender");
            Assert.ArgumentNotNull(args, "args");
            string str = this.Filename.Value;
            if (str.Length == 0)
            {
                SheerResponse.Alert("Select a media item.", new string[0]);
            }
            else
            {
                Item root = this.DataContext.GetRoot();
                if (root != null)
                {
                    Item rootItem = root.Database.GetRootItem();
                    if ((rootItem != null) && (root.ID != rootItem.ID))
                    {
                        str = FileUtil.MakePath(root.Paths.Path, str, '/');
                    }
                }
                MediaItem item = this.DataContext.GetItem(str);
                if (item == null)
                {
                    SheerResponse.Alert("The media item could not be found.", new string[0]);
                }
                else if (!(MediaManager.GetMedia(MediaUri.Parse((Item)item)) is ImageMedia))
                {
                    SheerResponse.Alert("The selected item is not an image. Select an image to continue.", new string[0]);
                }
                else
                {
                    MediaUrlOptions shellOptions = MediaUrlOptions.GetShellOptions();
                    string text = !string.IsNullOrEmpty(HttpContext.Current.Request.Form["AlternateText"]) ? HttpContext.Current.Request.Form["AlternateText"] : item.Alt;
                    Tag image = new Tag("img");
                    this.SetDimensions(item, shellOptions, image);
                    image.Add("Src", MediaManager.GetMediaUrl(item, shellOptions));
                    image.Add("Alt", StringUtil.EscapeQuote(text));
                    //
                    if (!string.IsNullOrEmpty(item.Title))
                        image.Add("Title", StringUtil.EscapeQuote(item.Title));
                    //
                    if (this.Mode == "webedit")
                    {
                        SheerResponse.SetDialogValue(StringUtil.EscapeJavascriptString(image.ToString()));
                        base.OnOK(sender, args);
                    }
                    else
                    {
                        SheerResponse.Eval("scClose(" + StringUtil.EscapeJavascriptString(image.ToString()) + ")");
                    }
                }
            }
        }

Also you should copy the SetDimensions method from the InsertImageForm class.
Example:

1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void SetDimensions(MediaItem item, MediaUrlOptions options, Tag image)
        {
            Assert.ArgumentNotNull(item, "item");
            Assert.ArgumentNotNull(options, "options");
            Assert.ArgumentNotNull(image, "image");
            NameValueCollection form = HttpContext.Current.Request.Form;
            if ((!string.IsNullOrEmpty(form["Width"]) && (form["Width"] != item.InnerItem["Width"])) && (form["Height"] != item.InnerItem["Height"]))
            {
                int num;
                int num2;
                if (int.TryParse(form["Width"], out num))
                {
                    options.Width = num;
                    image.Add("width", num.ToString());
                }
                if (int.TryParse(form["Height"], out num2))
                {
                    options.Height = num2;
                    image.Add("height", num2.ToString());
                }
            }
            else
            {
                image.Add("width", item.InnerItem["Width"]);
                image.Add("height", item.InnerItem["Height"]);
            }
        }

Build the solution and move the .dll file to the /Website/bin folder. Change <CodeBeside Type="Sitecore.Shell.Controls.RichTextEditor.InsertImage.InsertImageForm,Sitecore.Client"/> in the InsertImage.xml file.
 Example:
   <CodeBeside="Namespace.YourProcessorClass, AssemblylName" />

Hope this helps any of you who might currently be facing this problem !
And a big thanks to Support for acknowledging this problem !

Wednesday, December 10, 2014

Sitecore Hidden Gems: Admin Pages (based on Sitecore 8)

Introduction

This page is meant to provide insight into what tools are available in an ootb installation of Sitecore with regards to specific administrative tools decoupled from the actual Sitecore Content Management System.

* Update * - When you read through this document be sure to check out the update on more recent versions of Sitecore here: 
http://kverheire.blogspot.be/2016/02/sitecore-hidden-gems-updated-admin.html

These can obviously be expanded upon by installing additional modules and/or related tooling that creates new functionality in this Admin section.
The pages described below are made available under the webserver that provides access to the "/sitecore/admin" URL. In other words : "http://company.domain/sitecore/admin/tool.aspx".
Make sure that the aforementioned URL is protected and not accessible from the web or at least correctly shielded through authentication with Sitecore since a number of the tools described below can divulge information regarding the setup of your Sitecore environment and/or impact performance. Pre-Sitecore 6.6 versions did not have this ootb as you can now see on each of the pages:


The list

Every version of Sitecore comes with a slighty different list of available admin pages. To ensure the most up to date and correct listing I chose to use the Technical Preview of Sitecore 8 instance and the listing contained therein.


The admin pages - one by one

Since this list of admin pages provide significant features to developers and administrators it is important to keep them top of mind during any project. They provide quite the tool-set in investigating issues with running instances and can help you optimize your solution.

Since most of these pages have no implicit documentation and could therefore be perceived as obscure admin pages, we have listed each of these below in order to identify their purpose and where they can assist you throughout your implementation or maintenance.

Cache.aspx

Located at /sitecore/admin/cache.aspx, this page displays details about the configured cache settings as well as the current use. Measured and retrieved caches include database pre-fetch, data cache, item cache, HTML cache as well as specifically defined caches. This information can provide the needed insight into the cache levels during development / acceptance / load tests. It can give you information related to the relation between the current in-use cache levels and the defined maximum thresholds.Use of this page is vital when fine tuning and tweaking caching settings on your site. Latest versions of this page work under the password protected approach. However, when using an older version (<6.6) do please check this as it might display sensitive site information and expose site vulnerabilities as well as allowing any users to instantly clear the Sitecore caches.

The interface has two buttons : "Refresh" and "Clear All" - These should be pretty self-explanatory, but it is still mention-worthy that you best click refresh a number of times to get the correct results visualized.

I recommend using the https://marketplace.sitecore.net/en/Modules/Cache_Tuner.aspx DB Cache tuner to optimize your application.

DBBrowser.aspx

Located at /sitecore/admin/dbbrowser.aspx this page displays a shorthand view on the Sitecore databases and structure as well as the filesystem. The look and feel kind off related to the content tree / content editor interface but has clearly been brought down to basics.

This interface is mainly meant as a very quick responding insight tool that allows for cleanup and management of the content contained therein. Most of the basic functionalities related to pure content management are made available here.
However, features such as DMS, devices, layouts and so on are not manageable through this interface. This interface is quick to work with and does this (amongst other approaches) by only loading sub-items when parent items are selected.

FillDB.aspx

Located at /sitecore/admin/FillDB.aspx this page allows you to quickly create huge amounts of content based on a number of variables that are configurable in the tool. Fully configurable and disabled by default, this tool allows for automation through the creation of powershell scripts that allow you to define the needed variables and steps that are required to run. Initial setup requires all steps to run, after the initial setup only the last 3 steps are needed to be ran.
These are the following: 4) Clear site caches 5) Generate items 6) Rebuild Index(es).

More information on the updates to this tool that shipped with version 7.2 and onwards can be found here:
http://www.sitecore.net/Learn/Blogs/Technical-Blogs/Sitecore-7-Development-Team/Posts/2014/03/FillDb-Updates.aspx

LinqScratchPad.aspx

Located at /sitecore/admin/LinqScratchPad.aspx this page allows you to run LINQ queries against your indexes all within the browser!
Not only this but you can play around with different POCO's, settings and also test the performance of your queries out of the context of the entire running solution.
The tool can even inter-operate with snippets of code presented on Sitecore sites provided you have a local Sitecore 7 running (coupling through the instance-name).


More information on this tool can be found here:
http://www.sitecore.net/Learn/Blogs/Technical-Blogs/Sitecore-7-Development-Team/Posts/2013/05/Sitecore-7-LinqScratchPad.aspx

Login.aspx

Located at /sitecore/admin/Login.aspx this page serves as the default admin login form.
Unauthorized access into the admin pages or restricted pages on your website will redirect you here. Thank to the use of the query string parameter "returnUrl" it allows you to return after successful authentication.

MediaHash.aspx

Located at /sitecore/admin/Mediahash.aspx this page helps you generate a specificMedia URL that holds the value for the dynamic image scaling properties.
This functionalitiy appears to have become an integral part of the Sitecore product as every Media URL now holds a hash key. Little to no information is currently found on the use and restrictions of this hash key that is appended to the media item's URL.


Pipelines.aspx

Located at /sitecore/admin/Pipelines.aspx this page helps you gain more insight in the processes run on page requests and web site operation.
By default the Pipeline profiler is disabled since it has a performance impact when the CPU time and processor behavior is being measured.

After modifying the described files/setting in the configurations of your Sitecore instance the following page is presented after refreshing the Pipelines.aspx page:


This overview give a good insight into what pipelines are executed, how many times executions takes place and what the total execution time/percentage is and what the impact is on the servers CPU's.
Furthermore, a visual indication is given on the heavy hitters per pipeline section in the processing lifecycle, so the needed attention can be given during optimizing of the solution.

John West Blog post on the usage thereof: http://www.sitecore.net/Learn/Blogs/Technical-Blogs/John-West-Sitecore-Blog/Posts/2013/04/Sitecore-7-Pipeline-Profiling.aspx

RebuildReportingDB.aspx

Located at /sitecore/admin/RebuildReportingDB.aspx this page allows you to rebuild the Analytics reporting database since Sitecore 7.5

In order to minimize interruptions to reporting functionality, the rebuild reporting database process now works with a dedicated, secondary instance of the reporting database. When the rebuild process has finished, you then replace the primary reporting database with the secondary reporting database. Report rebuilding is performed using the new /sitecore/admin/RebuildReportingDB.aspx page. This replaced the Refresh Aggregated Data in Reports wizard.

Source: http://sdn.sitecore.net/Products/Sitecore%20V5/Sitecore%20CMS%207,-d-,5%20Preview/ReleaseNotes/Release%20History/Release%20History%20SC75.aspx

RemoveBrokenLinks.aspx

Located at /sitecore/admin/RemoveBrokenLinks.aspx this page is used to remove all broken links in your selected databases. This tool is especially valuable when content was re-structured, importe or cleaned up. The altered items can be serialized so that they can be restored on different instances if needed.


Restore.aspx

Located at /sitecore/admin/Restore.aspx this page helps you reset Archived content back to a specified database.
This admin tool feels somewhat needless and outdatedand does not adhere to the authentication and look&feel used in the other tools.


Serialization.aspx

Located at /sitecore/admin/Serialization.aspx this page helps you serialize database content into XML.
Serialization allows you to backup database content / place it into version control and create the basis for a version comparison. Just like when creating Sitecore packages, where content is serialized in the background, this is a direct interface to help serialize database content into flat files for further use. The tool also allows for either Serialization or updating of the Sitecore databases.


SetSACEndPoint.aspx

Located at /sitecore/admin/SetSACEndPoint.aspx this page allows you to change the Sitecore App Center endpoint. It is useful when playing whit Email Campaign Manager


ShowConfig.aspx

Located at /sitecore/admin/ShowConfig.aspx this page shows the compiled Sitecore config. Do keep in mind that this only shows you the content of the <sitecore> node and not the full web.config. A perfect way to see the culmination of all the configuration modifications in your project. Configuration modification are supported in Sitecore through custom .config files placed in the /App_Config/Include/ folder whereafter these files are merged in with the web.config.
Useful for checking the final settings during debugging when you are unsure whether your config files are being used. Especially make sure this page can not be accessed without the proper access rights since this contains sensitive configuration data.

John West information: http://sitecorejohn.wordpress.com/2010/03/11/tool-to-examine-sitecore-web-config-after-accounting-for-include-files/
Sitecore Marketplace module that uses this admin page: https://marketplace.sitecore.net/en/Modules/Detailed_Config_Report.aspx

Stats.aspx

Located at /sitecore/admin/Stats.aspx this page provides rendering statistics for all registered sites. Includes load times, cache sizes, etc.

This tool provides the necessary insight into what presentational components have been loaded for each site. It also provdes information on load time, amount of time it was loaded (and how many times the cache was hit), when it was last ran and so on.
Alongside with the showConfig, Pipelines and Cache pages, this page serves as a vital tool for fine tuning and tweaking of your solution.

Unlock_admin.aspx

Located at /sitecore/admin/Unlock_admin.aspx this page helps you unlock the locked-out admin account.
When the Administrator account would become locked out of the system due to for example too many invalid login attempts, this page can be used.
As a means of securing this page and functionality, the "Unlock Administrator" button is disabled by default, modify the ASPX to enable further functionality.


UpdateInstallationWizard.aspx

Located at /sitecore/admin/UpdateInstallationWizard.aspx this page allows you to update Sitecore using an update package.

This page is used for many update packages or other functionalities and should be well known to most Sitecore developers.

Saturday, December 6, 2014

ASP.NET and MVC / Let's combine with Sitecore

Ok,

I have been delaying this too long. It's time to get onto the bandwagon and join all you guys out there with MVC and Sitecore.

And since I recently heard a Sitecore representative say that Sitecore is embracing and enforcing the MVC approach I find it high time.

So, lets try to find all information I possibly can to make sure I get a good start on this.
First off, I found this information :

-          http://sitecore-community.github.io/docs/documentation/Sitecore%20MVC/index.html - Very up to date, thank you Martina Wehlander !
-          http://www.alen.me.uk/2012/08/learning-sitecore-mvc-part-1.html - Learning Sitecore MVC and the subsequent post 2,3,4 dates from 2012 though….
-          http://mhwelander.net/2014/05/28/posting-forms-in-sitecore-mvc-part-1-view-renderings/ - Posting forms (again : Martina Wehlander) – 2014
-          https://github.com/Sitecore-Community/sample-sitecore-mvc - more Martina Wehlander
-          http://www.hhogdev.com/blog/2012/august/sitecore-mvc-prototype-part1.aspx - Hedgehog mid/eind 2012 subsequent posts 2,3,4
-          http://www.sitecore.net/learn/blogs/best-practice-blogs/chris-van-de-steeg/posts/2012/03/sitecore-mvc.aspx - Sitecore MVC starter app – 2012 (outdated?)

Wondering if the above, combined with the information om the VirtualSummit will provide me with all the information I need to make this work flawlessly.

And let's hope all modules and products are able to do what I want to do through MVC as well...

-update- (!) Found the following KB article on Sitecore giving good insight on what modules and products can be used with Sitecore MVC approach: https://kb.sitecore.net/articles/522918/