Over the weekend, I posted part 1 of a discussion of this thing I created that I’m calling “conditional pages”.  I promised to elaborate on the technical details, so here I am with some code samples and instructions that hopefully will allow others to reproduce what I have done.

Before I begin, let me once again thank Sitecore CTO John West - without whose blog posts and assistance on the SDN forums, I might have never figured this stuff out.  I haven’t found a better source of information on rules engine customizations.  If you’re looking for more information, check out his blog here http://goo.gl/5V4Gg

This whole process begins when a request comes in to the Sitecore pipelines.  By implementing a custom StartTrackingProcessor, I am able to intercept the request, inspect the item that was requested and if it is a conditional page, execute the rules defined on the page to determine what item should replace the originally requested item in the Sitecore context.

To create my custom processor, I just created a class that derives from Sitecore’s StartTrackingProcessor and implemented an override for the Process() method.  The declaration looks like this:

    public class ConditionalPageTrackingProcessor : 
StartTrackingProcessor { public override void Process(StartTrackingArgs args) { } }

Within my Process() method, I first check if Sitecore.Context.Item is using the Conditional Page template.  I described this template in my previous post, but here’s a quick screenshot of what it looks like in Sitecore:

Screen Shot 2012-06-11 at 9.45.58 PM

I’ll explain the path you see in the source for the Rules field in a little bit.

If the requested item is not a conditional page, then there is nothing for my processor to do so the code just returns.  However, if it IS a conditional page – I pull the value from the Rules field like this:

    string rulesXml = Context.Item["Rules"];

Note, there is no strongly-typed Field-derived class for fields of type Rules, so I’m pulling out the raw XML string.  This string now needs to be parsed, and that is done by a method on the Sitecore.Rules.RuleFactory class - ParseRules<T>():

    var parsed = RuleFactory.ParseRules<ConditionalPageRuleContext>
(Sitecore.Context.Database, rulesXml);

Now you may be asking – what is this ConditionalPageRuleContext class?  This is my custom rules engine context.  It derives from Sitecore.Rules.RulesContext and adds a property that indicates what item (if any) the rules want the user redirected to.  The concept of a rules context seems a bit confusing at first, but suffice it to say that this class is what allows the rules engine to communicate information back to the code that executes it.  Here’s what the ConditionalPageRuleContext class looks like in code:

    public class ConditionalPageRuleContext : Sitecore.Rules.RuleContext
    {
        public Item NewItem { get; set; }
    }

In order to proceed, I need to construct an object of this class and tell it what item it is acting on:

    ConditionalPageRuleContext ruleContext = 
new ConditionalPageRuleContext(); ruleContext.Item = Context.Item;

And then, I run the rules that were parsed – passing in my rule context:

    RuleList<ConditionalPageRuleContext> rules = 
        new RuleList<ConditionalPageRuleContext>();
    rules.Name = Context.Item.Paths.Path;
    rules.AddRange(parsed.Rules);
    rules.Run(ruleContext);

When this returns, I check if ruleContext.NewItem was set and if it was, I set Sitecore.Context.Item = ruleContext.NewItem.

So wait – how does the NewItem property on my context get set by the rules engine?  Let’s take a closer look at an example rule that redirects some users to a page “Test 1” and others to “Test 2” instead:

image

The actions here are “set current item to …”.  This is a custom rules engine action that only runs within a ConditionalPageRuleContext and sets the NewItem property of that context to the specified value.  Here’s the code:

    public class SwitchToItemAction<T> : 
        RuleAction<T> where T : 
            Rules.ConditionalPageRuleContext
    {
        public string ItemId { get; set; }

        public override void Apply(T ruleContext)
        {
            ruleContext.NewItem = 
                ruleContext.Item.Database.GetItem(new ID(ItemId));
        }
    }

If you haven’t seen a custom action before, the public property gets set by Sitecore to the value selected in the rule editor dialog (the ID of “Test 1” or “Test 2” in the above example), and the Apply() method gets called only for the actions whose conditions pass.  Making this action available in the rules editor requires something in Sitecore.  Remember that source path on the Rules field for the Conditional Page template?

Inside the /sitecore/System/Settings/Rules/ folder, I created a folder named “Conditional Page”.  Within that folder, I created a folder named “Actions”.  The rules editor looks at the field’s source and restricts the actions that can be chosen to those within the “Actions” sub-folder.  So, to configure my action, I created an item in this Actions folder named “Switch to Item” using the /sitecore/templates/System/Rules/Action template.

There are two fields to fill in on this item – Text and Type.  Type is simply a pointer to the above SwitchToItemAction class (in the usual Namespace.Class, Assembly format).  Text is special.  Mine looks like this:

image

The text outside of the square brackets is what the user will see in the rules editor.  Inside the square brackets are four comma-separated values:

ItemId – The name of the property on the class to be set to the selected value.

Tree – The type of UI element to present to the user for choosing a value.

root=… – An argument passed to the UI element.  In this case, the root item for the tree.

an item – The text to show in the rules editor before an item has been chosen.

Note – I haven’t found a documented list of available UI elements and what their arguments are.  I just saw another example using “Tree”.

There’s one more thing I found it necessary to do to make everything work…  My StartTrackingProcessor was never called if the conditional page item didn’t have a layout set on it.  Instead, Sitecore would abort in an earlier pipeline and display the “layout not found” error.  I just fixed this by setting the standard values for the Conditional Page template to use a blank layout.

If you read Part 1 of this series, I talked quite a bit about a Page Design condition…  Reading and writing data from a site visitor’s profile is pretty simple, but I’ll cover that and how to create a custom rules engine condition in my next blog post. :)

I hope this helps somebody.  Please, let me know if you use this idea or think of any ways I could improve it.  And if you have any questions, just send them to me via direct message on Twitter - @williamsk000.

A few days ago, I posed a question here (and on Twitter and on the SDN forum and some other places) regarding accessing visitor profile data from the HttpRequestBegin pipeline.  I promised to post about why I needed to do that once I had everything working, so here’s the story.  Sorry – it’s a bit of a long one. :)

Introduction

Recently, an NTT Data client asked me if I could do something with Sitecore that I had never imagined before…  Essentially, they wanted to A/B test multiple pages across a visit to their site.  If a visitor saw homepage A, they would also see the “A” versions of landing pages, etc.  The changes between versions were not minor – every rendering on a page was likely to change between the “A” and “B” version, some renderings would use completely different datasource templates, etc.

First, let me say - I completed OMS training and certification a year and a half ago, but this was my first real marketing suite request.  The client’s site is being built on current Sitecore 6.5, meaning the latest DMS features were available - but I had little familiarity with them.  I’ve developed a working solution, but I imagine there may be a better way to accomplish it.  If you know of one, I would love to hear about it!

Anyhow - I could not figure out a way to do this with stock DMS features (based on my limited experience), but eventually I thought of a simple customization that would make it possible…  A custom rules engine condition that would check a visitor’s profile for a “Page Design” key with a value of “A” or “B”.  If they did not yet have a value, randomly choose one, save it to their profile, and then make a comparison.

The Page Design Condition

Screen Shot 2012-06-10 at 1.58.45 AM

With this in place, I was able to set personalization rules on multiple renderings on a page, and have them each evaluate my custom condition (e.g. except where the visitor’s page design is “A”, hide component – see above screenshot).  This worked, but it made a crazy mess for content authors within the page editor…  Both versions of the page were visible at the same time and it was terribly confusing to try and determine which renderings were meant to appear on which page version, much less edit any content.

Back to the drawing board, then.  What I needed was a way to create two separate items in the content tree so they could be edited separately, but allow them to share the same URL or have an alias that redirected to them without changing the URL seen by visitors.  I went down many dead end roads trying to realize this idea, but the concept I ended up with is what I’m calling a “conditional page” – an item with rules applied (when the visitor’s page design is “A”, change the current item to “Homepage A”.  When the visitor’s page design is “B”, change the current item to “Homepage B”) that changes Sitecore’s context item to allow the page that was requested (the conditional page) to appear as the alternate page.

I present for you here the working solution I eventually landed upon.

Conditional Pages

A conditional page defines a set of rules under which the site visitor may be “redirected” to another item which will then appear to the visitor in place of the originally requested page.

Screen Shot 2012-06-10 at 2.04.15 AM

The above screenshot is of an item using the Conditional Page data template.  It is named “demo” and is a child of the site’s homepage.  Here, I am using the page design condition discussed above along with a custom action that causes the Sitecore context item to change (I’ll discuss how momentarily).  The effect is that when a visitor goes to the /demo URL, they will see either Landing Page A or Landing Page B depending on which page design has been chosen for them during their visit.

The Conditional Page data template has just one field – Rules – of type “Rules”.  The Source for this field is set to a folder I created under /sitecore/system/Settings/Rules named “Conditional Page”.  This folder has sub-folders named Actions and Conditions containing my custom actions and condition respectively.  For more information about this folder structure, you can read John West’s blog post about using the rules engine here http://goo.gl/aadSf

The key to making conditional pages work was to intercept the initial item request, execute the rules stored in the Rules field, and change Sitecore.Context.Item early enough in the process that everything else would treat it like that was the page requested all along…  It took some trial and error (see previous question about the HttpRequestBegin pipeline) and a little help from John West on the SDN forum, but I eventually found just the spot – the StartTracking pipeline just before the ProcessItem processor.

The technical details of how all of this is done will fill up another blog post, so I’ll save that for later (I promise to post in the next day or two).  But if you’re really interested now – take a look at John West’s post I linked above where he is doing something similar using the rules engine to change the context device for certain requests.

By the way – conditional pages also work with other DMS conditions, not just my custom “page design” one.  So you can have the page that comes up be based on GeoIP rules or if a visitor has achieved a DMS goal or search engine keywords, etc, etc.  It’s kind of like a rules-powered alias.

I hope this concept will be useful to someone else. :)  If you have any questions, comments, suggestions, etc – please reach out to me on Twitter @williamsk000.  Thanks for reading!

Sorry that this isn't a tutorial-style post today, but I promise if I get all of this working that I will post the full story in a few days. For now, I'm having a Sitecore problem...

I have an HttpRequestBegin pipeline processor that runs right after the stock ItemResolver. I need for it to read a value from the current visitor's profile (or if a value isn't there, write one). Here's what my code looks like:

var currentRow = Sitecore.Analytics.Tracker.CurrentVisit.Profile.FirstOrDefault(row => (row.ProfileName == "foo" ));
if ( currentRow == null )
{
   currentRow = Sitecore.Analytics.Tracker.CurrentVisit.CreateProfile("foo");
   currentRow.PatternValues = "bar";
   currentRow.AcceptChanges();
   Sitecore.Analytics.Tracker.CurrentVisit.AcceptChanges();
}

This code when placed in a sublayout works as expected - the first time, the profile value is created and subsequent times it is read back out. However, doing this in the HttpRequestBegin pipeline seems to have no effect at all. Anyone know - is there no way to interact with the current visitor's profile in the pipeline?

There's actually a lot more going on here involving rules engine, etc... As I said, I'll post the full story if I can get it working 'cause it's pretty neat. But for now, I have to get past this particular hurdle...

If you want to contact me regarding this post, it's probably best to use Twitter. You can DM me at @williamsk000

Filed under: , , ,

A while back, I wrote about opening Sitecore’s media library browser from a button in the Content Editor ribbon.  Recently, I decided it would be really useful to do something similar with the Field Editor dialog – only this time, from the Page Editor’s ribbon.  If you’re not familiar with the dialog in question, here’s a screenshot:

FieldEditor

Adding a button to the page editor ribbon isn’t a big deal – it’s very similar to how I added the Thumbnail button to the content editor ribbon.  Essentially, I just opened the Core database, drilled down to /Applications/WebEdit/Ribbons/WebEdit/Page Editor/Edit and added a new Large Button.  This adds the new button to the “Edit” chunk in the “Home” strip.  Here’s a screenshot of that:

Button

And here’s what it looks like in the page editor:

Ribbon

I used a .config file (placed in /App_Config/Include so that Sitecore will automatically load it) to hook the “example:MetadataButton” command to a class in a DLL.  That looks like this:

   1:  <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
   2:    <sitecore>
   3:      <commands>
   4:        <command name="example:MetadataButton" type="Kevin.MetadataButton, MetadataButton" />
   5:      </commands>
   6:    </sitecore>
   7:  </configuration>

So all that leaves is the code to actually open the field editor…  I had to do some digging with .NET Reflector to figure this out.  Thank you Sitecore, for not obfuscating this stuff!  Here’s the critical bit of code:

   1:  // Get the field descriptor objects.
   2:  ListString fieldNames = new ListString("Title|Meta Description|Meta Keywords");
   3:  var fields = fieldNames.Select(f => new FieldDescriptor(item, f));
   4:   
   5:  // Set the field editor options.
   6:  PageEditFieldEditorOptions options = new PageEditFieldEditorOptions(form, fields)
   7:  {
   8:      Title = "Edit Metadata",
   9:      Icon = string.Empty
  10:  };
  11:   
  12:  // Show the dialog.
  13:  SheerResponse.ShowModalDialog(options.ToUrlString().ToString(), "720", "520", 
  14:      string.Empty, true);
  15:  args.WaitForPostBack();

What this does is creates a list of FieldDescriptor objects for the named fields on the current item, constructs a PageEditFieldEditorOptions object, and calls SheerRespose.ShowModalDialog().  Just like in my ThumbnailButton module code, we wait for a postback.  When that postback comes in, this one line of code takes the values from the field editor and saves them into the current item:

   1:  PageEditFieldEditorOptions.Parse(args.Result).SetPageEditorFieldValues();

I’ll attach the full .cs file and .config file to this post once it’s live on my blog in case you don’t want to mess with all of the details yourself.  UPDATE:  Attachments don't seem to be visible to everyone on the DNM site, so here's a link to the ZIP file:  http://www.killeverything.com/zak/MetadataButton.zip

In other news – as of April of 2012, my employer (The Revere Group) have taken on the parent company’s name.  Along with several other affiliated companies in North America, we are now collectively known as NTT DATA.  I’m proud to be a part of the NTT DATA family here in the Americas, and am looking forward to new opportunities the combined companies will be able to tackle!

Filed under:

Something I have wanted to know how to do for years, but hadn’t bothered to put any thought into…  You know that “Folder” tab that appears in the content editor when you create a new folder (using the /Templates/Common/Folder template)?  Here’s a screenshot:

FolderTab1

I have never known how to get this to appear for my own folder types.  Let me see if I can come up with an example…  Let’s say I had a Gallery template that allows you to create individual Photo and Video items underneath it.  So, I would create my templates, and on the Gallery template’s standard values, I would set the insert options to allow creation of Photo and Video items.

I then create a new Gallery item in the content tree and select it as in the above screenshot, but note – the Content tab is displayed by default!

FolderTab2

I just want the same behavior as Sitecore’s “Folder” template…  But how is that done?  Turns out it is very simple.  In the Appearance chunk of the Configure slice of the ribbon, there’s a button named “Editors” – this is the key.  If you go look at the standard values for Sitecore’s “Folder” template, and click on the Editors button, you’ll see something like this:

FolderTab3

It’s as easy as replicating this setting on my Gallery template’s standard values.  After doing that (and adding a couple of photos and a video as children), here’s what my demo gallery looks like now:

FolderTab4

Man, that was easy.  Don’t know why it took me so long to look into doing it – it will definitely come in useful in the future!

Sitecore comes with some other editors you may find a use for – just experiment.  Also, it’s possible to create your own custom editor tabs and make them available for selection in the Custom Editors dialog.  I haven’t done it yet, but it’s on my list of things to try out someday.  Here’s a link to a blog post Mark van Aalst wrote on the subject:  http://www.markvanaalst.com/sitecore/creating-a-item-editor/

Filed under: ,

When I set out to create an easier way to set thumbnails in Sitecore, I had a picture in my mind of how I wanted it to work, but I didn’t really know where to start!  I hadn’t built a custom ribbon button before.  I hadn’t created a modal dialog before nor did I know how to display an existing one.  And I had no idea how to receive results from one even if I could display it.  I had a lot of digging to do, so I fired up Google and .NET Reflector and got to work.

The first step was figuring out how to put a button where I wanted it in the ribbon with the text and icon I wanted to display.  Google gave me a few blog posts discussing this, but I never found exactly the info I was looking for.  I ended up just playing with it until I got it to work, but in the process this is what I figured out:

  • The ribbon is made of tabs or “strips”.  These appear across the top of Content Editor windows and I’m sure you’re familiar with them…  “Home”, “Navigate”, “Review”, “Analyze”, “Publish”, etc.  There is a template used to create these – /sitecore/templates/System/Ribbon/Strip.
  • These strips are then broken into “chunks”.  These are the boxes that group the buttons in the ribbon.  For example, in Content Editor’s “Home” strip, you would see these chunks:  “Edit”, “Insert”, “Operations”, “Clipboard”, “Rename”, and “Sorting”.  The template used to create chunks is /sitecore/templates/System/Ribbon/Chunk.
  • Lastly, within chunks there are buttons.  And there are different types of buttons – small buttons, large buttons, buttons that make a drop-down appear...  I used a large button (template is /sitecore/templates/System/Ribbon/Large Button) for my thumbnail button, but it looks like there are a lot of interesting possibilities here.
  • If you want to add your own strips, chunks, and/or buttons to the ribbon, open up the Core database and drill down to /Applications/Content Editor/Ribbons.  Note these are built to be re-usable, so there is a folder for strips and a folder for chunks – the Default ribbon has children using the Reference template (/sitecore/templates/System/Reference) pointing to the actual strips (so the same strip can be pointed to multiple times) and each strip’s children also use references pointing to its chunks (so the same chunk can appear in multiple strips).  It doesn’t appear that Sitecore is using references for buttons and I didn’t try it, but it may be possible to place buttons into multiple chunks that way as well.

So to get into specifics, I wanted to add a Thumbnail button to the Appearance chunk on the Configure strip (this is where Sitecore placed their “Icon” button, so it seemed like a good fit).  So in the Core database, I drilled down to /Applications/Content Editor/Ribbons/Chunks/Appearance and added a new Large Button using the /sitecore/templates/System/Ribbon/Large Button template.  Here’s a screenshot:

ThumbnailFields

I think the fields in this screenshot should be self-explanatory except for maybe “Click”.  This is the event you want raised when your button is clicked.  If you’re not familiar with these events, take a look at App_Config\Commands.config in one of your Sitecore solutions – it lists a ton of Sitecore’s internal events and the classes that handle them.

After adding the above, my button was already appearing in the ribbon - it just didn’t do anything when I clicked it.  If you looked at the Commands.config file, the next step may be clear...  I needed to wire my event (“example:Thumbnail” in the screenshot) to a class.  I took a look at some of the classes in Commands.config using .NET Reflector and discovered they all implement the Sitecore.Shell.Framework.Commands.Command abstract base class.

So, I created my own class that inherits Command and implemented the Execute() method.  I then created the following config include file and placed it in App_Config\Include\

 <configuration xmlns:patch= "http://www.sitecore.net/xmlconfig/ " 
                xmlns:x= "http://www.sitecore.net/xmlconfig/ ">
   <sitecore>
     <commands>
       <command name= "example:Thumbnail " type= "Example.Namespace.Class,Example.Assembly " />
     </commands>
   </sitecore>
 </configuration>
 

After doing this, I was able to place a breakpoint in my Execute() method and see that it was indeed being hit when I clicked the button.  Success!  But, what should my code inside of Execute() look like?  This is the point where I had to do a LOT of digging on Google and using Reflector.  I knew I wanted to display Sitecore’s media browser, but the question was HOW?

I won’t bore you with the entire process I went through (I don’t remember half of the things I tried anyway).  This is the key bit of code, though:

 UrlString  url = new  UrlString (UIUtil .GetUri("control:Sitecore.Shell.Applications.Media.MediaBrowser" ));
 Item  folderItem = masterDb.GetItem("/sitecore/media library/Images" );
 url["ro" ] = folderItem.Uri.ToString();
 SheerResponse.ShowModalDialog(url.ToString(), true );

As far as I can tell, "control:Sitecore.Shell.Applications.Media.MediaBrowser” is Sitecore’s “magic string” identifying the media browser dialog.  This code builds a URL pointing to the dialog with a querystring parameter identifying the root item for the browser (in this case, /sitecore/media library/Images), and then shows the dialog.

Initially, I placed this code in my class’ Execute() method.  After re-compiling, I was able to click the button and see the media browser, choose an image, and click OK.  But then nothing happened...  No way to capture what image was selected and save it to the database!

After lots and lots more exploring and experimenting, I found that I needed to start a client pipeline before showing the dialog and then wait for a postback in order to capture its result.  Here’s the minimal code to start the pipeline:

  NameValueCollection  parameters = new  NameValueCollection ();
  Context.ClientPage.Start(this , "Run" , parameters);
 

This basically tells Sitecore to start a pipeline and execute the “Run” method in the current class.  So I moved the ShowModalDialog() code into a new Run() method in my class.  The method gets passed a ClientPipelineArgs object, so the method signature looks something like this:

 protected  void  Run(ClientPipelineArgs  args)
 {
 }
 

Calling WaitForPostBack(true) on the args parameter after showing the dialog causes the pipeline to call my method again when a postback occurs (like, when the media browser dialog is closed).  When that happens, args.IsPostBack will be true AND args.Result will contain the dialog’s result.  So the Run() method skeleton looks like this:

 protected  void  Run(ClientPipelineArgs  args)
 {
     Database  masterDb = Factory .GetDatabase("master" );
 
     if  (args.IsPostBack)
     {
         // Do something with args.Result here.
      }
     else
      {
         // If this is not a postback, we want to display's media browser dialog.
          UrlString  url = new  UrlString (UIUtil .GetUri("control:Sitecore.Shell.Applications.Media.MediaBrowser" ));
 
         // We want the browser to be rooted in the Images folder in the media library.
          Item  folderItem = masterDb.GetItem("/sitecore/media library/Images" );
         url["ro" ] = folderItem.Uri.ToString();
 
         // These two lines displays the dialog and causes a postback to this method when it is closed.
          SheerResponse .ShowModalDialog(url.ToString(), true );
         args.WaitForPostBack(true );
     }
 }
 

One last thing I want to cover.  I wanted to limit when my button would appear (it doesn’t make sense to set a Thumbnail for items other than renderings and templates, I don’t think).  Luckily, this is pretty easy.  In your Command class, you can override the QueryState() method and have it return a CommandState telling Sitecore if your button should be enabled, disabled, or hidden.  It receives a CommandContext object that can be used to find out what the current item is in the Content Editor.

I’ll take this opportunity to once again link my full Thumbnail Button Module ThumbnailButtonModule-1.zip which contains the full source.  In addition to what I’ve covered here, it contains the QueryState() code, the code to update the Thumbnail field on the current item, and some code that passes the existing thumbnail in to the media browser so that it’s pre-selected when the dialog opens.

Being able to display Sitecore’s media browser dialog to allow a user to choose or upload an image will come in handy for other projects, so I’m really glad I put the effort into figuring out how to make it work.  Hopefully, I’ve been able to share this knowledge here and other people will be able to take advantage of it as well!  If you have any questions, comments, critiques, etc – please post a comment here on the blog or reach out to me via Twitter – @williamsk000.

with 2 comment(s)
Filed under:

ThumbnailModule

Once I discovered how helpful it was to present thumbnails to content authors in the Page Editor, I started adding them to all of the templates and renderings that I created.  Very quickly, I started to get frustrated with the process (see my part 1 post for the details)...  I don’t like to leave standard fields visible all of the time, so having to turn those on and off and having to dig through them to find the Thumbnail field got old fast.  So I had an idea – add a custom button to the ribbon that would let me choose a thumbnail quickly without all of that hassle. 

The process of building a custom ribbon button, making it pop open the media browser dialog, handling the result, and updating the item’s thumbnail was rather complex and involved a bit of a learning curve for me.  So I’ve decided to leave the in-depth discussion for another blog post and just give the final solution here.

So, may I present - ThumbnailButtonModule-1.zip

The zip file contains a ready-to-go Sitecore package ZIP that you can install using Sitecore’s package installation wizard as well as the source code if you want to see how it was done.  If you compile the source yourself, you will need to update the namespace, class, and assembly name in the config file before placing it in your site’s App_Config\Include directory.  Also, if you don’t install the package then you will need to add the button to the ribbon in the Core database yourself.

I’m already working on another post for later today detailing how I built this module, so if you’re interested in the gory details - I'll have something for you soon!  And if you have any questions or comments or critiques, please let me know either in comments here or via Twitter @williamsk000.

with no comments
Filed under:

With Sitecore 6.4 and 6.5, the new unified Page Editor is wonderful for giving content authors a friendlier experience and more control over their page layouts.  I was never a fan of the page designer in previous 6.x releases, so I was thrilled to see the Page Editor changes.  One of the coolest parts, in my opinion, is the support for thumbnails when inserting new components or pages.  If you’re not familiar with them, here are a couple of screenshots.

InsertPage InsertRendering

Template and Rendering Select Dialogs with Thumbnails Provided

Now I may not be using it exactly as intended (anyone who knows for sure, feel free to comment), but I think this is a great opportunity to give content authors a more friendly interface for choosing what rendering to stick in a given placeholder or what type of page they want to create.

So how do you do it?  Today, I’ll show you the hard way using built-in Sitecore functionality.  Then tomorrow I’ll introduce a module I came up with to make the process much more streamlined (how the module was built deserves a blog post all to itself).  Let’s get started...

The key here is a new standard field named __Thumbnail.  It is in the Appearance section on all items deriving from Standard Template.  This is the “hard way” because that section is not visible within Content Editor by default, so you have to turn on visibility of Standard Fields.  I’ll walk you through the process for a template:

  1. Open Template Manager and navigate to the template you want to provide a thumbnail for.
  2. In the Ribbon, click on the View tab.
  3. In the View chunk, check the checkbox next to “Standard Fields”

    StandardFields
    Standard Fields Checkbox
  4. Switch to the “Content” tab for the template.

    ContentTab
    Content Tab
  5. Scroll down to the “Appearance” section (you may have to expand it) and look for the Thumbnail field.

    ThumbnailField
    Thumbnail Field
  6. Choose an image in this field and it will be displayed in the Insert dialog in the Page Editor.  You might want to use a screenshot from a comp or an actual page on the site instead of the lame wireframe I created for this post – it’s up to you.  Be sure to save your changes to the template!

This same process works for Branch Templates, XSL Renderings, and Sublayouts as well.  Note, to get renderings and sublayouts to appear in the Insert Renderings dialog, you will have to add them to the Allowed Controls on a placeholder settings item.  If you don’t know how that works and want me to post about it too, send me a message on Twitter or post a comment here.

Sitecore’s thumbnail feature is a great usability improvement in recent releases and can really help to guide a content author when making decisions about what type of page to create or which rendering to stick in a given placeholder.  Unfortunately, the field is a little difficult to get to in Sitecore’s default interface.  Tomorrow, I’ll post about a module I have created that adds a “Thumbnail” button to the ribbon to give you a convenient shortcut to assigning thumbnails.

One quick comment to the Sitecore guys regarding the unified Page Editor.  It’s bounds ahead of the old page designer, but I recently had an opportunity to work with Sitefinity 4.  Their drag-and-drop interface is even more intuitive – I would love to see something like that come to Sitecore!

with no comments
Filed under: ,

So the next release of EviBlog for Sitecore is going to be called WeBlog… The new trac page and SVN have been set up - you can see for yourself here http://trac.sitecore.net/WeBlog/

Being the curious soul that I am, I decided to grab the latest code from Subversion and try to get it running on the latest Sitecore 6.5.0 Update-1. The primary difficulty I had was the lack of an up-to-date package ZIP to get the items into a clean Sitecore database (the WeBlog-pre 2.0.0.zip in Subversion was pretty out of date). I powered through and I think I’ve found all of the Sitecore items that needed to be updated. WeBlog does appear to be working, at least. :)


Figure 1 - The WeBlog tab in the Page Editor ribbon

So what’s new? Hard for me to say because I actually haven’t kept up on EviBlog development… So some of these features may be new to me, but not new to WeBlog. The first thing I noticed is the integration with Sitecore’s page editor. There is now a “WeBlog” tab in the ribbon with icons for creating new blogs, creating categories within a blog, or posting a new blog entry (see Figure 1). I only tried this as an admin user, so I don’t know how the security is set up on these buttons - but I imagine it’s possible to hide the new blog button from non-admins. However, restricting who can post to an individual blog doesn’t appear to be included and seems like it would be rather complicated to implement using Sitecore security. Maybe WeBlog needs a field on the Blog template to let you specify a security Role allowed to create new entries and they could check that when the New Entry button is clicked?


Figure 2 - Administration component

The next new thing I noticed was an Administration component at the bottom of the right rail (Figure 2). This only appears while in Edit mode and currently only allows you to modify what theme the blog is using. I couldn’t get this to work at all (changing the value in the drop-down caused the page to post back, but the change wasn’t reflected and it wasn’t possible to click the Save icon in the ribbon). An admin function might be better implemented using an EditFrame with a button to open the field editor. It looks like they’re already doing this with the “Blog” button in the “Settings” chunk in the ribbon.

Speaking of themes, WeBlog comes with a few but they are all just color variations of the same basic theme. It would be nice to see how flexible the mark-up and styling is - hopefully someone good at CSS can produce a really different looking theme to show off the capabilities. As far as how themes are implemented, they appear to just be a Sitecore item with one field pointing to a .CSS file on disk.

Additional new features include CAPTCHA support (with a built-in option as well as reCAPTCHA), and AddThis support for Facebook like buttons, a Tweet button (along with a counter), and the usual AddThis drop down to support other sharing possibilities (I see a sublayout for ShareThis too, but don’t know what it takes to get it working or if it’s global or can be configured per-blog).

In this build, some things definitely don’t work the way I’d expect. When I add a new entry to my blog in page editor using the “New Entry” button in the ribbon, it prompts me for the name of the new entry, but then doesn’t navigate me to the entry so that I can edit it (I suspect this may be due to WeBlog using the NewsMover module to move it into a year/month folder structure maybe). Also, the new entry doesn’t show up in the list of entries on the blog’s main page when it re-loads. If I force a refresh, it shows up and I can click on it to get to the entry and edit it. I already mentioned the non-working Administration component. WeBlog is still pre-release software, so I can’t ask for much… I just wanted to check it out since it’s been a while. It looks really good and I can’t wait to try out the release - hopefully coming soon!

Filed under: , ,

For a while now, I’ve been primarily using Sitecore sublayouts as my rendering-of-choice. The suite of controls available are hard to resist, and it’s easier for someone that doesn’t know XSLT or Sitecore to modify the sublayouts (they’re just user controls, after all). Recently, I’ve started data binding SItecore items to ASP.NET Repeater controls in my sublayouts in a new way using LINQ.

For example, let’s say we have a multilist field on the current item and we want to display a list of the linked items with thumbnails and short descriptions. Here’s how I might now build my Repeater for that:

<asp:Repeater id=“SeeMoreRepeater” runat=“server”>
        <ItemTemplate>
                <sc:Image runat=“server” Item=“<%# Container.DataItem %>” Field=“Thumbnail” />
                <div class=“header”>
                        <sc:Text runat=“server” Item=“<%# Container.DataItem %>” Field=“Title” />
                </div>
                <p>
                        <sc:FieldRenderer runat=“server” Item=“<%# Container.DataItem %>” Field=“ShortDescription” />
                </p>
        </ItemTemplate>
</asp:Repeater>

Code-behind looks like this:

MultiListField seeMoreField = Sitecore.Context.Item.Fields[“SeeMore”];
SeeMoreRepeater.DataSource = seeMoreField.TargetIDs.Select( id => Sitecore.Context.Database.GetItem(id) );
SeeMoreRepeater.DataBind();

This seems like a very clean way to build a Repeater control and a clean way to data bind in code-behind. Additionally, using the <sc:Image>, <sc:Text>, and <sc:FieldRenderer> controls enables the content to be edited when the page is viewed in Sitecore’s page editor.

What do you think?

with 6 comment(s)
Filed under: , ,

It’s spring break and I wasn’t going to make any blog posts this week, but I just ran across this post ( http://www.markvanaalst.com/custom-field/using-jquery-in-custom-fields/ ) from Mark van Aalst concerning using jQuery in Sitecore’s content editor and I just had to comment on it...

I have tried to do this a few times in the past with little to no success. The problem is that, as Mark’s post points out - you need to call $.noConflict() first thing before any other script libraries get loaded. The key that he found in Alexey Rusakov’s FiedTypes module source code (available at http://trac.sitecore.net/FieldTypes/ by the way) was exactly how to do that... You can insert a custom processor into the renderContentEditor pipeline to output the jQuery script first thing. And the truly brilliant part - Alexey is ensuring it is the very first processor in the pipeline by using the new auto-include config file feature in Sitecore 6! (if you haven’t seen that feature before either, check out http://sdn.sitecore.net/faq/administration/how%20to%20auto-include%20configuration%20files.aspx on SDN and be amazed)

Mark’s post didn’t 100% put the pieces together for me, so I’ll spell it out here:

Step 1) Create a pipeline processor class to add jQuery to the page’s <head>. Mark’s post has a great example, so I won’t repeat it here.

Step 2) Create a new .config file in /App_Config/Include. The contents just need to look something like this:

<configuration xmlns:x=“http://www.sitecore.net/xmlconfig/“>
  <sitecore>
    <pipelines>
      <renderContentEditor>
        <processor x:before=“*[1]” type=“Your.Type,Your.Assembly” />
      </renderContentEditor>
    </pipelines>
  </sitecore>
</configuration>

The magic bit is the before=“*[1]”. This is explained in the SDN link above, but in case you can’t get to that - you can specify any XPath query (relative to the attribute’s node’s parent). *[1] represents the first child, so in this instance we are asking Sitecore to insert our new processor before the existing first child of the <renderContentEditor> element. This ensures it runs first before any other processor has a chance to inject a script into the content editor page.

In the past when trying to get fancy with a custom field type, I’ve had to fall back on using prototype and give up fancy stuff like scriptaculous or jquery while working in the content editor. No more! With this technique, you can always apply jQuery’s $.noConflict() early on and not worry about some other library calling the wrong $() implementation and causing weird errors. Thank you, Mark! And thank you Alexey for sharing your source!

For the last few weeks, I have been working on a project to customize Able Commerce 7.0.4. When I started on this project, I had never seen Able before and certainly had no idea about the right way to go about doing some of these customizations. Over the course of the project, I’ve figured out a few “best practices” and I figured I’d share them with my blog readers. If you’re reading this and have worked with Able before, feel free to share any other thoughts you may have or correct me if there’s an even better way. :)

The first step in customization is to create a new site theme to contain your work. Note - this is important even if you don’t plan to customize the colors, graphics, and layout of the site. To create a new theme, log in as an admin and navigate to the “Themes File Manager” page on the “Website” menu.

Able01.l5UWbEhSx35A.jpg

(click for larger image)

In the lower-left corner of this screen is a box to create a new theme by copying an existing one. For this discussion, I have copied the YellowJacket theme and created a new one called “MyTheme”.

Able02.H5sM8AtnVCz2.jpg

This theme will act as a sort of “container” for your customizations and allow you or your end users to easily activate and deactivate them through the Able UI.

Next, you’ll need to copy a clean Scriptlets folder into your theme (I don’t know why copying an existing theme doesn’t just do this for you... *shrug*). In a standard Able Commerce 7.0.4 install, the Scriptlets folder is located in the App_Data folder under the root of the site. Copy it into the root of your theme’s folder (in my case, I copied /App_Data/Scriptlets to /App_Themes/MyTheme/Scriptlets). If you look inside this folder, you’ll see a Default folder (containing all of the default scriptlets that come with Able) and a Custom folder (containing a structure of empty folders). If we copy a scriptlet inside of the Custom folder, Able will automatically use it in place of the default one. In fact, this is done automatically for you when you customize a scriptlet in Able’s admin interface. But I’ll get to that in a bit.

Now - to actually customize something... Here’s something simple - by default, the Contact Us page just displays some contact information. I’ll add a form to allow the user to submit feedback through the website.

First, I created a new ASP.NET user control - ContactForm.ascx and put it in the /ConLib/Custom folder. This spot seems to exist specifically for custom controls like this. Previously, I have copied controls that come with Able (from the parent ConLib folder) here to make minor changes to them as well.

My ContactForm.ascx is very simple - a few text boxes, a few labels, and a submit button plus code to send an e-mail to an address that is specified via a property. You would probably want to fancy it up a bit with some validation controls, error handling, etc. If you want to see the code I’ve created though, you can download it here: http://www.kevinwilliams.name:8000/dotNetAndStuff/AbleContactForm.zip. The Able Commerce magic comes from this comment at the top of the .ascx:

<%--

<conlib>

<summary>

Displays a simple “contact us” or feedback form on the site that allows the user to type a message

and have it submitted to the site’s owner via e-mail.

</summary>

<param name=“EmailTo” default=“admin@example.com”>

Specifies the e-mail address you want the contents of the form submitted to.

</param>

</conlib>

--%>

This is the help text that will be displayed inside Able Commerce for this control. To see it, log in to the Able admin and choose the “ConLib Reference” option from the “Help” menu. In the “Select Control” drop-down, scroll to the bottom and select Custom\ContactForm and the help for the control will be displayed. Note, this also includes a “Usage” that looks like this:

[[ConLib:Custom\ContactForm EmailTo=“admin@example.com”]]

This is how the new control is placed onto a scriptlet - which happens to be the last step I need to do to make the contact form appear on the site. In the Able admin, choose the “Content and Layout” option from the “Website” menu. In the “Show Scriptlets From Theme” drop-down, choose the theme being customized (in my case, “MyTheme”). Able will present a list of all scriptlets for that theme. Scrolling down a bit, I see the “Contact Us” scriptlet. To the right of each scriptlet there is an “Edit” button (the icon looks like a notebook with a pencil). Clicking this brings up the screen used to customize a scriptlet:

Able03.n4rhGVQY1GtO.jpg

(click to enlarge)

If you look at this screenshot, I have basically just copy/pasted the example usage from the help to the bottom of the existing scriptlet content. Clicking the “Save” button takes me back to the list of scriptlets. But when I scroll down to “Contact Us”, I can now see an X in the “Custom” column - indicating that I have customized this scriptlet.

Anyhow - that’s it! When I log out of the admin interface and go to the Contact Us page on the site, I can see and use my new contact form.

The practices I’ve mentioned here (place your customizations inside a custom theme, use the Able interface to customize scriptlets, add the XML comments to your custom user controls, and placing your user controls in the ConLib\Custom folder) should make it easier to upgrade your site to new releases of Able Commerce, make it easier for you to share your customizations with other Able users, make your work easier to maintain, and make it easy to enable or disable your customizations through the Able admin interface. Have fun!

Filed under:

Mark van Aalst’s EviBlog shared source module takes advantage of the new RSS feed features added to Sitecore in version 6.2, but if you haven’t set that up yet (I hadn’t!) then you may be wondering how to make it work. It’s actually quite simple!

In Content Editor, navigate in the tree to where you want your RSS feed URL to live. Add a content item using the /System/Feeds/RSS Feed data template and name it as you want it to appear in the URL. In my case, I wanted all of my site’s RSS feeds to have URLs such as http://www.kevinwilliams.name:8001/RSS/BlogName.aspx so I created a folder named RSS and created an RSS Feed matching my blog name (in this example, I used “TestBlog”). Heres a screenshot:

Screenshot2010-03-07at1.03.43AM.iUv4jNJOT7M5.jpg

When setting up a Sitecore 6.2 RSS feed, the “Items” field defines what items will be included in the feed. You can either use a Sitecore query ( like query:/sitecore/content/Home/TestBlog/*[@@templatekey=‘blogentry’] ) or simply provide the path to an item whose children should be included in the feed like I did above. Enter a title and description for your blog, and that’s it! EviBlog is already configured with the proper Feed device settings for Sitecore 6.2, so this should be all you have to do. Publish changes and hit your URL to see the RSS feed for your blog! My test one is at http://www.kevinwilliams.name:8001/RSS/TestBlog.aspx.

Something that doesn’t come with EviBlog, but I wanted to add to my site was a “Subscribe via RSS” link on my blog page. To do this, I created a new XSLT Rendering called “RSS Link” and gave it a parameter to control the text that appears like this:

<xsl:param name="Link_Text">Subscribe via RSS</xsl:param>

Then I made the body of the template look like this:

<xsl:template match="*" mode="main">
<sc:link type="application/rss+xml">
<img src="/sitecore/shell/Themes/Standard/Custom/16x16/rss.png" alt="RSS Icon" border="0"/>
<xsl:value-of select="$Link_Text"/>
</sc:link>

</xsl:template>

I want this link to appear in my blog’s sidebar, but the renderings allowed there are restricted. To allow my rendering, I opened the content editor to /sitecore/Layout/Placeholder Settings/phBlogSidebar and added the “RSS Link” rendering to the Allowed Controls.

Lastly, I opened the main blog content item in the page designer, selected the “phBlogSidebar” placeholder, and added my RSS Link rendering. I opened the properties for the rendering and set the Data Source to the RSS feed I created earlier, clicked OK, and clicked Save in the designer. The “Subscribe via RSS” link now appears in my blog’s sidebar!

The only thing left to do would be add support for auto-discovery of my RSS feed (for aggregators like Google Reader). It’s rather simple ( there is an article about it here: http://www.petefreitag.com/item/384.cfm ), but requires inserting some HTML into your page’s <head> tag. One idea for doing this would be to re-implement the above RSS Link rendering as a sublayout instead and then add the HTML to Page.Header.Controls in the ASCX file’s Page_Load() or something. I’ll leave that as an exercise to the reader. :)

EviBlog makes good use of Sitecore 6.2’s new RSS feeds feature and therefore it is very easy to add RSS to your blog. If you’d like more information about the new RSS feed functionality in Sitecore, take a look at the Presentation Component Cookbook on SDN or feel free to contact me if you need any help!

with 1 comment(s)
Filed under: , ,

Most of my posts here are directed towards developers writing code or building solutions with tools like Visual Studio, Sitecore, or Silverlight. This particular post talks to more of a System Administrator person... I’ve found that sometimes you have to know how to configure the server yourself (or at least be willing to figure it out), and that was the case for me this time. But while I had to figure it out myself, I’m going to save the next person the trouble by documenting my work here. :)

Windows Media Services 2008 is actually an optional component for Windows Server 2008, but I did my install using the MSU (Microsoft Stand-alone Update) files from here http://www.microsoft.com/downloads/details.aspx?FamilyID=9ccf6312-723b-4577-be58-7caab2e1c5b7&displaylang=en. I downloaded the three 32-bit files (my Win2k8 Server is 32-bit) and installed them in the order Core, then Admin, and then Server. I don’t know if installation order matters - that’s just what I used. :)

Installing these updates just makes the roles available to your server, but it doesn’t make them active. To do that, you will need to open Server Manager, go to Roles, and click Add Roles. Find the Streaming Media Services role and select it for installation. When prompted for the role services, I selected the Windows Media Server and Web-based Administration options. When prompted for the transfer protocols, RTSP was pre-selected and HTTP was grayed out. After some investigation, I learned that HTTP will be grayed out if you already have IIS running on port 80 on this server (which I do) - but it’s possible to enable HTTP on an alternate port after everything else is set up, so I allowed installation of the role to finish.

At this point, I discovered a new Windows Media Services icon in my Administrative Tools control panel. If you open this, an MMC console will open with Windows Media Services at the root of the tree, but there are no servers under it! You can simply right-click on this, select “Add Server”, and type the name or IP address of your server.

Screenshot2010-03-04at9.17.38PM.Ws6xw4ERr2SA.jpg

After adding the server, you can expand it and you’ll see a node labelled “Publishing Points”. After the initial install, there will be two publishing points defined - one “on demand” and one “broadcast”. These do exactly what they sound like - the on-demand publishing point serves up videos as they are requested and the broadcast publishing point broadcasts videos that users can tune into (like tuning into a television broadcast). For the purposes of my project, an on-demand publishing point will do the trick. I want to serve individual videos on the website as users request them - on demand.

On-demand publishing points serve video from a specific source... This source can be many things including a playlist or even another media server. But for my needs, a directory on the filesystem serves nicely. The default on-demand publishing point created when you install Media Services is a directory - C:\WMPub\WMRoot. You can see this by clicking on the <Default> publishing point and then selecting the Source tab on the right (as pictured below).

Screenshot2010-03-04at10.47.18PM.Mrnf0sHca7eP.jpg

Note that by default, this on-demand publishing point is not enabled. Clicking on the icon in the lower left of the right pane will turn it on. At this point, you can actually try streaming one of the sample files. I opened Windows Media Player on one of my other computers, and hit CTRL+U (for “Open URL”). In the dialog that popped up, I entered the path to one of the sample files listed in the screenshot above (I chose pinball.wmv).

\Screenshot2010-03-04at10.54.49PM.zbuuDaNRRm1k.jpg

This is an RTSP URL (remember I said earlier RTSP was enabled, but HTTP was not). “server1” is my server and pinball.wmv is the file I chose to stream. Clicking OK on the dialog caused Media Player to immediately start playing the video - IT WORKS! I can now throw any WMV videos I want to make available for streaming into the C:\WMPub\WMRoot and my server will stream them on a URL like that one.

Let me quickly go through the process of setting up HTTP. This is important because Silverlight (well, Minoplayer at the very least) does not seem to support RTSP. If you go back to Server Manager and drill down into Roles, Streaming Media Services, Windows Media Service, and click on your server. Then on the right, click on the Properties tab, select the “Control Protocol” category, and find the HTTP Protocol Plug-in (see screenshot below).

Screenshot2010-03-04at11.06.01PM.ilep39Ufpidc.jpg

Right-click on the HTTP Server Control Protocol and select Properties to bring up this screen:

Screenshot2010-03-04at11.08.26PM.bMLs00Z750OY.jpg

I had to “Use other port” and choose something other than port 80 since IIS is already using it (note - I didn’t use 81 either because in my configuration, IIS is also using that port). Click OK, and then right-click on HTTP again and select “Enabled” to enable it.

Now you can go back to Windows Media Player, hit CTRL+U again, and this time enter an HTTP URL (such as http://server1:82/pinball.wmv - note the port number), and it should play just like the RTSP stream did before.

One last thing I’d like to mention before I wrap up this post. Although my server was streaming to local clients just fine, when I opened the HTTP port on my firewall and forwarded it to my server - I couldn’t get any clients to work! A lot of digging uncovered this hotfix to Windows Media Services: http://support.microsoft.com/kb/960372. After installing that hotfix and rebooting my server, everything worked perfectly!

I can’t claim to be an expert on setting up Windows Media Services, but following the steps above I was able to get a server set up to stream WMV videos to Windows Media Player and to Minoplayer over the Internet. The next steps were wrapping up MinoPlayer in an ASP.NET custom control, building a Sitecore sublayout to wrap that, and building some infrastructure in Sitecore to allow definition of publishing points, describing videos hosted on those publishing points, and possibly even a custom field type in Sitecore to allow uploading of new videos to the directory from the CMS. I’ll follow up this post in the next few days, but if you have questions in the meantime - feel free to contact me!

For quite a while now, I’ve been wanting a simple video streaming solution that I could recommend to clients for whom progressive video downloads won’t cut it and who don’t want to pay to use a CDN like Edgecast or UVault or Limelight. Clients who don’t need to serve a ton of video on their site, and would be able to host it themselves if it were easy and integrated with their WebCMS.

I’ve started working on just such a solution. Right now, I’m using Windows Media Services 2008 (an optional component of Windows 2008 Server - Standard and Enterprise editions) to host and stream the videos, Sitecore to manage uploading and publishing of new videos and related content, and a Silverlight video player I found called Minoplayer. This requires that videos be encoded to WMV format, but I’m already thinking about ways to support Flash video for people who don’t want to use Silverlight (lighttpd’s mod_flv_streaming module looks promising). And of course, HTML5’s <video> element looks interesting too (although codec support problems may make it more difficult to implement).

You can see an early example of the end result of my work here - http://www.kevinwilliams.name:8001/Kologarn.aspx

(be kind to my server - I’m asking a lot from it running Sitecore, SQL Server, Media Services, and a bunch of other stuff on crappy old hardware)

I will post details of my Media Services installation and configuration experience, some information about the Sitecore solution, etc in the next few days.

More Posts Next page »