Tridion 2011 Favorites

Tridion 2011 is full of small useful improvements. One of those is the addition of the ‘Favorites’ section next to Custom Pages in the tree menu. We can have shortcuts to Structure Groups, Folders, Pages, Components, and even Categories Keywords. This is very handy, especially for Demos and Tridion Webinars. Saves a lot of time!

Adding an Item to Tridion 2011 Favorites

Sending an item to Favorites is as easy as a right-click on any item.

Then the item is in the Favorites tree.

I use it for my Template Folders and common Structure Groups for publishing.

GUI Customizations with the Favorites

It is possible to use a Data Extender GUI Customization with a Favorites folder the same as we do for any list item in Tridion. Warner Soditus asked a question on SatckOverflow this week and with the help of Nuno (otherwise known as KnewKnow) and Puf we have another good solution for improving the Tridion experience.

Thanks a lot for adding another favorite feature to Tridion 2011!

Tridion 2011 Upgrade in 10 Easy Steps

Tridion 2011 provides too many benefits for the organization and development team to be overlooked any longer. I recently upgraded a system from Tridion 5.3 to Tridion 2011 and it was a lot less scary than I originally thought. Tridion has provided us a better installer and documentation than past versions and an amazing new product full of features. Having the right approach and knowing where to focus your efforts are a key to a successful upgrade. In this post I hope to share some of my experiences with the upgrade and provide some tips to help make it an easy one.

1. Read the install manual and upgrade manual.

No, really, please print it, sit in your favorite chair or lotus position, and read it – all. The Live Documentation site also has it online. Now, go back and circle or highlight things you need to double-check in your environment such as Java version installed on your Deployer or Broker, SQL Server SP version, and the version of Windows Server you are running on the CMS.

2. Upgrade the Database

Tridion provides a great DB tool for upgrading the database, located in the Installer/Database folder named ‘DatabaseManager.exe’.  My database was a 5.3 SP1 SQL Server 2005 DB and the upgrade ran perfectly and was done in around 15 minutes. This is a no risk step and in my experience always works.  Please backup your DB before you begin.

Upgrade both the CMS Database and the Broker Database.

The tool requires the SA account (or one with equivalent permissions) and the password of the TCMDBUser and other Tridion user accounts.

3. Upgrade the CMS

Very easy with the included installer.  The installer has been improved and adds more manual detail control over what is installed. Don’t check Audience Manager (Outbound Email) or Translation Manager (world Server / TMS) unless you are using them. Not nice to have unused Tridion pieces installed and not configured in your environment – and also not nice to configure something you’re not using. You can add them back later using the same installer files (not add/remove programs because this throws an error – just use the original installer file).

This is a next, next, next process and also very low risk. Great job by the installer team.

If you have SiteEdit code in your templates, first install and register SiteEdit extension DLL.   Then add the Extension to the Tridion MMC snap-in.

4. Test the CMS

Login to the CMS and you will see a new GUI Screen and a progress indicator. Be patient – the new Tridion GUI takes longer to load on the first time – but after it is about 20-30% faster on the same hardware. Sweet! :)

Things to test:

- Opening and saving Components. Do you use the Event System?  See below for tips on the Event System.

- Previewing. Do you use SiteEdit? You must re-register the SiteEdit DLL in the Tridion MMC SnapIn.

- Creating a new Component and new Page.

- Custom pages – The Tridion 2011 TOM API is fully supported and backwards compatible. These custom pages should just work. However, many of the original Powertools will not work because they re-used js from the old Tridion GUI. A new Powertools initiative has been started and a Page Publisher tool is already finished. Please join the fun and help us make the 2011 Powertools better.

- Publishing – not yet! Wait until the next step.

5. Installing the Broker and Deployer

There is not a nice installer here and it is a manual copy / paste action, especially if you’re using a Java based Content Delivery system. There are a lot of new 3rd party jar files and yes, you need them all.

- Add the SQL Server jar from Microsoft if using SQL Server. Please note there are different jar files for Java versions. Java 5 requires sqljdbc.jar and Java 6 requries sqljdbc4.jar. Tridion documentation for Content Delivery has more details.

- Create a cd_storage_conf file – The cd_broker_conf file is deprecated and replaced with a new cd_storage_conf. Grab the example one from the install folder, Tridion 2011 SP1\Content Delivery\resources\configurations, edit the connection string to the DB, and define the ItemTypes mapping.

- Update the logging config – Another new item here is the logback logger used. It has its own config file and has extensive documentation. This is one of many examples where Tridion took great, existing frameworks and put them under the new Tridion 2011 architecture – great job.

6. Test the Deployer

- Publish a Page with only a Page Template producing static HTML and no Component Presentations. This tests the basic ability to publish to the Filesystem. Try to view the published page from the website after. Works – yay! Doesn’t work – double check your deployer storage_config.

- Publish a Page with Component Presentations. This will add link data to the Broker and insert records in a DB or write new files on the filesystem, depending on your bindings in the config.

- Publish a dynamic Component Presentation to the Broker DB. This tests your Broker DB connection. If it does not work, go review the cd_storage_conf.

7. Test the Broker

The broker API is 100% improved and still is fully backwards compatible. All my 5.3 broker calls worked perfectly.  If you’ve written your own SQL against the broker db you should test it well.

- View one of your existing pages that queries the Broker. If you do not have any yet, you can see the Tridion Content Broker Query documentation or my JSP example for some inspiration.

- Configure cache channel support

- Load test all your pages using Broker Queries.  They’ve re-written the Broker and you want to confirm all performs as well as before.

Stop and congratulate yourself for performing a successful upgrade. However, we’re not yet finished since you’ve likely developed some custom code in custom pages, event system, or gui extensions that also needs to be reviewed and tested.

Now we know we can publish our site and our thousands of lines of templates work fine.

8. Custom Pages and GUI Customizations

If you wrote your own custom pages using the Tridion API there is a very good chance this works 100%.  For me I had around 20 custom pages and all worked perfectly.  For asp.net solutions you’ll want to update them to use the new Tridion 2011 dlls in the client folder.  Tridion TOM is 100% supported in the 2011 but has a deprecated status.  Our custom pages should work 100% unless the Tridion ASP or JS GUI files are required (most times not, except in cases like Powertools).

We’ve been warned not to change the existing Tridion GUI asp and js files and the warning was for times like this – when we upgrade and lose those very handy little icons in the GUI.  This is the tricky area where someone modified Tridion GUI js or asp files.  I would re-evaluate each customization and think if you really must have it, and if so if you could rewrite it using a Tridion 2011 GUI extension.

I have written a few articles to help you get started with 2011 GUI extensions.  Fear not – the Tridion R&D team has provided us a great new GUI Architecture that is more open and allows us to legally extend the GUI in many supported ways. :) I have written a tutorial on creating your first GUI Extension and another about getting a quick start adapting the GUI Extension tutorial code for a new extension. The key here is expectations setting and planning. Do you really use all those extensions every day? Can the editors live without some of them while they’re being re-written in the new framework? Can you write an ASP custom page now in your old version (or also 2011) that does the same thing until the new shiny extension is ready?

9. Event System

Open the Cms config mmc, events section, what has a 1 is turned on.  For each of these it is a good idea to test it.  There can be complex logic, so take your time with this step.  Also you will need to configure the Cms to use your legacy event system.  Tridion re-wrote the event system for 2011 and I have a small article here about getting started.  But you can also keep running your old code.

- Tridion 2011 supports the old Event System and also provides a completely new framework for building a new one. The new Event System is really nice and the Tridion 2011 Delta Training is a good place to start learning more about it.

- Read about the old Event System support here.

- Use the Legacy Events Adapter for your old Event System. It is highly recommended to re-write the old Events to the Tridion 2011 Event System, but it is not mandatory before using Tridion 2011. This is something to be planned with the development team.

- You can also write a small script that resaves all components to trigger the oncomponentsave event, or to trigger other events.  This is a good idea in general as a way to test Event System functionality.

10. Templates

- All VBScript templates are 100% supported.

- SiteEdit?  I use SiteEdit and needed to register the SiteEdit dll using RegAsm (for SiteEdit 1.3) and also add it to the MMC snapin.

- Upgrade your templates to use the new Razor Mediator. It is very fast to write templates with Razor syntax, it is similar to VBScript but a lot more powerful, and much easier to learn than the DWT mediator or the XSLT mediator.  This assumes you know how to create a Compound Component Template.

Get the Razor Mediator

VBScript to Razor Guide

Razor introduction article

Summary

Upgrading the Tridion system is much easier with the new Tridion 2011 tools and support. The community is more active than ever and there are many nice Tridion 2011 extensions available from Tridion World.  In my experience the upgrade was a lot easier than previous upgrades – a real surprise when I think they replaced or upgraded a lot of the technologies under the platform.  Congrats to the installer and R & D teams!  We also have great new frameworks available in the new version, such as .NET 4.0, Solr, Logback, WCF, etc. With a sensible plan and step by step testing of various components we can perform the upgrade with ease and confidence. I hope this article gives you some hope that the upgrade is within reach and with some careful planning can be achieved with little risk.

Razor templates with Tridion 2011 – Getting started

The Tridion Razor Mediator brings all the goodness of the Razor template engine to Tridion.  The Razor mediator uses the official Microsoft Razor Engine and is dependent on .Net 4.0 or higher.  This is good news for us – any improvements in the script engine by Microsoft will be available to us.  Even better, the Razor Mediator is open source; we can see all the code and also update a dependency and recompile if we choose.

The Razor Mediator wraps the Tridion API and provides a more fluent interface to accessing items such as Components and Pages.  Not only that, but many helper functions are also included such as IsFirst, a method to get ComponentPresentations by template name, and super-easy access to Component Link fields and Embedded Fields.  You do not need to know C# or .NET to use it, but if you do then you can use existing .NET methods directly in the templates.  There are many other cool features that I will discuss here in the post.

What is a Mediator

The Tridion Mediator Framework enables developers to create alternative template engines for the Tridion CMS. In Tridion versions 4 and until version 5.2 there was no Mediator framework and we only had Tridion’s built-in “mediator” available and wrote templates in VBScript, JScript, or XSLT. Starting with version 5.3 with the introduction of Compound Templating any developer could create their own template engine, or Mediator, and use this instead of the built-in languages. The first Mediator was an XSLT mediator (for Compound Templating) created by Chris Summers and Yoav Niran. This is still a popular mediator today. However, the new Razor Mediator from Alex Klock promises to provide as much power as XSLT with a lot less sweating involved. :)

The Razor Mediator is built on top of the Razor syntax engine from Microsoft, released with ASP.NET MVC, and requries .NET 4.0 and Tridion 2011. If you have done any ASP.NET MVC development then you are familiar with the syntax. The Razor Mediator is not the first external template engine using Microsoft’s Razor engine.  Umbraco version 5 uses the Razor engine as its’ default template language, replacing the XSLT standard, and has been well received by the community, even by the XSLT die hards.

So, with all that said what are we waiting for?  Let’s dive in and start writing some Razor code.

10 Benefits of Razor Templating:

  • Lots of existing Razor code samples on the web
  • Great Razor Mediator documentation
  • Built on top of the official Microsoft Razor syntax engine. No custom coding or regex matches here! It’s all official! The Mediator is mostly a wrapper around Tridion’s object model with a few helper functions built-in.  Full .NET Framework available in Templates, including functions for Date/Time parsing.
  • Built-in helper functions for iterating over Component Presentations by Template Name (new in 1.2)
  • Smart rendering functionalities like auto-detecting RTF fields and calling ResolveXHTML for us.
  • Easy to access Component Link fields and Embedded Fields – no more looking up the Embedded Field syntax in the reference guide!
  • Logging to the Template Builder ouput window with @Debug(“”)
  • Best template import system of any mediator – can import standard libraries from the config file and not need to include them in each template.  Inline imports allow us to import any type of code – from HTML to CSS, JS, and Razor snippets (imports added in 1.2)
  • Clean syntax calls and requires less code than other mediators.  Less code = less typing = less bugs = happier.
  • Includes its’ own installer – a first for any Tridion Mediator

Getting started with the Tridion Razor Mediator

Getting started is easier than any other Mediator because it comes with its’ own Installer!

1. Download the latest Razor Mediator Installer here (http://code.google.com/p/razor-mediator-4-tridion/downloads/list)
2. Copy installer to the CMS Server
3. Run installer
4. Shut down COM+, restart Publisher

What does the installer do?
- Creates a new Template Building Block Type, Razor Mediator
- Updates the Tridion System.config file at /Tridion/config. If you want to modify the config and add your own default TBB includes this is the place to do it.

Try the new Razor Mediator

- In Tridion, create a new TBB, select Razor as the template language.  If you do not see it here, you may need to re-start your CMS.
- Type some Razor code, save. (ie. <h1>@Component.Title</h1>). Save in a new folder called Razor templates.  VBScript to Razor code samples
- Open Template Builder, create a new Compound Template, type Component Template.
- See if the Folder ‘Razor templates’ is there in the template list of the left. If not, then refresh the template list.
- Add your new Razor template, preview, and witness the magic.

Good news! We’re all ready to begin our small exercise to create a Detail Page using the Razor mediator. I want to highlight the new features from version 1.2, including the GetComponentPresentationsByTemplate, the TBB imports functionality and the IsFirst and IsLast methods.

Microsoft Razor syntax reference:

http://haacked.com/archive/2011/01/06/razor-syntax-quick-reference.aspx
http://www.asp.net/web-pages/tutorials/basics/2-introduction-to-asp-net-web-programming-using-the-razor-syntax

Tridion Razor examples:

http://code.google.com/p/razor-mediator-4-tridion/wiki/VBScriptToRazorExamples
Razor helpers and functions
Razor 1.2 new features

I’ll show a few examples of the power and simplicity of the Razor engine highlighting new features from the 1.2 version. I will not cover Tridion dynamic links or navigation since it requires too much logic / detail for this overview.

The Example – A story of on Index page and a Detail page

We will create an Index Page and a Detail page using the Twitter Bootstrap style and HTML.  Our Index page will show 1 Large text banner and a max of 4 intro articles.  Our Detail page will show the article with the Detail Template and also a max of 4 articles in the right-side rail / sidebar.

Detail Page

The detail page will contain 1 news article and a list of related articles in the right sidebar. First we’re going to need HTML before we start coding the template. This is a pre-requisite for any Tridion template and most of the time the template developer is not a front-end HTML developer, and in my case this is also true. Thanks to the Twitter Bootstrap project we have the HTML and CSS done for us – we simply need to fill in some content.

Schema Article Fields:

Heading
Sub-heading
Summary
Body
Links (embedded schema)
Link Title
Link URL External
Link URL Component Link

Source:  Embedded Link Schema
Source:  Detail Schema

Page Template Detail

The Page Template’s primary goal is to write out all the Component Presentations in the right location. It will also include all necessary js and css files, as well as specify a header and meta tags for our page. Page Templates do not write out Component fields. In this example I will only focus on writing out the Component Presentations. Find the location of the Article Component HTML and cut it out – replace with a comment “Article CT Here”. We will do the same for the Sidebar. This leaves us a nice Page Template beginning that we’ll come back to later. Leave the other hard-coded stuff in the HTML file. Later we will replace all content in the HTML page with a Component Presentation or a key/value string. We should never have any hard-coded content in any template – if we do then we have to change the template to update content – something we never want to do.

Tridion Page Template Shell

 

Component Template Detail

The Detail Component Template displays almost all the fields from the Detail page. Notice how we effortlessly display the embedded fields.

Component Template Sidebar

The sidebar template has a special requirement that we need to add a special css class to the first element in the list. For this we’ll use the IsFirst helper method in the Razor Mediator. Other Mediator’s do not have this out of the box.

Index Page

Displays the Article with the ct_banner_text template and up to 4 ct_home_intro Components on the bottom of the screen.

Index Page Templates

Page Template Index

Write the Component Template Code

- Create new Razor TBBs
- Create new TBB. In source tab, first choose the TemplateType of ‘RazorTemplate’. If you forget to do this you will not see it appear in Template Builder since we cannot use VBScritp templates in Compound Templates (default is VBScript in this window).
- Write code in text editor (Notepad++ or VS 2010), copy / paste into the window. Save and close.
- Create new Compound Template in Template Builder, type Component Template. Select the View menu and choose ‘Reload Template Building Blocks. You should now see your new TBB.
- Add TBB. Test with Article.
- Choose File, ‘Close and Open in Content Manager’
- In the ‘Linked Schemas’ tab, Add the appropriate Linked Schema(s). Save and close.
- Save and close. Ready for use on PT now. Copy Component Template name to Page Template ‘GetComponentPresentationsByTemplate’ method.

ct_home_intro


ct_home_banner

Banner Text Template Source

Razor Imports

I have a common <head> section for both templates and would like to re-use the HTML. For this I will use the new Razor Mediator @importRazor(“tbb webdav url”) method.

Configuring the Razor Imports
To use this I need to open the System.config file (from Tridion/config) and in the <razor.mediator node I should add the adminUser attribute:

adminUser=”DOMAIN\Username”

The User account running te COM+ service is usually MTSUser. Make sure this user is an impersonation user in the Tridion MMC snap-in. In my case it was not and I needed to add it. After adding it I shutdown COM+ and it was working fine.

Now it looks like:

<razor.mediator cacheTime=”60″ extractBinaries=”true” adminUser=”Dev2011\curlette”>

Accessing other properties

From Alex, “Every *Model component has a property, .TridionObject, that returns the actual Tridion object (so ComponentModel will return a Component).”
To access the Revisor of a Component we can use:
@Component.TridionObject.Revisor

Better Error Messages

On save it tries to compile your template against the Razor engine. Syntax errors are caught here. Warning- unfortunately the line # does not correspond to the real line #.
When running in Template Builder, any invalid field names are reported as:
“DynamicItemFields: Key ‘subheader’ Not Found In ItemFields”

Much better than the old error “Object or method not found”

Summary

If you are using Tridion 2011 then please give the Razor Mediator a try.  With as little as 1 hour you can run the installer, wrie a sample CT, and experience the simplicity and power of the Mediator.  As you can see the Razor Mediator makes it very easy to write Tridion templates while at the same time using the standard Razor syntax of Microsoft. We handled embedded fields and IsFirst conditions with ease and it is this kind of approach that makes templates faster to write and easier to maintain in the future. We only covered some of the possibilities with the Mediator and did not go into using existing .NET classes in our templates. A big thanks to Alex Klock for creating the Razor Mediator and continuing to add new features to it. I look forward to what is coming next in version 1.3!

Using a Tridion 2011 DataExtender to add a new metadata column to the GUI

DataExtenders are one of the coolest features in Tridion 2011 – and allow us to add our own column into the default Tridion ListView for all users.  We can save time when finding content – no need to open 10s of Components to find a specific value. However, with this new power comes a greater responsibility, and we must take extra care to make our code lightning-fast and test it well. In this example I will provide a working solution for adding a Metadata field column as well as explain how to do something similar yourself. All we need now is time and a little bit of luck to pull it off.

Tridion DataExtenders edit the response sent back from the GUI to the Browser.  In other words, our code runs every time for every user using the Tridion GUI.  DataExtenders are not limited to adding additional columns to the ListView.  Tridion uses this approach for the recent SDL World Server connector where they provide extra fields in the Schema edit screen, for example.  However, we’ll first start here on the ListView as it is the most useful GUI Extension for our scenario.

Tridion editors in my current project add the product sku to the Metadata field of each product.  When changing content or updating products they often have a product name or sku – and having this sku visible in the ListView provides a big time-saving.  The GUI also nicely provides the sort and filter functionality available from other columns to our new column.  However, to add this extra column our code will take time to find the sku value – and this will add a little bit to the response time of the GUI – especially for folders with lots of Components (100s).  So, it is a trade-off – will your users wait 1 second more for every 100 items in a folder if it means they can see the product Sku?  Do most of your folders contain less than 100 items?  In my case, yes, it is worth it, and we almost never have more than 100 items in a folder.

Example, note the Metadatafield column:

Metadata Column added to Tridion GUI

Getting started – Download the Example and Run the Code

1.  Get the example here: https://github.com/rcurlette/DataExtenderMetadataCol.  Open in Visual Studio 2010.

2.  Set the metadata fieldname.  Open the AddMetadataColumn.cs file, change ‘article_number’ to your fieldname.

3.  Compile.  Copy ALL files in the VS output folder (/bin/Debug) to the CMS Server at /Tridion/web/WebUI/WebRoot/bin.

4.  Create a new Folder on the CMS server for your DataExtender GUI Extension.  For example, create the DataExtender folder here: /Tridion/web/WebUI/Editors/DataExtender 

5.  Copy the DataExtender.config file to the folder above in step 4.

6.  Add the DataExtender config location to the System.config file in Tridion\web\WebUI\WebRoot\Configuration\System.config.

<editors default="CME">
  ...
  <editor name="DataExtender">
    <!-- DLL Files for DataExtender to be deployed to /Tridion/web/WebUI/WebRoot/bin -->
    <installpath>
     C:\Program Files (x86)\Tridion\web\WebUI\Editors\DataExtender\
    </installpath>
    <configuration>DataExtender.config</configuration>
    <vdir/>
  </editor>
</editors>

7.  Refresh the GUI and behold your new GUI ListView Column

Overview

How did we make that happen?  Well, DataExtenders are a special type of GUI Extension and allow us to modify the Response the GUI sends to the clients.  This is quite different than ContextMenu GUI Extensions.  Here our code is in ASPX / C#  while the ContextMenu code is mostly in JavaScript.  It feels like we’re hooking into a different aspect of the Tridion GUI and it requires a different approach – not only to how we develop, but also to how we test the code as well as how we debug and deploy.  Read on to find out how this was built and learn some tips and tricks for building your own DataExtenders.

Creating a new DataExtender

Speed is our primary concern when writing DataExtender code.   Not how fast you can type, but how fast your code executes.   The code is executed for every response – and we filter the response for the GetList command; all items in the listview.  Test the code with a folder containing hundreds of items – not only a few!  This cannot be overstated and is why I start with this disclaimer.  With the Tracing log feature you can view how much time your code is taking and adjust accordingly.  This is the most important and limiting aspect of developing a DataExtender since it affects all users and all content.

Create the .NET Class Project -  Create a new .NET Class Project and add a new Class file.

Extend the DataExtender Class - First we need to extend the DataExtender class.

public class AddMetadataColumn : DataExtender

Add the Namespace:

using Tridion.Web.UI.Core.Extensibility;

Reference the Assembly:  (located in Tridion/web/WebUI/WebRoot/bin)

Tridion.Web.UI.Core

Override the ProcessResponse Class

The ProcessResponse class is the main entry point for the DataExtender and is called for different types of GUI responses.  Notice here we check the command to see if it is for ‘GetList’.  This is critical for filtering out other requests and only listening to the listview.

This code is from a great example written by GUI Hacker Serguei Martchenko at http://www.sdltridionworld.com/community/2011_extensions/parentchangenotifier.aspx.

public override XmlTextReader ProcessResponse(XmlTextReader reader, PipelineContext context)
{
  XmlTextReader xReader = reader;
  string command = context.Parameters["command"] as String;
  if (command == "GetList")  // Code runs on every GetList
  {
    try
    {
      xReader = PreprocessListItems(reader, context);
...

Disclaimer: Any errors in the PreprocessListItems breaks the GUI.  If your XmlTextReader does not return at least the original data you will have missing data in the GUI.

 

ReCreate the <tcm:Item /> node, return as XmlTextReader

As mentioned above, we need to pass back at least the data that Tridion is sending back.  Thanks to the example code from Serguei we only need to follow a couple of simple rules.

1.  Re-write all existing attributes to the <tcm:Item node.

 xWriter.WriteAttributes(xReader, false);

2.  Add code and logic to get additional data.

attrValue = GetMetadataValue(comp, "article_number");

 

Getting the metadata value

In the example code I call a GetMetadataValue method for getting my data.

private string GetMetadataValue(Component comp, string fieldname)
{
  string value = "";
  xmlDoc.LoadXml(comp.GetXML(Tridion.ContentManager.Interop.TDSDefines.XMLReadFilter.XMLReadDataContent));
  string xPath = String.Format("//*[local-name()='{0}']", fieldname  );
  if (xmlDoc.SelectSingleNode(xPath) != null)
  {
    value = xmlDoc.SelectSingleNode(xPath).InnerText;
  }
  return value;
}
The performance criteria of the Metadata field example pushed me to use a TDSEWrapper instead of the Core Service.  The Core Service was quite slow – although I did not use Jaime’s approach with the tcp_Binding and instead used the default http_Binding.  I tried to create the WCF client once and re-use it, but maybe I did it wrong?  Anyways, it was the slowest of my examples.  Sergeui Martchenko also uses a TDSEWrapper for his code samples – maybe for the same reason?
Performance tests with folder of 250 Components:
Core Service 12 seconds
TDSE Object Model 12 seconds
TDSE GetXml 2 seconds

The load times are surprising and I would look to persisting Tridion data to an external system such as Redis or a database to improve performance times.  This cannot be emphasized enough – the Tridion API might not be fast enough – and you should seriously think about getting the data from another source.

3. Display the value with XPath in the DataExtender.config file

 <column xmlns=”http://www.sdltridion.com/2009/GUI/extensions/List”
                             id=”Metadatafield” type=”data” title=”Metadatafield”
                             selector=”@metadataFieldValue” translate=”String” />

Debugging – Enabling GUI Tracing

While writing this example I used the Trace debugging a lot – not only for timing certain actions – but also in my try/catch blocks for writing out errors.  This is the only way to Debug DataExtender code and it works well.  However, our log file grows REALLY fast – so you might not want to keep it running all the time.  In the C# code we can use Trace.Write to write output to the GUI Trace log.  Don’t use Trace.WriteLine – it doesn’t work.  This is also the best way to know our DataExtender is being executed. If we do not see the DataExtender name in the log file then it is not being loaded.

1.  Backup original file. Rename Tridion\web\WebUI\WebRoot\bin\Tridion.Web.UI.Core.dll to Tridion\web\WebUI\WebRoot\bin\Tridion.Web.UI.Core.dll.bak

2.  Copy Tridion.Web.UI.Core.dll Trace DLL to /bin.  Location:  \Tridion\web\WebUI\WebRoot\bin\trace\Tridion.Web.UI.Core.dll

3.  Turn on Tracing in \Tridion\web\WebUI\WebRoot\Web.Config

<compilation debug="true" defaultLanguage="c#">

4.  Confirm Trace File is Created.  Refresh GUI, Trace log, Tridion.Web.trace, created in Webroot\bin.

To delete Trace file – stop IIS (net stop w3svc) and then delete.

* Warning - This produces a LOT of log output – you do not want to do this in Production.

Example Trace code to output start time

Trace.Write("==========================Start PreprocessListItems " + System.DateTime.Now.ToShortDateString() + ", " + System.DateTime.Now.ToLongTimeString() + Environment.NewLine);
Trace File Output – Notice my GUI Extension is there ‘AddMetadataCol’.

Example Trace Code to display <tcm:Item XML

return xReader;  //around line 157
Trace.Write(sWriter.ToString() + Environment.NewLine);
// Trace.WriteLine breaks code

Quickstart:  Sample Empty DataExtender Class

If you are starting a fresh DataExtender you can use this class to get started instead of my  AddMetadataColumn.cs class.

This code is the basis of every DataExtender – and does nothing more than re-writing the XML output.

 

1.  Rename Example Classname to yours.

2.  Add your custom code to append content to the tcm:item node.

3.  Use Trace.Write to write to logTrace.Write(sWriter.ToString() + Environment.NewLine);

* Trace.WriteLine does NOT work – will break code.

4.  Update the Tridion Project References

using Tridion.ContentManager; // C:\Program Files (x86)\Tridion\bin\client
using Tridion.Web.UI.Core.Extensibility; // C:\Program Files (x86)\Tridion\web\WebUI\WebRoot\bin

 

Compile, Deploy, and Update DataExtender Config

As with all GUI Extensions – getting the right configuration is half the battle.

1. Copy the GUI Extension DLL and ALL other DLLs in the /Debug/bin (or /Release/bin) from the output of your VS build command to the Tridion Server folder \Program Files (x86)\Tridion\web\WebUI\WebRoot\bin

2. Add extension.config file to the /Editors/YourDataExtender folder. Check out the relationships between your Namespace, Classname, and AssemblyName for the config.

Take special note of the DLL Name (from the Project Properties window) and how it corresponds to the Config.  This was the most difficult part of writing the DataExtender for me.

type=”Namespace.Classname, Assemblyname” 

DataExtender Assembly Name
DataExtender Assembly Name
DataExtender Class File
DataExtender Class File

Tridion DataExtender Config fileTridion DataExtender Config File

3. Update the System.config file with the location of your config file

 

Add the DataExtender GUI Extension to the System Config

As soon as you do this your GUI Extension is ‘enabled’ and any errors / issues will be seen immediately in the GUI for all users.

Save in:  C:\Program Files (x86)\Tridion\web\WebUI\Editors\DataExtender\ DataExtender.config

Update the System.config file 

<editors default="CME">
  ...
  <editor name="DataExtender">
    <!-- DLL Files for DataExtender to be deployed to /Tridion/web/WebUI/WebRoot/bin -->
    <installpath>
     C:\Program Files (x86)\Tridion\web\WebUI\Editors\DataExtender\
    </installpath>
    <configuration>DataExtender.config</configuration>
    <vdir/>
  </editor>
</editors>

 

DataExtender Tips:

Be Fast, be very fast - Your code is going to slow down the GUI, no question about it. But, how fast can you make your code? This is a key factor to the success of rolling out your GUI Extension.

Document it -  your code will be executed for every list view in every Publication of the GUI. Knowing what is happening there will help all developers maintain it in the future. Flow diagrams are good here.

Use your own Dev Server -  I broke the GUI a lot of times before getting it to work. So – best to do this on your own local instance or in the middle of the night.

Troubleshooting:

Nothing shows in the lists – Comment out your extension in the System.config.  Does it work now?  Ok, you definitely broke it.

Write out the Tridion tcm:Item XML.  See line 166 in the AddMetadataColumn.cs file.

xWriter.WriteAttributes(xReader, false);

Make sure the default tcm:Item attributes are added the the XML.

attrValue = GetMetadataValue(comp, "article_number");

 

Summary

Big thanks to the Tridion R&D team for giving us the power to do this.  It allows us to mold the Tridion CMS for our own organizations and improve efficiency while saving time.  This  can be very handy.  Programming the DataExtender is quite simple and most of our effort is in the Tridion API code itself – something we should all be familiar with. I am very happy with the approach and possibilities. We are very lucky that the base code has been provided from Seguei and we only need to get our config correct and deploy the files. One last warning that your code will be executed for every GetList request, so if your code is not fast then it is not for this type of extension. I can imagine for some use-cases going to the Tridion API for each piece of data will be too time-consuming and you may need to persist that data to an external system such as Redis that is much faster.  Have fun and try to remember to be kind.

5 Ways to maintain quality in Tridion Templates

Recently while updating an old VBScript Component Template I was surprised at seeing several bad practices in place and began to update the template. When we update a template we should always try to clean it, add comments, etc and leave it in a better state than we found it. Here I will give some tips for keeping things in order:

1. Good indentation – Tridion Templates open in their own browser window. Don’t edit the template there – DON’T DO IT! IT can be tempting, and maybe save you 30 seconds of copying it to your text editor – but you’ll screw up your indentation and make it impossible to follow for your other colleagues who are using text editors for template development.

Update: Set Notepad + to use spaces instead of tabs. Thanks Ingmar for the comment! http://stackoverflow.com/questions/455037/notepad-tabs-to-spaces

2. Access Component Presentations in Page Templates, Fields in Component Templates. Looping through Component Presentations in the Component Template is bad practice, slows the template down, ais not consistent with data model of Tridion and doesn’t make sense.

3. Use local variables in functions and subs. Using global variables in functions and sub-routines is bad practice. Respect the scope of a function or sub and pass in all variables, otherwise, it makes it very difficult to debug later.

4. Set variables when you declare them. For example, in VBScript use

Dim body : body = ""

5. Consistency with if conditions. Don’t write if statements on 1 line – especially within a nested if in VBScript. Makes it terribly difficult to follow.

I hope we can all establish good coding practices and follow them to keep our templates clean and in good health!

Tridion 2011 Core Service Console App

Tridion implements the Core Service using WCF 3.5 and this is the suggested interface to use for accessing the Tridion API outside of the Event System or Templates. Although I have heard horror stories of the configuration options and how difficult WCF is to work with, so far I did not have such experiences using the Core Service with ‘Add Service Reference’ in Tridion and then doing simple things. Today was different.

Today I tried making a small Console application using the config-less Core Service code from Jaime Santos’s post about the Data Extenders. This brought me into touch with the various bindings and security aspects – and I had a new respect and fear of WCF that I had not known before. Jaime uses the tcp binding and I understand this is the best performing binding. However, my Tridion Server declined the connection for TCP and I assume the port is blocked. Then, I tried modifying his code to use an HTTP Binding – but many of the options he uses are TCP only and I was quickly making a mess of the code. For some strange reason I tried using a WSHTTP binging – but that wants me to use https and the Tridion WCF Core Service does not accept it (or maybe my web server is not configured for it?). By this time I took another look at the Config-less Core Service Example from Puf and found new inspiration for making this work. His example requires a password for the account while the TCP example did not. I wonder why this is? I borrowed Puf’s code and adapted it to take advantage of some of Jaime’s ideas in his Handler. During the process I learned that the TCP binding is much better performing and we need to explicitly open and close the connections - the cost of opening a connection is very high.

Jaime uses the Core Service in a Data Extender where performance is  extremely important, so I understand why Jaime choses the TCP binding over HTTP.

In the end I have a small Console app that calls the Core Service using a BasicHttp binding. It gives us an easy way to get started testing Core Service code that later might end up in a GUI Extension or Import app.

Get the Code at https://github.com/rcurlette/TridionCoreServiceConsole

 

Adding a URI Column to the Listview using Tridion DataExtenders

Adding a new column to the Listview in Tridion 2011 is easy with using Data Extenders. With a few simple config changes we can add the TCM URI column to our default view – no code needed! In this article I will explain how to add the URI column as well as give some debugging tips.

Concept

The Tridion Listview can be extended using DataExtenders. the idea is that the config file for the extender specifies an XPath expression and matches some data in the GUI Response.  We are lucky that the URI is part of the default GUI response and we simply need a little XSLT and config to show it.  However, we can also add new data to the GUI Response is by extending the DataExtender class in .NET.   I do not cover that here but there is an example in the Tridion LiveDocs.

We will:
1. Create a new GUI Extension – but only providing our config file since the URI is part of the default GUI Response
2. Add our new extension location to the System.config folder.

Steps for Adding the ListViewTCM Extension

1. Create a new folder under Tridion\Web\WebUI\Editors\ called ‘ListViewTcm’
2. Copy the extension config file below there. The important part in this code is the selector. It is doing an XPath match on the XML the Gui response is sending and selecting the ID attribute. We are lucky the ID is part of the response. Otherwise, we would extend the DataExtender class in .NET and is something I do not cover here.

Interesting part:

<ext:columns>
  <column xmlns="http://www.sdltridion.com/2009/GUI/extensions/List  "id="MyColumnID" type="data" title="URI"
  selector="@ID" translate="String" />
</ext:columns>

Whole config file:

3. Update the System.config to let it know about our new GUI “Extension”. :)

<editor name="ListViewTcm">
  <installpath>C:\Program Files (x86)\Tridion\web\WebUI\Editors\ListViewTcm\  </installpath>
  <configuration>ListViewTcm.config</configuration>
  <vdir/>
</editor>

4. Refresh the GUI and marvel at your new URI List column. I know I was delighted and surprised when I first saw it.

Debugging tips

Mostly useful when you start building your own DataExtenders to put more info in the Response. Not used here though, since URI is already part of our response:

1. Enable debug output for the GUI
System.config, <client debug=”true”>

2. Enable GUI debugging in the Browser

http://TridionDev2011/WebUI/Editors/CME/Views/Dashboard/Dashboard.aspx?mode=debug

3. View the Tridion.Web.Trace file in the WebUI/WebRoot folder. This is mostly used when debugging the .NET DataExtenders and something not covered here. Check if your extension is listed. This means the config is good and the GUI is trying to load it. When it does, you will see this message. This is good output: “Executing request-extension : ‘ListViewTcm’”. This is bad and most likely due to wrong Namespace / Class: “Configured dataextender ‘AddSchemaTitle, ListViewTcm’ can not be created, check .Net’s fusion log for more information”

Summary

Great job to the Tridion GUI Team for giving us the power over the Listview and ability to add columns. This extra information will save countless hours when searching for that extra piece of information and not having to open the item (or mouseover) to find it. The new column gets sorting and filtering for free and behaves just like the other columns. Overall I cannot wait to play more with this new and powerful feature.

BlueCopy – Tridion GUI Extension QuickStart

GUI Extensions create a seamless experience for Tridion editors, providing shortcuts, new possibilities for bulk-editing and blueprint-aware tools that ease the task of daily content maintenance and improves the efficiency of all operations.  In this article I quickly create a new GUI Extension using the WhoDidIt example as the basis.  I also show how to convert an existing custom page, BCopy, to a new GUI Extension using the Core Service.  I hope after reading this you will be able to also convert your custom pages to GUI Extensions with little effort.

Getting Started
I use the previous GUI Extension tutorial, WhoDidIt?, as a basis for creating this new GUI Extension. There will be lots of find/replace action going on – so if this is your first time creating a GUI Extension then I strongly recommend you work your way through my previous article before continuing here. The first article explains the overall concepts and the relationships between pieces. Here I will focus on getting a GUI Extension created as soon as possible – re-using as many pieces from the GUI Extension WhoDidIt. In the first part I will walk through how to create the GUI Extension client using the previous solution of WhoDidIt as the basis on our BlueCopy extension. The second part focuses on the “Core” work – migrating the Tridion TOM API code to use the new Core Service.

What are BlueTools?
BlueTools are my Tridion Blueprint-focused tools to help you work with Tridion Blueprinted content.  This first extension in the BlueTools suite is ‘BlueCopy’, a modern interpretation on the BCopy custom ASP page. BCopy and this extension will do 1 thing and try to do it well – copy an item with its’ Blueprint children.

Downloads

WhoDidIt? GUI Extension Files- Start
BlueCopy GUI Extension Files – Solution- We create this below

Overview
Step 1: GUI Extension Client-Setup – Show a popup (~30 minutes)

Step 2:  GUI Extension Server Setup – Create the Web Service locally and call the Tridion Core Service (~15 mins)

Step 3:  Adding a new Web Service – Adding our new Service to ServiceStack (~15 mins)

Step 4:  Deploy the GUI Extension Web Service to our CMS (~20 mins)

Step 5:  Wire the GUI Extension client to the Web Service on the Server

Step 6: Converting ASP TOM API code to Tridion 2011 Core Service code

Step 7:  Finishing up – polishing the GUI and adding another field

Step 1: GUI Extension Client-Setup – Show a popup (~30 minutes)

1. Get the GUI Extension WhoDidIt files from GitHub, https://github.com/rcurlette/WhoDidIt/downloads. Extract it and rename the files from WhoDidIt to our extension name. Rename the folder from ‘rcurlette-WhoDidIt-552c9a2′ to ‘BlueTools’ or your GUI Extension.

2. Rename the files 

  • WhoDidItCmd.js ->GuiExtensions\BlueTools\GuiExtension\client\js\BlueToolsCmd.js
  • WhoDidIt.css -> GuiExtensions\BlueTools\GuiExtension\client\css\BlueTools.css
  • WhoDidIt.config -> GuiExtensions\BlueTools.config

3. Update files.  Find / replace WhoDidIt and Sherlock with your tool name.

  • BlueTools.config -> Find / replace ‘Sherlock’ with BlueTools and ‘WhoDidIt’ with BlueCopy. Replace the text ‘Who Did It?’ with what text you want shown on the right-click, for example, ‘BlueCopy’.
  • Open the GUI Extension BlueToolsCmd.js file.  Find / Replace Sherlock with BlueTools and WhoDidIt with BlueCopy. Save.

4. Update the GUI Extension action – Open the BlueToolsCmd.js file, change the _execute method  alert message to ‘alert(‘Really Excellent!’);’ and comment out all lines starting with ‘var selectedID’ until popup.open();.  This update will show only the popup and comment out all other lines, not worrying about other client HTML / JS files.

5.  Update BlueTools.config file and add an assignid value.  Whenever you change the config file the GUI flushes the cache automagically.  Nice!  :)

old:

<ext:extension name="BlueToolsExtension" assignid="" insertbefore="cm_refresh">

new:

<ext:extension name="BlueToolsExtension" assignid="BlueCopy" insertbefore="cm_refresh">

 

6. Deploy to Server – On the CMS server, create a new folder under ‘C:\Program Files (x86)\Tridion\web\WebUI\Editors’ for the new GUI Extension. I create a folder called BlueTools. Copy all the files in the GuiExtensions\BlueTools\GuiExtension folder to the server at ‘C:\Program Files (x86)\Tridion\web\WebUI\Editors\BlueTools’.  Then you should have BlueTools\GuiExtension.

7. Create IIS Virtual Dir –  Open IIS on CMS Server, Go To Web Sites, SDL Tridion 2011, WebUI, Editors. Right-click, select create a new IIS Virtual Directory to host the GUI Extension, name it BlueTools, and browse to the folder you copied the BlueTools GUI Extension to on the server.

8. Edit the System.Config located at ‘c:\Program Files (x86)\Tridion\web\WebUI\WebRoot\Configuration\System.Config‘, and let Tridion know about our new extension.

<editor name="BlueCopy">
  <installpath>C:\Program Files (x86)\Tridion\web\WebUI\Editors\BlueTools\GuiExtension\</installpath>
  <configuration>BlueTools.config</configuration>
  <vdir>BlueTools</vdir>
</editor>

9. Flush browser cache.  (Ctrl-shift-delete in Chrome) Refresh the GUI, see our new option in the right-click context menu. Since WhoDidIt did not include a ribbon extension you will not have a ribbon button here.

10. Test the GUI Extension client using the right-click menu option ‘BlueCopy’. You should see an alert with the text ‘Really Excellent!’

*Note: On my first test I saw the text in the menu but clicking on it did not do anything! Opening up the Javascript console in Chrome (F12 key) and in the Console window I see this message: “Command ‘BlueToolsCommand’ is not registered“. To fix this I needed to add an ID to the <ext:extension line. Maybe this is because I have more than 1 GUI Extension registered and also inserting at the same position? For more info about all the values in the config file have a look at my previous post, http://www.curlette.com/?p=279.

old:

<ext:extension name="BlueToolsExtension" assignid="" insertbefore="cm_refresh">

new:

<ext:extension name="BlueToolsExtension" assignid="BlueTools" insertbefore="cm_refresh">

Review:

We did it! We have successfully added another GUI Extension Client. It doesn’t do much yet – no Tridion API magic.  Now time to create the server-side web service to do something with the Tridion API and call our popup from the _execute method.  If you have any problems – review the config file and my debug article.

Step 2:  GUI Extension Server Setup – Create the Web Service locally and call the Tridion Core Service (~15 mins)

1. Get the Tridion2011ServiceStack project from GitHub

2. Add your CMS Url.  Open the solution in Visual Studio 2010 SP1. Do a find / replace for TridionDev2011 with your CMS server name for all files in Solution. Change the look-in option to ‘Entire solution. You should have 53 replacements. Save all.

3. Update the web.config file and put in your CMS server URL, Username, and password

4. Add the Tridion Core Service DLL reference to the solution. Get it from your Tridion server in the /bin/client folder. Copy it locally before adding it – don’t add it from a network share. It is not included in the ServiceStack project because it is a Tridion file.

5. Step through code.  Build. Hit F5 (play) to Debug solution – the test page for WhoDidIt appears.  Note the url and port # visual studio uses in your browser. If your URL is not ‘http://localhost:61860′ then copy it and update the page ‘GetTridionItem.htm’, replacing the URL with your localhost URL. Otherwise, hit the ‘Go’ button and you should hit the breakpoint ‘ return Repository.GetByUri(request.Uri);’ in the OnGet method of our ‘TridionItemRepository’.

Review

Developing locally is great –  we can write our Tridion API code in the Service, develop and debug our Core Service Tridion API calls directly in our Visual Studio development environment.  Our test page calls the Tridion2011ServiceStack Web Service via AJAX and we hit our Service method calling the Tridion API and can step through the code. So far, so good.

Step 3:  Adding a new Web Service – Adding our new Service to ServiceStack (~15 mins)

1. Create a new model class. Right-click on the models folder, select ‘Add new class’.  Add any properties to the class you want to return to the js client. You can also copy/paste the properties from the TridionItem class. I am creating a ‘BlueCopyItem’ model and adding 3 properties I know I’ll need – Title, URI, and Error (to hold the error message to pass back to the js client).

namespace Tridion2011ServiceStack.Models
{
    public class BlueCopyItem
    {
        public string Title { get; set; }
        public string Uri { get; set; }
        public string Error { get; set; }
    }
}

2. Create a new Service class. This handles the request from the GUI Extension client.  Right-click on the Services folder, select ‘Add new class’. I called mine ‘TridionBlueCopyService.cs’. Copy / paste the code from TridionItemService. Replace ‘TridionItem’ with the name of your model class from step 1, ‘BlueCopyItem’. Don’t forget to change the ‘Look in’ option to ‘Current document’ and not ‘Entire Solution’.   You should have 4 replacements.  Also, select the match case – otherwise it will rename both your Class name (TridionItem) and the variable names (tridionItem).

Remember to inherit from the RestServiceBase class.

: RestServiceBase<BlueCopyItem>

3. Create a new Repository class. Right-click on the Repositories folder, select ‘Add new class’. I called mine ‘BlueCopyRepository’.  Copy / Paste code from TridionItemRepository.  Update the code – rename ‘TridionItemRepository’ with ‘YourModelClassRepository’. Replace ‘TridionItem’ with ‘BlueCopyItem’ and ‘tridionItem’ with ‘blueCopyItem’.  Remove the line 24 adding the LastModifiedProperty since we do not have it in our model. // remove -> tridionBlueCopy.LastModifiedBy = versionInfo.Revisor.Title;

4. Add our service mapping – Open AppHost.cs and add 1 more line below ‘.Add<TridionItem>(“/tridionItem”)’, where TridionItem is your model class name and /tridionItem is the URL you want to use for your web service. This can be whatever you want.  I added this:

.Add<BlueCopyItem>("/blueCopy");

5. Register our repository - In AppHost.cs register your new Repository. Add a new line below ‘container.Register(new TridionItemRepository());’ on line 62 and change TridionItemRepository with your repository name.

container.Register(new BlueCopyRepository());

6. Build, add namespaces as needed.

7. All done! No config needed. :) Service Stack is built using the convention over configuration principle and steps 4 and 5 are all we need to do to make our new service visible to Service Stack.

8. Make a new test page. Copy / paste GetTridionItem.htm and give it a new name such as ‘BlueCopyTest.htm’

9. Put the new Web Service URL in the test htm page from the AppHost.cs file (ie’ /tridionBlueCopy). Replace ‘http://localhost:61860/api/tridionItem’ with ‘http://localhost:61860/api/yourServiceUrl’ located in the test htm file.  Mine is: ‘url: “http://localhost:61860/api/blueCopy”,’

10. Set the new test page as your default start page by right-clicking on it and choose ‘Set as Start Page’.

11. Add a breakpoint to the new Repository class (ie. BlueCopyRespository.cs), line ‘CoreServiceClient client = new CoreServiceClient();’ (assuming you did not change anything in the Repository code yet).

12. Hit play, run in debug mode. Your new htm test page should show up. Push the ‘Go’ button and your new breakpoint should be hit. Step through the Repository OnGet code, and at the end your page will show the Title and URI of the item. Congratulations – you are now ready to add your new code.

Note: If you get a popup and the text looks like jquery2189072189723131 then you’ve got an error in the Repository Tridion code. :) Time to debug the server. I decided to place another breakpoint on the OnGet method in the BlueCopyService class. This is called first. I got into the debugger this time, but when pressing F11 to step into the repostitory I got a popup from Visual Studio saying it could not find my repository. I forgot to add it to the AppHost Repositories Funq container! To sovle this I opened the AppHost.cs file, and added

container.Register(new TridionBlueCopyRepository());

Review

It’s fun to add a new web service so easily and then step through the code in Visual Studio with the debugger.  Creating a web service and configuring it for test is not an easy step – there are several files involved and many places we find/replace the original class names with our new model class. No worries – once this is done you will not need to do it again for this web service. Also, I find it fairly straight-forward and if you follow the steps above you should have your new web service ready to go in no time. One advantage to this approach is you can call your new web service from any client, an HTML test page as shown above, your new GUI Extension, or a classic ASP custom page!

 

Step 4:  Deploy the GUI Extension Web Service to our CMS (~20 mins)

1. Copy Tridion2011ServiceStack files to server, usually I create a new folder under InetPub\wwwroot.  I called mine ‘BlueToolsWebService’.  I deploy my MVC website using the ‘Publish’ option of Visual Studio.  I have a drive mapped to my server and then choose ‘File System’ in the publish method listbox.  Then, in IIS, create a website to host the ServiceStack MVC Web Service (or host the Web Service as a Windows Service or Console App).  Don’t forget to change the App Pool to a .NET 4.0 App Pool or it will not run.  You may also want to run it on a different port.  In my previous post  I describe this in more detail.

2.  Test the Web Service.  Open a web browser and go to the URL of your web service.  You should see a reply from ServiceStack like this one:  “Snapshot of BlueCopyItem generated by ServiceStack”. This works! Open the popup.js file on our local dev box and chage the URL to the website URL from the browser.

3.  Debug the results in Chrome.  Now hit F5 and run the test page again in Visual Studio.  Use the Developer Tools (F12 key) and go to the Scripts tab.  Select the BlueCopyTest.htm file in the dropdown and set a breakpoint on the line with ‘ $(“#feedback”).html(“<div class=’successMessage’>Title’.  Now, hit ‘Go’ and our breakpoint will be hit.  then mouseover the data object in the line with ‘success: function (data) {‘ and see the title and uri properties.  You can also highlight ‘data’, right-click, and select ‘Add Watch’ to see the values.

 

Step 5:  Wire the GUI Extension client to the Web Service on the Server

1. Enable the popup.  Open the GUI Extension .js file with the _execute method. Mine is called ‘BlueToolsCmd.js’.  The location on the server might be something like: C:\Program Files (x86)\Tridion\web\WebUI\Editors\BlueTools\client\js\BlueToolsCmd.js UnComment the lines starting with ‘selectedId’ and ending with ‘popup.open’

2.  Add text to popup.htm.  The original WhoDidIt popup only had an AJAX call and does not display anything.  Let’s add ‘Hello World’ text to the popup.htm so we have something to see when we call it.

3. Confirm the url to the popup is working. Popup on server might be located at ‘WebUI\Editors\BlueTools\client\html’. Test this in the browser.  If your CMS URL is http://TridionDev2011 then the test URL would be http://TridionDev2011/WebUI/Editors/BlueTools/client/html/popup.htm.

4.  Test in CMS.  Now let’s clear our browser cache and try our GUI Extension again.  If you see the popup- congrats! If not, double-check your .js file _execute command, make sure it is deployed, and refresh your browser.  Also, open up the Chrome debugger or FireBug and see my post about debugging.

3. Add web service URL to popup.js. Our client is now 100% working and also showing the popup. Let’s call our new Web Service.  Change the URL property in the popup.js file located in the C:\Program Files (x86)\Tridion\web\WebUI\Editors\BlueTools\client\html\js folder to point to our new web service and try again. This assumes you have not changed any code in the repository class.

You will see the URL as url:  “‘http://TridionDev2011:8001/Tridion2011ServiceStack/api/tridionItem”. Change TridionDev2011 to your CMS URL and ‘tridionItem’ to your new Web Service URL (should look like your test htm page). My new url is ‘http://TridionDev2011:8001/BlueToolsWebService/api/blueCopy’  Note: Clear browser cache again and refresh.

4. Test in GUI, Debug the data returned in Chrome.

- Run GUI Extension

- When popup is open, load the Chrome Developer Tools (F12), scripts window, select popup.js.

- Put breakpoint on line $(“#suspect”).text(data.lastModifiedBy);

- Reload popup html window, breakpoint is hit.

- Minimize call stack window on right, open Scope variables

- Open Closure, data and see your properties here. This is your model object returned from ServiceStack. Notice your propery names are camelCased.

Review

This is the most critical part – where we see our 2 major pieces talking to each other. Give yourself a pat on the back – you’ve made it through the most difficult part.  Now we’re ready to move onto the real work – using the Tridion API to do something. Right now all the pieces are in place, working, and we’re finally ready!  The 5 pieces are:  Extension Config -> .js (with _execute) -> popup.htm -> popup.js -> Web Service -> Tridion Core Service

Step 6: Converting ASP TOM API code to Tridion 2011 Core Service code

Tridion introduced the Core Service in Tridion 2011 and announced this is the official way to talk with the Tridion API outside of the Event System or Templates.  We will use the Core Service to talk to the API and do the work.  Our AJAX call is passing the Component URI to the Web Service.

I do this all locally and use a local htm test page with the javascript / css locally as well.  Just as we did in Step 2 above – we will set a breakpoint in our Repository class and step through the Tridion Core Service Code.

In this example I need to port my existing classic ASP Custom Page code for copying an item and BluePrint children to the new Core Service.  Below are some highlights and points about the differences.

The Core Service code has 3 main parts:

1. Create a new copy of the Parent source item (Page or Component)
2. Get Localized Versions of the source item
3. For each Localized Version, localize the new copy and update the contents with the localized source item.

1.  Copy the Parent Tridion Object

TOM API:

Function CreateNewItemCopy(organizationalItemUri, itemType, title, xml, directory, filename)
	'response.write "create new item" & organizationalItemUri & "," & itemType & "," & title & "," & xml & "," & directory & "," & filename
	Dim newItem : set newItem = tdse.GetNewObject(itemType, organizationalItemUri)
	newItem.UpdateXml(xml)
	newItem.Title = title

	if(itemType = 64) then ' page
		newItem.FileName = filename
	elseif(itemType = 4) then ' sg
		newItem.Directory = directory
	end if

	newItem.save(true)
	CreateNewItemCopy = newItem.id
	set newItem = nothing
End Function

Core Service API: *Note: I did change the fundamental approach here since I now use the copy method

private string CreateNewItemCopy(string title, RepositoryLocalObjectData source, string filename)
        {
            string newItemUri = "";
            try
            {
                ItemType tridionItemType = GetTridionItemType(source);
                string orgItemUri = source.LocationInfo.OrganizationalItem.IdRef;
                var newItem = client.Copy(source.Id, orgItemUri, true, new ReadOptions());
                newItem.Title = title;
                if (tridionItemType == ItemType.Page)
                {
                    PageData pageData = newItem as PageData;
                    pageData.FileName = filename;
                    client.Update(pageData, new ReadOptions());
                }
                else
                {
                    client.Update(newItem, new ReadOptions());
                }
                newItemUri = newItem.Id;
            }
            catch (Exception ex)
            {
                throw;
            }

            return newItemUri;
        }

Highlights / Differences:

The Tridion TOM provides us a nice easy way to create content in any type of item – UpdateXml.  The Tridion Core Service does not have this method but instead uses an Update method on the Web Service client.  I posted a question on StackOverflow about this and got a great response – not only was my answer provided, but a new suggestion of using the Copy method of the API instead of UpdateXML. :)

Copy item – also passing in Read options to make sure I can read data later.

' VBScript / TOM
Dim newItem : set newItem = tdse.GetNewObject(itemType, organizationalItemUri)
newItem.UpdateXml(xml)
// Tridion CORE Service / .NET
var newItem = client.Copy(source.Id, orgItemUri, true, new ReadOptions());

2. Get Localized Versions

I really like the new approach with BluePrintChainFilterData instead of GetListUsingItems (from TOM) to get the localized child elements. The Core Service and the filter BluePrintChainFilterData also returns the Parent item – so watch out – you may need to filter it out as I do here. Big thanks to user978511 on StackOverflow for the help and example code http://stackoverflow.com/questions/9515647/getlistusingitems-with-tridion-core-service-returns-more-items-than-tom.

TOM API:

Function GetLocalizedItemNodes(itemUri)
	Dim tridionItem : set tridionItem = tdse.GetObject(itemUri,1)
	Dim rowFilter : set rowFilter = tdse.CreateListRowFilter()
	call rowFilter.SetCondition("ItemType", GetItemType(itemUri))
	call rowFilter.SetCondition("InclLocalCopies", true)
	Dim usingItemsXml : usingItemsXml = tridionItem.Info.GetListUsingItems(1919, rowFilter)

	Dim domDoc : set domDoc = GetNewDOMDocument()
	domDoc.LoadXml(usingItemsXml)
	Dim nodeList : set nodeList = domDoc.SelectNodes("/tcm:ListUsingItems/tcm:Item[@CommentToken='LocalCopy']")

	set tridionItem = nothing
	set domDoc = nothing
	set GetLocalizedItemNodes = nodeList
End Function

Core Service API:

private XContainer GetLocalizedItems(string itemUri)
        {
            XContainer localizedItems = null;
            try
            {
                BluePrintChainFilterData filter = new BluePrintChainFilterData();
                filter.Direction = BluePrintChainDirection.Down;
                localizedItems = client.GetListXml(itemUri, filter);
            }
            catch (Exception ex)
            {
                throw;
            }
            return localizedItems;
        }

3.  Update Localized Items

Some lines in the code commented out with //… – there is code there – please see the source code on GitHub.

TOM API:

Sub UpdateLocalizedItem(itemXml, itemUri, pubUri, filename, directory)
	Dim newTridionCopy : set newTridionCopy = tdse.getObject(itemUri,1, pubUri)
//...
	if(newTridionCopy.Info.IsLocalized = false) then
		newTridionCopy.Localize
	end if
	//...code removed...
	newTridionCopy.UpdateXml(itemXml)
	newTridionCopy.Title = newParentTitle

	' set sg and page props
	if(itemType = 64) then ' page
		newTridionCopy.FileName = filename
	elseif(itemType = 4) then ' sg
		newTridionCopy.Directory = directory
	end if

	newTridionCopy.Save(true)
// ...
End Sub

Core Service API:

private string UpdateLocalizedItem(string title, string uriLocalizedSource, string newItemUri)
{
	try
	{
		ItemType tridionItemType = GetTridionItemType(uriLocalizedSource);
		var newItem = client.Read(newItemUri, new ReadOptions()) as RepositoryLocalObjectData;
		var oldItem = client.Read(uriLocalizedSource, new ReadOptions());
		if (newItem.MetadataSchema != null)
		{
			var newItemMetadataSchema = client.Read(newItem.MetadataSchema.IdRef, new ReadOptions()) as SchemaData;
			newItem.Metadata = GetMetadata(newItem.Metadata, newItemMetadataSchema.NamespaceUri);
		}

		if (tridionItemType == ItemType.Page)
		{
			PageData newPage = newItem as PageData;
			PageData oldPage = oldItem as PageData;

			newPage.ComponentPresentations = oldPage.ComponentPresentations;
			newPage.Title = title;
			client.Update(newPage, new ReadOptions());
			return newPage.Id;
		}
		else if (tridionItemType == ItemType.Component)
		{
			ComponentData newComp = newItem as ComponentData;
			ComponentData oldComp = oldItem as ComponentData;

			newComp.Schema = oldComp.Schema;
			newComp.MetadataSchema = oldComp.MetadataSchema;
			newComp.Content = oldComp.Content;
			newComp.Metadata = oldComp.Metadata;
			newComp.Title = title;
			return newComp.Id;
		}
	}
	catch (Exception ex)
	{
		log.Error(ex.Source + "," + ex.Message + "," + ex.ToString());
		log.Error(ex);
	}
	return uriLocalizedSource;
}

 

Review:  Creating the Core Service code is where we get to talk with the Tridion API and some familiar old school objects and names come back into the light.  I usually do all my Core Service development locally, including debug, and only use the Server log files to know that something went wrong.  No more fighting with other developers over remote Windows Server sessions! :)  I cannot express enough how nice this is – and how it speeds up the development / debug / deploy cycle.  While there is a lot more to know about the Core Service to build good solutions – the community and documentation examples provided the help I needed.  Please grab the source code from GitHub for all the details.

 

Step 7:  Finishing up – polishing the GUI and adding another field

GUI Extensions are by nature a client-side HTML / JavaScript / jQuery application making Web Service calls.  The better your client side dev skills are – the better your GUI Extension will feel.  Unfortunately, most Tridion developers have spent little time doing client development (me included!) and this is a time consuming part of writing a GUI Extension.  We can no longer avoid JavaScript!

Adding new properties – SourceTitle and Filename

Currently we only return the title of the new copied item- but what if we wanted to also return the title of the original item?  No problem.

1.  Add the property to the Model

public class TridionCopyItem
    {
        public string Title { get; set; }
        public string SourceTitle { get; set; }
        public string Filename { get; set; }

2.  Set the property value

// Create the Response Object to send back via Ajax to our GUI Client
TridionCopyItem tridionItem = new TridionCopyItem()
{
	Title = GetCmsEditUrl(newItemUri, title),
	Uri = newItemUri,
	SourceTitle = itemToCopy.Attribute("Title").Value,
        Filename = filename
 };

3.  Read the value in the js client

success: function (data) {
$(document).ready(function () {
	/* Render the template with the movies data */
	$.each(data, function () {
		$('<div>' + this.sourceTitle + '<span class="icon-arrow-right" style="padding-right:4px;padding-left:4px;"></span>' + this.title + '</div>').appendTo("#componentList");
	});

 

Adding input fields to HTML form for the Title

Adding another input field is no problem.  We simply add it to our HTML form and it automatically gets serialized by jQuery into JSON and sent via AJAX to our ServiceStack Web Service.  In the Web Service our Model should have a Property with the same name, and our Service class needs an input parameter with the same name.

Look and feel

I use the Twitter Bootstrap CSS framework for all custom pages and GUI Extensions.  This time I also decided to adopt the Golden Ratio for the popup size.  Overall I am very happy with the design and the look.

I added more jQuery and HTML to the final form but did not change the Web Service.  Maybe this is typical for a GUI Extension to first get the Core Service working and then spend lots of time polishing the jQuery and HTML interaction with the user. Consider the skillset for your extensions – find your local JavaScript / jQuery expert and get them involved in the GUI Extension project.

Summary:

Building GUI Extensions involves 3 main activities.  First, get the menu option in the GUI and a popup saying ‘Hello’.   Second, setup the Web Service.  Third, get the Core Service doing the magic bits with the Tridion API.  The first step, with the GUI, involves a lot of server-side work of updating config files, deploying js files, and working with IIS.   However, the Tridion API work with the Core Service feels completely different – doing the work in the Visual Studio development tool and being able to iterate quickly.  Overall I like the separation of concerns – it just needs to become clear in our minds what happens where and we can easily design nice GUI Extensions without too much work.

I hope you managed to follow along and feel more comfortable about creating GUI Extensions.  Now time to start coding the next one… Â

Downloads

WhoDidIt? GUI Extension Files- Start
BlueCopy GUI Extension Files - Solution

Workflow Dreamin’

Workflow has been in the Tridion product since version 4 and is one of the most often requested and least often implemented or used features in the product.  The upcoming bundles feature in the product has sparked up some discussions this week.  In this article I will attempt to de-construct these old assumptions and provide my dreams for workflow.

Overview

Chris Summers and Dominic Cronin brought us great posts this week about Tridion Workflow and I agree with both Dominic and Chris’s points. However, they suggest we might be missing a method in the API or the business needs to think and plan more for the workflow. But, I disagree. Tridion has added API features since it was built but the concept has remained the same since v4. I would argue that the assumptions that workflow was built for in 2001 do not exist today. These ficticious organizations and ficticious Authors are not there and therefore the workflow system we have does not work. Current Tridion workflow assumptions are reviewed below:

Assumption: Authors need everything reviewed all the time.

Tridion workflow currently assumes that the we have some rogue users in our Tridion system that need every change they make reviewed and approved every time for all content using a particular schema, for example an Article, with no exceptions. These rogue users are believed to be dangerous and we need to watch everything they do otherwise our site will fall to ruins.
In reality, this is very far from the truth. Our Tridion users are regular Tridion users, most of them daily users. They are experts in the content and know it better than most people in the organization. They know when they need approvals or not – and want to do the right thing by requesting an approval for a completely new article. However, for correcting a typo in some content they will not need to have an approval since it is a small change. In other words – we need to empower our Authors and make it very easy for them to get approval when they need it or want it, and all other times stay out of the way.

Assumption: Content needs approval every time.

Currently Tridion workflow is assigned to a Schema and whenever any content using that Schema is modified, even a little bit, the content goes into workflow and needs approval. A lot of content updates are for fixing typos, updating an image, adding 1 line to the text. What we need an approval for is big content changes and new items. And, who knows when we need an approval? – the Author. Because we trust them to know their content.

Assumption: All content using this Schema should go into workflow.

Context matters. Today when workflow is assigned to a Schema, all content using that Schema goes into workflow when edited. Maybe we want to have all articles under the Press Release folder to go into workflow A and the articles in the News folder into Workflow B. Or maybe the articles in the News folder don’t go into workflow, because the Author is the person in the organization responsible for that content – and we trust them to make the right decisions. We don’t want to turn workflow off for this – we want to specify the context the workflow is turned on.

Assumption: Workflow will protect our content by allowing certain roles to make changes

If we want to restrict users – then use the excellent Tridion security system with roles and rights. Want to not allow an author to change content? Set the security rights. Limit publishing to Staging? No problem, restrict publishing. But, I argue, limiting what users can do is a matter of security, not workflow.

Solution – Dreams for a New Workflow- If This Then That

My proposal is to flip workflow on its’ head. Think of the app If This Then That. The idea is simple – If ‘This’ happens then do ‘That’. Here are some examples, http://ifttt.com/recipes, Imagine these Tridion recipes:

If ‘I’ create an ‘article’ AND
If the ‘article’ is in the folder ‘News’ AND
If the date is ‘today’ THEN
Mark it for ‘Needs Approval’ AND
Notify ‘John’ with ‘once per day’ by ‘Email’

Or, maybe a pull workflow created by ‘John’ the manager:

If ‘anyone’ creates an ‘article’ AND
If the ‘article’ is in the folder ‘News’ THEN
Notify ‘me’ ‘once per day’ by ‘Email’

Or, maybe a pull workflow created by ‘Sally’ the web products manager:

If ‘anyone’ publishes ‘anything’ to ‘live’ AND
If the ‘article’ is in the structure group ‘products’ THEN
Notify ‘me’ ‘each time’ by ‘workflow notification center’

The power of this is amazing. We can create flexible rules that follow our organic organizations. And, we can empower our users.

Summary

The core concept here is notifications – notify someone that something has happened and request an approval. That’s it.  My dream is to allow users to pull and push notifications for actions in the GUI. I believe Tridion users and not only editors, but are owners of content, and responsible for the content they publish online. I believe they want to do the right thing – and we should help them do that with a flexible rules system that includes notifications and approvals.

Thoughts? Please share.

Show Template Source – A Tridion Custom Page

If you’re like me and you work in a lot of legacy Tridion implementations then there’s a good chance you spend time each week hunting for that 1 line of code to update, burried somewhere in the thousands of lines of VBScript templates. Oh, you don’t have this problem, lucky you! :)

Show Template Source Custom Page

I created a very small custom page that loops through 1 folder and displays all the template code to the screen. My folder structure specifies 1 template type per folder and the custom page is setup that way, and it loops through child folders too.  Also – you can pass in any URI of a folder and get back the source. You need to use ‘View Source’ in your browser and then copy the source to your favorite text editor. One tip – wait until the whole page finishes loading – otherwise you’ll not see all the templates.

*Update:  Pages also supported – thanks to Mihai’s suggestion in the comments.

Code highlights

' Show Template
Response.Write template.Content

The Code is hosted on GitHub as a Gist, https://gist.github.com/2044332 and also embedded here:

Enjoy!