October 13, 2010

Setting and Customizing the Rich Text Field Editor

When it rains it pours… I’ve been so busy that I haven’t had a chance to update this as much as I’d like! However, here’s a little tidbit that I struggled with before learning the better way of doing it through Sitecore training: how to make the rich text editor a bit snazzier!

This is well documented in the Sitecore documentation and elsewhere, but I always forget where so this post is definitely for my own benefit (and anyone else like me who doesn’t know where to look right away).

There are two ways of changing around the rich text editor that I’ll cover, I’ll start with the easier one:

1. Setting the source property for the rich text field on your template

templatesource

I was pretty thrilled to learn this, just go into your content editor or template manager, open up the template with the rich text field that you want to set this for and choose one of the following options as the source (in italics).

Rich Text Default:

/sitecore/system/Settings/Html Editor Profiles/Rich Text Default

This is the default (shocking!) and the control portion looks like the following:rtdefault

Rich Text Full:

/sitecore/system/Settings/Html Editor Profiles/Rich Text Full

This is a much more filled out editor shown below:

rtfull

Rich Text Medium:

/sitecore/system/Settings/Html Editor Profiles/Rich Text Medium

This is the middle of the road editor, more than just the default and less than the Full version.

rtmedium

Our next method of changing the rich text editor comes about when the above (or the ones not listed: IDE, Mail) do not meet your needs, or if they Almost do but need to be adjusted.

2. Modifying the default rich text editor

To do this you need to switch to the Core Database – at the bottom right in Desktop view is a little grey icon: click that and choose Core from the popup.

Once the screen refreshes open up the Content Editor and we need to browse to the HTML Editor Profiles (the paths above are where we are going). If you want to change the properties of the default editor for all rich text fields Copy the Rich Text Default and rename it (just in case!) and then you can pick and choose items from the other Profiles – just copy them over to the Rich Text Default item.

rtfull-folder As seen on the left there are a number of folders and then sets of toolbars: the toolbars are where the magic is at and the folders contain data that can be displayed and modified.

For example, you can change the inline styles that are available by selecting the inline style item, and then changing the children (or adding new children for your own custom styles).

If you wanted to add Inline styles to your Rich Text Default you can do the following: make sure to copy the Inline Styles folder to Rich Text Default, and then make sure to add the drop down option for css (called Css Class in Toolbar 3 from Full) to the toolbar in Rich Text Default.

Each toolbar is separated by a solid line around it or displayed on a new row on the edit screen and you can add, copy, modify or rearrange items as you wish like any other set of items. They can be deleted as well, so it’s always a good idea to keep a copy of the profile you’re editing if something goes wrong.

I hope that helps anyone else who has wanted to make changes to the default rich text editor and wasn’t sure where to begin!

September 16, 2010

Custom Error Pages

whoops

One of the important steps of any website is setting it up to fail Nicely. Sitecore has done a lot of this for us with their error pages, but that may not be the look you want your visitors to see! And what if Sitecore isn’t able to help at all? Not so pretty with ASP.NET error pages…

But do not fear! With the configuration files Sitecore makes available, this is a snap to set up and fix.***

***You Will need to change the web.config file, so please back it up before making any changes suggested here!

The first and hardest step – make your error/not found pages that you want your visitors to see – these can be html pages, aspx pages, or even an existing page within Sitecore.

Quick Edit!-- As a commenter pointed out: using Sitecore pages for your 404/page not found type errors can allow you to make use of the Sitecore features for multilingual sites as well as analytics. Not to mention, it makes it very easy for business users to make the changes.

Usually Sitecore will handle your errors nicely, but if .NET explodes you will need to display something to the user that will Not fail, so I’d VERY STRONGLY recommend an html page for errors and not aspx pages: if there’s an error in the error page, you’re back to square one.

Upload these files to your Website directory or a subfolder within it – for our example we have saved the files in Website/ErrorPages/.

If you’re using Sitecore Items, set those up within your content tree and publish them (somewhere other than where your html error page resides to keep things simple).

Now for the magic: In the website folder is a folder called App_Config and inside that is the Include folder. This folder automagically updates the web.config with new settings – it doesn’t require anything to be restarted and immediately takes effect. Also – using these files instead of modifying the web.config directly means you can make web.config type changes in packages without completely destroying the site.

There should be a file in that directory called: SitecoreSettings.config.example

This is what we will be changing into SitecoreSettings.config and adding our custom ‘not found’ page details.

Currently the file looks like this, along with some comments describing the use of the file at the top:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<
sitecore>
<
settings>
<!--
REQUIRE LOCK BEFORE EDITING
If true, the user must have a lock on a document before
he can edit it, otherwise it is always ready for editing
-->
<
setting name="RequireLockBeforeEditing" value="false"/>

</
settings>
</
sitecore>
</
configuration>

We are going to erase this, and put in the following:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
<
sitecore>
<
settings>
<
setting name="ItemNotFoundUrl">
<
patch:attribute name="value">/ErrorPages/404.html</patch:attribute>
</
setting>
<
setting name="LinkItemNotFoundUrl">
<
patch:attribute name="value">/ErrorPages/404.html</patch:attribute>
</
setting>
<
setting name="LayoutNotFoundUrl">
<
patch:attribute name="value">/ErrorPages/404.html</patch:attribute>
</
setting>
<
setting name="ErrorPage">
<
patch:attribute name="value">/ErrorPages/Error.html</patch:attribute>
</
setting>
</
settings>
</
sitecore>
</
configuration>

The above basically tells the web.config file to update the specified settings with our new and improved values.

You can choose other files to use or have different files for each – and these special pages do not stop any logging from happening on the server – they simply give a better experience for your users when your site is having some trouble. 

ItemNotFoundUrl and LinkItemNotFoundUrl will come up when a visitor tries to access an item that doesn’t exist or hasn’t been published (it doesn’t exist yet on the web database). This replaces the default value of: /sitecore/service/notfound.aspx with our own /ErrorPages/404.html

You’ll notice that the default is pulling from /sitecore/service ß if you have blocked this directory or don’t have it available, you will need to make the changes above so that users see Some kind of page instead of a browser default.

LayoutNotFoundUrl will come up when the user tries to visit an item that does exist, but no layouts have been assigned to the item so Sitecore doesn’t know what to display for the user. This replaces /sitecore/service/nolayout.aspx in the default web.config file.

ErrorPage should come up whenever there is a generic error within Sitecore – the default setting we are overwriting is: /sitecore/service/error.aspx

Save your new file without the .example extension and you should now see your custom error pages whenever you try to access missing items!

The next step is the change to the web.config for handling errors when sitecore can’t handle them for us – save a backup of your web.config and then open it up in an editor.

Here is what we are looking for:

<!--  CUSTOM ERROR MESSAGES
Set customError mode values to control the display of user-friendly
error messages to users instead of error details (including a stack trace):

"On" Always display custom (friendly) messages
"Off" Always display detailed ASP.NET error information.
"RemoteOnly" Display custom (friendly) messages only to users not running
on the local Web server. This setting is recommended for security purposes, so
that you do not display application detail information to remote clients.
-->
<
customErrors mode="On" />

Search for customErrors to find it quickly. It may also have one of the above settings, RemoteOnly or Off. I would recommend On or RemoteOnly if you won’t have visitors accessing the site locally.

We want to change the setting to also include a redirect to our new Error page:

<customErrors mode="RemoteOnly" defaultRedirect="/ErrorPages/Error.html"/>

Now, if anything serious should happen, your users will not end up seeing an ASP.NET error page telling them it is broken and will instead get to see a page of your choice! This should Not point to a page you have in Sitecore since it will not work in the case of ASP.NET failing.

Anyone have any tips on making the user experience better in the case of errors?

September 1, 2010

Sitecore Training: Sitecore 6.2 .net Developer Series Experiences

128739161_5a5c4eaf3d_z

At the beginning of August, I was able to go out to Mill Valley, CA for the .net developer series training at Sitecore USA Headquarters. The course was 4 days of Sitecore goodness, with a certification and a day of hands-on building with Sitecore. Once I found out I would be heading to training, I spent a fair bit of time trying to find out what it would be like and searched for details of the certification without much luck. So for those out there who want to know a little bit more before you’re in the thick of things, here is what happened for me!

The quick and dirty description, for those who want to avoid the wall of text: I’d say this training is a must for any developer switching over to Sitecore – without it, it can be really hard to get the whole picture of the product and really see what it is capable of. Even for those of us who had been using Sitecore for a bit before training (there were a number of us in the class), it was very useful to see how to do things the ‘Sitecore way’ and to learn a few things that are just not available through searching alone. The Fundamentals day will introduce you to what Sitecore is all about and why you should be so excited to use it – it will also show you how to begin using it as a developer or user. The two developer days will give you a good background for doing most tasks that will be requested from clients, and the day of prototyping will give some hands-on practice in doing just that. Also, certification will grant you access to other areas of SDN and the ability to request support through them for the product. It’s also part of your company becoming a Sitecore Partner.

So... here are my experiences, from beginning to end... after the cut!

August 24, 2010

Saving Images for the Web in Photoshop

Recently we ran into a problem where we had uploaded some images and they were using CMYK – which will not work on some browsers and can result in images not being shown or displaying as broken. To avoid this you can easily save your images in a format that is more ideal for the web (RGB).

To do this in Photoshop (CS4 shown, it’s similar for other versions) just do the following:

1. Open your original file, adjust according to your needs.

2. When ready, click File -> Save for Web and Devices

clip_image001

3. When that comes up, make sure the checkbox to convert to sRGB is checked and it is in the format you desire (small note: PNG files will not work properly in IE6).

SaveForSettings

4. Click Save!

You now have an image that will work properly!

A Simple Site Map

Similar to creating a menu – creating a site map is even easier, there are modules that can do this but with a little preparation it can be very easy to create yourself.

To start we are assuming every template used for the pages includes some ‘base template’ for common aspects for all pages.

To do this, create (or select if already created) the Base Template with the information you want to have and to that base template, add:

InSiteMap: Checkbox

Then create or modify the Page templates with the other information you want. From those templates, click to the Content tab, and select the Base template to be included:

sitecoretemplatecontent

In the Standard values for the base template, you may want to have InSiteMap checked so that it will be on by default for all the pages.

For the sitemap itself, we’re going to create a rendering and then we can place it wherever we would like.

The rendering creates a basic nested list of all the items that have InSiteMap checked.

<xsl:template match="*" mode="main">
<
ul>
<
li>
<
sc:link select="$home">
Home
</sc:link>
<
xsl:variable name="hasSubItems" select="$home/item[sc:fld('InSiteMap',.) = '1']"/>
<
xsl:if test="$hasSubItems">
<
xsl:call-template name="subitems">
<
xsl:with-param name="itemparent" select="$home" />
</
xsl:call-template>
</
xsl:if>

</
li>
</
ul>
</
xsl:template>

<
xsl:template name="subitems">
<
xsl:param name="itemparent" />
<
ul>
<
xsl:for-each select="$itemparent/item[sc:fld('InSiteMap',.) = '1']">
<
li>
<
sc:link>
<
sc:text field="Page Title" />
</
sc:link>
</
li>
<
xsl:variable name="hasSubItems" select="item[sc:fld('InSiteMap',.) = '1']"/>
<
xsl:if test="$hasSubItems">
<
xsl:call-template name="subitems">
<
xsl:with-param name="itemparent" select="." />
</
xsl:call-template>
</
xsl:if>
</
xsl:for-each>
</
ul>
</
xsl:template>

Above we list the link to the home item in an unordered list:

 <sc:link select="$home">
Home
</sc:link>

<sc:link> with no parameters will link to the current item that is being processed by the xslt file – if not specified by any settings this will default to the page that the rendering is on. Since the current page is Not actually the home page, we are choosing to use $home as the source for the link (if the source for the link was actually in a field in the item you’d used field=”field name”).


Moving on, if there are any items under home that are listed as ‘InSiteMap’ it will call our template named subitems and pass the value for the parent of the item.

        <xsl:variable  name="hasSubItems" select="$home/item[sc:fld('InSiteMap',.) = '1']"/>
<
xsl:if test="$hasSubItems">
<
xsl:call-template name="subitems">
<
xsl:with-param name="itemparent" select="$home" />
</
xsl:call-template>
</
xsl:if>

Here the variable hasSubItems is created and the value for this is determined by any items within $home containing the field InSiteMap being checked (=’1’ – unchecked would be =’0’).


If we have any items that will be in the sitemap under $home, we call our template.


Within the template, we create a new unordered list, and then go through each item which will be listed in the site map and display a link using the ‘Page Title’ (this is any field that we want to have displayed to represent the item). We then check to see if we have any subitems to display and run the template again! With a bit of recursion, we head through all the items on the site as long as they and their parents have InSiteMap checked.


All that is left is adding the rendering to a page to be seen, and it will display a nested list of the pages on the site to be styled as needed!


Alternately, instead of checking for a selected checkbox, it could run through all pages with a specific template(or selection of templates) if you did not need to worry about excluding any specific pages that are using it.

External and Internal Links as Items

I ran into a problem creating the navigation for the footer rendering on a page – On there I needed to have links to the following pages: terms, contact, careers, and the sitemap. The problem arose when trying to add ‘Contact’ and ‘Careers’: ‘Contact’ was a few levels down in the tree of content items and ‘Careers’ was an external page. Initially, I had a checkbox in the template of each page for if the item was in the footer (ie: InFooterNav checked) and then the XSLT file would go through the entire list of items to find what would be in the footer navigation. It wasn’t an ideal solution when so few items had the tag in the entire site and it did not help with my external link at all. Thus was born: The Link Template!

The new template basically consisted of:

Link Data:

  • Link: General Link //This is the link to our item or the URL for the external page
  • Nav Title: Single Line Text //The title we want to have displayed in our menu – this is the same as in my regular items
  • Target: Single Line Text (or a drop down list) //The target if we want to open the page in a new window – **this can be skipped since general link has this option 

Properties:

  • InFooterNav: Checkbox //Just a checkbox to see if this link is going to be in our footer, this is the same as regular items.

Within the Standard Values I assigned a new layout for the items with the following code within:

<% Sitecore.Data.Items.Item item = Sitecore.Context.Item; 
Response.Redirect(((Sitecore.Data.Fields.LinkField)item.Fields["Link"]).Url); %>

The above redirects the user to whatever URL was provided within the “Link” field.


I then created a bunch of items with the appropriate links in the folder where other footer only type items also lived – for our example let us say “/sitecore/content/Home/Footer/”


To retrieve my footer items I now only had to check that folder and not search the entire site to actually see if the box is checked.


And a little more useful - using this template, I could put a link to any external page under any item – allowing me to have external links within my navigation such as Careers.


The above layout will work fine for my footer, but what if you wanted links to open in other windows? Or didn’t want to take the extra step of creating a layout? The rendering can be changed to make use of our new template:

    <ul>
<
xsl:for-each select="$home/Footer/item[sc:fld('InFooterNav',.) = '1']">
<
li>
<
xsl:choose>
<
xsl:when test="@template = 'link template'">
<
xsl:variable name="linkTarget" select="sc:fld('Target',.)" />
<
sc:link field="Link" target="{$linkTarget}" >
<
sc:text field="Nav Title" />
</
sc:link>
</
xsl:when>
<
xsl:otherwise>
<
sc:link>
<
sc:text field="Nav Title" />
</
sc:link>
</
xsl:otherwise>
</
xsl:choose>
</
li>
</
xsl:for-each>
</
ul>


Above we have a choose statement to determine if this is using the new link template or not (called “Link Template” but listed in lowercase):

<xsl:when test="@template = 'link template'">

Then we create a variable for our target and create the link based on our General Link field called “Link” by specifying it for field:

<xsl:variable name="linkTarget" select="sc:fld('Target',.)" />
<
sc:link field="Link" target="{$linkTarget}" >
<
sc:text field="Nav Title" />
</
sc:link>

Otherwise if it is a normal item in the tree, we give it a normal link and continue to the next item!

<xsl:otherwise>
<
sc:link>
<
sc:text field="Nav Title" />
</
sc:link>
</
xsl:otherwise>

** General Links can specify the target for you so a lot of the above isn’t necessary as long as you’re using sc:link!

A Simple Single Level Menu with Rounded Edges

After taking some time to figure this out, I thought I’d share my approach to a simple single level menu rendering with rounded edges. Initially, the idea here is very straight forward – create a list, style it, voila! Unfortunately, Round edges and dynamic content make it a little less forgiving.

Here is an Example of what we are trying to achieve:

menubar

Each of these items would be a sub item in the site, all at the same level  under ‘/Sitecore/Content/Site’

In our XSLT  rendering we need to grab the list, and apply the appropriate styles to the appropriate items, notably: The first item needs to have a round corner on the left, the Last item needs to have a round corner on the right, and the inner items need to have borders around them all – and we need to be able to Hover for a different effect.

To do this I did the following:

<xsl:template match="*" mode="main">
<
ul id="MainNav">
<
xsl:for-each select="$SiteContent/item[sc:fld('InTopNav',.) = '1']">
<
xsl:variable name="EdgeClass">
<
xsl:if test="position()='1'">FirstItem</xsl:if>
<
xsl:if test="position() = last()">LastItem</xsl:if>
</
xsl:variable>
<
xsl:if test="position() = last()">
<
li class="preLastItem">
<
span>.</span>
</
li>
</
xsl:if>
<
li class="{$EdgeClass}" >
<
span>
<
sc:link >
<
sc:text field="Nav Title" />
</
sc:link>
</
span>
</
li>
</
xsl:for-each>
</
ul>
</xsl:template>

The above runs through every item which has InTopNav checked in that level (if you had /SiteCore/Content/Site/Home and then all the items under Home, it would be a bit different)


In terms of what happens when this runs:


1. First item is read and link displayed -- given the “FirstItem” class.


2. 2nd item is read -- link is displayed with No class assigned.



N. Last item is read: $EdgeClass is now “LastItem”, list item with a period is displayed followed by the list item for the last link -- given the “LastItem” class.


All that is left is styling the menu: I created extra wide images for the left rounded edge, right rounded edge and the general middle links so that they could overlap and slide around depending on the length of the text and set them as the background images for the links (ie: #Menu li.FirstItem a).

Web Forms for Marketers: Send Email

To have the save action for your form actually send email, you will need to change one of the settings, otherwise you will receive this error whenever submitting the form:

We experience a technical difficulty while processing your request. Your data may not have been correctly saved.

Also in your log (/data/logs/newest log file) you will see this error after the form has been submitted:

Exception: System.Net.WebException
Message: The remote name could not be resolved: 'example.host'
Source: System
at System.Net.ServicePoint.GetConnection(PooledStream PooledStream, Object owner, Boolean async, IPAddress& address, Socket& abortSocket, Socket& abortSocket6, Int32 timeout)
at System.Net.PooledStream.Activate(Object owningObject, Boolean async, Int32 timeout, GeneralAsyncDelegate asyncCallback)
at System.Net.PooledStream.Activate(Object owningObject, GeneralAsyncDelegate asyncCallback)
at System.Net.ConnectionPool.GetConnection(Object owningObject, GeneralAsyncDelegate asyncCallback, Int32 creationTimeout)
at System.Net.Mail.SmtpConnection.GetConnection(String host, Int32 port)
at System.Net.Mail.SmtpTransport.GetConnection(String host, Int32 port)
at System.Net.Mail.SmtpClient.GetConnection()
at System.Net.Mail.SmtpClient.Send(MailMessage message)
WARN Web Forms for Marketers: an unhandled exception: Failure sending mail. has occured while trying to execute an action.

In your content tree, browse down to: /sitecore/system/Modules/Web Forms for Marketers/Settings/Actions/Save Actions/Send Mail


Under that item there will be a submit section with parameters:


wffmpara


Just replace example.host with your SMTP host information for the server, and form@example.host with the address you want to send mail from – save, and republish!


That should correct the error above and, barring any other issues, hopefully the form will be working as intended!

August 23, 2010

Hello World!

I’ve been itching to get this going for some time now, and decided to simply take the plunge!  I’ll be initially importing my previous posts from the Arke Systems Blog and then should have some more new tidbits shortly after.

I am somewhat new to the blogging world (and newly certified with Sitecore) and my hope is that this can eventually become a handy resource for others getting started with our favorite CMS! Initially there was a lot of struggle for me to find out basic information on how to do seemingly simple things (training really is the best way to go), so I’ll be posting a lot of small tips as I go along, and if I gloss over anything – comment!

One thing I'm really hoping for from this blog is some feedback – so please, comment and let me know where things can be improved or if this was useful at all – or if you’d like me to post about a particular topic.

Looking forward to the future!