Get users by taxonomy category

Ektron’s taxonomy feature allows you to categorise not only content but also users and user groups too. Putting a user into a category has all kinds of uses such as identifying users who have performed a certain task on your site like signing up to a feature or adding something to their profile.

There is a little bit of a grey area in terms of whether you would use a user group or custom user properties for some of the use cases. Taxonomy is always going to be the more powerful option as it provides a hierarchical structure whereas groups and properties are flat.  Taxonomies themselves can also be extended through the use of custom properties on the category.

So consider what you will use it for before you go ahead and choose the right approach.

Here is a simple code sample:

// Use the Framework API from versions 8.5 onwards
Ektron.Cms.Framework.User.UserManager uMgr = new Ektron.Cms.Framework.User.UserManager();
Ektron.Cms.User.UserTaxonomyCriteria criteria = new Ektron.Cms.User.UserTaxonomyCriteria();

// Get users based on taxonomy ID
//criteria.AddFilter(Ektron.Cms.User.UserTaxonomyProperty.Id, Ektron.Cms.Common.CriteriaFilterOperator.EqualTo, 98);

// Or get users based on Taxonomy Path
criteria.AddFilter(Ektron.Cms.User.UserTaxonomyProperty.Path, Ektron.Cms.Common.CriteriaFilterOperator.EqualTo,
"\\UserTax");

List userList = uMgr.GetList(criteria);

Response.Write(userList.Count().ToString());

The above code uses the Ektron Framework API to get the information so you will need to be using Ektron version 8.5 or greater.

Geo IP lookup API in Ektron

A useful feature of Ektron CMS is the ability to target content at specific people based on their geographic location. This is commonly done within the Targeted Content widget.

However there are often times when you need the ability to do this in code outside of a Pagebuilder widget. Fortunately the Ektron API provides you with a simple way of determining where the user is coming from:

Ektron.Cms.UserLocationData userLocationInfo = Ektron.Cms.UserContext.GetLocationInfo("192.168.1.1");

if (userLocationInfo.CountryCode == "GB")
{
// User is from Great Britain
}

The simple example given above determines if a user resides in Great Britain or not by checking the CountryCode property of the UserLocationData object.  The GetLocationInfo() method takes a string parameter that holds the IP address that you want to look up.  Typically you would get this address by calling something like Request.UserHostAddress.

There are many other properties available from the UserLocationData object such as:

  • CountryName
  • City
  • Latitude
  • Longitude
  • Postalcode

The CMS makes use of three data files that are stored in your App_Data folder to get this information.  Those files are:

  • GeoIPDomain.dat
  • GeoIPOrg.dat
  • GeoLiteCity.dat

These data files are from an organisation called MaxMind so it is possible to update the data files from there and also to purchase a more complete file that contains advanced information (like what company a user works for).

Slow login to Ektron

I recently discovered a problem on a client’s site whereby it was taking a long time to login to the CMS. They had Active Directory integration enabled but we were able to rule that out as being the cause of the slowness by temporarily disabling it.

We also investigated the possibility that there may have been some plug-ins / extensions running that could be performing some kind of background task and slowing it down.  However this was not the case either. The problem did turn out to be related to plug-ins though…

Remember that from v8.0 Ektron introduced Extensions to replace the older plug-in technology. Plug-ins and Extensions allow you to write code modules that execute code following on from events that occur within the CMS. Such an event might be related to creating a user or deleting a content item.

There is a setting in the Ektron web.config file that turns the old plug-ins on or off:

<add key="ek_extensionServiceEnabled" value="true"/>

If you are on version 8.0 or greater then this setting should always be “false”.  Unbeknownst to me at the time, adding new content items was also running slowly. This was also due to this setting being set at “true”. Basically, the Ektron was looking for the old plug-ins and waiting for a set amount of time before giving up – hence the delay.

Setting this to “false” suddenly made adding content and logging in users much faster!

Get content taxonomy using Ektron API

Ever wondered how to get the taxonomies that a content item is assigned to whilst using the Framework API?

In the older APIs there was a method called Ektron.Cms.API.Content.Taxonomy.ReadAllAssignedCategory().  This worked fine, but what if we want to use the fabby new Framework API?  Well here is how:

/// <summary>
/// Return the Taxonomy ID for a given content item. Only picks
/// the first taxonomy if there are more than one.
/// </summary>
/// <param name="contentId">Content Id</param>
/// <returns>Taxonomy ID</returns>
public long GetContentItemTaxonomyId(long contentId)
{
    long taxonomyId = default(long);
    var taxItemMgr = new TaxonomyItemManager();
    var itemCriteria = new TaxonomyItemCriteria();
    itemCriteria.AddFilter(TaxonomyItemProperty.ItemId, CriteriaFilterOperator.EqualTo, contentId);

    List<TaxonomyItemData> taxonomyItemsList = taxItemMgr.GetList(itemCriteria);

    if (taxonomyItemsList.Any())
    {
        taxonomyId = taxonomyItemsList.First().TaxonomyId;
    }

    return taxonomyId;
}

This method returns the Taxonomy Id but could easily be adapted to return the TaxonomyItemData object instead.

CSS Aggregation targeting specific browser version in Ektron

I have mentioned the benefits of CSS aggregation previously when using Ektron: reduce HTTP requests, reduce overall page download size and boost performance.

One thing I discovered recently was the ability to use Ektron’s CSS aggregation feature but to be able to specify a target web browser.

You have probably seen conditional comments in CSS before:

<!--[if IE 6]>
Special instructions for IE 6 here
<![endif]-->

If you want to use this feature in tandem with CSS aggregation then you need these two lines of code:

Ektron.Cms.Framework.Content.ContentManager contentMgr = new Ektron.Cms.Framework.Content.ContentManager();
Ektron.Cms.API.Css.RegisterCss(this, contentMgr.SitePath + "/css/file.css", "css_file", Ektron.Cms.API.Css.BrowserTarget.IE7);

As you can see from the final parameter in the RegisterCSS() method, you can specify a target browser. In the example above I have specified IE7.

Get content item in preview mode using Ektron API

When content has been checked-in and has a status of “I” it will appear on the site if the site is in preview mode. Using preview mode allows you to see what content will look like on your site before you click the publish button.

The code below simulates the site being in preview mode and uses the Framework API:

Ektron.Cms.Framework.Core.Content.Content contentApi = new Ektron.Cms.Framework.Core.Content.Content(ApiAccessMode.Admin);
contentApi.InPreviewMode = true;
CB.Text = contentApi.GetItem(ContentBlockId).Html;

Add content item in a checked-in state using Ektron API

During a recent content migration exercise I had need to bulk insert a lot of content that must be added in a checked-in state, i.e. the content must not have been published previously.

I was unable to find a solution using the Framework API or even the version 7 API (e.g. Ektron.CMS.API.Content.Content) so I had to delve deeper into the past!

The code below actually comes from the Workarea itself and uses the awful Visual Basic Collections (arrrrggghhh) :

using Microsoft.VisualBasic;

public partial class CheckIn : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        // Use a VB Collection to define the content item

        Collection objCol = new Collection();
        {
            objCol.Add(1, "ContentType"); // 1 = HTML / SmartForm
            objCol.Add("&lt;root&gt;&lt;MyField&gt;Value goes here&lt;/MyField&gt;&lt;/root&gt;", "ContentHtml"); // Content (XML)
            objCol.Add("my comment", "Comment"); // Comment field
            objCol.Add(0, "ContentID"); // Content ID (zero for new content)
            objCol.Add(2057, "ContentLanguage"); // UK English
            objCol.Add("my teaser", "ContentTeaser"); // Teaser / Summary field
            objCol.Add(72, "FolderID"); // Folder where content should be added to
            objCol.Add("my search text", "SearchText");
            objCol.Add("", "GoLive");
            objCol.Add("", "EndDate");
            objCol.Add(2, "EndDateAction");
            objCol.Add("my content title", "ContentTitle"); // Content title
            objCol.Add(true, "AddToQlink");
            objCol.Add(true, "IsSearchable");
            objCol.Add("7", "MultiXmlID"); // Smartform Id
        }

        long intContentId = 0;

        ContentAPI m_refContApi = new ContentAPI();

        // The old API uses current use by default, so switch to Internal Admin
        // in order to be able to add content.
        // Remember the ID of the original user so we can switch back to that again afterwards.
        long iOrig = m_refContApi.RequestInformationRef.CallerId;
        m_refContApi.RequestInformationRef.CallerId = 
          (long)Ektron.Cms.Common.EkEnumeration.UserGroups.InternalAdmin;
        m_refContApi.ContentLanguage = 2057;

        // Adds content, then checks it in
        intContentId = m_refContApi.EkContentRef.AddNewContentv2_0(objCol);
        m_refContApi.EkContentRef.CheckContentInv2_0(intContentId);

        // Set API back to original user ID
        m_refContApi.RequestInformationRef.CallerId = iOrig;
    }
}

Hopefully this code will save you having to dig through the old workarea code.

Aliased custom 404 error page

This article describes how to create a custom 404 error page in Ektron CMS that will return a HTTP status code 404, use a friendly aliased URL and give content authors the ability to change the content within the page.

Create the template

Create a new ASPX Web Form template called Error404.aspx (or something similar).  Add a ContentBlock to the HTML source view and set the DynamicParameter property to “id”.

Add the template to the CMS in the Settings > Configuration > Template Configuration section in the Ektron workarea.

Now create a new content item in the CMS and assign it to the Error404.aspx template that you created earlier.  Assign an alias to the content item, something like “/page-not-found/”.

Test the page loads of by browsing directly to /page-not-found/.

HTTP status code 404

Now you need to tell the template to return the correct HTTP status code.  At present it is returning a status code of 200 which means “success”.  This will cause search engines to incorrectly believe that your 404 page is actually valid content – in other words, it will be indexed and returned in Google’s results!

To prevent this, go to the code-behind file (this is in C# of course):

    protected void Page_PreRender(object sender, EventArgs e)
    {
        Response.TrySkipIisCustomErrors = true;
        Response.Status = "404 Not Found";
        Response.StatusCode = 404; 
    }

What this does is set the HTTP status code to be 404.  This will indicate to search engines that they have found a missing page so they will not index it.

You can test your page by browsing to an invalid page and seeing if the custom error page is returned.

Enable custom error handling

The next step is to tell .Net that we want to use a custom error page.  This is done within the web.config file like so :

    <system.web>      
      <customErrors mode="On">
          <error statusCode="404" redirect="/page-not-found/" />
      </customErrors>
    <system.web>

This tells .Net to send any “404 page not found” errors to an alias called “/page-not-found/”.

Problems with invalid aliases

You may find that your custom 404 error page isn’t being activated if you try to browse to an invalid alias.  What I have found is that you instead get a nasty server 500 error instead:

Server Error in Application “###”

Internet Information Services 7.5

Error Summary

HTTP Error 500.0 – Internal Server Error

Internal Server Error

Detailed Error Information

Module ManagedPipelineHandler
Notification ExecuteRequestHandler
Handler ExtensionlessUrlHandler-Integrated-4.0
Error Code 0x800703e9
Requested URL http://###:80/wibble/
Physical Path C:\inetpub\wwwroot\###\wibble\
Logon Method Forms
Logon User ###

Eeek!  Where is my custom error page?!?!

I discovered that the problem was due to an incorrect setting in my web.config file.  I needed to remove a handler called “ExtensionlessUrlHandler-Integrated-4.0”, like so :

<system.webServer>
    <handlers>
        <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
    </handers> 
</system.webServer>

(Please note I am using IIS 7)

By removing this HTTP handler it allows the request to be passed through to your custom 404 error page instead.

URL Redirects with Ektron 8.6

One of the new features of Ektron version 8.6 is to allow CMS administrators to define URL redirects from within the CMS itself.  Prior to 8.6 this could only be done by setting up redirects in IIS – this made it more of an IT/Server administrator role instead.

To access the new feature follow these steps :

  1. Open the workarea and browse to the Settings > Configuration > URL Aliasing section.
  2. Click Settings.
  3. Click Edit.
  4. Tick the checkbox labelled “Enable URL Redirects”.
  5. A new option will now appear in the URL Aliasing folder called “Redirects”.
  6. Click Redirects.
  7. Click  the “Add Redirect” button.
  8. You have the following options:
  • Choose which website the redirect is applied to.
  • Choose the redirect code.  This is an important SEO (Search Engine Optimisation) factor.  The “301 Permanent Redirect” is often used when moving content to a new website; it is used to tell search engines that a page which used to live in one place has now moved permanently to another.  The idea is that search engines won’t visit the old URL again and will instead visit the new one.
  • You may also set the new and original URLs.

Setting up redirects is a useful tool in preventing users and search engines from hitting dead links on your site.  Typically these dead links are introduced when you move to a new website or to a new CMS.

 

Add a PageBuilder page using the Ektron API

Pagebuilder pages are an Ektron feature that allow content authors to create flexible web pages by dragging and dropping widgets onto the page.  A widget is a module that can be added to a web page which provides a specific purpose such as an image, video, form or a block of HTML text.

There might be instances in which, during the course of a project, it becomes necessary to add pages into the CMS en masse, for instance, during a content migration excercise.

The following block of code below will allow you to create a Pagebuilder page and add a widget into it.

EDIT: Updated as original code sample wasn’t verbose enough
The code adds an Ektron ContentBlock control to the page.

long folderId = 86; // where to add the page to
var tmpPageData = new PageData(); // temporary object for page config

string controlUrl = "ContentBlock.ascx"; // name of the widget user control in widgets folder
string dropZoneId = "Middle"; // id of the DropZone control on the wireframe

var widget = new WidgetData
{
ControlURL = controlUrl,
ColumnID = 0,
Order = 0,
Minimized = false,
DropID = dropZoneId,
Settings = String.Format("{0}", 30);
};

tmpPageData.Widgets = new List(); // initialise widgetdata list on page
tmpPageData.Widgets.Add(widget); // add ContentBlock widget to page

// Create a drop zone data object
var dropZoneMain = new DropZoneData {DropZoneID = "Middle", Columns = new List()};

// Create a column data object
var columnDataMain = new ColumnData {columnID = 0, width = 100, unit = Units.percent};

// Add the column to the drop zone
dropZoneMain.Columns.Add(columnDataMain);

// Add the drop zone to the page
tmpPageData.Zones = new List {dropZoneMain};
tmpPageData.IsMasterLayout = false;

// Call a method to add the page (see method below)
AddPage(gameToPush.Title, gameToPush.Alias, folderId, 2, tmpPageData, 2057);

So the process above is add widgets to the PageData.Widgets property then add the Drop Zones to the PageData.Zones property (which also includes Columns).

The above code depends upon a method called “AddPage()” which is given below:

private void AddPage(string pageTitle, string alias, long folderId, long wireFrameId,
Ektron.Cms.PageBuilder.PageData pageData, int langId = 2057,
ContentMetaData[] metaData = null)
{

    var pageManager = new PageModel();
    var contentManagerOld = new Ektron.Cms.API.Content.Content();
    pageManager.RequestInformation = contentManagerOld.RequestInformationRef;

    var tmpPageData = new PageData();

    // First create the page entity in the CMS
    pageManager.Create(pageTitle, folderId, alias, langId, wireFrameId, String.Empty, "summary", out tmpPageData, true);

    // Assign widgets and drop zones
    tmpPageData.Widgets = pageData.Widgets;
    tmpPageData.Zones = pageData.Zones;

    // Save to the CMS
    pageManager.CheckIn(tmpPageData);
    pageManager.Publish(tmpPageData);

    // Assign metadata
    if (tmpPageData.pageID > 0)
    {
        if (metaData != null)
        {
            if (metaData.Length > 0)
            {
                contentManagerOld.ContentLanguage = langId;

                foreach (ContentMetaData meta in metaData)
                {
                    contentManagerOld.UpdateContentMetaData(tmpPageData.pageID, meta.Id, meta.Text);
                }
            }
        }
    }
}

At first glance this seems a bit counter-intuitive.  The addition of widgets and drop zones to the page is done separately, whereas you may have thought that widgets go into columns which go into zones which go pages.  In fact the widgets and zones are accessed through different properties as you can see above.