Category Archives: Sitecore

How to shrink a Sitecore database

We had some databases that were 25 gb each due to some large media items.

To shrink the database, it is not as simple as deleting the large items.

After you have identified and deleted any unnecessary items from Sitecore, do this on each database (or publish the parent section) and then Empty the Sitecore recycle bin (in each database, via the Sitecore Desktop menu).

Then you have to run the Sitecore Clean Up Database wizard. This will remove the orphaned items from the DB. Finally you can shrink the databases and the space will actually be reclaimed.

How to migrate users and passwords between Sitecore instances

If you ever package users from one Sitecore instance to another you will find that upon install the users are disabled and the passwords need to be reset.

What if you were moving them from one version to another and need to keep the same passwords?

Fear not, just run this SQL script. It will update the passwords of all matching usernames to the original passwords, and enable the accounts. The databases must be on the same instance.

/******

 SELECT Upgraded Core DB in SQL Studio.

 In script below, Replace Old_Core with name of old DB

 First run the SELECT only to see what it's going to do, then run the update script.

 ******/
SELECT TOP 1000
      m.[UserId],
      om.userid,
      m.[Password],
      om.password,
      m.[PasswordSalt],
      om.passwordsalt,
      u.username,
     ou.username,
      m.comment,
     m.islockedout,
     om.islockedout,
     m.isapproved,
     om.isapproved
  FROM [aspnet_Membership] m
  inner join [aspnet_Users] u ON m.UserID = u.UserID
  inner join Old_Core.dbo.aspnet_Users ou ON ou.username = u.username
  inner join Old_Core.dbo.aspnet_Membership om ON ou.userid = om.userid

   UPDATE [aspnet_Membership]
  SET
  --comment = ou.username,    -- TEST!
  Password = om.Password,
  PasswordSalt = om.PasswordSalt,
  IsLockedOut = om.IsLockedOut,
  IsApproved = om.IsApproved
  FROM [aspnet_Membership] m
  inner join [aspnet_Users] u ON m.UserID = u.UserID
  inner join Old_Core.dbo.aspnet_Users ou ON ou.username = u.username
  inner join Old_Core.dbo.aspnet_Membership om ON ou.userid = om.userid

Sitecore 8 Federated Experience Manager

I recently posted a short introduction to the Sitecore FXM on the e3 blog, below is a more detailed version!

One new feature in Sitecore 8 is the Federated Experience Manager (FXM). This is a brand new tool designed to allow you to apply Sitecore’s marketing features to existing non-Sitecore sites. This would be ideal for clients who are investing in the Sitecore platform but also have legacy sites which aren’t being redeveloped into Sitecore. For example, associated WordPress blogs, Drupal communities, even flat microsites could contribute to a user’s Sitecore Experience profile and affect personalisation across all these sites. I’ve had a chance to experiment with this tool and this is what I found.

This new tool is an option in the new Sitecore Launchpad. It presents you with a list of sites that you have added already, along with number of visits that have been tracked through the FXM:

After creating a federated site they show in this list. For testing purposes I have added the e3 test website as a federated site. You need to enter the site’s domain and then paste some tracking script onto every page of the target site. The details of my federated site are as follows:

Now comes the fun bit. Clicking on “Open in Experience Editor” brings up a new version of the Experience Editor, geared towards being able to edit federated sites. In my instance, here you can see the e3 homepage showing up within the experience editor of my fresh Sitecore 8 instance:

From this visual editor you are able to do various things such as:

  • Attach Sitecore functionality to links / button clicks (such as triggering a goal)
  • Assign goals/campaigns/events to trigger when certain page(s) are viewed
  • Add Sitecore placeholders at any point within the existing site, to inject new content or replace existing content

As a basic example, we could trigger a goal when a user views a case study and then display a personalised block on the homepage to highlight a particular case study, such as this one about Unicef Launchpad.

The first thing you must do is add a Page Filter. This is how Sitecore will target your personalisation to decide which page(s) it affects. Here we create a filter to match all case study pages, and assign a custom “Viewed Case Study” goal I made earlier:


Next, for the personalisation on the Homepage, I can click “Add Placeholder” and then click on a part of the page. This selects the component I have clicked and gives a choice of adding before or after that component:

In this case I have chosen “Add before” as I want to add a new component in above “Our Latest Work”. Once the placeholder is added, I can add any existing Sitecore layout in the new placeholder (for example any design component you already have built for your Sitecore site), and display the desired content. The federated site may need updated CSS to correctly display design elements from the Sitecore site, otherwise they might appear unstyled. Once I’ve finished adding the new component it looks like this:

By default this new content will display all the time. The final step is to apply some personalisation to the new block. To do this, I can select the block and choose Edit personalisation from the floating toolbar:

The following personalisation settings will show the custom content if the user has viewed a case study, otherwise hide the component. You could add multiple conditions in here to display different content depending on the user’s activity.

Once all this is done and published, I can browse to the target site and it appears as normal. If I browse to any case study and then back to the homepage, I can see the new component has been injected into the page’s content:

There are many possibilities in terms of the personalisation logic you could apply, and this new ability to apply marketing features to external sites really adds a new dimension to Sitecore’s experience platform.

Automated Site Setup Scripts (Sitecore / Umbraco)

We wanted a simple way to get a new environment set up on a developer machine, but without the hassle of Virtual Machines.

Enter, Microsoft’s appcmd.

This lets you manipulate IIS7 via command line calls. There is lots of documentation on the IIS site but it takes a while to figure out which commands you need to do everything to set up a site. So I’ve put together a selection of the useful commands below in a sample site setup script.

We save these as batch files (.bat) and put them in a shared folder.

Prerequisites:

  • You work on Windows using IIS7
  • (if Sitecore) You have all relevant Sitecore installation zips in a shared network folder
  • (if Umbraco) You use Nuget package to distribute Umbraco CMS (or you could do the zip thing)
  • You run sites locally with custom host name, using a shared DB
  • All team members setup sites in the same folder path e.g. c:\work
  • You have admin rights on the local machine

Sample setup script:

Put this in a .bat file and save in a shared folder. Keep as many steps as required, and replace the relevant placeholders. To run, right click Run as Administrator.

@ECHO OFF

ECHO *** MUST BE RUN AS ADMIN - IF NOT PLEASE CLOSE AND RUN AGAIN, OTHERWISE: ***
PAUSE

ECHO *** CHECKING OUT FROM SVN ***

IF not exist c:\PATH_TO_TRUNK svn checkout -q https://SVN_PATH_TO_TRUNK c:\PATH_TO_TRUNK

ECHO *** EXTRACTING SITECORE ***

"C:\Program Files\7-Zip\7z" x -y "PATH_TO_SITECORE_ZIPS\Sitecore 7.0 rev. 140120.zip" -oc:\PATH_TO_TRUNK "Sitecore 7.0 rev. 140120\Data" "Sitecore 7.0 rev. 140120\Website"

ECHO *** RENAMING SITECORE ***

rename "c:\PATH_TO_TRUNK\Sitecore 7.0 rev. 140120" www

ECHO *** COPY LICENSE ***

copy PATH_TO_LICENSE\license.xml c:\PATH_TO_TRUNK\www\Data

ECHO *** CREATING APP POOL ***

C:\Windows\System32\inetsrv\appcmd add apppool /name:"APP_POOL_NAME" -managedRuntimeVersion:v4.0

ECHO *** CREATING SITE ***

C:\Windows\System32\inetsrv\appcmd add site /name:"APP_POOL_NAME" /bindings:http://site.localhost:80 /physicalPath:"c:\PATH_TO_TRUNK\www\Website" -applicationDefaults.applicationPool:APP_POOL_NAME

ECHO *** CREATING VIRTUAL DIRECTORIES ***

C:\Windows\System32\inetsrv\appcmd add vdir /app.name:"APP_POOL_NAME/" /path:/siteAssets /physicalPath:c:\PATH_TO_TRUNK\siteAssets

ECHO *** ADDING TO HOSTS FILE ***

find /c "	site.localhost" c:\windows\system32\drivers\etc\hosts
if %errorlevel% equ 1 goto notfound
echo Already there
goto done
:notfound
ECHO 127.0.0.1	site.localhost >> c:\windows\system32\drivers\etc\hosts
goto done
:done
  
ECHO *** BUILDING SOLUTION ***

C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe c:\PATH_TO_TRUNK\src\Site.sln /verbosity:quiet

ECHO *** OPENING SITE ***

start http://site.localhost/

PAUSE

Hope that’s helpful to someone!

How to hide the Set associated content button in Sitecore

Sitecore Page Editor provides a Set associated content button in the floating toolbar around each component:

set-associated-content

This allows you to set the Data source for the component.

The selection can be restricted by Template or Location (in the Sitecore tree) by setting the page editor options on the component:

page-editor-options

If you have some components that require a data source and others that do not, it can be confusing for editors because the Set associated content button is always visible. The only way to see if it is intended to be used in a particular instance is by clicking it and seeing whether the developer has set the restrictions – if not then it allows you to pick any item from the whole site tree and you realise you probably aren’t meant to use it.

I thought it would be nice to only show the button if the Template restriction has been set, so the editor doesn’t try to use it when it isn’t intended.

To do this, I created a custom class to replace the built-in SetDatasource command:

using Sitecore.Data.Items;
using Sitecore.Shell.Applications.WebEdit.Commands;
using Sitecore.Shell.Framework.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Training.Utilities.BaseCore.Commands
{
    public class SetDatasourceIfTemplateSet : SetDatasource
    {
        public override CommandState QueryState(CommandContext context)
        {
            Sitecore.Data.ID renderingId;
            if (Sitecore.Data.ID.TryParse(context.Parameters["renderingId"], out renderingId))
            {
                Item renderingItem = Sitecore.Context.Database.GetItem(renderingId);
                if (string.IsNullOrEmpty(renderingItem["Datasource Template"]))
                {
                    return CommandState.Hidden;
                }
            }
            return base.QueryState(context);
        }
    }
}

Then in the /App_Config/Commands.config file, replace the webedit:setdatasource command type with our custom version:

<command name="webedit:setdatasource" type="Training.Utilities.BaseCore.Commands.SetDatasourceIfTemplateSet,Training.Utilities"/>

Then the button will only show up if a Datasource Template has been assigned.

How to get a spreadsheet of Sitecore template usage

I wanted to get an overview of all the templates in a Sitecore project along with how many times each has been used.

I thought there might be some marketplace module for doing this but couldn’t find one, nor could I find a suitable report in the ASR module.

So I wrote a little aspx script to write this out, hopefully it will be useful to someone:

<%@ Page Language="C#" AutoEventWireup="true" %><%

Response.ContentType = "text/csv";
var db = Sitecore.Data.Database.GetDatabase("master");
var templates = db.GetItem("/sitecore/templates/User Defined");
foreach (var template in templates.Axes.GetDescendants())
{
	if (template.TemplateName == "Template")
	{
		var usage = Sitecore.Globals.LinkDatabase.GetReferrerCount(template);

		if (template.Children["__Standard Values"] != null)
			usage--;

		Response.Write(template.ID + "," + template.Paths.Path + "," + usage + "," + Environment.NewLine);
	}
}

%>

Style up an sc:link field for Sitecore Page Editor

If you have a normal Link field which you render using an <sc:link /> control then you can select the link in a nice friendly way when editing through the Page Editor.

However if you have a custom css class to style your link then you might expect the link field to use that style in edit mode. Here’s an example link and the HTML we want it to render:

<a class="arrow-link" href="/">Read more</a>

However, when converted into an <sc:Link CssClass=”arrow-link” /> this is what Sitecore renders during edit mode, when you haven’t yet set a link:

Note that this doesn’t include an <a> tag at all. However, it does include the CSS class, albeit encoded into the sc_parameters attribute of the <code> element.

To make it styled-up using the same CSS class I added to the CSS an additional selector for the style:

So now as well as the .arrow-link class applying to actual .arrow-links, it also applies itself to Sitecore’s scTextWrapper span (which is where the [No text in field] is rendered). Now, before you fill it in, it looks like this:

Nice. This really helps if you have lots of similar-looking fields (e.g. Text, Links, etc) all below each other, as the editor can see which is meant for which. I would like to see if anyone has a nicer way of doing this by extending Sitecore, but I thought doing it in CSS would be a simple workaround.

Auto deploy Sitecore items using Unicorn and TeamCity

I recently discovered the Unicorn project by @kamsar, which implements an event handler to serialize Sitecore items to disk when they are modified, and a sync script which restores them on request.

There were a few things which I had to figure out when setting this up to use for continuous integration in our environment, so I will outline the process.

Install and configure Unicorn

First, install the Unicorn nuget package.

Second, configure it to work on only the developer-owned items in your Sitecore tree. For these items we will consider the ‘master’ copy is that in source control, just like your codebase. The configuration is in /App_Config/Include/Serialization.config and I modified mine thus:

<sitecore>
 <serialization>
  <default>
   <include database="master" path="/sitecore/layout/Layouts/SITE" />
   <include database="master" path="/sitecore/layout/Placeholder Settings/SITE" />
   <include database="master" path="/sitecore/layout/Renderings/SITE" />
   <include database="master" path="/sitecore/layout/Sublayouts/SITE" />
   <include database="master" path="/sitecore/media library/System/SITE" />
   <include database="master" path="/sitecore/templates/SITE" />
  </default>
 </serialization>
</sitecore>

Where SITE is a site-specific named folder containing all our site-specific items.

Next, serialize each of these Items using the Serialize Tree option in Sitecore’s Developer toolbar, and commit the serialized files from the $data/serialization folder.

From now on, when any of these items is modified in Sitecore, the corresponding file(s) will be modified and you can commit them along with code changes. These can be merged into your test / production branch along with other code.

Get the serialized files to be deployed

This step depends on your setup, but we set up our TeamCity CI to use WebDeploy to publish the Web Application Project to the server as per Troy Hunt’s article.

To get our items to be deployed required two things:

  1. Serialization folder must be under Website. I moved it to /App_Data and changed the path in Web.config
  2. An additional build step to sync the serialization folder:
C:\Program Files\IIS\Microsoft Web Deploy\msdeploy -verb:sync -source:contentPath=%teamcity.build.checkoutDir%\www\Website\App_Data\serialization -dest:contentPath=%env.DeployIisAppPath%/App_Data/serialization,wmsvc=https://%env.TargetServer%,userName=%env.PublishUsername%,password=%env.PublishPassword% -allowUntrusted

This ensures that when the build runs, new items will be added and old ones deleted to match what is in version control.

Get the items to be installed on build

This is done by the sync-database.aspx script included with Unicorn.

It will install the items if you are logged in as an Administrator, or if you include an Authenticate header matching a preconfigured token.

So add an app setting:

<add key="DeploymentToolAuthToken" value="{GUID OR TOKEN HERE}"/>

And then to make TeamCity call the script with the token I used wget (install for Windows here) and added a command line build step in TeamCity with the script:

C:\Program Files (x86)\GnuWin32\bin\wget %env.SyncScriptURL% -O - --header=Authenticate:%env.SyncScriptToken%

Then, if the build is successful, the script will run and Sitecore DB will be updated. In case it fails it should return non-200 and TeamCity flags this as an error.

We decided it would be ideal to publish the items as well as installing them into master db, so I added the following code into the sync-database.aspx.cs :

 /// <summary>
 /// Publish the preset folder as per docs in http://sdn.sitecore.net/upload/sitecore6/64/content_api_cookbook_sc64_and_later-usletter.pdf
 /// </summary>
 /// <param name="preset"></param>
 private static void PublishPreset(IncludeEntry preset)
 {
  if (preset.Database == "master")
  {
   Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
   Sitecore.Data.Database target = Sitecore.Configuration.Factory.GetDatabase("web");
   Sitecore.Data.Items.Item home = master.GetItem(preset.Path);
   Sitecore.Data.Database[] targetDatabases = { target };
   Sitecore.Globalization.Language[] languages = master.Languages;
   bool deep = true;
   bool compareRevisions = true;
   Sitecore.Publishing.PublishManager.PublishItem(home, targetDatabases, languages, deep, compareRevisions);
  }
 }

I call this code from within ProcessPreset:

new SerializationLoader().LoadTree(
 new AdvancedLoadOptions(preset)
 {
 Progress = progress,
 ForceUpdate = false,
 DeleteOrphans = true
 });

PublishPreset(preset);

Now my items are installed and published on deploy.

Strongly typed repeaters in ASP.NET 4.5 (Sitecore 7)

If you use Web Forms then this might be helpful.

In a Repeater (and other data binding container controls) instead of something like this:

<%# ((Sitecore.Data.Items.Item)Container.DataItem)["Field"] %>

You can now do this:

<%# Item["Field"] %>

If you include this Repeater attribute:

ItemType="Sitecore.Data.Items.Item"

We can do this with Sitecore 7 J

For more information http://stackoverflow.com/questions/937244/strong-typed-container-in-webforms